backport 3.1 branch to default (duh...)
authorsylvain.thenault@logilab.fr
Wed, 15 Apr 2009 17:36:09 +0200
changeset 1374 9d61b146f505
parent 1355 8a3102fb4760 (diff)
parent 1371 a81d3babb582 (current diff)
child 1377 6c079ce26fa3
backport 3.1 branch to default (duh...)
--- a/.hgtags	Thu Jan 15 10:13:25 2009 +0100
+++ b/.hgtags	Wed Apr 15 17:36:09 2009 +0200
@@ -12,3 +12,17 @@
 18d3e56c1de4a6597ab36536964bc66b5550cf98 cubicweb-debian-version-3_0_2-1
 0cb027c056f939ec3580ea1cc0aeda9f9884f0fa cubicweb-version-3_0_3
 a736bae56d4a703a26933fb9875fb9caab216c6b cubicweb-debian-version-3_0_3-1
+2e400b8dfc25ae30db602f64601e30e210b3fade cubicweb-version-3_0_4
+fc222bc99929d395c1c2235c40d3bb6f247b4ba9 cubicweb-debian-version-3_0_4-1
+7ad527099393ef56f27af313392022bb8ed73082 cubicweb-version-3_0_9
+a8e9e53b245d53838a07aa8c76d1bed352692a9f cubicweb-debian-version-3_0_9-1
+a711c7c185d15a1bd22b7eaab46a26b98b74fbf3 cubicweb-version-3_1_0
+dd3efdf58d281286d6f52f7416db349b75b7789c cubicweb-debian-version-3_1_0-1
+ce8094084165419ff1717bdb2f426574bcaaad93 cubicweb-version-3_1_1
+dfaedb0bba88e3a4e931948bb0c6a9587269303f cubicweb-debian-version-3_1_1-1
+a9ba200ab15098704a6255387c558c02488551c6 cubicweb-version-3_1_2
+a823124b812f4fa494bfceb773f3ca1cd00407e8 cubicweb-debian-version-3_1_2-1
+a5dc91adb7c133f83f5ad9cceb07bc246d21ed01 cubicweb-version-3_1_3
+9e98dec0768b87363a7826a04636dc161ed0ec7d cubicweb-debian-version-3_1_3-1
+e0e0a1c3d80f4fbf4bbd55066278e467b75df8a4 cubicweb-version-3_1_4
+0e132fbae9cc5e004f4b79a8b842addad43519a7 cubicweb-debian-version-3_1_4-1
--- a/MANIFEST.in	Thu Jan 15 10:13:25 2009 +0100
+++ b/MANIFEST.in	Wed Apr 15 17:36:09 2009 +0200
@@ -25,6 +25,6 @@
 recursive-include web/test/data *.js *.css *.png *.gif *.jpg *.ico external_resources
 recursive-include devtools/test/data *
 
-recursive-include skeleton *.py*.css *.js *.po compat *.in *.tmpl 
+recursive-include skeleton *.py *.css *.js *.po compat *.in *.tmpl
 
 prune misc/cwfs
--- a/__init__.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/__init__.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,9 +2,9 @@
 relations between entitites.
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: General Public License version 2 - http://www.gnu.org/licenses
+:license: Library General Public License version 2 - http://www.gnu.org/licenses
 """
 __docformat__ = "restructuredtext en"
 from cubicweb.__pkginfo__ import version as __version__
--- a/__pkginfo__.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/__pkginfo__.py	Wed Apr 15 17:36:09 2009 +0200
@@ -6,11 +6,11 @@
 distname = "cubicweb"
 modname = "cubicweb"
 
-numversion = (3, 0, 3)
+numversion = (3, 1, 5)
 version = '.'.join(str(num) for num in numversion)
 
-license = 'LCL'
-copyright = '''Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE).
+license = 'LGPL v2'
+copyright = '''Copyright (c) 2003-2009 LOGILAB S.A. (Paris, FRANCE).
 http://www.logilab.fr/ -- mailto:contact@logilab.fr'''
 
 author = "Logilab"
@@ -27,11 +27,12 @@
 * a bunch of other management tools
 """
 
-web = ''
-ftp = ''
-pyversions = ['2.4']
+web = 'http://www.cubicweb.org'
+ftp = 'ftp://ftp.logilab.org/pub/cubicweb'
+pyversions = ['2.4', '2.5']
 
 
+import sys
 from os import listdir, environ
 from os.path import join, isdir
 import glob
@@ -60,7 +61,8 @@
     # --home install
     pydir = 'python'
 else:
-    pydir = join('python2.4', 'site-packages')
+    python_version = '.'.join(str(num) for num in sys.version_info[0:2])
+    pydir = join('python' + python_version, 'site-packages')
 
 try:
     data_files = [
@@ -90,7 +92,6 @@
         [join('share', 'cubicweb', 'cubes', 'shared', 'i18n'),
          [join(i18n_dir, fname) for fname in listdir(i18n_dir)]],
         # skeleton
-        
         ]
 except OSError:
     # we are in an installed directory, don't care about this
--- a/_exceptions.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/_exceptions.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
--- a/common/appobject.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/appobject.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """Base class for dynamically loaded objects manipulated in the web interface
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -12,6 +12,8 @@
 from simplejson import dumps
 
 from logilab.common.deprecation import obsolete
+
+from rql.nodes import VariableRef, SubQuery
 from rql.stmts import Union, Select
 
 from cubicweb import Unauthorized
--- a/common/entity.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/entity.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """Base class for entity objects manipulated in clients
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -41,6 +41,8 @@
                                'inlineview'))
 
     def __init__(self, eclass, tagdefs):
+        # XXX if a rtag is redefined in a subclass,
+        # the rtag of the base class overwrite the rtag of the subclass
         self.eclass = eclass
         self._tagdefs = {}
         for relation, tags in tagdefs.iteritems():
@@ -391,6 +393,10 @@
         res['source'] = self.req.source_defs()[res['source']]
         return res
 
+    def clear_local_perm_cache(self, action):
+        for rqlexpr in self.e_schema.get_rqlexprs(action):
+            self.req.local_perm_cache.pop((rqlexpr.eid, (('x', self.eid),)), None)
+
     def check_perm(self, action):
         self.e_schema.check_perm(self.req, action, self.eid)
 
@@ -998,6 +1004,7 @@
         _done.add(self.eid)
         containers = tuple(self.e_schema.fulltext_containers())
         if containers:
+            yielded = False
             for rschema, target in containers:
                 if target == 'object':
                     targets = getattr(self, rschema.type)
@@ -1008,6 +1015,9 @@
                         continue
                     for container in entity.fti_containers(_done):
                         yield container
+                        yielded = True
+            if not yielded:
+                yield self
         else:
             yield self
                     
--- a/common/migration.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/migration.py	Wed Apr 15 17:36:09 2009 +0200
@@ -312,12 +312,18 @@
         """a configuration option's type has changed"""
         self._option_changes.append(('typechanged', optname, oldtype, newvalue))
         
-    def cmd_add_cube(self, cube):
+    def cmd_add_cubes(self, cubes):
+        """modify the list of used cubes in the in-memory config
+        returns newly inserted cubes, including dependencies
+        """
+        if isinstance(cubes, basestring):
+            cubes = (cubes,)
         origcubes = self.config.cubes()
-        newcubes = [p for p in self.config.expand_cubes([cube]) 
+        newcubes = [p for p in self.config.expand_cubes(cubes) 
                        if not p in origcubes]
         if newcubes:
-            assert cube in newcubes
+            for cube in cubes:
+                assert cube in newcubes
             self.config.add_cubes(newcubes)
         return newcubes
 
@@ -346,7 +352,7 @@
             if optdescr[0] == 'added':
                 optdict = self.config.get_option_def(optdescr[1])
                 if optdict.get('default') is REQUIRED:
-                    self.config.input_option(option, optdict)
+                    self.config.input_option(optdescr[1], optdict)
         self.config.generate_config(open(newconfig, 'w'))
         show_diffs(configfile, newconfig)
         if exists(newconfig):
--- a/common/mixins.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/mixins.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -145,7 +145,6 @@
         return self.iterchildren()
 
     def is_leaf(self):
-        print '*' * 80
         return len(self.children()) == 0
 
     def is_root(self):
@@ -165,21 +164,25 @@
     
     @property
     def state(self):
-        return self.in_state[0].name
+        try:
+            return self.in_state[0].name
+        except IndexError:
+            self.warning('entity %s has no state', self)
+            return None
     
     @property
     def displayable_state(self):
         return self.req._(self.state)
 
     def wf_state(self, statename):
-        rset = self.req.execute('Any S, SN WHERE S name %(n)s, S state_of E, E name %(e)s',
+        rset = self.req.execute('Any S, SN WHERE S name SN, S name %(n)s, S state_of E, E name %(e)s',
                                 {'n': statename, 'e': str(self.e_schema)})
         if rset:
             return rset.get_entity(0, 0)
         return None
     
     def wf_transition(self, trname):
-        rset = self.req.execute('Any T, TN WHERE T name %(n)s, T transition_of E, E name %(e)s',
+        rset = self.req.execute('Any T, TN WHERE T name TN, T name %(n)s, T transition_of E, E name %(e)s',
                                 {'n': trname, 'e': str(self.e_schema)})
         if rset:
             return rset.get_entity(0, 0)
@@ -189,6 +192,7 @@
         """change the entity's state according to a state defined in given
         parameters
         """
+        assert not isinstance(stateeid, basestring), 'change_state wants a state eid'
         if trcomment:
             self.req.set_shared_data('trcomment', trcomment)
         if trcommentformat:
@@ -366,22 +370,18 @@
     """provide default implementations for IProgress interface methods"""
 
     @property
-    @cached
     def cost(self):
         return self.progress_info()['estimated']
 
     @property
-    @cached
     def revised_cost(self):
         return self.progress_info().get('estimatedcorrected', self.cost)
 
     @property
-    @cached
     def done(self):
         return self.progress_info()['done']
 
     @property
-    @cached
     def todo(self):
         return self.progress_info()['todo']
 
@@ -400,6 +400,6 @@
             return 100. * self.done / self.revised_cost
         except ZeroDivisionError:
             # total cost is 0 : if everything was estimated, task is completed
-            if self.progress_info().get('notestmiated'):
+            if self.progress_info().get('notestimated'):
                 return 0.
             return 100
--- a/common/registerers.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/registerers.py	Wed Apr 15 17:36:09 2009 +0200
@@ -101,6 +101,8 @@
     def equivalent(self, other):
         if _accepts_interfaces(self.vobject) != _accepts_interfaces(other):
             return False
+        if getattr(self.vobject, 'require_groups', ()) != getattr(other, 'require_groups', ()):
+            return False
         try:
             newaccepts = list(other.accepts)
             for etype in self.vobject.accepts:
--- a/common/rest.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/rest.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,9 +1,19 @@
 """rest publishing functions
 
-contains some functions and setup of docutils for cubicweb
+contains some functions and setup of docutils for cubicweb. Provides the
+following ReST directives:
+
+* `eid`, create link to entity in the repository by their eid
+
+* `card`, create link to card entity in the repository by their wikiid
+  (proposing to create it when the refered card doesn't exist yet)
+
+* `winclude`, reference to a web documentation file (in wdoc/ directories)
+
+* `sourcecode` (if pygments is installed), source code colorization
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -156,6 +166,36 @@
                               'encoding': directives.encoding}
 directives.register_directive('winclude', winclude_directive)
 
+try:
+    from pygments import highlight
+    from pygments.lexers import get_lexer_by_name, LEXERS
+    from pygments.formatters import HtmlFormatter
+except ImportError:
+    pass
+else:
+    _PYGMENTS_FORMATTER = HtmlFormatter()
+
+    def pygments_directive(name, arguments, options, content, lineno,
+                           content_offset, block_text, state, state_machine):
+        try:
+            lexer = get_lexer_by_name(arguments[0])
+        except ValueError:
+            import traceback
+            traceback.print_exc()
+            print sorted(aliases for module_name, name, aliases, _, _  in LEXERS.itervalues())
+            # no lexer found
+            lexer = get_lexer_by_name('text')
+        print 'LEXER', lexer
+        parsed = highlight(u'\n'.join(content), lexer, _PYGMENTS_FORMATTER)
+        context = state.document.settings.context
+        context.req.add_css('pygments.css')
+        return [nodes.raw('', parsed, format='html')]
+     
+    pygments_directive.arguments = (1, 0, 1)
+    pygments_directive.content = 1
+    directives.register_directive('sourcecode', pygments_directive)
+
+
 class CubicWebReSTParser(Parser):
     """The (customized) reStructuredText parser."""
 
--- a/common/selectors.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/selectors.py	Wed Apr 15 17:36:09 2009 +0200
@@ -20,12 +20,12 @@
 above by::
 
     # in Python2.5
-    from cubicweb.selectors import traced_selection
+    from cubicweb.common.selectors import traced_selection
     with traced_selection():
         self.view('calendar', myrset)
 
     # in Python2.4
-    from cubicweb import selectors
+    from cubicweb.common import selectors
     selectors.TRACED_OIDS = ('calendar',)
     self.view('calendar', myrset)
     selectors.TRACED_OIDS = ()
@@ -50,7 +50,6 @@
 from cubicweb.cwconfig import CubicWebConfiguration
 from cubicweb.schema import split_expression
 
-
 # helpers for debugging selectors
 SELECTOR_LOGGER = logging.getLogger('cubicweb.selectors')
 TRACED_OIDS = ()
@@ -62,8 +61,9 @@
     def traced(cls, *args, **kwargs):
         ret = selector(cls, *args, **kwargs)
         if TRACED_OIDS == 'all' or cls.id in TRACED_OIDS:
-            SELECTOR_LOGGER.warning('selector %s returned %s for %s', selector.__name__, ret, cls)
+            SELECTOR_LOGGER.critical('selector %s returned %s for %s', selector.__name__, ret, cls)
         return ret
+    traced.__name__ = selector.__name__
     return traced
 
 class traced_selection(object):
@@ -110,12 +110,12 @@
 norset_selector = deprecated_function(none_rset)
 
 @lltrace
-def rset(cls, req, rset, *args, **kwargs):
+def any_rset(cls, req, rset, *args, **kwargs):
     """accept result set, whatever the number of result"""
     if rset is not None:
         return 1
     return 0
-rset_selector = deprecated_function(rset)
+rset_selector = deprecated_function(any_rset)
 
 @lltrace
 def nonempty_rset(cls, req, rset, *args, **kwargs):
@@ -161,13 +161,20 @@
 def paginated_rset(cls, req, rset, *args, **kwargs):
     """accept result sets with more rows than the page size
     """
-    if rset is None or len(rset) <= req.property_value('navigation.page-size'):
+    page_size = kwargs.get('page_size')
+    if page_size is None:
+        page_size = req.form.get('page_size')
+        if page_size is None:
+            page_size = req.property_value('navigation.page-size')
+        else:
+            page_size = int(page_size)
+    if rset is None or len(rset) <= page_size:
         return 0
     return 1
 largerset_selector = deprecated_function(paginated_rset)
 
 @lltrace
-def sorted_rset(cls, req, rset, row=None, col=None):
+def sorted_rset(cls, req, rset, row=None, col=None, **kwargs):
     """accept sorted result set"""
     rqlst = rset.syntax_tree()
     if len(rqlst.children) > 1 or not rqlst.children[0].orderby:
@@ -222,7 +229,7 @@
 @lltrace
 def authenticated_user(cls, req, *args, **kwargs):
     """accept if user is authenticated"""
-    return not anonymous_selector(cls, req, *args, **kwargs)
+    return not anonymous_user(cls, req, *args, **kwargs)
 not_anonymous_selector = deprecated_function(authenticated_user)
 
 @lltrace
@@ -499,7 +506,7 @@
     propval = req.property_value('%s.%s.context' % (cls.__registry__, cls.id))
     if not propval:
         propval = cls.context
-    if context is not None and propval is not None and context != propval:
+    if context is not None and propval and context != propval:
         return 0
     return 1
 contextprop_selector = deprecated_function(match_context_prop)
@@ -529,28 +536,36 @@
 # compound selectors ##########################################################
 
 non_final_entity = chainall(nonempty_rset, _non_final_entity)
+non_final_entity.__name__ = 'non_final_entity'
 nfentity_selector = deprecated_function(non_final_entity)
 
 implement_interface = chainall(non_final_entity, _implement_interface)
+implement_interface.__name__ = 'implement_interface'
 interface_selector = deprecated_function(implement_interface)
 
 accept = chainall(non_final_entity, accept_rset)
+accept.__name__ = 'accept'
 accept_selector = deprecated_function(accept)
 
-accept_one = chainall(one_line_rset, accept_selector)
+accept_one = chainall(one_line_rset, accept)
+accept_one.__name__ = 'accept_one'
 accept_one_selector = deprecated_function(accept_one)
 
 rql_condition = chainall(non_final_entity, one_line_rset, _rql_condition)
+rql_condition.__name__ = 'rql_condition'
 rqlcondition_selector = deprecated_function(rql_condition)
 
 
 searchstate_accept = chainall(nonempty_rset, match_search_state, accept)
+searchstate_accept.__name__ = 'searchstate_accept'
 searchstate_accept_selector = deprecated_function(searchstate_accept)
 
 searchstate_accept_one = chainall(one_line_rset, match_search_state,
                                   accept, _rql_condition)
+searchstate_accept_one.__name__ = 'searchstate_accept_one'
 searchstate_accept_one_selector = deprecated_function(searchstate_accept_one)
 
 searchstate_accept_one_but_etype = chainall(searchstate_accept_one, but_etype)
+searchstate_accept_one_but_etype.__name__ = 'searchstate_accept_one_but_etype'
 searchstate_accept_one_but_etype_selector = deprecated_function(
     searchstate_accept_one_but_etype)
--- a/common/test/unittest_entity.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/test/unittest_entity.py	Wed Apr 15 17:36:09 2009 +0200
@@ -250,8 +250,7 @@
         self.assertListEquals(rbc(e.relations_by_category('generic')),
                               [('primary_email', 'subject'),
                                ('evaluee', 'subject'),
-                               ('for_user', 'object'),
-                               ('bookmarked_by', 'object')])
+                               ('for_user', 'object')])
         # owned_by is defined both as subject and object relations on EUser
         self.assertListEquals(rbc(e.relations_by_category('generated')),
                               [('last_login_time', 'subject'),
@@ -263,7 +262,8 @@
                                ('owned_by', 'subject'),
                                ('created_by', 'object'),
                                ('wf_info_for', 'object'),
-                               ('owned_by', 'object')])
+                               ('owned_by', 'object'),
+                               ('bookmarked_by', 'object')])
         e = self.etype_instance('Personne')
         self.assertListEquals(rbc(e.relations_by_category('primary')),
                               [('nom', 'subject'), ('eid', 'subject')])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/test/unittest_mixins.py	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,25 @@
+from logilab.common.testlib import unittest_main
+from cubicweb.devtools.apptest import EnvBasedTC
+
+class WorkfloableMixInTC(EnvBasedTC):
+    def test_wf_state(self):
+        s = self.add_entity('State', name=u'activated')
+        self.execute('SET X state_of ET WHERE ET name "Bookmark", X eid %(x)s',
+                     {'x': s.eid})
+        es = self.user().wf_state('activated')
+        self.assertEquals(es.state_of[0].name, 'EUser')
+        
+    def test_wf_transition(self):
+        t = self.add_entity('Transition', name=u'deactivate')
+        self.execute('SET X transition_of ET WHERE ET name "Bookmark", X eid %(x)s',
+                     {'x': t.eid})
+        et = self.user().wf_transition('deactivate')
+        self.assertEquals(et.transition_of[0].name, 'EUser')
+
+    def test_change_state(self):
+        user = self.user()
+        user.change_state(user.wf_state('deactivated').eid)
+        self.assertEquals(user.state, 'deactivated')
+    
+if __name__ == '__main__':
+    unittest_main()
--- a/common/uilib.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/uilib.py	Wed Apr 15 17:36:09 2009 +0200
@@ -4,7 +4,7 @@
 contains some functions designed to help implementation of cubicweb user interface
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -180,21 +180,27 @@
             if add_ellipsis:
                 return text + u'...'
             return text
-        
-def text_cut(text, nbwords=30):
+
+def text_cut(text, nbwords=30, gotoperiod=True):
     """from the given plain text, return a text with at least <nbwords> words,
     trying to go to the end of the current sentence.
 
+    :param nbwords: the minimum number of words required
+    :param gotoperiod: specifies if the function should try to go to
+                       the first period after the cut (i.e. finish
+                       the sentence if possible)
+
     Note that spaces are normalized.
     """
     if text is None:
         return u''
     words = text.split()
-    text = ' '.join(words) # normalize spaces
-    minlength = len(' '.join(words[:nbwords]))
-    textlength = text.find('.', minlength) + 1
-    if textlength == 0: # no point found
-        textlength = minlength 
+    text = u' '.join(words) # normalize spaces
+    textlength = minlength = len(' '.join(words[:nbwords]))
+    if gotoperiod:
+        textlength = text.find('.', minlength) + 1
+        if textlength == 0: # no period found
+            textlength = minlength
     return text[:textlength]
 
 def cut(text, length):
@@ -213,6 +219,21 @@
     
 # HTML generation helper functions ############################################
 
+def simple_sgml_tag(tag, content=None, **attrs):
+    """generation of a simple sgml tag (eg without children tags) easier
+
+    content and attributes will be escaped
+    """
+    value = u'<%s' % tag
+    if attrs:
+        value += u' ' + u' '.join(u'%s="%s"' % (attr, html_escape(unicode(value)))
+                                  for attr, value in attrs.items())
+    if content:
+        value += u'>%s</%s>' % (html_escape(unicode(content)), tag)
+    else:
+        value += u'/>'
+    return value
+
 def tooltipize(text, tooltip, url=None):
     """make an HTML tooltip"""
     url = url or '#'
--- a/common/view.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/common/view.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -28,9 +28,9 @@
   <!ATTLIST html xmlns:cubicweb CDATA  #FIXED \'http://www.logilab.org/2008/cubicweb\'  >
 
 <!ENTITY % coreattrs
- "id          ID             #IMPLIED
-  class       CDATA          #IMPLIED
-  style       CDATA   #IMPLIED
+ "id          ID            #IMPLIED
+  class       CDATA         #IMPLIED
+  style       CDATA         #IMPLIED
   title       CDATA         #IMPLIED
 
  cubicweb:sortvalue         CDATA   #IMPLIED
@@ -53,12 +53,14 @@
  cubicweb:vid               CDATA   #IMPLIED
  cubicweb:rql               CDATA   #IMPLIED
  cubicweb:actualrql         CDATA   #IMPLIED
- cubicweb:rooteid           CDATA   #IMPLIED   
+ cubicweb:rooteid           CDATA   #IMPLIED
  cubicweb:dataurl           CDATA   #IMPLIED
- cubicweb:size              CDATA   #IMPLIED   
+ cubicweb:size              CDATA   #IMPLIED
  cubicweb:tlunit            CDATA   #IMPLIED
  cubicweb:loadurl           CDATA   #IMPLIED
  cubicweb:uselabel          CDATA   #IMPLIED
+ cubicweb:facetargs         CDATA   #IMPLIED
+ cubicweb:facetName         CDATA   #IMPLIED
   "> ] '''
 
 TRANSITIONAL_DOCTYPE = u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" %s>\n'
@@ -71,7 +73,7 @@
 
     A view is instantiated to render a [part of a] result set. View
     subclasses may be parametred using the following class attributes:
-    
+
     * `templatable` indicates if the view may be embeded in a main
       template or if it has to be rendered standalone (i.e. XML for
       instance)
@@ -85,14 +87,14 @@
     time to a write function to use.
     """
     __registry__ = 'views'
-    
+
     templatable = True
     need_navigation = True
     # content_type = 'application/xhtml+xml' # text/xhtml'
     binary = False
     add_to_breadcrumbs = True
     category = 'view'
-    
+
     def __init__(self, req, rset):
         super(View, self).__init__(req, rset)
         self.w = None
@@ -102,7 +104,7 @@
         if self.req.xhtml_browser():
             return 'application/xhtml+xml'
         return 'text/html'
-    
+
     def set_stream(self, w=None):
         if self.w is not None:
             return
@@ -118,14 +120,14 @@
         return stream
 
     # main view interface #####################################################
-            
+
     def dispatch(self, w=None, **context):
         """called to render a view object for a result set.
 
         This method is a dispatched to an actual method selected
         according to optional row and col parameters, which are locating
         a particular row or cell in the result set:
-        
+
         * if row [and col] are specified, `cell_call` is called
         * if none of them is supplied, the view is considered to apply on
           the whole result set (which may be None in this case), `call` is
@@ -147,7 +149,7 @@
     # should default .call() method add a <div classs="section"> around each
     # rset item
     add_div_section = True
-    
+
     def call(self, **kwargs):
         """the view is called for an entire result set, by default loop
         other rows of the result set and call the same view on the
@@ -169,10 +171,10 @@
     def cell_call(self, row, col, **kwargs):
         """the view is called for a particular result set cell"""
         raise NotImplementedError, self
-        
+
     def linkable(self):
         """return True if the view may be linked in a menu
-        
+
         by default views without title are not meant to be displayed
         """
         if not getattr(self, 'title', None):
@@ -181,7 +183,7 @@
 
     def is_primary(self):
         return self.id == 'primary'
-    
+
     def url(self):
         """return the url associated with this view. Should not be
         necessary for non linkable views, but a default implementation
@@ -197,7 +199,7 @@
         self.req.set_content_type(self.content_type)
 
     # view utilities ##########################################################
-    
+
     def view(self, __vid, rset, __fallback_vid=None, **kwargs):
         """shortcut to self.vreg.render method avoiding to pass self.req"""
         try:
@@ -207,7 +209,7 @@
                 raise
             view = self.vreg.select_view(__fallback_vid, self.req, rset, **kwargs)
         return view.dispatch(**kwargs)
-    
+
     def wview(self, __vid, rset, __fallback_vid=None, **kwargs):
         """shortcut to self.view method automatically passing self.w as argument
         """
@@ -234,7 +236,7 @@
             label = label or self.req._(action.title)
             return u'<a href="%s">%s</a>' % (html_escape(action.url()), label)
         return u''
-    
+
     def html_headers(self):
         """return a list of html headers (eg something to be inserted between
         <head> and </head> of the returned page
@@ -242,7 +244,7 @@
         by default return a meta tag to disable robot indexation of the page
         """
         return [NOINDEX]
-    
+
     def page_title(self):
         """returns a title according to the result set - used for the
         title in the HTML header
@@ -292,7 +294,7 @@
         """ return the url of the entity creation form for a given entity type"""
         return self.req.build_url('add/%s'%etype, **kwargs)
 
-        
+
 # concrete views base classes #################################################
 
 class EntityView(View):
@@ -300,8 +302,9 @@
     """
     __registerer__ = accepts_registerer
     __selectors__ = (accept,)
+    accepts = ('Any',)
     category = 'entityview'
-    
+
     def field(self, label, value, row=True, show_label=True, w=None, tr=True):
         """ read-only field """
         if w is None:
@@ -316,7 +319,7 @@
         if row:
             w(u'</div>')
 
-        
+
 class StartupView(View):
     """base class for views which doesn't need a particular result set
     to be displayed (so they can always be displayed !)
@@ -325,7 +328,7 @@
     __selectors__ = (match_user_group, none_rset)
     require_groups = ()
     category = 'startupview'
-    
+
     def url(self):
         """return the url associated with this view. We can omit rql here"""
         return self.build_url('view', vid=self.id)
@@ -345,9 +348,9 @@
     """
     __registerer__ = accepts_registerer
     __selectors__ = (chainfirst(none_rset, accept),)
-    
+
     default_rql = None
-    
+
     def __init__(self, req, rset):
         super(EntityStartupView, self).__init__(req, rset)
         if rset is None:
@@ -357,7 +360,7 @@
     def startup_rql(self):
         """return some rql to be executedif the result set is None"""
         return self.default_rql
-    
+
     def call(self, **kwargs):
         """override call to execute rql returned by the .startup_rql
         method if necessary
@@ -376,14 +379,14 @@
             return self.build_url(vid=self.id)
         return super(EntityStartupView, self).url()
 
-    
+
 class AnyRsetView(View):
     """base class for views applying on any non empty result sets"""
     __registerer__ = priority_registerer
     __selectors__ = (nonempty_rset,)
-    
+
     category = 'anyrsetview'
-    
+
     def columns_labels(self, tr=True):
         if tr:
             translate = display_name
@@ -400,7 +403,7 @@
                 label = translate(self.req, attr)
             labels.append(label)
         return labels
-    
+
 
 class EmptyRsetView(View):
     """base class for views applying on any empty result sets"""
@@ -419,7 +422,7 @@
     __selectors__ = (match_user_group,)
 
     require_groups = ()
-    
+
     def template(self, oid, **kwargs):
         """shortcut to self.registry.render method on the templates registry"""
         w = kwargs.pop('w', self.w)
--- a/cwconfig.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/cwconfig.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 """common configuration utilities for cubicweb
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -10,7 +10,7 @@
 import sys
 import os
 import logging
-from os.path import exists, join, expanduser, abspath, basename
+from os.path import exists, join, expanduser, abspath, normpath, basename, isdir
 
 from logilab.common.decorators import cached
 from logilab.common.logging_ext import set_log_methods, init_log
@@ -148,9 +148,11 @@
     if os.environ.get('APYCOT_ROOT'):
         mode = 'test'
         CUBES_DIR = '%(APYCOT_ROOT)s/local/share/cubicweb/cubes/' % os.environ
+        # create __init__ file
+        file(join(CUBES_DIR, '__init__.py'), 'w').close()
     elif exists(join(CW_SOFTWARE_ROOT, '.hg')):
         mode = 'dev'
-        CUBES_DIR = join(CW_SOFTWARE_ROOT, '../cubes')
+        CUBES_DIR = abspath(normpath(join(CW_SOFTWARE_ROOT, '../cubes')))
     else:
         mode = 'installed'
         CUBES_DIR = '/usr/share/cubicweb/cubes/'
@@ -223,7 +225,7 @@
         """
         if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'):
             return join(CW_SOFTWARE_ROOT, 'web')
-        return join(cls.cubes_dir(), 'shared')
+        return cls.cube_dir('shared')
         
     @classmethod
     def i18n_lib_dir(cls):
@@ -234,26 +236,38 @@
 
     @classmethod
     def available_cubes(cls):
-        cubes_dir = cls.cubes_dir()
-        return sorted(cube for cube in os.listdir(cubes_dir)
-                      if os.path.isdir(os.path.join(cubes_dir, cube))
-                      and not cube in ('CVS', '.svn', 'shared', '.hg'))
+        cubes = set()
+        for directory in cls.cubes_search_path():
+            for cube in os.listdir(directory):
+                if isdir(join(directory, cube)) and not cube in ('CVS', '.svn', 'shared', '.hg'):
+                    cubes.add(cube)
+        return sorted(cubes)
     
     @classmethod
-    def cubes_dir(cls):
-        """return the application cubes directory"""
-        return env_path('CW_CUBES', cls.CUBES_DIR, 'cubes')
+    def cubes_search_path(cls):
+        """return the path of directories where cubes should be searched"""
+        path = []
+        try:
+            for directory in os.environ['CW_CUBES_PATH'].split(os.pathsep):
+                directory = abspath(normpath(directory))
+                if exists(directory) and not directory in path:
+                    path.append(directory)
+        except KeyError:
+            pass
+        if not cls.CUBES_DIR in path:
+            path.append(cls.CUBES_DIR)
+        return path
     
     @classmethod
     def cube_dir(cls, cube):
         """return the cube directory for the given cube id,
         raise ConfigurationError if it doesn't exists
         """
-        cube_dir = join(cls.cubes_dir(), cube)
-        if not exists(cube_dir):
-            raise ConfigurationError('no cube %s in %s' % (
-                cube, cls.cubes_dir()))
-        return cube_dir
+        for directory in cls.cubes_search_path():
+            cubedir = join(directory, cube)
+            if exists(cubedir):
+                return cubedir
+        raise ConfigurationError('no cube %s in %s' % (cube, cls.cubes_search_path()))
 
     @classmethod
     def cube_migration_scripts_dir(cls, cube):
@@ -339,12 +353,14 @@
     @classmethod
     def cls_adjust_sys_path(cls):
         """update python path if necessary"""
+        cubes_parent_dir = normpath(join(cls.CUBES_DIR, '..'))
+        if not cubes_parent_dir in sys.path:
+            sys.path.insert(0, cubes_parent_dir)
         try:
-            templdir = abspath(join(cls.cubes_dir(), '..'))
-            if not templdir in sys.path:
-                sys.path.insert(0, templdir)
-        except ConfigurationError:
-            return # cube dir doesn't exists
+            import cubes
+            cubes.__path__ = cls.cubes_search_path()
+        except ImportError:
+            return # cubes dir doesn't exists
 
     @classmethod
     def load_cwctl_plugins(cls):
@@ -356,10 +372,9 @@
             if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
                 load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
                 cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
-        templdir = cls.cubes_dir()
         for cube in cls.available_cubes():
-            pluginfile = join(templdir, cube, 'ecplugin.py')
-            initfile = join(templdir, cube, '__init__.py')
+            pluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
+            initfile = join(cls.cube_dir(cube), '__init__.py')
             if exists(pluginfile):
                 try:
                     __import__('cubes.%s.ecplugin' % cube)
@@ -486,17 +501,16 @@
 class CubicWebConfiguration(CubicWebNoAppConfiguration):
     """base class for cubicweb server and web configurations"""
     
+    INSTANCE_DATA_DIR = None
     if CubicWebNoAppConfiguration.mode == 'test':
         root = os.environ['APYCOT_ROOT']
         REGISTRY_DIR = '%s/etc/cubicweb.d/' % root
-        INSTANCE_DATA_DIR = REGISTRY_DIR
         RUNTIME_DIR = '/tmp/'
         MIGRATION_DIR = '%s/local/share/cubicweb/migration/' % root
         if not exists(REGISTRY_DIR):
             os.makedirs(REGISTRY_DIR)
     elif CubicWebNoAppConfiguration.mode == 'dev':
         REGISTRY_DIR = expanduser('~/etc/cubicweb.d/')
-        INSTANCE_DATA_DIR = REGISTRY_DIR
         RUNTIME_DIR = '/tmp/'
         MIGRATION_DIR = join(CW_SOFTWARE_ROOT, 'misc', 'migration')
     else: #mode = 'installed'
@@ -559,7 +573,8 @@
     @classmethod
     def instance_data_dir(cls):
         """return the instance data directory"""
-        return env_path('CW_INSTANCE_DATA', cls.INSTANCE_DATA_DIR,
+        return env_path('CW_INSTANCE_DATA',
+                        cls.INSTANCE_DATA_DIR or cls.REGISTRY_DIR,
                         'additional data')
         
     @classmethod
--- a/cwctl.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/cwctl.py	Wed Apr 15 17:36:09 2009 +0200
@@ -173,19 +173,18 @@
                     continue
                 print '   ', line
         print 
+        cubesdirs = ', '.join(CubicWebConfiguration.cubes_search_path())
         try:
-            cubesdir = CubicWebConfiguration.cubes_dir()
             namesize = max(len(x) for x in CubicWebConfiguration.available_cubes())
         except ConfigurationError, ex:
             print 'No cubes available:', ex
         except ValueError:
-            print 'No cubes available in %s' % cubesdir
+            print 'No cubes available in %s' % cubesdirs
         else:
-            print 'Available cubes (%s):' % cubesdir
+            print 'Available cubes (%s):' % cubesdirs
             for cube in CubicWebConfiguration.available_cubes():
                 if cube in ('CVS', '.svn', 'shared', '.hg'):
                     continue
-                templdir = join(cubesdir, cube)
                 try:
                     tinfo = CubicWebConfiguration.cube_pkginfo(cube)
                     tversion = tinfo.version
@@ -198,7 +197,7 @@
                                            or tinfo.__doc__)
                     if shortdesc:
                         print '    '+ '    \n'.join(shortdesc.splitlines())
-                    modes = detect_available_modes(templdir)
+                    modes = detect_available_modes(CubicWebConfiguration.cube_dir(cube))
                     print '    available modes: %s' % ', '.join(modes)
         print
         try:
@@ -620,7 +619,11 @@
         config = CubicWebConfiguration.config_for(appid)
         config.creating = True # notice we're not starting the server
         config.verbosity = self.config.verbosity
-        config.set_sources_mode(self.config.ext_sources or ('migration',))
+        try:
+            config.set_sources_mode(self.config.ext_sources or ('migration',))
+        except AttributeError:
+            # not a server config
+            pass
         # get application and installed versions for the server and the componants
         print 'getting versions configuration from the repository...'
         mih = config.migration_handler()
--- a/cwvreg.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/cwvreg.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """extend the generic VRegistry with some cubicweb specific stuff
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -12,7 +12,7 @@
 
 from rql import RQLHelper
 
-from cubicweb import Binary, UnknownProperty
+from cubicweb import Binary, UnknownProperty, UnknownEid
 from cubicweb.vregistry import VRegistry, ObjectNotFound, NoSelectableObject
 
 _ = unicode
@@ -322,9 +322,9 @@
         if vocab is not None:
             if callable(vocab):
                 # list() just in case its a generator function
-                vocabfunc = lambda e: list(vocab(propkey, req))
+                vocabfunc = lambda **kwargs: list(vocab(propkey, req))
             else:
-                vocabfunc = lambda e: vocab
+                vocabfunc = lambda **kwargs: vocab
             w = StaticComboBoxWidget(self, 'EProperty', self.schema['value'], 'String',
                                      vocabfunc=vocabfunc, description=tr(pdef['help']),
                                      **attrs)
@@ -337,7 +337,11 @@
         rqlst = self.rqlhelper.parse(rql)
         def type_from_eid(eid, session=session):
             return session.describe(eid)[0]
-        self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
+        try:
+            self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
+        except UnknownEid:
+            for select in rqlst.children:
+                select.solutions = []
         return rqlst
 
     @property
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian.hardy/compat	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,1 @@
+5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian.hardy/control	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,131 @@
+Source: cubicweb
+Section: web
+Priority: optional
+Maintainer: Logilab S.A. <contact@logilab.fr>
+Uploaders: Sylvain Thenault <sylvain.thenault@logilab.fr>,
+           Julien Jehannet <julien.jehannet@logilab.fr>,
+           Aurélien Campéas <aurelien.campeas@logilab.fr>
+Build-Depends: debhelper (>= 5), python-dev (>=2.4), python-central (>= 0.5)
+Standards-Version: 3.8.0
+Homepage: http://www.cubicweb.org
+XS-Python-Version: >= 2.4, << 2.6
+
+
+Package: cubicweb
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-twisted (= ${source:Version}), cubicweb-client (= ${source:Version})
+XB-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3
+Recommends: postgresql | mysql | sqlite3
+Description: the complete CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package will install all the components you need to run cubicweb on
+ a single machine. You can also deploy cubicweb by running the different
+ process on different computers, in which case you need to install the
+ corresponding packages on the different hosts.
+
+
+Package: cubicweb-server
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Conflicts: cubicweb-multisources
+Replaces: cubicweb-multisources
+Provides: cubicweb-multisources
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-indexer (>= 0.6.1), python-psycopg2 | python-mysqldb | python-pysqlite2
+Recommends: pyro, cubicweb-documentation (= ${source:Version})
+Description: server part of the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides the repository server part of the system.
+ .
+ This package provides the repository server part of the library and
+ necessary shared data files such as the schema library.
+
+
+Package: cubicweb-twisted
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Provides: cubicweb-web-frontend
+Depends: ${python:Depends}, cubicweb-web (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-twisted-web2
+Recommends: pyro, cubicweb-documentation (= ${source:Version})
+Description: twisted-based web interface for the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides a twisted based HTTP server to serve
+ the adaptative web interface (see cubicweb-web package).
+ .
+ This package provides only the twisted server part of the library.
+
+
+Package: cubicweb-web
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-docutils, python-vobject, python-elementtree
+Recommends: fckeditor
+Description: web interface library for the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides an adaptative web interface to the CubicWeb server.
+ Install the cubicweb-twisted package to serve this interface via HTTP.
+ .
+ This package provides the web interface part of the library and
+ necessary shared data files such as defaut views, images...
+
+
+Package: cubicweb-common
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Depends: ${python:Depends}, python-logilab-mtconverter (>= 0.6.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml, python-logilab-common (>= 0.38.1), python-yams (>= 0.20.2), python-rql (>= 0.20.2), python-simplejson (>= 1.3)
+Recommends: python-psyco
+Conflicts: cubicweb-core
+Replaces: cubicweb-core
+Description: common library for the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides the common parts of the library used by both server
+ code and web application code.
+
+
+Package: cubicweb-ctl
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version})
+Description: tool to manage the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides a control script to manage (create, upgrade, start,
+ stop, etc) CubicWeb applications. It also include the init.d script
+ to automatically start and stop CubicWeb applications on boot or shutdown.
+
+
+Package: cubicweb-client
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Depends: ${python:Depends}, cubicweb-ctl (= ${source:Version}), pyro
+Description: RQL command line client for the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides a RQL (Relation Query Language) command line client using
+ pyro to connect to a repository server.
+
+
+Package: cubicweb-dev
+Architecture: all
+XB-Python-Version: ${python:Versions}
+Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-web (= ${source:Version}), python-pysqlite2
+Suggests: w3c-dtd-xhtml
+Description: tests suite and development tools for the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides the CubicWeb tests suite and some development tools
+ helping in the creation of application.
+
+
+Package: cubicweb-documentation
+Architecture: all
+Recommends: doc-base
+Description: documentation for the CubicWeb framework
+ CubicWeb is a semantic web application framework.
+ .
+ This package provides the system's documentation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian.hardy/rules	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,78 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+PY_VERSION:=$(shell pyversions -d)
+
+build: build-stamp
+build-stamp: 
+	dh_testdir
+	# XXX doesn't work if logilab-doctools, logilab-xml are not in build depends
+	# and I can't get pbuilder find them in its chroot :(
+	# cd doc && make
+	# FIXME cleanup and use sphinx-build as build-depends ?
+	python setup.py build
+	touch build-stamp
+
+clean: 
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+	rm -rf build
+	#rm -rf debian/cubicweb-*/
+	find . -name "*.pyc" -delete
+	rm -f $(basename $(wildcard debian/*.in))
+	dh_clean
+
+install: build $(basename $(wildcard debian/*.in))
+	dh_testdir
+	dh_testroot
+	dh_clean
+	dh_installdirs
+
+	#python setup.py install_lib --no-compile --install-dir=debian/cubicweb-common/usr/lib/python2.4/site-packages/
+	python setup.py -q install --no-compile --prefix=debian/tmp/usr
+
+	# Put all the python library and data in cubicweb-common
+	# and scripts in cubicweb-server
+	dh_install -vi
+	#dh_lintian XXX not before debhelper 7
+
+	# Remove unittests directory (should be available in cubicweb-dev only)
+	rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/server/test
+	rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/sobjects/test
+	rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/site-packages/cubicweb/web/test
+	rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/common/test
+
+	# cubes directory must be managed as a valid python module
+	touch debian/cubicweb-common/usr/share/cubicweb/cubes/__init__.py
+
+%: %.in
+	sed "s/PY_VERSION/${PY_VERSION}/g" < $< > $@
+
+# Build architecture-independent files here.
+binary-indep: build install
+	dh_testdir
+	dh_testroot -i
+	dh_pycentral -i
+	dh_installinit -i -n --name cubicweb -u"defaults 99"
+	dh_installlogrotate -i
+	dh_installdocs -i -A README
+	dh_installman -i
+	dh_installchangelogs -i
+	dh_link -i
+	dh_compress -i -X.py -X.ini -X.xml
+	dh_fixperms -i
+	dh_installdeb -i
+	dh_gencontrol  -i
+	dh_md5sums -i
+	dh_builddeb -i
+
+binary-arch:
+
+binary: binary-indep 
+.PHONY: build clean binary binary-indep binary-arch
+
--- a/debian/changelog	Thu Jan 15 10:13:25 2009 +0100
+++ b/debian/changelog	Wed Apr 15 17:36:09 2009 +0200
@@ -1,3 +1,52 @@
+cubicweb (3.1.4-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Aurélien Campéas <aurelien.campeas@logilab.fr>  Mon, 06 Apr 2009 14:30:00 +0200
+
+cubicweb (3.1.3-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Mon, 06 Apr 2009 08:52:27 +0200
+
+cubicweb (3.1.2-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Aurélien Campéas <aurelien.campeas@logilab.fr>  Wed, 10 Mar 2009 12:30:00 +0100
+
+cubicweb (3.1.1-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Aurélien Campéas <aurelien.campeas@logilab.fr>  Wed, 9 Mar 2009 18:32:00 +0100
+
+cubicweb (3.1.0-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Wed, 25 Feb 2009 18:41:47 +0100
+
+cubicweb (3.0.10-1) unstable; urgency=low
+
+  * merge cubicweb-core package into cubicweb-common
+  * simplify debian/rules
+
+ -- Julien Jehannet <julien.jehannet@logilab.fr>  Thu, 19 Feb 2009 16:24:09 +0100
+
+cubicweb (3.0.9-1) unstable; urgency=low
+
+  * new upstream (interim) release
+
+ -- Aurélien Campéas <aurelien.campeas@logilab.fr>  Tue, 10 Feb 2009 14:05:12 +0100
+
+cubicweb (3.0.4-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Tue, 27 Jan 2009 16:05:12 +0100
+
 cubicweb (3.0.3-1) DISTRIBUTION; urgency=low
 
   * new upstream release
--- a/debian/compat	Thu Jan 15 10:13:25 2009 +0100
+++ b/debian/compat	Wed Apr 15 17:36:09 2009 +0200
@@ -1,1 +1,1 @@
-5
+7
--- a/debian/control	Thu Jan 15 10:13:25 2009 +0100
+++ b/debian/control	Wed Apr 15 17:36:09 2009 +0200
@@ -1,17 +1,21 @@
 Source: cubicweb
 Section: web
 Priority: optional
-Maintainer: Logilab Packaging Team <contact@logilab.fr>
-Uploaders: Sylvain Thenault <sylvain.thenault@logilab.fr> 
-Build-Depends: debhelper (>= 5.0.37.1), python (>=2.4), python-dev (>=2.4), python-central (>= 0.5)
+Maintainer: Logilab S.A. <contact@logilab.fr>
+Uploaders: Sylvain Thenault <sylvain.thenault@logilab.fr>,
+           Julien Jehannet <julien.jehannet@logilab.fr>,
+           Aurélien Campéas <aurelien.campeas@logilab.fr>
+Build-Depends: debhelper (>= 7), python-dev (>=2.4), python-central (>= 0.5)
 Standards-Version: 3.8.0
+Homepage: http://www.cubicweb.org
 XS-Python-Version: >= 2.4, << 2.6
 
+
 Package: cubicweb
 Architecture: all
 XB-Python-Version: ${python:Versions}
 Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-twisted (= ${source:Version}), cubicweb-client (= ${source:Version})
-XBS-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3
+XB-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3
 Recommends: postgresql | mysql | sqlite3
 Description: the complete CubicWeb framework
  CubicWeb is a semantic web application framework.
@@ -51,13 +55,13 @@
  This package provides a twisted based HTTP server to serve
  the adaptative web interface (see cubicweb-web package).
  .
- This package provides only the twisted server part of the library. 
+ This package provides only the twisted server part of the library.
 
 
 Package: cubicweb-web
 Architecture: all
 XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-simplejson (>= 1.3), python-docutils, python-vobject, python-elementtree
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-docutils, python-vobject, python-elementtree
 Recommends: fckeditor
 Description: web interface library for the CubicWeb framework
  CubicWeb is a semantic web application framework.
@@ -72,8 +76,10 @@
 Package: cubicweb-common
 Architecture: all
 XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, cubicweb-core (= ${source:Version}), python-logilab-mtconverter (>= 0.4.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml
+Depends: ${python:Depends}, python-logilab-mtconverter (>= 0.6.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml, python-logilab-common (>= 0.38.1), python-yams (>= 0.20.2), python-rql (>= 0.20.2), python-simplejson (>= 1.3)
 Recommends: python-psyco
+Conflicts: cubicweb-core
+Replaces: cubicweb-core
 Description: common library for the CubicWeb framework
  CubicWeb is a semantic web application framework.
  .
@@ -84,7 +90,7 @@
 Package: cubicweb-ctl
 Architecture: all
 XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, cubicweb-core (= ${source:Version})
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version})
 Description: tool to manage the CubicWeb framework
  CubicWeb is a semantic web application framework.
  .
@@ -100,21 +106,10 @@
 Description: RQL command line client for the CubicWeb framework
  CubicWeb is a semantic web application framework.
  .
- This package provides a RQL (Relation Query Language) command line client using 
+ This package provides a RQL (Relation Query Language) command line client using
  pyro to connect to a repository server.
 
 
-Package: cubicweb-core
-Architecture: all
-XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, python-logilab-common (>= 0.37.2), python-yams (>= 0.20.2), python-rql (>= 0.20.2)
-Description: core library for the CubicWeb framework
- CubicWeb is a semantic web application framework.
- .
- This package provides the core part of the library used by anyone having 
- to do some cubicweb programming in Python.
-
-
 Package: cubicweb-dev
 Architecture: all
 XB-Python-Version: ${python:Versions}
--- a/debian/cubicweb-client.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-usr/lib/python2.4/site-packages/cubicweb/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-client.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,1 @@
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/hercule.py usr/lib/PY_VERSION/site-packages/cubicweb
--- a/debian/cubicweb-common.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-usr/lib/python2.4/site-packages/cubicweb
-usr/lib/python2.4/site-packages/cubicweb/common
-usr/share/cubicweb/cubes/shared
-usr/share/doc/cubicweb-common
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-common.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,17 @@
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/common/ usr/lib/PY_VERSION/site-packages/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/entities/ usr/lib/PY_VERSION/site-packages/cubicweb
+debian/tmp/usr/share/cubicweb/cubes/shared/i18n usr/share/cubicweb/cubes/shared/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/rset.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/gettext.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/toolsutils.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/cwvreg.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/_exceptions.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/schemaviewer.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/dbapi.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/cwconfig.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/__init__.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/md5crypt.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/schema.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/interfaces.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/vregistry.py usr/share/pyshared/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/__pkginfo__.py usr/share/pyshared/cubicweb
--- a/debian/cubicweb-core.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-usr/lib/python2.4/site-packages/cubicweb
-usr/share/doc/cubicweb-core
--- a/debian/cubicweb-ctl.cubicweb.init	Thu Jan 15 10:13:25 2009 +0100
+++ b/debian/cubicweb-ctl.cubicweb.init	Wed Apr 15 17:36:09 2009 +0200
@@ -11,5 +11,22 @@
 # Short-Description: Start cubicweb application at boot time
 ### END INIT INFO
 
+# FIXME Seems to be inadequate here
+# FIXME If related to pyro, try instead:
+# export PYRO_STORAGE="/tmp"
 cd /tmp
-/usr/bin/cubicweb-ctl $1 --force
+
+# FIXME Work-around about the following lintian error
+#     E: cubicweb-ctl: init.d-script-does-not-implement-required-option /etc/init.d/cubicweb start
+#
+# Check if we are sure to not want the start-stop-daemon machinery here
+# Refer to Debian Policy Manual section 9.3.2 (Writing the scripts) for details.
+
+case "$1" in
+	"force-reload")
+		/usr/bin/cubicweb-ctl reload --force
+		;;
+	"*|restart")
+		/usr/bin/cubicweb-ctl $1 --force
+		;;
+esac
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-ctl.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,3 @@
+debian/tmp/usr/bin/cubicweb-ctl usr/bin/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/cwctl.py usr/lib/PY_VERSION/site-packages/cubicweb
+debian/cubicweb-ctl.bash_completion etc/bash_completion.d/cubicweb-ctl
--- a/debian/cubicweb-ctl.postinst	Thu Jan 15 10:13:25 2009 +0100
+++ b/debian/cubicweb-ctl.postinst	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 
 case "$1" in
     configure|abort-upgrade|abort-remove|abort-deconfigure)
-        update-rc.d cubicweb defaults >/dev/null
+        update-rc.d cubicweb defaults 99 >/dev/null
     ;;
     *)
         echo "postinst called with unknown argument \`$1'" >&2
--- a/debian/cubicweb-dev.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-usr/lib/python2.4/site-packages/cubicweb
-usr/lib/python2.4/site-packages/cubicweb/common
-usr/lib/python2.4/site-packages/cubicweb/web
-usr/lib/python2.4/site-packages/cubicweb/server
-usr/lib/python2.4/site-packages/cubicweb/sobjects
-usr/lib/python2.4/site-packages/cubicweb/entities
-usr/share/doc/cubicweb-dev
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-dev.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,7 @@
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/devtools/ usr/lib/PY_VERSION/site-packages/cubicweb/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/skeleton/ usr/lib/PY_VERSION/site-packages/cubicweb/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/test usr/lib/PY_VERSION/site-packages/cubicweb/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/common/test usr/lib/PY_VERSION/site-packages/cubicweb/common/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/server/test usr/lib/PY_VERSION/site-packages/cubicweb/server/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/test usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/web/test usr/lib/PY_VERSION/site-packages/cubicweb/web/
--- a/debian/cubicweb-documentation.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-usr/share/doc/cubicweb-documentation/
-usr/share/doc/cubicweb-documentation/devmanual_fr
-usr/share/doc-base/
--- a/debian/cubicweb-documentation.install	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-debian/cubicweb-doc usr/share/doc-base/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-documentation.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,2 @@
+doc/book usr/share/doc/cubicweb-documentation
+debian/cubicweb-doc usr/share/doc-base/cubicweb-doc
--- a/debian/cubicweb-server.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-usr/lib/python2.4/site-packages/cubicweb/
-usr/share/cubicweb
-usr/share/doc/cubicweb-server
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-server.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,4 @@
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/server/ usr/lib/PY_VERSION/site-packages/cubicweb
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/ usr/lib/PY_VERSION/site-packages/cubicweb
+debian/tmp/usr/share/cubicweb/schemas/ usr/share/cubicweb/
+debian/tmp/usr/share/cubicweb/migration/ usr/share/cubicweb/
--- a/debian/cubicweb-twisted.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-usr/lib/python2.4/site-packages
-usr/lib/python2.4/site-packages/cubicweb
-usr/share/doc/cubicweb-twisted
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-twisted.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,1 @@
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/etwist/ usr/lib/PY_VERSION/site-packages/cubicweb/
--- a/debian/cubicweb-web.dirs	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-usr/lib/python2.4/site-packages/
-usr/lib/python2.4/site-packages/cubicweb
-usr/share/cubicweb/cubes/shared
-usr/share/doc/cubicweb-web
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-web.install.in	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,3 @@
+debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/web usr/lib/PY_VERSION/site-packages/cubicweb
+debian/tmp/usr/share/cubicweb/cubes/shared/data usr/share/cubicweb/cubes/shared
+debian/tmp/usr/share/cubicweb/cubes/shared/wdoc usr/share/cubicweb/cubes/shared
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-web.lintian-overrides	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,1 @@
+cubicweb-web: embedded-javascript-library usr/share/cubicweb/cubes/shared/data/jquery.js
--- a/debian/rules	Thu Jan 15 10:13:25 2009 +0100
+++ b/debian/rules	Wed Apr 15 17:36:09 2009 +0200
@@ -4,12 +4,16 @@
 
 # Uncomment this to turn on verbose mode.
 #export DH_VERBOSE=1
+
+PY_VERSION:=$(shell pyversions -d)
+
 build: build-stamp
 build-stamp: 
 	dh_testdir
 	# XXX doesn't work if logilab-doctools, logilab-xml are not in build depends
 	# and I can't get pbuilder find them in its chroot :(
-	#cd doc && make
+	# cd doc && make
+	# FIXME cleanup and use sphinx-build as build-depends ?
 	python setup.py build
 	touch build-stamp
 
@@ -18,78 +22,41 @@
 	dh_testroot
 	rm -f build-stamp configure-stamp
 	rm -rf build
-	rm -rf debian/cubicweb-*/
-	find . -name "*.pyc" | xargs rm -f
+	#rm -rf debian/cubicweb-*/
+	find . -name "*.pyc" -delete
+	rm -f $(basename $(wildcard debian/*.in))
 	dh_clean
 
-install: build
+install: build $(basename $(wildcard debian/*.in))
 	dh_testdir
 	dh_testroot
-	dh_clean -k
+	dh_clean
 	dh_installdirs
-	########## core package #############################################
-	# put : 
-	# * all the python library and data in cubicweb-core
-	# * scripts in cubicweb-server
-	#
-	# pick from each latter to construct each package
-	python setup.py -q install_lib --no-compile --install-dir=debian/cubicweb-core/usr/lib/python2.4/site-packages/
-	python setup.py -q install_data --install-dir=debian/cubicweb-core/usr/
-	python setup.py -q install_scripts --install-dir=debian/cubicweb-server/usr/bin/
-	########## common package #############################################
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/common/ debian/cubicweb-common/usr/lib/python2.4/site-packages/cubicweb
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/entities/ debian/cubicweb-common/usr/lib/python2.4/site-packages/cubicweb
-	# data
-	mv debian/cubicweb-core/usr/share/cubicweb/cubes/shared/i18n debian/cubicweb-common/usr/share/cubicweb/cubes/shared/
+
+	#python setup.py install_lib --no-compile --install-dir=debian/cubicweb-common/usr/lib/python2.4/site-packages/
+	python setup.py -q install --no-compile --prefix=debian/tmp/usr
+
+	# Put all the python library and data in cubicweb-common
+	# and scripts in cubicweb-server
+	dh_install -vi
+	dh_lintian
+
+	# Remove unittests directory (should be available in cubicweb-dev only)
+	rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/server/test
+	rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/sobjects/test
+	rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/site-packages/cubicweb/web/test
+	rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/common/test
+
+	# cubes directory must be managed as a valid python module
 	touch debian/cubicweb-common/usr/share/cubicweb/cubes/__init__.py
-	########## server package #############################################
-	# library
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/server/ debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/sobjects/ debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb
-	# data
-	mv debian/cubicweb-core/usr/share/cubicweb/schemas/ debian/cubicweb-server/usr/share/cubicweb/
-	mv debian/cubicweb-core/usr/share/cubicweb/migration/ debian/cubicweb-server/usr/share/cubicweb/
-	########## twisted package ############################################
-	# library
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/etwist/ debian/cubicweb-twisted/usr/lib/python2.4/site-packages/cubicweb/
-	########## web package ################################################
-	# library
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/web/ debian/cubicweb-web/usr/lib/python2.4/site-packages/cubicweb/
-	# data / web documentation
-	mv debian/cubicweb-core/usr/share/cubicweb/cubes/shared/data debian/cubicweb-web/usr/share/cubicweb/cubes/shared/
-	mv debian/cubicweb-core/usr/share/cubicweb/cubes/shared/wdoc debian/cubicweb-web/usr/share/cubicweb/cubes/shared/
-	########## ctl package ################################################
-	# scripts
-	mv debian/cubicweb-server/usr/bin/cubicweb-ctl debian/cubicweb-ctl/usr/bin/
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/cwctl.py debian/cubicweb-ctl/usr/lib/python2.4/site-packages/cubicweb
-	mv debian/cubicweb-ctl.bash_completion debian/cubicweb-ctl/etc/bash_completion.d/cubicweb-ctl
-	########## client package #############################################
-	# library
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/hercule.py debian/cubicweb-client/usr/lib/python2.4/site-packages/cubicweb
-	########## dev package ################################################
-	# devtools package
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/devtools/ debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/skeleton/ debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/
-	# tests directories
-	mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/
-	mv debian/cubicweb-common/usr/lib/python2.4/site-packages/cubicweb/common/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/common/
-	mv debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb/server/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/server/
-	mv debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb/sobjects/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/sobjects/
-	mv debian/cubicweb-web/usr/lib/python2.4/site-packages/cubicweb/web/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/web/
-	########## documentation package ######################################
-	cp -r doc/book debian/cubicweb-documentation/usr/share/doc/cubicweb-documentation/
-	########## core package ###############################################
-	# small cleanup
-	rm -rf debian/cubicweb-core/usr/share/cubicweb/
-	# undistributed for now
-	rm -rf debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/goa
-	rm -rf debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/wsgi
+
+%: %.in
+	sed "s/PY_VERSION/${PY_VERSION}/g" < $< > $@
 
 # Build architecture-independent files here.
 binary-indep: build install
 	dh_testdir
 	dh_testroot -i
-	dh_install -i
 	dh_pycentral -i
 	dh_installinit -i -n --name cubicweb -u"defaults 99"
 	dh_installlogrotate -i
--- a/devtools/__init__.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/devtools/__init__.py	Wed Apr 15 17:36:09 2009 +0200
@@ -260,6 +260,8 @@
        - http://www.sqlite.org/cvstrac/tktview?tn=1327,33
        (some dates are returned as strings rather thant date objects)
     """
+    if hasattr(querier.__class__, '_devtools_sqlite_patched'):
+        return # already monkey patched
     def wrap_execute(base_execute):
         def new_execute(*args, **kwargs):
             rset = base_execute(*args, **kwargs)
@@ -288,7 +290,7 @@
             return rset
         return new_execute
     querier.__class__.execute = wrap_execute(querier.__class__.execute)
-
+    querier.__class__._devtools_sqlite_patched = True
 
 def init_test_database(driver='sqlite', configdir='data', config=None,
                        vreg=None):
--- a/devtools/apptest.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/devtools/apptest.py	Wed Apr 15 17:36:09 2009 +0200
@@ -407,6 +407,7 @@
         self.__close(self.cnxid)
 
     # other utilities #########################################################
+    
     def set_debug(self, debugmode):
         from cubicweb.server import set_debug
         set_debug(debugmode)
@@ -452,7 +453,7 @@
         self.__commit = repo.commit
         self.__rollback = repo.rollback
         self.__close = repo.close
-        self.cnxid = repo.connect(*self.default_user_password())
+        self.cnxid = self.cnx.sessionid
         self.session = repo._sessions[self.cnxid]
         # XXX copy schema since hooks may alter it and it may be not fully
         #     cleaned (missing some schema synchronization support)
@@ -499,6 +500,6 @@
         self.rollback()
         self.session.unsafe_execute('DELETE Any X WHERE X eid > %(x)s', {'x': self.maxeid})
         self.commit()
-        if close:
-            self.close()
+        #if close:
+        #    self.close()
     
--- a/devtools/devctl.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/devtools/devctl.py	Wed Apr 15 17:36:09 2009 +0200
@@ -284,12 +284,11 @@
     
     def run(self, args):
         """run the command with its specific arguments"""
-        CUBEDIR = DevCubeConfiguration.cubes_dir()
         if args:
-            cubes = [join(CUBEDIR, app) for app in args]
+            cubes = [DevCubeConfiguration.cube_dir(cube) for cube in args]
         else:
-            cubes = [join(CUBEDIR, app) for app in listdir(CUBEDIR)
-                         if exists(join(CUBEDIR, app, 'i18n'))]
+            cubes = [DevCubeConfiguration.cube_dir(cube) for cube in DevCubeConfiguration.available_cubes()]
+            cubes = [cubepath for cubepath in cubes if exists(join(cubepath, 'i18n'))]
         update_cubes_catalogs(cubes)
 
 def update_cubes_catalogs(cubes):
@@ -385,6 +384,11 @@
     arguments = '<cubename>'
 
     options = (
+        ("directory",
+         {'short': 'd', 'type' : 'string', 'metavar': '<cubes directory>',
+          'help': 'directory where the new cube should be created',
+          }
+         ),
         ("verbose",
          {'short': 'v', 'type' : 'yn', 'metavar': '<verbose>',
           'default': 'n',
@@ -419,14 +423,20 @@
         #if ServerConfiguration.mode != "dev":
         #    self.fail("you can only create new cubes in development mode")
         verbose = self.get('verbose')
-        cubedir = ServerConfiguration.CUBES_DIR
-        if not isdir(cubedir):
-            print "creating apps directory", cubedir
+        cubesdir = self.get('directory')
+        if not cubesdir:
+            cubespath = ServerConfiguration.cubes_search_path()
+            if len(cubespath) > 1:
+                raise BadCommandUsage("can't guess directory where to put the new cube."
+                                      " Please specify it using the --directory option")
+            cubesdir = cubespath[0]
+        if not isdir(cubesdir):
+            print "creating cubes directory", cubesdir
             try:
-                mkdir(cubedir)
+                mkdir(cubesdir)
             except OSError, err:
-                self.fail("failed to create directory %r\n(%s)" % (cubedir, err))
-        cubedir = join(cubedir, cubename)
+                self.fail("failed to create directory %r\n(%s)" % (cubesdir, err))
+        cubedir = join(cubesdir, cubename)
         if exists(cubedir):
             self.fail("%s already exists !" % (cubedir))
         skeldir = join(BASEDIR, 'skeleton')
@@ -503,17 +513,22 @@
             raise BadCommandUsage("no argument expected")
         import re
         requests = {}
-        for line in sys.stdin:
+        for lineno, line in enumerate(sys.stdin):
             if not ' WHERE ' in line:
                 continue
             #sys.stderr.write( line )
-            rql, time = line.split('--')
-            rql = re.sub("(\'\w+': \d*)", '', rql)
-            req = requests.setdefault(rql, [])
-            time.strip()
-            chunks = time.split()
-            cputime = float(chunks[-3])
-            req.append( cputime )
+            try:
+                rql, time = line.split('--')
+                rql = re.sub("(\'\w+': \d*)", '', rql)
+                if '{' in rql:
+                    rql = rql[:rql.index('{')]
+                req = requests.setdefault(rql, [])
+                time.strip()
+                chunks = time.split()
+                cputime = float(chunks[-3])
+                req.append( cputime )
+            except Exception, exc:
+                sys.stderr.write('Line %s: %s (%s)\n' % (lineno, exc, line))
 
         stat = []
         for rql, times in requests.items():
@@ -521,8 +536,11 @@
 
         stat.sort()
         stat.reverse()
+
+        total_time = sum(time for time, occ, rql in stat)*0.01
+        print 'Percentage;Cumulative Time;Occurences;Query'
         for time, occ, rql in stat:
-            print time, occ, rql
+            print '%.2f;%.2f;%s;%s' % (time/total_time, time, occ, rql)
         
 register_commands((UpdateCubicWebCatalogCommand,
                    UpdateTemplateCatalogCommand,
--- a/devtools/fill.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/devtools/fill.py	Wed Apr 15 17:36:09 2009 +0200
@@ -136,6 +136,9 @@
         
     def generate_integer(self, attrname, index):
         """generates a consistent value for 'attrname' if it's an integer"""
+        choosed = self.generate_choice(attrname, index)
+        if choosed is not None:
+            return choosed
         minvalue, maxvalue = get_bounds(self.e_schema, attrname)
         if maxvalue is not None and maxvalue <= 0 and minvalue is None:
             minvalue = maxvalue - index # i.e. randint(-index, 0)
--- a/devtools/repotest.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/devtools/repotest.py	Wed Apr 15 17:36:09 2009 +0200
@@ -3,7 +3,7 @@
 This module contains functions to initialize a new repository.
 
 :organization: Logilab
-:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -72,7 +72,7 @@
     def __contains__(self, key):
         return key in self.iterkeys()
     def __getitem__(self, key):
-        for key_, value in self.iteritems():
+        for key_, value in list.__iter__(self):
             if key == key_:
                 return value
         raise KeyError(key)
@@ -80,6 +80,17 @@
         return (x for x, y in list.__iter__(self))
     def iteritems(self):
         return (x for x in list.__iter__(self))
+    def items(self):
+        return [x for x in list.__iter__(self)]
+
+class DumbOrderedDict2(object):
+    def __init__(self, origdict, sortkey):
+        self.origdict = origdict
+        self.sortkey = sortkey
+    def __getattr__(self, attr):
+        return getattr(self.origdict, attr)
+    def __iter__(self):
+        return iter(sorted(self.origdict, key=self.sortkey))
 
 
 from logilab.common.testlib import TestCase
@@ -249,7 +260,8 @@
 _orig_select_principal = rqlannotation._select_principal
 
 def _select_principal(scope, relations):
-    return _orig_select_principal(scope, sorted(relations, key=lambda x: x.r_type))
+    return _orig_select_principal(scope, relations,
+                                  _sort=lambda rels: sorted(rels, key=lambda x: x.r_type))
 
 try:
     from cubicweb.server.msplanner import PartPlanInformation
@@ -257,15 +269,15 @@
     class PartPlanInformation(object):
         def merge_input_maps(*args):
             pass
-        def _choose_var(self, sourcevars):
+        def _choose_term(self, sourceterms):
             pass    
 _orig_merge_input_maps = PartPlanInformation.merge_input_maps
-_orig_choose_var = PartPlanInformation._choose_var
+_orig_choose_term = PartPlanInformation._choose_term
 
 def _merge_input_maps(*args):
     return sorted(_orig_merge_input_maps(*args))
 
-def _choose_var(self, sourcevars):
+def _choose_term(self, sourceterms):
     # predictable order for test purpose
     def get_key(x):
         try:
@@ -278,17 +290,7 @@
             except AttributeError:
                 # const
                 return x.value
-    varsinorder = sorted(sourcevars, key=get_key)
-    if len(self._sourcesvars) > 1:
-        for var in varsinorder:
-            if not var.scope is self.rqlst:
-                return var, sourcevars.pop(var)
-    else:
-        for var in varsinorder:
-            if var.scope is self.rqlst:
-                return var, sourcevars.pop(var)
-    var = varsinorder[0]
-    return var, sourcevars.pop(var)
+    return _orig_choose_term(self, DumbOrderedDict2(sourceterms, get_key))
 
 
 def do_monkey_patch():
@@ -298,7 +300,7 @@
     ExecutionPlan.tablesinorder = None
     ExecutionPlan.init_temp_table = _init_temp_table
     PartPlanInformation.merge_input_maps = _merge_input_maps
-    PartPlanInformation._choose_var = _choose_var
+    PartPlanInformation._choose_term = _choose_term
 
 def undo_monkey_patch():
     RQLRewriter.insert_snippets = _orig_insert_snippets
@@ -306,5 +308,5 @@
     ExecutionPlan._check_permissions = _orig_check_permissions
     ExecutionPlan.init_temp_table = _orig_init_temp_table
     PartPlanInformation.merge_input_maps = _orig_merge_input_maps
-    PartPlanInformation._choose_var = _orig_choose_var
+    PartPlanInformation._choose_term = _orig_choose_term
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/bootstrap_cubes	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,1 @@
+person, comment
--- a/devtools/test/data/bootstrap_packages	Thu Jan 15 10:13:25 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-eperson, ecomment
--- a/devtools/testlib.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/devtools/testlib.py	Wed Apr 15 17:36:09 2009 +0200
@@ -78,6 +78,8 @@
     return center - before <= line_no <= center + after
 
 ## base webtest class #########################################################
+VALMAP = {None: None, 'dtd': DTDValidator, 'xml': SaxOnlyValidator}
+
 class WebTest(EnvBasedTC):
     """base class for web tests"""
     __abstract__ = True
@@ -93,35 +95,28 @@
     #  SaxOnlyValidator : guarantees XML is well formed
     #  None : do not try to validate anything
     # validators used must be imported from from.devtools.htmlparser
-    validators = {
-        # maps vid : validator name
-        'hcal' : SaxOnlyValidator,
-        'rss' : SaxOnlyValidator,
-        'rssitem' : None,
-        'xml' : SaxOnlyValidator,
-        'xmlitem' : None,
-        'xbel' : SaxOnlyValidator,
-        'xbelitem' : None,
-        'vcard' : None,
-        'fulltext': None,
-        'fullthreadtext': None,
-        'fullthreadtext_descending': None,
-        'text' : None,
-        'treeitemview': None,
-        'textincontext' : None,
-        'textoutofcontext' : None,
-        'combobox' : None,
-        'csvexport' : None,
-        'ecsvexport' : None,
+    content_type_validators = {
+        # maps MIME type : validator name
+        #
+        # do not set html validators here, we need HTMLValidator for html
+        # snippets
+        #'text/html': DTDValidator,
+        #'application/xhtml+xml': DTDValidator,
+        'application/xml': SaxOnlyValidator,
+        'text/xml': SaxOnlyValidator,
+        'text/plain': None,
+        'text/comma-separated-values': None,
+        'text/x-vcard': None,
+        'text/calendar': None,
+        'application/json': None,
+        'image/png': None,
         }
-    valmap = {None: None, 'dtd': DTDValidator, 'xml': SaxOnlyValidator}
-    no_auto_populate = ()
-    ignored_relations = ()
+    # maps vid : validator name (override content_type_validators)
+    vid_validators = dict((vid, VALMAP[valkey])
+                          for vid, valkey in VIEW_VALIDATORS.iteritems())
     
-    def __init__(self, *args, **kwargs):
-        EnvBasedTC.__init__(self, *args, **kwargs)
-        for view, valkey in VIEW_VALIDATORS.iteritems():
-            self.validators[view] = self.valmap[valkey]
+    no_auto_populate = ()
+    ignored_relations = ()    
         
     def custom_populate(self, how_many, cursor):
         pass
@@ -163,21 +158,24 @@
         self.commit()
 
     @nocoverage
-    def _check_html(self, output, vid, template='main'):
+    def _check_html(self, output, view, template='main'):
         """raises an exception if the HTML is invalid"""
-        if template is None:
-            default_validator = HTMLValidator
-        else:
-            default_validator = DTDValidator
-        validatorclass = self.validators.get(vid, default_validator)
+        try:
+            validatorclass = self.vid_validators[view.id]
+        except KeyError:
+            if template is None:
+                default_validator = HTMLValidator
+            else:
+                default_validator = DTDValidator
+            validatorclass = self.content_type_validators.get(view.content_type,
+                                                              default_validator)
         if validatorclass is None:
             return None
         validator = validatorclass()
-        output = output.strip()
-        return validator.parse_string(output)
+        return validator.parse_string(output.strip())
 
 
-    def view(self, vid, rset, req=None, template='main', htmlcheck=True, **kwargs):
+    def view(self, vid, rset, req=None, template='main', **kwargs):
         """This method tests the view `vid` on `rset` using `template`
 
         If no error occured while rendering the view, the HTML is analyzed
@@ -194,8 +192,6 @@
         #     print 
         req.form['vid'] = vid
         view = self.vreg.select_view(vid, req, rset, **kwargs)
-        if view.content_type not in ('application/xml', 'application/xhtml+xml', 'text/html'):
-            htmlcheck = False
         # set explicit test description
         if rset is not None:
             self.set_description("testing %s, mod=%s (%s)" % (vid, view.__module__, rset.printable_rql()))
@@ -207,15 +203,18 @@
         elif template == 'main':
             _select_view_and_rset = TheMainTemplate._select_view_and_rset
             # patch TheMainTemplate.process_rql to avoid recomputing resultset
-            TheMainTemplate._select_view_and_rset = lambda *a, **k: (view, rset)
+            def __select_view_and_rset(self, view=view, rset=rset):
+                self.rset = rset
+                return view, rset
+            TheMainTemplate._select_view_and_rset = __select_view_and_rset
         try:
-            return self._test_view(viewfunc, vid, htmlcheck, template, **kwargs)
+            return self._test_view(viewfunc, view, template, **kwargs)
         finally:
             if template == 'main':
                 TheMainTemplate._select_view_and_rset = _select_view_and_rset
 
 
-    def _test_view(self, viewfunc, vid, htmlcheck=True, template='main', **kwargs):
+    def _test_view(self, viewfunc, view, template='main', **kwargs):
         """this method does the actual call to the view
 
         If no error occured while rendering the view, the HTML is analyzed
@@ -227,10 +226,7 @@
         output = None
         try:
             output = viewfunc(**kwargs)
-            if htmlcheck:
-                return self._check_html(output, vid, template)
-            else:
-                return output
+            return self._check_html(output, view, template)
         except (SystemExit, KeyboardInterrupt):
             raise
         except:
@@ -238,19 +234,16 @@
             # is not an AssertionError
             klass, exc, tcbk = sys.exc_info()
             try:
-                msg = '[%s in %s] %s' % (klass, vid, exc)
+                msg = '[%s in %s] %s' % (klass, view.id, exc)
             except:
-                msg = '[%s in %s] undisplayable exception' % (klass, vid)
+                msg = '[%s in %s] undisplayable exception' % (klass, view.id)
             if output is not None:
                 position = getattr(exc, "position", (0,))[0]
                 if position:
                     # define filter
-                    
-                    
                     output = output.splitlines()
                     width = int(log(len(output), 10)) + 1
                     line_template = " %" + ("%i" % width) + "i: %s"
-
                     # XXX no need to iterate the whole file except to get
                     # the line number
                     output = '\n'.join(line_template % (idx + 1, line)
@@ -259,12 +252,15 @@
                     msg+= '\nfor output:\n%s' % output
             raise AssertionError, msg, tcbk
 
-        
-    def iter_automatic_rsets(self):
+
+    def to_test_etypes(self):
+        return unprotected_entities(self.schema, strict=True)
+    
+    def iter_automatic_rsets(self, limit=10):
         """generates basic resultsets for each entity type"""
-        etypes = unprotected_entities(self.schema, strict=True)
+        etypes = self.to_test_etypes()
         for etype in etypes:
-            yield self.execute('Any X WHERE X is %s' % etype)
+            yield self.execute('Any X LIMIT %s WHERE X is %s' % (limit, etype))
 
         etype1 = etypes.pop()
         etype2 = etypes.pop()
@@ -281,23 +277,26 @@
         """returns the list of views that can be applied on `rset`"""
         req = rset.req
         only_once_vids = ('primary', 'secondary', 'text')
-        skipped = ('restriction', 'cell')
         req.data['ex'] = ValueError("whatever")
         for vid, views in self.vreg.registry('views').items():
             if vid[0] == '_':
                 continue
-            try:
-                view = self.vreg.select(views, req, rset)
-                if view.id in skipped:
-                    continue
-                if view.category == 'startupview':
+            if rset.rowcount > 1 and vid in only_once_vids:
+                continue
+            views = [view for view in views
+                     if view.category != 'startupview'
+                     and not issubclass(view, NotificationView)]
+            if views:
+                try:
+                    view = self.vreg.select(views, req, rset)
+                    if view.linkable():
+                        yield view
+                    else:
+                        not_selected(self.vreg, view)
+                    # else the view is expected to be used as subview and should
+                    # not be tested directly
+                except NoSelectableObject:
                     continue
-                if rset.rowcount > 1 and view.id in only_once_vids:
-                    continue
-                if not isinstance(view, NotificationView):
-                    yield view
-            except NoSelectableObject:
-                continue
 
     def list_actions_for(self, rset):
         """returns the list of actions that can be applied on `rset`"""
@@ -305,27 +304,25 @@
         for action in self.vreg.possible_objects('actions', req, rset):
             yield action
 
-        
     def list_boxes_for(self, rset):
         """returns the list of boxes that can be applied on `rset`"""
         req = rset.req
         for box in self.vreg.possible_objects('boxes', req, rset):
             yield box
             
-        
     def list_startup_views(self):
         """returns the list of startup views"""
         req = self.request()
         for view in self.vreg.possible_views(req, None):
-            if view.category != 'startupview':
-                continue
-            yield view.id
-
+            if view.category == 'startupview':
+                yield view.id
+            else:
+                not_selected(self.vreg, view)
+                
     def _test_everything_for(self, rset):
         """this method tries to find everything that can be tested
         for `rset` and yields a callable test (as needed in generative tests)
         """
-        rqlst = parse(rset.rql)
         propdefs = self.vreg['propertydefs']
         # make all components visible
         for k, v in propdefs.items():
@@ -335,7 +332,7 @@
             backup_rset = rset._prepare_copy(rset.rows, rset.description)
             yield InnerTest(self._testname(rset, view.id, 'view'),
                             self.view, view.id, rset,
-                            rset.req.reset_headers(), 'main', not view.binary)
+                            rset.req.reset_headers(), 'main')
             # We have to do this because some views modify the
             # resultset's syntax tree
             rset = backup_rset
@@ -348,8 +345,6 @@
         for box in self.list_boxes_for(rset):
             yield InnerTest(self._testname(rset, box.id, 'box'), box.dispatch)
 
-
-
     @staticmethod
     def _testname(rset, objid, objtype):
         return '%s_%s_%s' % ('_'.join(rset.column_types(0)), objid, objtype)
@@ -360,14 +355,14 @@
     ## one each
     def test_one_each_config(self):
         self.auto_populate(1)
-        for rset in self.iter_automatic_rsets():
+        for rset in self.iter_automatic_rsets(limit=1):
             for testargs in self._test_everything_for(rset):
                 yield testargs
 
     ## ten each
     def test_ten_each_config(self):
         self.auto_populate(10)
-        for rset in self.iter_automatic_rsets():
+        for rset in self.iter_automatic_rsets(limit=10):
             for testargs in self._test_everything_for(rset):
                 yield testargs
                 
@@ -390,4 +385,36 @@
                 rset2 = rset.limit(limit=1, offset=row)
                 yield rset2
 
+def not_selected(vreg, vobject):
+    try:
+        vreg._selected[vobject.__class__] -= 1
+    except (KeyError, AttributeError):
+        pass
         
+def vreg_instrumentize(testclass):
+    from cubicweb.devtools.apptest import TestEnvironment
+    env = testclass._env = TestEnvironment('data', configcls=testclass.configcls,
+                                           requestcls=testclass.requestcls)
+    vreg = env.vreg
+    vreg._selected = {}
+    orig_select = vreg.__class__.select
+    def instr_select(self, *args, **kwargs):
+        selected = orig_select(self, *args, **kwargs)
+        try:
+            self._selected[selected.__class__] += 1
+        except KeyError:
+            self._selected[selected.__class__] = 1
+        except AttributeError:
+            pass # occurs on vreg used to restore database
+        return selected
+    vreg.__class__.select = instr_select
+
+def print_untested_objects(testclass, skipregs=('hooks', 'etypes')):
+    vreg = testclass._env.vreg
+    for registry, vobjectsdict in vreg.items():
+        if registry in skipregs:
+            continue
+        for vobjects in vobjectsdict.values():
+            for vobject in vobjects:
+                if not vreg._selected.get(vobject):
+                    print 'not tested', registry, vobject
--- a/doc/book/en/A000-introduction.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/A000-introduction.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,5 +1,6 @@
 .. -*- coding: utf-8 -*-
 
+.. _Part1:
 
 ===================================
 Part I - Introduction to `CubicWeb`
--- a/doc/book/en/A020-tutorial.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/A020-tutorial.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -20,6 +20,7 @@
 This tutorial will show how to create a `cube` and how to use it as an
 application to run an `instance`.
 
+.. include:: Z013-blog-less-ten-minutes.en.txt
 .. include:: A02a-create-cube.en.txt
 .. include:: A02b-components.en.txt
 .. include:: A02c-maintemplate.en.txt
--- a/doc/book/en/A02a-create-cube.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/A02a-create-cube.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -169,47 +169,45 @@
 
 .. _DefineViews:
 
-Define your entities views
---------------------------
+Define your entity views
+------------------------
 
-Each entity defined in a model inherits defaults views allowing
+Each entity defined in a model inherits default views allowing
 different rendering of the data. You can redefine each of them
-according to your needs and preferences. If you feel like it then
-you have to know how a view is defined.
+according to your needs and preferences. So let's see how the
+views are defined.
 
 
-The views selection principle
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The view selection principle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 A view is defined by a Python class which includes: 
   
   - an identifier (all objects in `CubicWeb` are entered in a registry
     and this identifier will be used as a key)
   
-  - a filter to select the resulsets it can be applied to
+  - a filter to select the result sets it can be applied to
 
 A view has a set of methods complying
 with the `View` class interface (`cubicweb.common.view`).
 
-`CubicWeb` provides a lot of standard views for the type
-`EntityView`, for a complete list, you
-will have to read the code in directory ``cubicweb/web/views/``
+`CubicWeb` provides a lot of standard views for the type `EntityView`;
+for a complete list, read the code in directory ``cubicweb/web/views/``.
 
 A view is applied on a `result set` which contains a set of
 entities we are trying to display. `CubicWeb` uses a selector
-mechanism which computes a score used to identify which view
-is the best to apply for the `result set` we are trying to 
-display. The standard library of selectors is in 
+mechanism which computes for each available view a score: 
+the view with the highest score is then used to display the given `result set`.
+The standard library of selectors is in 
 ``cubicweb.common.selector`` and a library of methods used to
 compute scores is available in ``cubicweb.vregistry.vreq``.
 
 It is possible to define multiple views for the same identifier
 and to associate selectors and filters to allow the application
-to find the best way to render the data. We will see more details
-on this in :ref:`DefinitionVues`.
+to find the best way to render the data. 
 
 For example, the view named ``primary`` is the one used to display
-a single entity. We will now show you hos to customize this view.
+a single entity. We will now show you how to customize this view.
 
 
 View customization
@@ -219,8 +217,8 @@
 overwrite the `primary` view defined in the module ``views`` of the cube
 ``cubes/blog/views.py``.
 
-We can for example add in front of the pulication date a prefix specifying
-the date we see is the publication date.
+We can for example add in front of the publication date a prefix specifying
+that the date we see is the publication date.
 
 To do so, please apply the following changes:
 
@@ -263,12 +261,13 @@
    :alt: modified primary view
 
 
-The above source code defines a new primary view for
-``BlogEntry``. 
+The above source code defines a new primary view for ``BlogEntry``. 
 
-Since views are applied to resultsets and resulsets can be tables of
-data, it is needed to recover the entity from its (row,col)
-coordinates. We will get to this in more detail later.
+Since views are applied to result sets and result sets can be tables of
+data, we have to recover the entity from its (row,col)-coordinates.
+The view has a ``self.w()`` method that is used to output data, in our
+example HTML output.
 
-The view has a ``self.w()`` method that is used to output data. In our
-example we use it to output HTML tags and values of the entity's attributes.
+You can find more details about views and selectors in :ref:`ViewDefinition`.
+
+
--- a/doc/book/en/A03a-concepts.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/A03a-concepts.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -11,19 +11,19 @@
 .. image:: images/archi_globale.en.png
 
 
-`CubicWeb` framework is a server/client application framework. Those two 
-parties communicates through RQL (`CubicWeb` query language implementation)
+`CubicWeb` framework is a server/client application framework. Those two
+parts communicate through RQL (`CubicWeb` query language implementation)
 and ResultSet (which will be explained in :ref:`TermsVocabulary`).
 
 The server manages all interactions with sources.
 
 
 .. note::
-  For real, the client and server sides are integrated in the same
-  process and interact directly, without the needs for distants
-  calls using Pyro. It is important to note down that those two
+  Usually, the client and server sides are integrated in the same
+  process and interact directly, without the need for distant
+  calls using Pyro. But, it is important to note that those two
   sides, client/server, are disjointed and it is possible to execute
-  a couple of calls in distincts processes to balance the load of
+  a couple of calls in distinct processes to balance the load of
   your web site on one or more machines.
 
 .. _TermsVocabulary:
@@ -42,9 +42,9 @@
   classes based on `yams`_ library. This is the core piece
   of an application. It is initially defined in the file system and is
   stored in the database at the time an instance is created. `CubicWeb`
-  provides a certain number of system entities included automatically as
-  it is necessary for the core of `CubicWeb` and a library of
-  cubes (which defined application entities) that can be explicitely 
+  provides a certain number of system entities included automatically    
+  (necessary for the core of `CubicWeb`) and a library of
+  cubes (which defined application entities) that can be explicitely
   included if necessary.
 
 *entity type*
@@ -57,7 +57,7 @@
   a relation the `subject` and the second the `object`.
 
 *final entity type*
-  Final types corresponds to the basic types such as string of characters,
+  Final types correspond to the basic types such as string of characters,
   integers... Those types have a main property which is that they can
   only be used as `object` of a relation. The attributes of an entity
   (non final) are entities (finals).
@@ -69,7 +69,7 @@
 *relation definition*
   A relation definition is a 3-uple (subject entity type, relation type, object
   entity type), with an associated set of property such as cardinality, constraints...
-  
+
 *repository*
   This is the RQL server side of `CubicWeb`. Be carefull not to get
   confused with a Mercurial repository or a debian repository.
@@ -77,42 +77,42 @@
 *source*
   A data source is a container of data (SGBD, LDAP directory, `Google
   App Engine`'s datastore ...) integrated in the
-  `CubicWeb` repository. This repository has at least one source, `system` which 
-  contains the schema of the application, plain-text index and others
+  `CubicWeb` repository. This repository has at least one source, `system` which
+  contains the schema of the application, plain-text index and other
   vital informations for the system.
 
 *configuration*
-  It is possible to create differents configurations for an instance:
+  It is possible to create different configurations for an instance:
 
   - ``repository`` : repository only, accessible for clients using Pyro
   - ``twisted`` : web interface only, access the repository using Pyro
-  - ``all-in-one`` : web interface and repository in a single process. 
+  - ``all-in-one`` : web interface and repository in a single process.
      The repository could be or not accessible using Pyro.
 
 *cube*
   A cube is a model grouping one or multiple data types and/or views
-  to provide a specific functionnality or a complete `CubicWeb` application
+  to provide a specific functionality or a complete `CubicWeb` application
   potentially using other cubes. The available cubes are located in the file
-  system at `/path/to/forest/cubicweb/cubes` for a Mercurial forest installation,
-  for a debian packages installation they will be located in 
+  system at `/path/to/forest/cubicweb/cubes` for a Mercurial forest installation.
+  For a debian packages installation they will be located in
   `/usr/share/cubicweb/cubes`.
-  Larger applications can be built faster by importing cubes,
-  adding entities and relationships and overriding the
-  views that need to display or edit informations not provided by
-  cubes.
+  Larger applications can be built quite fast by importing cubes,
+  adding entities and relationships, overriding the
+  *views* that display the cubes or by editing informations not provided by
+  the cubes.
 
 *instance*
-  An instance is a specific installation of one or multiple cubes. All the required 
+  An instance is a specific installation of one or multiple cubes. All the required
   configuration files necessary for the well being of your web application
   are grouped in an instance. This will refer to the cube(s) your application
   is based on.
   For example logilab.org and our intranet are two instances of a single
-  cube jpl, developped internally.
+  cube "jpl", developped internally.
   The instances are defined in the directory `/etc/cubicweb.d`.
 
 *application*
-  The term application is sometime used to talk about an instance
-  and sometimes to talk of a cube depending on the context. 
+  The term application is sometimes used to talk about an instance
+  and sometimes to talk of a cube depending on the context.
   So we would like to avoid using this term and try to use *cube* and
   *instance* instead.
 
@@ -127,7 +127,7 @@
 
 *query language*
   A full-blown query language named RQL is used to formulate requests
-  to the database or any sources such as LDAP or `Google App Engine`'s 
+  to the database or any sources such as LDAP or `Google App Engine`'s
   datastore.
 
 *views*
@@ -143,11 +143,11 @@
   the same identifier.
 
 *rql*
- Relation Query Language in order to empasize the way of browsing relations.
- This query language is inspired by SQL but is highest level, its implementation
- generates SQL.
+ Relation Query Language in order to emphasize the way of browsing relations.
+ This query language is inspired by SQL but is on a higher level;
+ its implementation generates SQL.
 
- 
+
 .. _`Python Remote Object`: http://pyro.sourceforge.net/
 .. _`yams`: http://www.logilab.org/project/yams/
 
@@ -156,9 +156,9 @@
 ~~~~~~~~~~~~~~~~~
 
 The engine in `CubicWeb` is a set of classes managing a set of objects loaded
-dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamics objects,
+dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamic objects,
 based on the schema or the library, are building the final application.
-The differents dymanic components are for example:
+The different dynamic components are for example:
 
 * client and server side
 
@@ -194,36 +194,36 @@
 ~~~~~~~~~~~~~~
 
 The Python API developped to interface with RQL is inspired from the standard db-api,
-with a Connection object having the methods cursor, rollback and commit essentially. 
+with a Connection object having the methods cursor, rollback and commit essentially.
 The most important method is the `execute` method of a cursor :
 
 `execute(rqlstring, args=None, eid_key=None, build_descr=True)`
 
 :rqlstring: the RQL query to execute (unicode)
-:args: if the query contains substitutions, a dictionnary containing the values to use
-:eid_key: 
-   an implementation detail of the RQL queries cache implies that if a substitution
+:args: if the query contains substitutions, a dictionary containing the values to use
+:eid_key:
+   an implementation detail of the RQL cache implies that if a substitution
    is used to introduce an eid *susceptible to raise the ambiguities in the query
-   type resolution*, then we have to specify the correponding key in the dictionnary
+   type resolution*, then we have to specify the corresponding key in the dictionary
    through this argument
 
 
 The `Connection` object owns the methods `commit` and `rollback`. You *should
 never need to use them* during the development of the web interface based on
-the `CubicWeb` framework as it determines the end of the transaction depending 
+the `CubicWeb` framework as it determines the end of the transaction depending
 on the query execution success.
 
 .. note::
-  While executing updates queries (SET, INSERT, DELETE), if a query generates
+  While executing update queries (SET, INSERT, DELETE), if a query generates
   an error related to security, a rollback is automatically done on the current
   transaction.
-  
+
 
 The `Request` class (`cubicweb.web`)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 A request instance is created when an HTTP request is sent to the web server.
-It contains informations such as forms parameters, user authenticated, etc.
+It contains informations such as form parameters, user authenticated, etc.
 
 **Globally, a request represents a user query, either through HTTP or not
 (we also talk about RQL queries on the server side for example).**
@@ -232,21 +232,21 @@
 
 * `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated
   user
-* `form`, dictionnary containing the values of a web form
-* `encoding`, characters encoding to use in the response
+* `form`, dictionary containing the values of a web form
+* `encoding`, character encoding to use in the response
 
 But also:
 
 :Session data handling:
-  * `session_data()`, returns a dictionnary containing all the session data
+  * `session_data()`, returns a dictionary containing all the session data
   * `get_session_data(key, default=None)`, returns a value associated to the given
     key or the value `default` if the key is not defined
   * `set_session_data(key, value)`, assign a value to a key
   * `del_session_data(key)`,  suppress the value associated to a key
-    
+
 
 :Cookies handling:
-  * `get_cookie()`, returns a dictionnary containing the value of the header
+  * `get_cookie()`, returns a dictionary containing the value of the header
     HTTP 'Cookie'
   * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
     with a minimal 5 minutes length of duration by default (`maxage` = None
@@ -268,7 +268,7 @@
   * `cursor()` returns a RQL cursor on the session
   * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
   * `property_value(key)`, properties management (`EProperty`)
-  * dictionnary `data` to store data to share informations between components
+  * dictionary `data` to store data to share informations between components
     *while a request is executed*
 
 Please note that this class is abstract and that a concrete implementation
@@ -290,7 +290,7 @@
   `__registry__`) and its identifier (attribute `id`). Usually we do not have
   to take care of the register, only the identifier `id`.
 
-We can find a certain number of attributes and methods defined in this class 
+We can find a certain number of attributes and methods defined in this class
 and common to all the application objects.
 
 At the recording, the following attributes are dynamically added to
@@ -333,7 +333,7 @@
     also call the method `complete()` on the entity before returning it
 
 :Data formatting:
-  * `format_date(date, date_format=None, time=False)` returns a string for a 
+  * `format_date(date, date_format=None, time=False)` returns a string for a
     mx date time according to application's configuration
   * `format_time(time)` returns a string for a mx date time according to
     application's configuration
@@ -342,8 +342,8 @@
 
   * `external_resource(rid, default=_MARKER)`, access to a value defined in the
     configuration file `external_resource`
-    
-  * `tal_render(template, variables)`, renders a precompiled page template with 
+
+  * `tal_render(template, variables)`, renders a precompiled page template with
     variables in the given dictionary as context
 
 .. note::
@@ -357,7 +357,7 @@
               PrimaryView.f(self, arg1)
 
   You'd better write: ::
-  
+
       class Truc(PrimaryView):
           def f(self, arg1):
               super(Truc, self).f(arg1)
@@ -372,9 +372,9 @@
 
 A cube is a model grouping one or more entity types and/or views associated
 in order to provide a specific feature or even a complete application using
-others cubes.
+other cubes.
 
-You can decide to write your own set of cubes if you wish to re-use the 
+You can decide to write your own set of cubes if you wish to re-use the
 entity types you develop. Lots of cubes are available from the `CubicWeb
 Forge`_ under a free software license.
 
@@ -388,12 +388,12 @@
 A cube is structured as follows:
 
 ::
-  
+
   mycube/
   |
   |-- data/
   |   |-- cubes.mycube.css
-  |   |-- cubes.mycube.js  
+  |   |-- cubes.mycube.js
   |   `-- external_resources
   |
   |-- debian/
@@ -437,12 +437,12 @@
   |
   `-- views.py
 
-    
+
 We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
 ``schema.py`` or ``hooks.py``. For example, we could have:
 
 ::
-  
+
   mycube/
   |
   |-- entities.py
@@ -451,7 +451,7 @@
       |-- forms.py
       |-- primary.py
       `-- widgets.py
-  
+
 
 where :
 
@@ -460,7 +460,7 @@
 * ``sobjects`` contains hooks and/or views notifications (server side only)
 * ``views`` contains the web interface components (web interface only)
 * ``test`` contains tests related to the application (not installed)
-* ``i18n`` contains messages catalogs for supported languages (server side and
+* ``i18n`` contains message catalogs for supported languages (server side and
   web interface)
 * ``data`` contains data files for static content (images, css, javascripts)
   ...(web interface only)
@@ -472,14 +472,14 @@
 * file ``__pkginfo__.py`` provides component meta-data, especially the distribution
   and the current version (server side and web interface) or sub-cubes used by
   the cube.
- 
- 
+
+
 At least you should have:
 
 * the file ``__pkginfo__.py``
 * the schema definition
-  XXX false, we may want to have cubes which are only adding a service, 
-  no persistent data (eg embeding for instance)
+  XXX false, we may want to have cubes which are only adding a service,
+  no persistent data (eg embedding for instance)
 
 
 Standard library
--- a/doc/book/en/B000-development.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B000-development.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,5 +1,6 @@
 .. -*- coding: utf-8 -*-
 
+.. _Part2:
 
 =====================
 Part II - Development
--- a/doc/book/en/B0010-define-schema.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B0010-define-schema.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,17 +1,18 @@
 .. -*- coding: utf-8 -*-
 
-Data model definition (*schema*)
-================================
+Data model definition: the *schema*
+===================================
 
-The schema is the core piece of a `CubicWeb` application as it defines
-the data model handled. It is based on entities types already defined
-in the `CubicWeb` standard library and others, more specific, we would 
-expect to find in one or more Python files under the `schema` directory.
+The **schema** is the core piece of a `CubicWeb` application as it defines
+the handled data model. It is based on entity types that are either already
+defined in the `CubicWeb` standard library; or more specific types, that 
+`CubicWeb` expects to find in one or more Python files under the directory 
+`schema`.
 
 At this point, it is important to make clear the difference between
-relation type and relation definition: a relation type is only a relation
+*relation type* and *relation definition*: a *relation type* is only a relation
 name with potentially other additionnal properties (see XXXX), whereas a 
-relation definition is a complete triplet 
+*relation definition* is a complete triplet 
 "<subject entity type> <relation type> <object entity type>". 
 A relation type could have been implied if none is related to a 
 relation definition of the schema.
--- a/doc/book/en/B0011-schema-stdlib.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B0011-schema-stdlib.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -3,14 +3,14 @@
 Pre-defined schemas in the library
 ----------------------------------
 
-The library defines a set of entities schemas that are required by the system
+The library defines a set of entity schemas that are required by the system
 or commonly used in `CubicWeb` applications.
 Of course, you can extend those schemas if necessary.
 
 
 System schemas
 ``````````````
-The system entities available are :
+The available system entities are:
 
 * `EUser`, system users
 * `EGroup`, users groups
@@ -31,40 +31,63 @@
 * `Bookmark`, an entity type used to allow a user to customize his links within
   the application
 
-Cubes available
+(The first 'E' in some of the names is the first letter of 'Erudi', 
+`CubicWeb`'s old name; it might be changed/removed some day.)
+
+Available cubes
 ```````````````
 
 An application is based on several basic cubes. In the set of available
 basic cubes we can find for example :
 
-* `comment`, provides an entity type for `Comment` allowing us to comment others
-  site's entities
-
-* `mailinglist`, provides an entity type for `Mailinglist` which groups informations
-  in a discussion list
+* addressbook_: PhoneNumber and PostalAddress
 
-* `file`, provides entity types for `File` et `Image` used to represent
-  files (text or binary) with additionnal informations such as MIME type or
-  encoding.
-  
-* `link`, provides an entity type for hypertext link (`Link`)
+* basket_: Basket (like a shopping cart)
 
-* `blog`, provides an entity type weblog (`Blog`)
-
-* `person`, provides an entity type for a person (`Person`)
+* blog_: Blog (a *very* basic blog)
 
-* `addressbook`, provides an entity type used to represent phone 
-  numbers (`PhoneNumber`) and mailing address (`PostalAddress`)
-  
-* `classtags`, categorization system based on tags (`Tag`)
+* comment_: Comment (to attach comment threads to entities)
 
-* `classfolders`, categorization system based on folders hierarchy in order 
-  to create navigation sections (`Folder`)
-
-* `email`, archiving management for emails (`Email`, `Emailpart`,
+* email_: archiving management for emails (`Email`, `Emailpart`,
   `Emailthread`)
 
-* `basket`, basket management (`Basket`) allowing to group entities
+* event_: Event (define events, display them in calendars)
+
+* file_: File (to allow users to upload and store binary or text files)
+
+* folder_: Folder (to organize things but grouping them in folders)
+
+* keyword_: Keyword (to define classification schemes)
+
+* link_: Link (to collect links to web resources)
+
+* mailinglist_: MailingList (to reference a mailing-list and the URLs
+  for its archives and its admin interface)
+
+* person_: Person (easily mixed with addressbook)
+
+* tag_: Tag (to tag anything)
+
+* task_: Task (something to be done between start and stop date)
+
+* zone_: Zone (to define places within larger places, for example a
+  city in a state in a country)
+
+.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
+.. _basket: http://www.cubicweb.org/project/cubicweb-basket
+.. _blog: http://www.cubicweb.org/project/cubicweb-blog
+.. _comment: http://www.cubicweb.org/project/cubicweb-comment
+.. _email: http://www.cubicweb.org/project/cubicweb-email
+.. _event: http://www.cubicweb.org/project/cubicweb-event
+.. _file: http://www.cubicweb.org/project/cubicweb-file
+.. _folder: http://www.cubicweb.org/project/cubicweb-folder
+.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
+.. _link: http://www.cubicweb.org/project/cubicweb-link
+.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
+.. _person: http://www.cubicweb.org/project/cubicweb-person
+.. _tag: http://www.cubicweb.org/project/cubicweb-tag
+.. _task: http://www.cubicweb.org/project/cubicweb-task
+.. _zone: http://www.cubicweb.org/project/cubicweb-zone
 
 To declare the use of a component, once installed, add the name of the component
 to the variable `__use__` in the file `__pkginfo__.py` of your own component.
--- a/doc/book/en/B0012-schema-definition.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B0012-schema-definition.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -3,26 +3,32 @@
 Entity type definition
 ----------------------
 
-An entity type is defined by a Python class which inherits `EntityType`. The
-class name correponds to the type name. Then the content of the class contains
-the description of attributes and relations for the defined entity type,
-for example ::
+An entity type is defined by a Python class which inherits from `EntityType`.
+The class definition contains the description of attributes and relations
+for the defined entity type.
+The class name corresponds to the entity type name. It is exepected to be
+defined in the module ``mycube.schema``.
 
-  class Personne(EntityType):
+
+For example ::
+
+  class Person(EntityType):
     """A person with the properties and the relations necessary for my
     application"""
 
     last_name = String(required=True, fulltextindexed=True)
     first_name = String(required=True, fulltextindexed=True)
-    title = String(vocabulary=('M', 'Mme', 'Mlle'))
+    title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
     date_of_birth = Date()
     works_for = SubjectRelation('Company', cardinality='?*')
 
+
 * the name of the Python attribute corresponds to the name of the attribute
   or the relation in `CubicWeb` application.
 
-* all built-in types are available : `String`, `Int`, `Float`,
-  `Boolean`, `Date`, `Datetime`, `Time`, `Byte`.
+* all `CubicWeb` built-in types are available : `String`, `Int`, `Float`,
+  `Boolean`, `Date`, `Datetime`, `Time`, `Byte`; they are and implicitely
+  imported (as well as the special the function "_").
 
 * each entity type has at least the following meta-relations :
 
@@ -34,21 +40,19 @@
   
   - `created_by` (`EUser`) (which user created the entity)
   
-  - `owned_by` (`EUser`) (who does the entity belongs to, by default the 
-     creator but not necessary and it could have multiple owners)
+  - `owned_by` (`EUser`) (to whom the entity belongs; by default the 
+     creator but not necessary, and it could have multiple owners)
      
   - `is` (`EEType`)
 
-  
-* it is also possible to define relations of type object by using `ObjectRelation`
-  instead of `SubjectRelation`
 
-* the first argument of `SubjectRelation` and `ObjectRelation` gives respectively
+* relations can be defined by using `ObjectRelation` or `SubjectRelation`.
+  The first argument of `SubjectRelation` or `ObjectRelation` gives respectively
   the object/subject entity type of the relation. This could be :  
 
   * a string corresponding to an entity type
 
-  * a tuple of string correponding to multiple entities types
+  * a tuple of string corresponding to multiple entity types
 
   * special string such as follows :
 
@@ -62,20 +66,20 @@
 
 * optional properties for attributes and relations : 
 
-  - `description` : string describing an attribute or a relation. By default
+  - `description` : a string describing an attribute or a relation. By default
     this string will be used in the editing form of the entity, which means
     that it is supposed to help the end-user and should be flagged by the
     function `_` to be properly internationalized.
 
-  - `constraints` : list of conditions/constraints that the relation needs to
+  - `constraints` : a list of conditions/constraints that the relation has to
     satisfy (c.f. `Contraints`_)
 
-  - `cardinality` : two characters string which specify the cardinality of the
+  - `cardinality` : a two character string which specify the cardinality of the
     relation. The first character defines the cardinality of the relation on
-    the subject, the second on the object of the relation. When a relation
-    has multiple possible subjects or objects, the cardinality applies to all
-    and not on a one to one basis (so it must be consistent...). The possible
-    values are inspired from regular expressions syntax :
+    the subject, and the second on the object. When a relation can have 
+    multiple subjects or objects, the cardinality applies to all,
+    not on a one-to-one basis (so it must be consistent...). The possible
+    values are inspired from regular expression syntax :
 
     * `1`: 1..1
     * `?`: 0..1
@@ -85,7 +89,7 @@
   - `meta` : boolean indicating that the relation is a meta-relation (false by
     default)
 
-* optionnal properties for attributes : 
+* optional properties for attributes : 
 
   - `required` : boolean indicating if the attribute is required (false by default)
 
@@ -98,11 +102,11 @@
     attribute.
 
   - `default` : default value of the attribute. In case of date types, the values
-    which could be used correpond to the RQL keywords `TODAY` and `NOW`.
+    which could be used correspond to the RQL keywords `TODAY` and `NOW`.
   
   - `vocabulary` : specify static possible values of an attribute
 
-* optionnal properties of type `String` : 
+* optional properties of type `String` : 
 
   - `fulltextindexed` : boolean indicating if the attribute is part of
     the full text index (false by default) (*applicable on the type `Byte`
@@ -113,17 +117,17 @@
 
   - `maxsize` : integer providing the maximum size of the string (no limit by default)
 
-* optionnal properties for relations : 
+* optional properties for relations : 
 
   - `composite` : string indicating that the subject (composite == 'subject')
     is composed of the objects of the relations. For the opposite case (when
-    the object is composed of the subjects of the relation), we just need
-    to set 'object' as the value. The composition implies that when the relation
+    the object is composed of the subjects of the relation), we just set 
+    'object' as value. The composition implies that when the relation
     is deleted (so when the composite is deleted), the composed are also deleted.
 
 Contraints
 ``````````
-By default, the available constraints types are :
+By default, the available constraint types are :
 
 * `SizeConstraint` : allows to specify a minimum and/or maximum size on
   string (generic case of `maxsize`)
@@ -135,7 +139,7 @@
 
 * `StaticVocabularyConstraint` : identical to "vocabulary=(...)"
 
-* `RQLConstraint` : allows to specify a RQL query that needs to be satisfied
+* `RQLConstraint` : allows to specify a RQL query that has to be satisfied
   by the subject and/or the object of the relation. In this query the variables
   `S` and `O` are reserved for the entities subject and object of the 
   relation.
@@ -143,18 +147,18 @@
 * `RQLVocabularyConstraint` : similar to the previous type of constraint except
   that it does not express a "strong" constraint, which means it is only used to
   restrict the values listed in the drop-down menu of editing form, but it does
-  not prevent another entity to be selected
+  not prevent another entity to be selected.
 
 
-Relation definition
--------------------
+Definition of relations
+-----------------------
 
 XXX add note about defining relation type / definition
 
 A relation is defined by a Python class heriting `RelationType`. The name
 of the class corresponds to the name of the type. The class then contains
 a description of the properties of this type of relation, and could as well 
-contains a string for the subject and a string for the object. This allows to create
+contain a string for the subject and a string for the object. This allows to create
 new definition of associated relations, (so that the class can have the 
 definition properties from the relation) for example ::
 
@@ -174,14 +178,14 @@
   table for the relation. This applies to the relation when the cardinality
   of subject->relation->object is 0..1 (`?`) or 1..1 (`1`)
 
-* `symetric` : boolean indication that the relation is symetrical, which
+* `symmetric` : boolean indicating that the relation is symmetrical, which
   means `X relation Y` implies `Y relation X`
 
 In the case of simultaneous relations definitions, `subject` and `object`
 can both be equal to the value of the first argument of `SubjectRelation`
 and `ObjectRelation`.
 
-When a relation is not inlined and not symetrical, and it does not require
+When a relation is not inlined and not symmetrical, and it does not require
 specific permissions, its definition (by using `SubjectRelation` and
 `ObjectRelation`) is all we need.
 
@@ -219,8 +223,8 @@
 Permissions definition
 ``````````````````````
 
-Define permissions is set through to the attribute `permissions` of entities and
-relations types. It defines a dictionnary where the keys are the access types
+Setting permissions is done with the attribute `permissions` of entities and
+relation types. It defines a dictionary where the keys are the access types
 (action), and the values are the authorized groups or expressions.
 
 For an entity type, the possible actions are `read`, `add`, `update` and
@@ -375,12 +379,16 @@
 Updating your application with your new schema
 ``````````````````````````````````````````````
 
-You have to get a shell on your application ::
+If you modified your schema, the update is not automatic; indeed, this is 
+in general not a good idea.
+Instead, you call a shell on your application, which is a 
+an interactive python shell, with an appropriate
+cubicweb environment ::
 
-   cubicweb-ctl shell moninstance
+   cubicweb-ctl shell myinstance
 
 and type ::
 
-   add_entity_type('Personne')
+   add_entity_type('Person')
 
 And restart your application!
--- a/doc/book/en/B0020-define-workflows.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B0020-define-workflows.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -2,78 +2,43 @@
 
 .. _Workflow:
 
-Workflow definition
-===================
+An Example: Workflow definition
+===============================
 
 General
 -------
 
-A workflow can be defined in a `CubicWeb` application thanks to the system 
-entities ``State`` and ``Transition``. Those are defined within all 
-`CubicWeb` application and can be set-up through the main administrator interface.
-
-Once your schema is defined, you can start creating the set of states and
-the required transitions for your applications entities.
-
-You first need to define the states and then the transitions between those
-to complete your workflow.
-
-A ``State`` defines the status of an entity. While creating a new state, 
-you will be first given the option to select the entity type the state
-can be applied to. By choosing ``Apply``, a new section will be displayed
-in the editing screen to enable you to add relation to the state you are
-creating.
+A workflow describes how certain entities have to evolve between 
+different states. Hence we have a set of states, and a "transition graph", 
+i.e. a list of possible transitions from one state to another state.
 
-A ``Transition`` is also based on an entity type it can be applied to.
-By choosing ``Apply``, a new section will be displayed in the editing 
-screen to enable you to add relation to the transition you are
-creating.
-
-At the transition level you will also define the group of user which can
-aplly this transition to an object.
-
-
-Example of a simple workflow
-----------------------------
-
-Please see the tutorial to view and example of a simple workflow.
-
-
-[Create a simple workflow for BlogDemo, to have a moderator approve new blog 
-entry to be published. This implies, specify a dedicated group of blog
-moderator as well as hide the view of a blog entry to the user until
-it reaches the state published]
+We will define a simple workflow for a blog, with only the following 
+two states: `submitted` and `published`. So first, we create a simple 
+`CubicWeb` in ten minutes (see :ref:`BlogTenMinutes`).
 
 Set-up a workflow
 -----------------
 
 We want to create a workflow to control the quality of the BlogEntry 
 submitted on your application. When a BlogEntry is created by a user
-its state should be `submitted`. To be visible to all, it needs to
-be in the state `published`. To move from `submitted` to `published`
-we need a transition that we can name `approve_blogentry`.
-
-We do not want every user to be allowed to change the state of a 
-BlogEntry. We need to define a group of user, `moderators`, and 
-this group will have appropriate permissions to approve BlogEntry
-to be published and visible to all.
+its state should be `submitted`. To be visible to all, it has to
+be in the state `published`. To move it from `submitted` to `published`,
+we need a transition that we can call `approve_blogentry`.
 
-There are two ways to create a workflow, form the user interface,
-and also by defining it in ``migration/postcreate.py``. 
+A BlogEntry state should not be modifiable by every user.
+So we have to define a group of users, `moderators`, and 
+this group will have appropriate permissions to publish a BlogEntry.
+
+There are two ways to create a workflow: from the user interface,
+or by defining it in ``migration/postcreate.py``. 
 This script is executed each time a new ``cubicweb-ctl db-init`` is done. 
-If you create the states and transitions through the user interface
-this means that next time you will need to initialize the database
-you will have to re-create all the entities. 
-We strongly recommand you create the workflow in ``migration\postcreate.py``
-and we will now show you how.
-The user interface would only be a reference for you to view the states 
-and transitions but is not the appropriate interface to define your
-application workflow.
+We strongly recommand to create the workflow in ``migration/postcreate.py``
+and we will now show you how. Read `Under the hood`_ to understand why.
 
 Update the schema
 ~~~~~~~~~~~~~~~~~
-To enable a BlogEntry to have a State, we have to define a relation
-``in_state`` in the schema of BlogEntry. Please do as follows, add
+If we want a State for our BlogEntry, we have to define a relation
+``in_state`` in the schema of BlogEntry. So we add
 the line ``in_state (...)``::
 
   class BlogEntry(EntityType):
@@ -86,59 +51,64 @@
       entry_of = SubjectRelation('Blog', cardinality='?*')
       in_state = SubjectRelation('State', cardinality='1*')
 
-As you updated the schema, you will have re-execute ``cubicweb-ctl db-init``
+As you updated the schema, you have to re-execute ``cubicweb-ctl db-init``
 to initialize the database and migrate your existing entities.
+
 [WRITE ABOUT MIGRATION]
 
 Create states, transitions and group permissions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-At the time the ``postcreate.py`` script is executed, several methods
-can be used. They are all defined in the ``class ServerMigrationHelper``.
-We will only discuss the method we use to create a wrokflow here.
+The ``postcreate.py`` script is executed in a special environment, adding
+several `CubicWeb` primitives that can be used.
+They are all defined in the ``class ServerMigrationHelper``.
+We will only discuss the methods we use to create a workflow in this example.
 
 To define our workflow for BlogDemo, please add the following lines
 to ``migration/postcreate.py``::
   
   _ = unicode
 
-  moderators      = add_entity('EGroup', name=u"moderators")
+  moderators = add_entity('EGroup', name=u"moderators")
+
+This adds the `moderators` user group.
+
+::
 
   submitted = add_state(_('submitted'), 'BlogEntry', initial=True)
   published = add_state(_('published'), 'BlogEntry')
 
+``add_state`` expects as first argument the name of the state you want
+to create, then the entity type on which the state can be applied,
+and an optional argument to say if it is supposed to be the initial state
+of the entity type.
+
+::
+
   add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),)
 
+
+``add_transition`` expects 
+
+  * as the first argument the name of the
+    transition, then the entity type on which the transition can be applied,
+  * then the list of states on which the transition can be trigged,
+  * the target state of the transition, 
+  * and the permissions
+    (e.g. a list of user groups who can apply the transition; the user
+    has to belong to at least one of the listed group to perform the action).
+
+::
+
   checkpoint()
 
 .. note::
   Do not forget to add the `_()` in front of all states and transitions names while creating
   a workflow so that they will be identified by the i18n catalog scripts.
 
-``add_entity`` is used here to define the new group of users that we
-need to define the transitions, `moderators`.
-If this group required by the transition is not defined before the
-transition is created, it will not create the relation `transition 
-require the group moderator`.
-
-``add_state`` expects as the first argument the name of the state you are
-willing to create, then the entity type on which the state can be applied, 
-and an optionnal argument to set if the state is the initial state
-of the entity type or not.
-
-``add_transition`` expects as the first argument the name of the 
-transition, then the entity type on which we can apply the transition,
-then the list of possible initial states from which the transition
-can be applied, the target state of the transition, and the permissions
-(e.g. list of the groups of users who can apply the transition, the user
-needs to belong to at least one of the listed group).
-
-
-We could have also added a RQL condition in addition to a group to 
-which the user should belong to. 
-
-If we use both RQL condition and group, the two must be satisfied 
-for the user to be allowed to apply the transition.
+In addition to the user group condition, we could have added a RQL condition. 
+In this case, the user can only perform the action if 
+the two conditions are satisfied. 
 
 If we use a RQL condition on a transition, we can use the following 
 variables:
@@ -150,9 +120,40 @@
 
 .. image:: images/lax-book.03-transitions-view.en.png
 
-You can now notice that in the actions box of a BlogEntry, the state
-is now listed as well as the possible transitions from this state
-defined by the workflow. This transition, as defined in the workflow,
-will only being displayed for the users belonging to the group
-moderators of managers.
+You can notice that in the action box of a BlogEntry, the state
+is now listed as well as the possible transitions defined by the workflow.
+The transitions will only be displayed for users having the right permissions.
+In our example, the transition `approve_blogentry` will only be displayed 
+for the users belonging to the group `moderators` or `managers`.
+
+
+Under the hood
+~~~~~~~~~~~~~~
+
+A workflow is a collection of entities of type ``State`` and of type ``Transition``
+which are standard `CubicWeb` entity types.
+For instance, the following lines::
+
+  submitted = add_state(_('submitted'), 'BlogEntry', initial=True)
+  published = add_state(_('published'), 'BlogEntry')
 
+will create two entities of type ``State``, one with name 'submitted', and the other
+with name 'published'. Whereas::
+
+  add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),)
+ 
+will create an entity of type ``Transition`` with name 'approve_blogentry' which will
+be linked to the ``State`` entities created before.
+As a consequence, we could use the administration interface to do these operations.
+But it is not recommanded because it will be uselessly complicated
+and will be only local to your instance.
+
+
+Indeed, if you create the states and transitions through the user interface,
+next time you initialize the database
+you will have to re-create all the entities. 
+The user interface should only be a reference for you to view the states 
+and transitions, but is not the appropriate interface to define your
+application workflow.
+
+
--- a/doc/book/en/B0030-data-as-objects.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B0030-data-as-objects.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -4,15 +4,15 @@
 Data as objects
 ===============
 
-We will in this chapter introduce the objects that are used to handle
+In this chapter, we will introduce the objects that are used to handle
 the data stored in the database.
 
-Classes `Entity` and `AnyEntity`
---------------------------------
+Class `Entity` and `AnyEntity`
+------------------------------
 
-To provide a specific behavior for each entity, we just need to define
-a class inheriting from `cubicweb.entities.AnyEntity`. In general, we have
-to defined those classes in a module of `entities` package of an application
+To provide a specific behavior for each entity, we have to define
+a class inheriting from `cubicweb.entities.AnyEntity`. In general, we
+define this class in a module of `mycube.entities` package of an application
 so that it will be available on both server and client side.
 
 The class `AnyEntity` is loaded dynamically from the class `Entity` 
@@ -22,7 +22,7 @@
 Descriptors are added when classes are registered in order to initialize the class
 according to its schema:
 
-* we can access the defined attributes in the schema thanks the attributes of
+* we can access the defined attributes in the schema thanks to the attributes of
   the same name on instances (typed value)
 
 * we can access the defined relations in the schema thanks to the relations of
@@ -33,12 +33,12 @@
 * `has_eid()`, returns true is the entity has an definitive eid (e.g. not in the
   creation process)
         
-* `check_perm(action)`, checks if the user has the permission to execcute the
+* `check_perm(action)`, checks if the user has the permission to execute the
   requested action on the entity
 
 :Formatting and output generation:
 
-  * `view(vid, **kwargs)`, apply the given view to the entity
+  * `view(vid, **kwargs)`, applies the given view to the entity
 
   * `absolute_url(**kwargs)`, returns an absolute URL to access the primary view
     of an entity
@@ -114,34 +114,134 @@
   * `relation_vocabulary(rtype, targettype, x, limit=None)`, called
     internally by `subject_relation_vocabulary` and `object_relation_vocabulary`
 
+Class `TreeMixIn`
+-----------------
+
+This class provides a tree interface. This mixin has to be inherited 
+explicitly and configured using the tree_attribute, parent_target and 
+children_target class attribute to benefit from this default implementation.
+
+This class provides the following methods:
+
+  * `different_type_children(entities=True)`, returns children entities
+    of different type as this entity. According to the `entities` parameter, 
+    returns entity objects (if entity=True) or the equivalent result set.
+
+  * `same_type_children(entities=True)`, returns children entities of 
+    the same type as this entity. According to the `entities` parameter, 
+    return entity objects (if entity=True) or the equivalent result set.
+  
+  * `iterchildren( _done=None)`, iters on the children of the entity.
+  
+  * `prefixiter( _done=None)`
+  
+  * `path()`, returns the list of eids from the root object to this object.
+  
+  * `iterparents()`, iters on the parents of the entity.
+  
+  * `notification_references(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.
+
+`TreeMixIn` implements also the ITree interface (``cubicweb.interfaces``):
+
+  * `parent()`, returns the parent entity if any, else None (e.g. if we are on the
+    root)
+
+  * `children(entities=True, sametype=False)`, returns children entities
+    according to the `entities` parameter, return entity objects or the
+    equivalent result set.
+
+  * `children_rql()`, returns the RQL query corresponding to the children
+    of the entity.
+
+  * `is_leaf()`, returns True if the entity does not have any children.
+
+  * `is_root()`, returns True if the entity does not have any parent.
+
+  * `root()`, returns the root object of the tree representation of
+    the entity and its related entities.
+
+Example of use
+``````````````
+
+Imagine you defined three types of entities in your schema, and they
+relates to each others as follows in ``schema.py``::
+
+  class Entity1(EntityType):
+      title = String()
+      is_related_to = SubjectRelation('Entity2', 'subject')
+
+  class Entity2(EntityType):
+      title = String()
+      belongs_to = SubjectRelation('Entity3', 'subject')
+
+  class Entity3(EntityType):
+      name = String()
+
+You would like to create a view that applies to both entity types
+`Entity1` and `Entity2` and which lists the entities they are related to.
+That means when you view `Entity1` you want to list all `Entity2`, and
+when you view `Entity2` you want to list all `Entity3`.
+
+In ``entities.py``::
+
+  class Entity1(TreeMixIn, AnyEntity):
+      id = 'Entity1'
+      __implements__ = AnyEntity.__implements__ + (ITree,)
+      __rtags__ = {('is_related_to', 'Entity2', 'object'): 'link'}
+      tree_attribute = 'is_related_to'
+
+      def children(self, entities=True):
+          return self.different_type_children(entities)
+
+  class Entity2(TreeMixIn, AnyEntity):
+      id = 'Entity2'
+      __implements__ = AnyEntity.__implements__ + (ITree,)
+      __rtags__ = {('belongs_to', 'Entity3', 'object'): 'link'}
+      tree_attribute = 'belongs_to'
+
+      def children(self, entities=True):
+          return self.different_type_children(entities)
+
+Once this is done, you can define your common view as follows::
+
+  class E1E2CommonView(baseviews.PrimaryView):
+      accepts = ('Entity11, 'Entity2')
+      
+      def render_entity_relations(self, entity, siderelations):
+          self.wview('list', entity.children(entities=False))
+
 
 *rtags*
 -------
 
-*rtags* allows to specify certain behaviors of relations relative to a given
+*rtags* allow to specify certain behaviors of relations relative to a given
 entity type (see later). They are defined on the entity class by the attribute
-`rtags` which is a dictionnary with as its keys the triplet ::
+`rtags` which is a dictionary with as keys the triplets ::
 
   <relation type>, <target entity type>, <context position ("subject" ou "object")>
 
-and as the values a `set` or a tuple of markers defining the properties that
+and as values a `set` or a tuple of markers defining the properties that
 apply to this relation.
 
-It is possible to simplify this dictionnary:
+It is possible to simplify this dictionary:
 
 * if we want to specifiy a single marker, it is not necessary to
-  use a tuple as the value, the marker by itself (characters string)
+  use a tuple as value, the marker by itself (character string)
   is enough
 * if we only care about a single type of relation and not about the target
   and the context position (or when this one is not ambigous), we can simply
-  use the name of the relation type as the key
+  use the name of the relation type as key
 * if we want a marker to apply independently from the target entity type,
-  we have to use the string `*` as the target entity type
+  we have to use the string `*` as target entity type
 
 
-Please note that this dictionnary is *treated at the time the class is created*.
+Please note that this dictionary is *treated at the time the class is created*.
 It is automatically merged with the parent class(es) (no need to copy the
-dictionnary from the parent class to modify it). Also, modify it after the 
+dictionary from the parent class to modify it). Also, modifying it after the 
 class is created will not have any effect...
 
 .. include:: B0031-define-entities.en.txt
+
--- a/doc/book/en/B0031-define-entities.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B0031-define-entities.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -5,8 +5,8 @@
 
 Dynamic default values
 ``````````````````````
-It is possible to define in the schema *static* default values.
-It is also possible to define in the schema *dynamic* default values
+It is possible to define *static* default values in the schema.
+It is also possible to define *dynamic* default values
 by defining in the entity class a method `default_<attribut name>` for
 a given attribute.
 
@@ -55,13 +55,21 @@
 It is possible to manage attributes/relations in the simple or multiple
 editing form thanks to the following *rtags*: 
 
-* `primary`, indicates that an attribute or a relation has to be inserted
-  in the simple or multiple editing forms. In the case of a relation,
-  the related entity editing form will be included in the editing form.
+* `primary`, indicates that an attribute or a relation has to be
+  inserted **in the simple or multiple editing forms**. In the case of
+  a relation, the related entity editing form will be included in the
+  editing form and represented as a combobox. Each item of the
+  combobox is a link to an existing entity.
 
-* `secondary`, indicates that an attribute or a relation has to be inserted
-  in the simple editing form only. In the case of a relation, the related
-  entity editing form sill be included in the editing form.
+* `secondary`, indicates that an attribute or a relation has to be
+  inserted **in the simple editing form only**. In the case of a
+  relation, the related entity editing form will be included in the
+  editing form and represented as a combobox. Each item of the combobox
+  is a link to an existing entity.
+
+* `inlineview`, includes the target entity's form in the editing form
+  of the current entity. It allows to create the target entity in the
+  same time as the current entity.
 
 * `generic`, indicates that a relation has to be inserted in the simple
   editing form, in the generic box of relation creation.
@@ -110,20 +118,22 @@
 1. we consider that the first column contains the entities to constraint
 2. we collect the first entity of the table (row 0) to represent all the 
    others
-3. for all the others variables defined in the original request:
+3. for all the other variables defined in the original request:
    
-   1. if the varaible is related to the main variable by at least one relation
+   1. if the variable is related to the main variable by at least one relation
    2. we call the method ``filterform_vocabulary(rtype, x)`` on the entity,
       if nothing is returned (meaning a tuple `Non`, see below), we go to the
       next variable, otherwise a form filtering element is created based on
       the vocabulary values returned
 
-4. there is no others limitations to the `RQL`, it can include sorting, grouping
-   conditions... Javascripts functions are used to regenerate a request based on the
+4. there are no other limitations to the `RQL`, it can include sorting, grouping
+   conditions... JavaScript functions are used to regenerate a request based on the
    initial request and on the selected values from the filtering form.
 
 The method ``filterform_vocabulary(rtype, x, var, rqlst, args, cachekey)`` takes 
-the name of a relation and the target as parameters, which indicates of the
+the name of a relation and the target as parameters,
+[XXX what does it mean ?]
+which indicates of the
 entity on which we apply the method is subject or object of the relation. It
 has to return:
 
@@ -149,18 +159,18 @@
 
     class Ticket(AnyEntity):
 
-	...
+	    ...
 
-	def filterform_vocabulary(self, rtype, x, var, rqlst, args, cachekey):
-	    _ = self.req._
-	    if rtype == 'type':
-		return 'string', [(x, _(x)) for x in ('bug', 'story')]
-	    if rtype == 'priority':
-		return 'string', [(x, _(x)) for x in ('minor', 'normal', 'important')]
-	    if rtype == 'done_in':
-		rql = insert_attr_select_relation(rqlst, var, rtype, 'num')
-		return 'eid', self.req.execute(rql, args, cachekey)
-	    return super(Ticket, self).filterform_vocabulary(rtype, x, var, rqlst,
+    	def filterform_vocabulary(self, rtype, x, var, rqlst, args, cachekey):
+	        _ = self.req._
+	        if rtype == 'type':
+        		return 'string', [(x, _(x)) for x in ('bug', 'story')]
+	        if rtype == 'priority':
+    	    	return 'string', [(x, _(x)) for x in ('minor', 'normal', 'important')]
+    	    if rtype == 'done_in':
+	        	rql = insert_attr_select_relation(rqlst, var, rtype, 'num')
+		        return 'eid', self.req.execute(rql, args, cachekey)
+	        return super(Ticket, self).filterform_vocabulary(rtype, x, var, rqlst,
 							     args, cachekey)
 
 .. note::
--- a/doc/book/en/B0040-migration.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B0040-migration.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -5,10 +5,10 @@
 Migration
 =========
 
-One of the main concept in `CubicWeb` is to create incremental applications
-and for this purpose multiple actions are provided to facilitate the improvement
-of an application and in particular changes applied to the data model
-without loosing existing data.
+One of the main concept in `CubicWeb` is to create incremental applications.
+For this purpose, multiple actions are provided to facilitate the improvement
+of an application, and in particular to handle the changes to be applied
+to the data model, without loosing existing data.
 
 The current version of an application model is provided in the file
 `__pkginfo__.py` as a tuple of 3 integers.
@@ -16,8 +16,8 @@
 Migration scripts management
 ----------------------------
 
-Migration scripts needs to be located in the directory `migration` of your
-application and nammed accordingly:
+Migration scripts has to be located in the directory `migration` of your
+application and named accordingly:
 
 ::
 
@@ -25,26 +25,27 @@
 
 in which : 
 
-* X.Y.Z is the model version number to which the script enable to migrate
+* X.Y.Z is the model version number to which the script enables to migrate.
 
-* *mode* (between the last "_" and the extension ".py") indicates which part
-  of the application (RQL server, web server) the script applies to in case
-  of distributed installation. Its value could be :
+* *mode* (between the last "_" and the extension ".py") is used for 
+  distributed installation. It indicates to which part
+  of the application (RQL server, web server) the script applies.
+  Its value could be :
 
   * `common`, applies to the RQL server as well as the web server and updates
     files on the hard drive (configuration files migration for example).
 
-  * `web`, applies only to the web server and updates files on the hard drive
+  * `web`, applies only to the web server and updates files on the hard drive.
 
   * `repository`, applies only to the RQL server and updates files on the
-    hard drive
+    hard drive.
 
   * `Any`, applies only to the RQL server and updates data in the database
-    (schema and data migration for example)
+    (schema and data migration for example).
 
 Again in the directory `migration`, the file `depends.map` allows to indicate
-that to migrate to a particular model version, you always have to first migrate
-to a particular `CubicWeb` version. This file can contains comments (lines
+that for the migration to a particular model version, you always have to first 
+migrate to a particular `CubicWeb` version. This file can contain comments (lines
 starting by `#`) and a dependancy is listed as follows: ::
   
   <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
@@ -53,33 +54,31 @@
 
   0.12.0: 2.26.0
   0.13.0: 2.27.0
-  # 0.14 works with 2.27 <= erudi <= 2.28 at least
+  # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
   0.15.0: 2.28.0
 
 Base context
 ------------
 
-The following identifiers are pre-defined in the migration scripts:
+The following identifiers are pre-defined in migration scripts:
 
 * `config`, instance configuration
 
 * `interactive_mode`, boolean indicating that the script is executed in
-  an intercative mode or not 
+  an interactive mode or not 
 
 * `appltemplversion`, application model version of the instance
 
-* `applerudiversion`, cubicweb instance version
-
 * `templversion`, installed application model version
 
-* `erudiversion`, installed cubicweb version
+* `cubicwebversion`, installed cubicweb version
 
-* `confirm(question)`, function interrogating the user and returning true
-  if the user answers yes, false otherwise (always returns true when in a
+* `confirm(question)`, function asking the user and returning true
+  if the user answers yes, false otherwise (always returns true in
   non-interactive mode)
 
-* `_`, function fonction equivalent to `unicode` allowing to flag the strings
-  to internationalize in the migration scripts
+* the function `_`, it is equivalent to `unicode` allowing to flag the strings
+  to internationalize in the migration scripts.
 
 In the `repository` scripts, the following identifiers are also defined:
 
@@ -89,7 +88,7 @@
   current migration)
 
 * `newschema`, installed schema on the file system (e.g. schema of 
-  the updated model and erudi)
+  the updated model and cubicweb)
 
 * `sqlcursor`, SQL cursor for very rare cases where it is really
    necessary or beneficial to go through the sql
@@ -99,7 +98,7 @@
                         
 Schema migration
 ----------------
-The following functions for schema migration are available in the `repository`
+The following functions for schema migration are available in `repository`
 scripts:
 
 * `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
@@ -109,7 +108,7 @@
 * `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
   existing entity type.
 
-* `rename_attribute(etype, oldname, newname, commit=True)`, rename an attribute
+* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
             
 * `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
   If `auto` is True, all the relations using this entity type and having a known
@@ -149,7 +148,7 @@
   or even relations definitions).
         
 * `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
-  properties of a relation definition by using the nammed parameters of the properties
+  properties of a relation definition by using the named parameters of the properties
   to change.
 
 * `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
@@ -160,19 +159,19 @@
 
 Data migration
 --------------
-The following functions for data migration are available in the `repository` scripts:
+The following functions for data migration are available in `repository` scripts:
 
 * `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
   query, either to interrogate or update. A result set object is returned.  
 
 * `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given
-  type. The attributes and relations values are specified using the nammed and
+  type. The attribute and relation values are specified using the named and
   positionned parameters.
 
 Workflow creation
 -----------------
 
-The following functions for workflow creation are available in the `repository`
+The following functions for workflow creation are available in `repository`
 scripts:
 
 * `add_state(name, stateof, initial=False, commit=False, **kwargs)`, adds a new state
@@ -186,10 +185,10 @@
 Configuration migration
 -----------------------
 
-The following functions for configuration migration are available in all the
+The following functions for configuration migration are available in all 
 scripts:
 
-* `option_renamed(oldname, newname)`, indicates that an option has been renammed
+* `option_renamed(oldname, newname)`, indicates that an option has been renamed
 
 * `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
   belong anymore to the same group.
@@ -203,7 +202,7 @@
 --------------------------
 Those functions are only used for low level operations that could not be 
 accomplished otherwise or to repair damaged databases during interactive 
-session. They are available in the `repository` scripts:
+session. They are available in `repository` scripts:
 
 * `sqlexec(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query
 * `add_entity_type_table(etype, commit=True)`
--- a/doc/book/en/B1020-define-views.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B1020-define-views.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,6 +1,6 @@
 .. -*- coding: utf-8 -*-
 
-.. _DefinitionVues:
+.. _ViewDefinition:
 
 Views definition
 ================
@@ -13,6 +13,8 @@
 understanding of the classes and methods available, then detail the view
 selection principle which makes `CubicWeb` web interface very flexible.
 
+A `View` is an object applied to another object such as an entity.
+
 Basic class for views
 ---------------------
 
@@ -61,19 +63,18 @@
 
 * `page_title()`, returns the title to use in the HTML header `title`
 
-* `creator(eid)`, returns the eid and the login of the entity creator of the entity
-  having the eid given in the parameter 
 
-Other basic views classes
-`````````````````````````
+Other basic view classes
+````````````````````````
 Here are some of the subclasses of `View` defined in `cubicweb.common.view`
-that are more concrete as they relates to data rendering within the application:
+that are more concrete as they relate to data rendering within the application:
 
 * `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
 * `StartupView`, start view that does not require a result set to apply to
 * `AnyRsetView`, view applied to any result set 
 * `EmptyRsetView`, view applied to an empty result set
 
+
 The selection view principle
 ----------------------------
 
@@ -83,14 +84,14 @@
   and this identifier will be used as a key). This is defined in the class
   attribute ``id``.
   
-- a filter to select the resulsets it can be applied to. This is defined in
+- a filter to select the result sets it can be applied to. This is defined in
   the class attribute ``__selectors__``, which expects a tuple of selectors
   as its value.
 
 
 For a given identifier, multiple views can be defined. `CubicWeb` uses
-a selector which computes scores so that it can identify and select the
-best view to apply in context. The selectors library is in 
+a selector which computes scores to identify and select the
+best view to apply in the given context. The selectors library is in 
 ``cubicweb.common.selector`` and a library of the methods used to
 compute scores is in ``cubicweb.vregistry.vreq``.
 
@@ -98,6 +99,9 @@
 
 Registerer
 ``````````
+[Registerers are deprecated: they will soon disappear for explicite 
+registration...] 
+
 A view is also customizable through its attribute ``__registerer__``.
 This is used at the time the application is launched to manage how
 objects (views, graphic components, actions, etc.) 
@@ -107,14 +111,11 @@
 object that is equivalent to an already registered object, which
 could happen when we define two `primary` views for an entity type.
 
-The purpose of a `registerer` is to control objects registry
-at the application startup whereas `selectors` controls objects
+The purpose of a `registerer` is to control object registry
+at the application startup whereas `selectors` control objects
 when they are selected for display.
 
 
-`CubicWeb` provides a lot of standard views for the default class
-`EntityType`. You can find them in ``cubicweb/web/views/``.
-
 .. include:: B1022-views-stdlib.en.txt
 
 
@@ -163,7 +164,7 @@
 If you want to change the way a ``BlogEntry`` is displayed, just override 
 the method ``cell_call()`` of the view ``primary`` in ``BlogDemo/views.py`` ::
 
-  01. from ginco.web.views import baseviews
+  01. from cubicweb.web.views import baseviews
   02.
   03. class BlogEntryPrimaryView(baseviews.PrimaryView):
   04.
@@ -179,15 +180,15 @@
 The above source code defines a new primary view (`line 03`) for
 ``BlogEntry`` (`line 05`). 
 
-Since views are applied to resultsets and resulsets can be tables of
-data, it is needed to recover the entity from its (row,col)
-coordinates (`line 08`). We will get to this in more detail later.
+Since views are applied to result sets which can be tables of
+data, we have to recover the entity from its (row,col)-coordinates (`line 08`).
+We will get to this in more detail later.
 
-The view has a ``self.w()`` method that is used to output data. Here `lines
+The view method ``self.w()`` is used to output data. Here `lines
 09-12` output HTML tags and values of the entity's attributes.
 
-When displaying same blog entry as before, you will notice that the
-page is now looking much nicer.
+When displaying the same blog entry as before, you will notice that the
+page is now looking much nicer. [FIXME: it is not clear to what this refers.]
 
 .. image:: images/lax-book.09-new-view-blogentry.en.png
    :alt: blog entries now look much nicer
@@ -206,22 +207,22 @@
   10.         self.wview('primary', rset)
 
 In the above source code, `lines 01-08` are similar to the previous
-view we defined.
+view we defined. [FIXME: defined where ?]
 
-At `line 09`, a simple request in made to build a resultset with all
+At `line 09`, a simple request is made to build a result set with all
 the entities linked to the current ``Blog`` entity by the relationship
 ``entry_of``. The part of the framework handling the request knows
 about the schema and infer that such entities have to be of the
 ``BlogEntry`` kind and retrieves them.
 
-The request returns a selection of data called a resultset. At 
-`line 10` the view 'primary' is applied to this resultset to output
+The request returns a selection of data called a result set. At 
+`line 10` the view 'primary' is applied to this result set to output
 HTML. 
 
 **This is to be compared to interfaces and protocols in object-oriented
-languages. Applying a given view to all the entities of a resultset only
-requires the availability, for each entity of this resultset, of a
-view with that name that can accepts the entity.**
+languages. Applying a given view called 'a_view' to all the entities
+of a result set only requires to have for each entity of this result set,
+an available view called 'a_view' which accepts the entity.**
 
 Assuming we added entries to the blog titled `MyLife`, displaying it
 now allows to read its description and all its entries.
@@ -232,7 +233,7 @@
 **Before we move forward, remember that the selection/view principle is
 at the core of `CubicWeb`. Everywhere in the engine, data is requested
 using the RQL language, then HTML/XML/text/PNG is output by applying a
-view to the resultset returned by the query. That is where most of the
+view to the result set returned by the query. That is where most of the
 flexibility comes from.**
 
 [WRITE ME]
@@ -242,7 +243,7 @@
 
 We will implement the `cubicweb.interfaces.ICalendarable` interfaces on
 entities.BlogEntry and apply the OneMonthCalendar and iCalendar views
-to resultsets like "Any E WHERE E is BlogEntry"
+to result sets like "Any E WHERE E is BlogEntry"
 
 * create view "blogentry table" with title, publish_date, category
 
@@ -262,7 +263,7 @@
 Templates
 ---------
 
-*Templates* are specific view that does not depend on a result set. The basic
+*Templates* are specific views that do not depend on a result set. The basic
 class `Template` (`cubicweb.common.view`) is derived from the class `View`.
 
 To build a HTML page, a *main template* is used. In general, the template of
@@ -280,16 +281,16 @@
 
 XML views, binaries...
 ----------------------
-For the views generating other formats that HTML (an image generated dynamically
-for example), and which can not usually be included in the HTML page generated
+For views generating other formats than HTML (an image generated dynamically
+for example), and which can not simply be included in the HTML page generated
 by the main template (see above), you have to:
 
-* set the atribute `templatable` of the class to `False`
+* set the attribute `templatable` of the class to `False`
 * set, through the attribute `content_type` of the class, the MIME type generated
   by the view to `application/octet-stream`
 
-For the views dedicated to binary content creation (an image dynamically generated
-for example), we have to set the attribute `binary` of the class to `True` (which
+For views dedicated to binary content creation (like dynamically generated 
+images), we have to set the attribute `binary` of the class to `True` (which
 implies that `templatable == False`, so that the attribute `w` of the view could be
 replaced by a binary flow instead of unicode).
 
--- a/doc/book/en/B1021-views-selectors.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B1021-views-selectors.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -5,7 +5,7 @@
 
 Selectors are scoring functions that are called by the view
 dispatcher to tell whenever a view can be applied to a given result
-set and request. Selector sets are the glue that tie views to the data
+set of a request. Selector sets are the glue that tie views to the data
 model. Using them appropriately is an essential part of the
 construction of well behaved cubes.
 
--- a/doc/book/en/B1022-views-stdlib.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B1022-views-stdlib.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -2,6 +2,10 @@
 
 Predefined views in the library
 ```````````````````````````````
+
+`CubicWeb` provides a lot of standard views. You can find them in
+``cubicweb/web/views/``.
+
 A certain number of views are used to build the web interface, which apply
 to one or more entities. Their identifier is what distinguish them from
 each others and the main ones are:
@@ -56,7 +60,8 @@
   This view displays usually a side box of some related entities 
   in a primary view.
 
-Start view:
+  
+Start view (e.g. views that don't apply to a result set):
 
 *index*
     This view defines the home page of your application. It does not require
--- a/doc/book/en/B1030-form-management.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B1030-form-management.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -13,7 +13,7 @@
 The form generated by default does not fit your needs? You are not
 required to re-do all by hands! :)
 
-* rtags primary, secondary, generated, generic, 
+* rtags primary, secondary, generated, generic,
   `Entity.relation_category(rtype, x='subject')`
 * inline_view (now a rtag?)
 * widget specification
@@ -36,8 +36,8 @@
    starting by `eid:` and also having a parameter `__type` associated
    (also *qualified* by eid)
 
-2. For all the attributes and the relations of an entity to edit: 
-   
+2. For all the attributes and the relations of an entity to edit:
+
    1. search for a parameter `edits-<relation name>` or `edito-<relation name>`
       qualified in the case of a relation where the entity is object
    2. if found, the value returned is considered as the initial value
@@ -50,24 +50,24 @@
 
    1. if a qualified parameter `__linkto` is specified, its value has to be
       a string (or a list of string) such as: ::
-        
+
         <relation type>:<eids>:<target>
-      
+
       where <target> is either `subject` or `object` and each eid could be
       separated from the others by a `_`. Target specifies if the *edited entity*
       is subject or object of the relation and each relation specified will
       be inserted.
 
     2. if a qualified parameter `__clone_eid` is specified for an entity, the
-       relations of the specified entity passed as value of this parameter are 
+       relations of the specified entity passed as value of this parameter are
        copied on the edited entity.
 
     3. if a qualified parameter `__delete` is specified, its value must be
        a string or a list of string such as follows: ::
-          
+
           <ssubjects eids>:<relation type>:<objects eids>
 
-       where each eid subject or object can be seperated from the other 
+       where each eid subject or object can be seperated from the other
        by `_`. Each relation specified will be deleted.
 
     4. if a qualified parameter `__insert` is specified, its value should
@@ -84,14 +84,14 @@
 
 
 .. note::
-   
+
    * If the parameter `__action_delete` is found, all the entities specified
      as to be edited will be deleted.
-   
+
    * If the parameter`__action_cancel` is found, no action is completed.
 
-   * If the parameter `__action_apply` is found, the editing is applied 
-     normally but the redirection is done on the form 
+   * If the parameter `__action_apply` is found, the editing is applied
+     normally but the redirection is done on the form
      (see :ref:`RedirectionControl`).
 
    * The parameter `__method` is also supported as for the main template
@@ -120,7 +120,7 @@
 
 * `__redirectparams`: forms parameters to add to the path
 
-* `__redirectrql`: redirection RQL request 
+* `__redirectrql`: redirection RQL request
 
 * `__redirectvid`: redirection view identifier
 
@@ -132,6 +132,6 @@
 * `__form_id`: initial view form identifier, used if `__action_apply` is
   found
 
-In general we use either `__redirectpath` and `__redirectparams` or 
+In general we use either `__redirectpath` and `__redirectparams` or
 `__redirectrql` and `__redirectvid`.
 
--- a/doc/book/en/B1060-templates.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B1060-templates.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -84,7 +84,7 @@
 
 ::
 
- from ginco.web.views.basetemplates import HTMLPageHeader
+ from cubicweb.web.views.basetemplates import HTMLPageHeader
  class MyHTMLPageHeader(HTMLPageHeader):
     def main_header(self, view):
         """build the top menu with authentification info and the rql box"""
@@ -143,7 +143,7 @@
 for HTMLPageFooter and override it in your views file as in : 
 ::
 
-  form ginco.web.views.basetemplates import HTMLPageFooter
+  form cubicweb.web.views.basetemplates import HTMLPageFooter
   class MyHTMLPageFooter(HTMLPageFooter):
       def call(self, **kwargs):
           self.w(u'<div class="footer">')
@@ -181,7 +181,7 @@
   whatever the number of entities to display
 * `__method`, if the result set to render contains only one entity and this 
   parameter is set, it refers to a method to call on the entity by passing it
-  the dictionnary of the forms parameters, before going the classic way (through
+  the dictionary of the forms parameters, before going the classic way (through
   step 1 and 2 described juste above)
 
 The MainTemplate is a bit complex as it tries to accomodate many
@@ -196,11 +196,9 @@
 the case we want to create new CSS style, the best is to define it a in a new
 CSS located under ``myapp/data/``.
 
-If you want to modify an existing CSS styling property, you will have to use
-``!important`` declaration to override the existing property. The application
-apply a higher priority on the default CSS and you can not change that. 
-Customized CSS will not be read first.
 
+.. [TRANSLATE ME FROM FRENCH]
+.. 03-XX-external_resources.fr.txt
 
 [TODO]
 Add login menu in left column
@@ -213,5 +211,5 @@
 
 [TODO]
 Rajouter une section pour definir la terminologie utilisee.
-Dans ginco-doc rajouter une section pour cubciweb-ctl shell ou
+Dans cubicweb-doc rajouter une section pour cubciweb-ctl shell ou
 on liste les commandes dispos.
--- a/doc/book/en/B1090-internationalization.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B1090-internationalization.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -96,5 +96,5 @@
 1. `cubicweb-ctl i18nupdate <component>`
 2. Edit the <component>/xxx.po  files and add missing translations (empty `msgstr`) 
 3. `hg ci -m "updated i18n catalogs"`
-4. `cubicweb-ctl i18n compile <myapplication>`
+4. `cubicweb-ctl i18ncompile <myapplication>`
 
--- a/doc/book/en/B2052-install.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/B2052-install.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -107,10 +107,10 @@
   $ python myapp/bin/laxctl i18ncompile 
 
 Ignore the errors that print "No translation file found for domain
-'erudi'". They disappear after the first run of i18ncompile.
+'cubicweb'". They disappear after the first run of i18ncompile.
 
 .. note:: The command  myapp/bin/laxctl i18nupdate needs to be executed
-   only if your application is using cubes from ginco-apps.
+   only if your application is using cubes from cubicweb-apps.
    Otherwise, please skip it.
 
 You will never need to add new entries in the translation catalog. Instead we would
--- a/doc/book/en/C000-administration.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/C000-administration.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,5 +1,6 @@
 .. -*- coding: utf-8 -*-
 
+.. _Part3:
 
 ==========================
 Part III - Administration
@@ -15,4 +16,4 @@
    C020-site-config.en.txt
    C030-instance-config.en.txt
    C040-rql.en.txt
-   C041-rql-tutorial.en.txt
+
--- a/doc/book/en/C010-setup.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/C010-setup.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,6 +1,6 @@
 .. -*- coding: utf-8 -*-
 
-.. _MiseEnPlaceEnv:
+.. _SetUpEnv:
 
 ===================================================
 Installation and set-up of a `CubicWeb` environment
--- a/doc/book/en/C011-installation.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/C011-installation.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -29,19 +29,25 @@
   deb http://ftp.logilab.org/dists/ hardy/
 
 
-You can now install the required packages with the following command: ::
+You can now install the required packages with the following command::
 
   apt-get update 
   apt-get install cubicweb
   apt-get install cubicweb-dev
 
+`cubicweb` installs the framework itself, allowing you to create
+new applications.
 
-This is it!
+`cubicweb-dev` installs the development environment allowing you to
+develop new cubes.
+
+There is also a wide variety of cubes listed on http://www.cubicweb.org/Project available as debian packages and tarball.
+
 
 Install from source
 ```````````````````
 
-You can download the archive containing the sources from our `ftp site`_ at: ::
+You can download the archive containing the sources from our `ftp site`_ at::
 
   http://ftp.logilab.org/pub/cubicweb/
 
@@ -67,9 +73,9 @@
 
 Then you can install:
 
-* `pyro` if you wish the repository is accessible through Pyro
+* `pyro` if you wish the repository to be accessible through Pyro
   or if the client and the server are not running on the same machine
-  (in suche case the packages will have to be isntalled on both
+  (in which case the packages will have to be installed on both
   machines)
 
 * `python-ldap` if you plan to use a LDAP source on the server
@@ -80,8 +86,8 @@
 -------------------------
 
 If you installed `CubicWeb` by cloning the Mercurial forest, then you
-will need to update the environment variable PYTHONPATH to add to it 
-the path to the forest ``cubicweb``.
+will need to update the environment variable PYTHONPATH by adding  
+the path to the forest ``cubicweb``:
 
 Add the following lines to either `.bashrc` or `.bash_profile` to configure
 your development environment ::
@@ -92,18 +98,35 @@
 Your new cubes will be placed in `/usr/share/cubicweb/cubes` and
 your applications will be placed in `/etc/cubicweb.d`.
 
+To use others directories then you will have to configure the
+following environment variables as follows::
+
+    export CW_CUBES_PATH=~/lib/cubes
+    export CW_REGISTRY=~/etc/cubicweb.d/
+    export CW_INSTANCE_DATA=$CW_REGISTRY
+    export CW_RUNTIME=/tmp
+
+.. note::
+    The values given above are our suggestions but of course
+    can be different.
+
 .. _ConfigurationPostgres:
 
 Postgres configuration
 ----------------------
 
+.. note::
+    If you already have an existing cluster and postgres server
+    running, you do not require to execute the initilization step
+    of your Postgres database.
+
 * First you have to initialize the database Postgres with the command ``initdb``.
   ::
 
     $ initdb -D /path/to/pgsql
 
   Once initialized, you can launch the database server Postgres 
-  with the command: ::
+  with the command::
   
     $ postgres -D /path/to/psql
 
@@ -113,26 +136,48 @@
  
     $ chown username /path/to/pgsql
 
-* Create a superuser for `CubicWeb` instance (**root**) ::
-
-    createuser -s username
-
-  Initialize the password of the superuser you juste created with 
-  ``su - postgres`` and ``psql``.
+* The database authentication can be either set to `ident sameuser`
+  or `md5`. 
+  If set to `md5`, make sure to use an existing user
+  of your database.
+  If set to `ident sameuser`, make sure that your
+  client's operating system user name has a matching user in
+  the database. If not, please do as follow to create a user::
+    
+    $ su
+    $ su - postgres
+    $ createuser -s username
 
-  This password will be asked to you later on where you will create an
-  instance with `cubicweb-ctl create`
+  If created with the options -P (for password prompt, 
+  ``createuser -s -P username``), the password will be encrypted with
+  the method set in the configuration file ``pg_hba.conf``. 
+  If you do not use this option, then the default value will be null
+  and this require to set the password in the database itself.
+  To do so: ::
+    
+    $ su 
+    $ su - postgres
+    $ psql
 
-[XXX]
-Est-ce que ces etapes sont vraiment necessaires? 
-sand : lors de l'installation de ma bdd cela n'a pas ete fait
-et il semble que tout aille bien. Doit etre verifie avec les experts.
+  And then execute de following query::
+    
+    ALTER USER username WITH PASSWORD `password`
+
+  This login/password will be requested when you will create an
+  instance with `cubicweb-ctl create` to initialize the database of
+  your application.
 
-* installation of plain-text index extension ::
+.. note::
+    The authentication method can be configured in ``pg_hba.conf``.
+
+
+.. FIXME Are these steps really necessary? It seemed to work without.
+
+* Installation of plain-text index extension ::
 
     cat /usr/share/postgresql/8.3/contrib/tsearch2.sql | psql -U username template1
 
-* installation of plpythonu language by default ::
+* Installation of plpythonu language by default ::
 
     createlang -U pgadmin plpythonu template1
 
@@ -140,7 +185,7 @@
 Pyro configuration
 ------------------
 
-If you use Pyro, it is required to have a name server Pyro runing on your
+If you use Pyro, it is required to have a name server Pyro running on your
 network (by default it is identified by a broadcast request).
 
 To do so, you need to :
@@ -151,6 +196,6 @@
   `pyro-nsd start`
 
 * edit the file ``/etc/default/pyro-nsd`` so that the name server pyro
-  will be launched automatically when the macine fire up
+  will be launched automatically when the machine fire up
 
 
--- a/doc/book/en/C012-create-instance.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/C012-create-instance.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -24,11 +24,11 @@
 
 A cube defines entities, their views, their schemas and workflows
 in an independant directory located in ``/path/to/forest/cubicweb/cubes/``
-for a Mercurila installation or in ``/usr/share/cubicweb/cubes`` for
-a debian packages installation.
+for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for
+a debian package installation.
 
 When an instance is created, you list one or more cubes that your instance
-will use. Use a cube means having the entities defined in your cube's schema
+will use. Using a cube means having the entities defined in your cube's schema
 available in your instance as well as their views and workflows.
 
 .. note::
@@ -62,6 +62,13 @@
 at the time the base is created (import_erschema('MyCube') will
 not properly work otherwise).
 
+.. note::
+    Please note that if you do not wish to use default directory
+    for your cubes library, then you want to use the option
+    --directory to specify where you would like to place
+    the source code of your cube:
+    ``cubicweb-ctl newcube --directory=/path/to/cubes/library cube_name``
+
 Instance creation
 -----------------
 
@@ -91,7 +98,7 @@
 possible, later on, to create others users for your final web application.
 
 When this command is completed, the definition of your instance is
-located in *~/etc/cubicweb.d/moninstance/*. To launch it, you just type ::
+located in *~/etc/cubicweb.d/myinstance/*. To launch it, you just type ::
 
   cubicweb-ctl start -D myinstance
 
--- a/doc/book/en/C040-rql.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/C040-rql.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -9,13 +9,13 @@
 Introduction
 ============
 
-Goals RQL
----------
+Goals of RQL
+------------
 
 The goal is to have a language emphasizing the way of browsing
 relations. As such, attributes will be regarded as cases of
-special relations (in terms of implementation, the user
-language not to see virtually no difference between an attribute and a
+special relations (in terms of implementation, the language
+user should see virtually no difference between an attribute and a
 relation).
 
 RQL is inspired by SQL but is the highest level. A knowledge of the 
@@ -34,7 +34,7 @@
 
 Versa
 `````
-Should I look in more detail, but here is already some ideas for
+We should look in more detail, but here are already some ideas for
 the moment ... Versa_ is the language most similar to what we wanted
 to do, but the model underlying data being RDF, there is some
 number of things such as namespaces or handling of the RDF types which 
@@ -54,19 +54,18 @@
 ------------------------------
 
 Search (`Any`)
-   This type of query can extract entities and attributes of entities.
+   Extract entities and attributes of entities.
 
-Inserting entities (`INSERT`)
-   This type of query is used to insert new entities in the database. It
-   will also create direct relationships entities newly created.
+Insert entities (`INSERT`)
+   Insert new entities or relations in the database.
+   It can also directly create relationships for the newly created entities.
 
-Update entities, relations creation (`SET`)
-   This type of query updates existing entities in the database,
+Update entities, create relations (`SET`)
+   Update existing entities in the database,
    or create relations between existing entities.
 
-Deletion of entities or relationship (`DELETE`)
-   This type of query allows for the removal of entities and relations existing
-   in the database.
+Delete entities or relationship (`DELETE`)
+   Remove entities or relations existing in the database.
 
 Search Query
 ------------
@@ -80,7 +79,7 @@
    Type of selected variables.
    The special type `Any` is equivalent to not specify a type.
 :restriction:
-   list of relations to go through whic follow the pattern
+   list of conditions to test successively 
      `V1 relation V2 | <static value>`
 :orderterms:
    Definition of the selection order: variable or column number followed by
@@ -92,13 +91,13 @@
 
 
 - *Search for the object of identifier 53*
-   ::
+  ::
 
         Any WHERE X
         X eid 53
 
 - *Search material such as comics, owned by syt and available*
-   ::
+  ::
 
         WHERE X Document
         X occurence_of F, F class C, C name 'Comics'
@@ -106,57 +105,65 @@
         X available true
 
 - *Looking for people working for eurocopter interested in training*
-   ::
+  ::
 
         Any P WHERE
-        P is Person, P work_for P, S name 'Eurocopter'
+        P is Person, P work_for S, S name 'Eurocopter'
         P interested_by T, T name 'training'
 
 - *Search note less than 10 days old written by jphc or ocy*
-   ::
+  ::
 
         Any N WHERE
         N is Note, N written_on D, D day> (today -10),
         N written_by P, P name 'jphc' or P name 'ocy'
 
 - *Looking for people interested in training or living in Paris*
-   ::
+  ::
 
         Any P WHERE
         P is Person, (P interested_by T, T name 'training') OR
         (P city 'Paris')
 
 - *The name and surname of all people*
-   ::
+  ::
 
         Any N, P WHERE
         X is Person, X name N, X first_name P
 
-   Note that the selection of several entities generally force
-   the use of "Any" because the type specification applies otherwise
-   to all the selected variables. We could write here
-   ::
+  Note that the selection of several entities generally force
+  the use of "Any" because the type specification applies otherwise
+  to all the selected variables. We could write here
+  ::
 
         String N, P WHERE
         X is Person, X name N, X first_name P
 
 
+  Note: You can not specify several types with * ... where X is FirstType or X is SecondType*.
+  To specify several types explicitely, you have to do
+
+  ::
+
+        Any X where X is in (FirstType, SecondType)
+
+
 Insertion query
 ---------------
 
     `INSERT` <entity type> V1 (, <entity type> V2) \ * `:` <assignments>
     [ `WHERE` <restriction>]
 
-: assignments:
+:assignments:
    list of relations to assign in the form `V1 relationship V2 | <static value>`
 
 The restriction can define variables used in assignments.
 
 Caution, if a restriction is specified, the insertion is done for 
-*each line results returned by the restriction*.
+*each line result returned by the restriction*.
 
 - *Insert a new person named 'foo'*
-   ::
+  ::
 
         INSERT Person X: X name 'foo'
 
@@ -178,12 +185,12 @@
     [ `WHERE` <restriction>]
 
 Caution, if a restriction is specified, the update is done *for
-each line results returned by the restriction*.
+each result line returned by the restriction*.
 
 - *Renaming of the person named 'foo' to 'bar' with the first name changed*
   ::
 
-        SET X name 'bar', X first_name 'original' where X is Person X name 'foo'
+        SET X name 'bar', X first_name 'original' WHERE X is Person, X name 'foo'
 
 - *Insert a relation of type 'know' between objects linked by 
   the relation of type 'friend'*
@@ -198,7 +205,7 @@
     [ `WHERE` <restriction>]
 
 Caution, if a restriction is specified, the deletion is made *for
-each line results returned by the restriction*.
+each line result returned by the restriction*.
 
 - *Deletion of the person named 'foo'*
   ::
@@ -211,8 +218,8 @@
         DELETE X friend Y WHERE X is Person, X name 'foo'
 
 
-Undocumented (yet) type of queries
-----------------------------------
+(yet) Undocumented types of queries
+-----------------------------------
 
 **Limit / offset**
 ::
@@ -302,14 +309,14 @@
 ``````````````
 
 The base types supported are string (between double or single quotes),
-integers or floats (the separator is the'.'), dates and
+integers or floats (the separator is '.'), dates and
 boolean. We expect to receive a schema in which types String,
 Int, Float, Date and Boolean are defined.
 
 * `String` (literal: between double or single quotes).
 * `Int`, `Float` (separator being'.').
 * `Date`, `Datetime`, `Time` (literal: string YYYY/MM/DD [hh:mm] or keywords
-   `TODAY` and `NOW`).
+  `TODAY` and `NOW`).
 * `Boolean` (keywords `TRUE` and `FALSE`).
 * `Keyword` NULL.
 
@@ -318,10 +325,10 @@
 ---------
 
 Logical Operators
-```````````````````
+`````````````````
 ::
 
-     AND, OR, ','
+     AND, OR, NOT, ','
 
 ',' is equivalent to 'AND' but with the smallest among the priority
 of logical operators (see :ref:`PriorityOperators`).
@@ -336,7 +343,7 @@
 ````````````````````
 ::
 
-     =, <, <=, >=, > = ~, IN, LIKE
+     =, <, <=, >=, >, ~=, IN, LIKE
 
 * The operator `=` is the default operator.
 
@@ -345,7 +352,7 @@
   must start or finish by a prefix/suffix:
   ::
 
-     Any X WHERE X name =~ 'Th%'
+     Any X WHERE X name ~= 'Th%'
      Any X WHERE X name LIKE '%lt'
 
 * The operator `IN` provides a list of possible values:
@@ -354,30 +361,32 @@
     Any X WHERE X name IN ( 'chauvat', 'fayolle', 'di mascio', 'thenault')
 
 
-XXX nico: A trick <> 'bar' would not it be more convenient than NOT A
-trick 'bar'?
+XXX nico: "A trick <> 'bar'" wouldn't it be more convenient than 
+"NOT A trick 'bar'" ?
 
 .. _PriorityOperators:
 
-Operators priority
-``````````````````
+Operator priority
+`````````````````
 
 1. '*', '/'
 
 2. '+', '-'
 
-3. 'and'
+3. 'not'
+
+4 'and'
 
-4. 'or'
+5 'or'
 
-5. ','
+6 ','
 
 
 Advanced Features
 -----------------
 
-Functions aggregates
-````````````````````
+Aggregate Functions
+```````````````````
 ::
 
      COUNT, MIN, MAX, AVG, SUM
@@ -468,11 +477,11 @@
      constant    ::= KEYWORD | STRING | FLOAT | INT
 
      # tokens
-     LOGIC_OP ::= ',' | 'GOLD' | 'AND'
+     LOGIC_OP ::= ',' | 'OR' | 'AND'
      MATH_OP  ::= '+' | '-' | '/' | '*'
      COMP_OP  ::= '>' | '>=' | '=' | '<=' | '<' | '~=' | 'LIKE'
 
-     FUNCTION ::= 'MIN' | 'MAX' | 'SUM' | 'AVG' | 'COUNT' | 'upper' | 'LOWER'
+     FUNCTION ::= 'MIN' | 'MAX' | 'SUM' | 'AVG' | 'COUNT' | 'UPPER' | 'LOWER'
 
      VARIABLE ::= '[A-Z][A-Z0-9]*'
      E_TYPE   ::= '[A-Z]\w*'
@@ -541,13 +550,13 @@
 
 ::
 
-     Select         ((Relationship | And | Gold)?, Group?, Sort?)
-     Insert         (Relations | And | Gold)?
-     Delete         (Relationship | And | Gold)?
-     Update         (Relations | And | Gold)?
+     Select         ((Relationship | And | Or)?, Group?, Sort?)
+     Insert         (Relations | And | Or)?
+     Delete         (Relationship | And | Or)?
+     Update         (Relations | And | Or)?
 
-     And            ((Relationship | And | Gold), (Relationship | And | Gold))
-     Or             ((Relationship | And | Gold), (Relationship | And | Gold))
+     And            ((Relationship | And | Or), (Relationship | And | Or))
+     Or             ((Relationship | And | Or), (Relationship | And | Or))
 
      Relationship   ((VariableRef, Comparison))
 
@@ -578,20 +587,20 @@
 
      Point P where P abs X, P ord Y, P value X+Y
 
-   is valid, but::
+  is valid, but::
 
      Point P where P abs X, P value X+Y, P ord Y
 
-   is not.
+  is not.
 
 RQL logs
 --------
 
-You can configure the `CubicWeb` application so that you keep a log
-of the queries executed against your database. To do so, you want to
+You can configure the `CubicWeb` application to keep a log
+of the queries executed against your database. To do so, 
 edit the configuration file of your application 
 ``.../etc/cubicweb.d/myapp/all-in-one.conf`` and uncomment the
-variable ``query-log-file``: ::
+variable ``query-log-file``::
 
   # web application query log file
   query-log-file=/tmp/rql-myapp.log
--- a/doc/book/en/D000-annex.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/D000-annex.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,9 +1,10 @@
 .. -*- coding: utf-8 -*-
 
+.. _Part4:
 
-=================
-Part IV - Annexes
-=================
+====================
+Part IV - Appendixes
+====================
 
 The following chapters are reference material.
  
--- a/doc/book/en/D010-faq.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/D010-faq.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -99,9 +99,9 @@
   the application `Error while publishing ...` for Rest text and plain text.
   The server returns a traceback like as follows ::
 
-      2008-10-06 15:05:08 - (erudi.rest) ERROR: error while publishing ReST text
+      2008-10-06 15:05:08 - (cubicweb.rest) ERROR: error while publishing ReST text
       Traceback (most recent call last):
-      File "/home/sandrine/src/blogdemo/ginco/common/rest.py", line 217, in rest_publish
+      File "/home/user/src/blogdemo/cubicweb/common/rest.py", line 217, in rest_publish
       File "/usr/lib/python2.5/codecs.py", line 817, in open
       file = __builtin__.open(filename, mode, buffering)
       TypeError: __init__() takes at most 3 arguments (4 given)
@@ -145,9 +145,15 @@
 
   It depends on what has been modified in the schema.
 
-  * Update of a non final relation.
+  * Update of an attribute permissions and properties: 
+    ``synchronize_eschema('MyEntity')``.
 
-  * Update of a final relation.
+  * Update of a relation permissions and properties: 
+    ``synchronize_rschema('MyRelation')``.
+
+  * Add an attribute: ``add_attribute('MyEntityType', 'myattr')``.
+
+  * Add a relation: ``add_relation_definition('SubjRelation', 'MyRelation', 'ObjRelation')``.
 
 
 * How to create an anonymous user?
@@ -156,17 +162,24 @@
   ``all-in-one.conf`` file of your instance, define the anonymous user
   as follows ::
 
-    # login of the Erudi user account to use for anonymous user (if you want to
+    # login of the CubicWeb user account to use for anonymous user (if you want to
     # allow anonymous)
     anonymous-user=anon
 
-    # password of the Erudi user account matching login
+    # password of the CubicWeb user account matching login
     anonymous-password=anon
 
   You also must ensure that this `anon` user is a registered user of
-  the DB backend. This could be the admin account (for development
+  the DB backend. If not, you can create through the administation
+  interface of your instance by adding a user with the role `guests`.
+  This could be the admin account (for development
   purposes, of course).
 
+.. note::
+    While creating a new instance, you can decide to allow access
+    to anonymous user, which will automatically executes what is
+    decribed above.
+
 
 * How to change the application logo?
 
@@ -206,7 +219,7 @@
     user-login-attr=uid
     # name of a group in which ldap users will be by default
     user-default-group=users
-    # map from ldap user attributes to erudi attributes
+    # map from ldap user attributes to cubicweb attributes
     user-attrs-map=gecos:email,uid:login
 
   Any change applied to configuration file requires to restart your
@@ -225,3 +238,13 @@
   This will yield additional WARNINGs, like this: ::
 
     2009-01-09 16:43:52 - (cubicweb.selectors) WARNING: selector one_line_rset returned 0 for <class 'cubicweb.web.views.basecomponents.WFHistoryVComponent'>
+
+* How to format an entity date attribute?
+
+  If your schema has an attribute of type Date or Datetime, you might
+  want to format it. First, you should define your preferred format using
+  the site configuration panel ``http://appurl/view?vid=systemepropertiesform``
+  and then set ``ui.date`` and/or ``ui.datetime``.
+  Then in the view code, use::
+    
+    self.format_date(entity.date_attribute)
--- a/doc/book/en/D030-architecture.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/D030-architecture.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -1,8 +1,8 @@
 .. -*- coding: utf-8 -*-
 
 
-Architecture du serveur
------------------------
+Server Architecture
+-------------------
 
 .. image:: images/server-class-diagram.png
 
--- a/doc/book/en/D070-cookbook.en.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/D070-cookbook.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -10,7 +10,7 @@
 * How to import LDAP users in `CubicWeb`?
 
   Here is a very usefull script which enables you to import LDAP users
-  into your `CubicWeb` application by runing the following: ::
+  into your `CubicWeb` application by running the following: ::
 
 
     import os
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z010-beginners.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,12 @@
+.. -*- coding: utf-8 -*-
+
+.. _QuickInstall:
+
+===========================================
+Quick Installation of a `CubicWeb` instance
+===========================================
+
+.. include:: C011-installation.en.txt
+.. include:: Z012-create-instance.en.txt
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z012-create-instance.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,79 @@
+.. -*- coding: utf-8 -*-
+
+Creation of your first instance
+===============================
+
+What is an instance?
+--------------------
+
+A `CubicWeb` instance is a container that
+refers to cubes and configuration parameters for your web application.
+Each instance is stored as a directory in ``~/etc/cubicweb.d`` which enables 
+us to run your application.
+
+What is a cube?
+---------------
+
+Cubes represent data and basic building bricks of your web applications :
+blogs, person, date, addressbook and a lot more.
+
+.. XXX They related to each other by a 'Schema' which is also the PostGres representation.
+
+Each cube defines entities, their views, their schemas and workflows
+in an independant directory located in ``/path/to/forest/cubicweb/cubes/``
+for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for
+a debian package installation. For example, the 'blog' cube defines the entities 
+blogs and blogentries.
+
+When an `CubicWeb` instance is created, you list the cubes that you want to use. 
+Using a cube means having the entities defined in your cube's schema
+available in your instance as well as their views and workflows.
+
+
+Creating a basic `CubicWeb` Instance 
+------------------------------------
+
+We can create an instance to view our
+application in a web browser. ::
+
+  cubicweb-ctl create blog myblog
+
+.. XXX or ::
+  
+.. XXX cubicweb-ctl create forge myforge
+
+
+.. note::
+   The commands used below are more detailled in the section dedicated to 
+   :ref:`cubicweb-ctl`.
+
+A series of questions will be prompted to you, the default answer is usually
+sufficient. You can allways modify the parameters later by editing
+configuration files. When a user/psswd is requested to access the database
+please use the login you create at the time you configured the database
+(:ref:`ConfigurationPostgres`).
+
+It is important to distinguish here the user used to access the database and
+the user used to login to the cubicweb application. When a `CubicWeb` application
+starts, it uses the login/psswd for the database to get the schema and handle
+low level transaction. But, when ``cubicweb-ctl create`` asks for
+a manager login/psswd of `CubicWeb`, it refers to an application user
+to administrate your web application. 
+The configuration files are stored in *~/etc/cubicweb.d/myblog/*. 
+
+To launch the web application, you just type ::
+
+  cubicweb-ctl start myblog
+
+You can see how it looks by
+visiting the URL `http://localhost:8080`. 
+To login, please use the cubicweb administrator login/psswd you 
+defined when you created the instance.
+
+To shutdown the instance ::
+
+  cubicweb-ctl stop myinstance
+
+.. XXX something like `cubicweb-ctl live-server intra` would be nice
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z013-blog-less-ten-minutes.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,86 @@
+.. -*- coding: utf-8 -*-
+
+.. BlogTenMinutes:
+
+Have a blog ready in less than ten minutes!
+-------------------------------------------
+
+Installation
+~~~~~~~~~~~~
+
+You need to install the following packages::
+
+    cubicweb, cubicweb-blog
+
+The package `cubicweb` is installing the command `cubicweb-ctl` that
+will allow you to create new application.
+
+The package `cubicweb-blog` is installing the blogging support for the
+`CubicWeb` framework.
+
+Application creation
+~~~~~~~~~~~~~~~~~~~~
+
+Creation and initialization of your application by running::
+    
+    cubicweb-ctl create blog myblog
+
+*myblog* is the name of the application you are creating.
+
+*blog* is the name of the component on which your application
+is based. 
+
+Application launch
+~~~~~~~~~~~~~~~~~~
+
+Your application is now ready to go::
+
+    cubicweb-ctl start -D myblog
+
+This is it. Your blog is ready to you. Go to http://localhost:8080 and enjoy!!
+
+
+A little code snapshot from behind the scene
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The component `blog`, referred as a `cube` in the book 
+(see :ref:`TermsVocabulary` for a complete definition), defines
+a data model in ``/usr/share/cubicweb/cubes/blog/schema.py``. 
+Here is the corresponding Python code::
+
+    from cubicweb.schema import format_constraint
+
+    class Blog(EntityType):
+        title = String(maxsize=50, required=True)
+        description_format = String(meta=True, internationalizable=True, maxsize=50,
+                                    default='text/rest', constraints=[format_constraint])
+        description = String()
+        rss_url = String(maxsize=128, description=_('blog\'s rss url (useful for when using external site such as feedburner)'))
+
+
+    class BlogEntry(EntityType):
+        title = String(required=True, fulltextindexed=True, maxsize=256)
+        content_format = String(meta=True, internationalizable=True, maxsize=50,
+                                default='text/rest', constraints=[format_constraint])
+        content = String(required=True, fulltextindexed=True)
+        entry_of = SubjectRelation('Blog', cardinality='?*')
+
+Two types of entities are defined here: Blog and BlogEntry.
+
+A Blog is defined by a title, a description and its format and a
+RSS URL to provide RSS feed.
+
+A BlogEntry is defined by a title, a content and its format and
+a relation to a Blog, meaning a BlogEntry belongs to a Blog.
+
+
+Next step
+~~~~~~~~~
+
+This was a brief demonstration of the re-usability of cubes and a way
+to show how you can use `CubicWeb` straigth out of the box.
+
+As a developper, you'll want to know more about how to develop new
+cubes and cutomize the views and this is what we talk about now. 
+
+
--- a/doc/book/en/index.txt	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/index.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -29,15 +29,16 @@
 
 The hacker will join development at the forge_.
 
-The impatient will move right away to :ref:`MiseEnPlaceEnv`.
+The impatient will go strait away to :ref:`QuickInstall`.
+
+The impatient developper will move right away to :ref:`SetUpEnv`.
 
 .. _Logilab: http://www.logilab.fr/
 .. _forge: http://www.cubicweb.org/project/
 .. _Python: http://www.python.org/
 
-Table of contents
-=================
-
+The book
+========
 
 .. toctree::
    :maxdepth: 2
@@ -45,7 +46,13 @@
    A000-introduction.en.txt
    B000-development.en.txt
    C000-administration.en.txt
-   D000-annex.en.txt
+   D000-annex.en.txt    
+
+
+Table of Contents
+-----------------
+
+Complete :ref:`TOC`.
 
 Indices and tables
 ==================
--- a/doc/book/en/makefile	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/en/makefile	Wed Apr 15 17:36:09 2009 +0200
@@ -43,7 +43,7 @@
 #apydoc: 
 #	epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py
 apidoc:
-	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../
+	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../
 
 # run sphinx ###
 html:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/toc.en.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,15 @@
+.. -*- coding: utf-8 -*-
+
+.. _TOC:
+
+Table of contents
+=================
+
+
+.. toctree::
+
+   A000-introduction.en.txt
+   B000-development.en.txt
+   C000-administration.en.txt
+   D000-annex.en.txt
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/fr/03-XX-external_resources.fr.txt	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,135 @@
+.. -*- coding: utf-8 -*-
+
+
+Les ressources externes
+=======================
+
+Les ressources externes à une application regroupent l'ensemble des fichiers qui seront chargés dans l'entête des pages XHTML générées.
+Elles sont donc constituées principalement des feuilles de styles, des scripts javascripts et de certaines ressources graphiques comme l'icône favicon par exemple.
+
+
+Liste des feuilles de styles utilisées par défaut
+-------------------------------------------------
+
+Les fichiers par défaut se trouve dans les sources du framework. En voici le tableau récapitulatif:
+
++--------------------------------------+----------------------------------------------------+-----------------------------------+
+| Fichiers                             | Utilisation                                        | Vues ou widget concernés          |
++======================================+====================================================+===================================+
+| web/data/cubicweb.acl.css            | formulaires pour le contrôle aux accès             | editgroups, security              |
+| web/data/cubicweb.calendar.css       | calendriers                                        | onemonthcal, oneweekcal           |
+| web/data/cubicweb.calendar_popup.css | popup calendriers                                  | DateWidget                        |
+| web/data/cubicweb.css                | gabarit principal de l'application                 |                                   |
+| web/data/cubicweb.facets.css         | surcharge du `MIT Simile Exhibit Web Widgets`_     | filter_box                        |
+| web/data/cubicweb.form.css           | formulaires                                        | creation, inline-creation, copya, |
+|                                      |                                                    | inline-edition, edition, muledit  |
+| web/data/cubicweb.html_tree.css      | style pour les widgets d'arborescence              |                                   |
+| web/data/cubicweb.ie.css             | dédié aux comportements de Internet Explorer       |                                   |
+| web/data/cubicweb.iprogress.css      | style pour les widgets d'avancement                |                                   |
+| web/data/cubicweb.login.css          | page et popup d'authentification                   | logform                           |
+| web/data/cubicweb.mailform.css       | style utilisé dans les formulaires d'envoi de mail |                                   |
+| web/data/cubicweb.preferences.css    | style pour la page des préférences utilisateurs    | systemepropertiesform             |
+| web/data/cubicweb.print.css          | style dédié à l'impression                         |                                   |
+| web/data/cubicweb.schema.css         | style dédié au schéma de l'application             |                                   |
+| web/data/cubicweb.suggest.css        | surcharge utilisée pour les suggestions            |                                   |
+| web/data/cubicweb.tablesorter.css    | surcharge pour le tri dans les tableau             |                                   |
+| web/data/cubicweb.tableview.css      | surcharge pour le tri sélectif                     |                                   |
+| web/data/cubicweb.timetable.css      | style pour le widget Timetable                     | timetable                         |
+| web/data/jquery.autocomplete.css     | surcharge pour le widget `jQuery autocompleter`_   |                                   |
+| web/data/jquery.treeview.css         | surcharge pour le widget `jQuery treeview`_        |                                   |
+| web/data/pygments.css                | style pour la coloration des blocs de code         |                                   |
+| web/data/timeline-bundle.css         | surcharge du `MIT Simile Timeline Web Widgets`_    | TimelineWidget                    |
+| web/data/ui.tabs.css                 | surcharge pour le widget Tabs de `jQuery UI`_      |                                   |
++--------------------------------------+----------------------------------------------------+-----------------------------------+
+
+.. _MIT Simile Exhibit Web Widgets: http://code.google.com/p/simile-widgets/wiki/Exhibit
+.. _MIT Simile Timeline Web Widgets: http://code.google.com/p/simile-widgets/wiki/Timeline
+.. _jQuery autocompleter: http://www.dyve.net/jquery/?autocomplete
+.. _jQuery treeview: http://plugins.jquery.com/project/treeview
+.. _jQuery UI: http://docs.jquery.com/UI
+
+D'une manière générale, si vous réutiliser un nom de fichier existant, vous écrasez le contenu du fichier d'origine.
+
+
+Changer les feuilles de styles
+------------------------------
+
+Configuration statique
+~~~~~~~~~~~~~~~~~~~~~~
+Dans les sources de votre nouveau cube, vous devez éditer le fichier *data/external_resources* et définir la variable de configuration:
+
+    # CSS stylesheets to include in HTML headers
+    # uncomment the line below to use template specific stylesheet
+    STYLESHEETS = DATADIR/cubicweb.css
+
+Les styles sont définis dans le fichier external_resources par 3 variables:
+
+- la variable STYLESHEETS est défine pour tous les types de médias
+- la variable STYLESHEETS_PRINT sont les styles applicables pour l'impression
+- la variable IE_STYLESHEETS s'appliquent uniquement aux versions d'Internet Explorer
+
+En copiant le fichier d'origine **cubicweb.css**, il est alors possible de modifier le gabarit de base du framework CubicWeb.
+Il est également possible de réutiliser le fichier d'origine.
+
+En créant un nouveau fichier **cubes.(le_nom_du_cube).css** dans le répertoire **data/** et en ajoutant une directive css @import, il est possible de réutiliser les styles définis par défaut:
+
+    @import url("cubicweb.css");
+
+
+Chargement dynamique de feuilles de style dans vos vues
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Il est possible de charger des css spécifiques pour une vue par l'utilisation de la méthode add_css():
+
+    self.req.add_css('mon_cube.css')
+
+
+Les ressources graphiques de base
+---------------------------------
+
+Vous pouvez changer certaines ressources graphiques comme:
+
+- le logo du site:
+
+    # path to the logo (relative to the application main script, seen as a
+    # directory, hence .. when you are not using an absolute path)
+    LOGO = DATADIR/logo.png
+
+- la 'favicon' du site:
+
+    FAVICON = DATADIR/favicon.ico
+
+- le logo des flux RSS:
+
+    RSS_LOGO = DATADIR/rss.png
+
+- l'icône permettant l'appel au widget 'calendrier':
+
+    CALENDAR_ICON = DATADIR/calendar.png
+
+- l'icône utilisée pour la validation d'une recherche:
+
+    SEARCH_GO = DATADIR/go.png
+
+- l'icône d'aide en ligne:
+
+    HELP = DATADIR/help.png
+
+
+Ajouter vos scripts javascripts
+-------------------------------
+
+Configuration statique
+~~~~~~~~~~~~~~~~~~~~~~
+Vous devez surcharger la variable JAVASCRIPTS dans le fichier *data/external_resources*  de votre cube.
+
+Chargement dynamique de script javascript dans vos vues
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Il est possible de charger vos scripts par la méthode add_js():
+
+    self.req.add_js('mon_script.js')
+
+
+Problèmes connus
+----------------
+
+Il est important de noter que la méthode de chargement dynamique ne marche pas avec les widgets Ajax. Vos fichiers devront déjà être au préalable avoir été chargés.
--- a/doc/book/fr/makefile	Thu Jan 15 10:13:25 2009 +0100
+++ b/doc/book/fr/makefile	Wed Apr 15 17:36:09 2009 +0200
@@ -43,7 +43,7 @@
 #apydoc: 
 #	epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py
 apidoc:
-	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../
+	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../
 
 # run sphinx ###
 html:
--- a/entities/__init__.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/entities/__init__.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """base application's entities class implementation: `AnyEntity`
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
--- a/entities/authobjs.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/entities/authobjs.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,3 +1,10 @@
+"""entity classes user and group entities
+
+: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 cached
 
 from cubicweb import Unauthorized
@@ -26,6 +33,7 @@
                   'in_group'   : 'primary', 
                   ('owned_by', '*', 'object') : ('generated', 'link'),
                   ('created_by','*','object') : ('generated', 'link'),
+                  ('bookmarked_by', '*', 'object'): ('generated', 'create'),
                   }
     
     # used by repository to check if  the user can log in or not
@@ -85,6 +93,13 @@
         """
         return self.matching_groups(group) == 1
 
+    def is_anonymous(self):
+        """ checks if user is an anonymous user"""
+        #FIXME on the web-side anonymous user is detected according
+        # to config['anonymous-user'], we don't have this info on
+        # the server side. 
+        return self.groups == frozenset(('guests', ))
+
     def owns(self, eid):
         if hasattr(self.req, 'unsafe_execute'):
             # use unsafe_execute on the repository side, in case
--- a/entities/lib.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/entities/lib.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """entity classes for optional library entities
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
--- a/etwist/server.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/etwist/server.py	Wed Apr 15 17:36:09 2009 +0200
@@ -86,7 +86,7 @@
         if config.repo_method == 'inmemory':
             reactor.addSystemEventTrigger('before', 'shutdown',
                                           self.shutdown_event)
-            # monkey path start_looping_task to get proper reactor integration
+            # monkey patch start_looping_task to get proper reactor integration
             self.appli.repo.__class__.start_looping_tasks = start_looping_tasks
             if config.pyro_enabled():
                 # if pyro is enabled, we have to register to the pyro name
@@ -182,7 +182,7 @@
             # don't allow anonymous on https connection
             return self.request_auth(req)            
         if self.url_rewriter is not None:
-            # XXX should occurs before authentication?
+            # XXX should occur before authentication?
             try:
                 path = self.url_rewriter.rewrite(host, origpath)
             except Redirect, ex:
--- a/goa/__init__.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/__init__.py	Wed Apr 15 17:36:09 2009 +0200
@@ -28,7 +28,7 @@
     regular python datetime object
     """
     if yamstype is None:
-        yamstype = guess_yamstype_from_date(datetimeobj)
+        yamstype = guess_yamstype_for_date(datetimeobj)
     assert yamstype is not None
     if yamstype == 'Datetime':
         # don't use date, db model doesn't actually support it, only datetime
--- a/goa/appobjects/components.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/appobjects/components.py	Wed Apr 15 17:36:09 2009 +0200
@@ -15,7 +15,7 @@
 from cubicweb.schema import display_name
 from cubicweb.common.view import StartupView, EntityView
 from cubicweb.common.selectors import (one_line_rset, match_search_state,
-                                    accept_selector)
+                                    accept)
 from cubicweb.web import Redirect
 from cubicweb.web.views import vid_from_rset
 from cubicweb.goa.db import rset_from_objs
@@ -31,7 +31,7 @@
     """
     id = 'search-associate'
     
-    __selectors__ = (one_line_rset, match_search_state, accept_selector)
+    __selectors__ = (one_line_rset, match_search_state, accept)
     accepts = ('Any',)
     search_states = ('linksearch',)
 
--- a/goa/db.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/db.py	Wed Apr 15 17:36:09 2009 +0200
@@ -391,7 +391,7 @@
 
     @classmethod
     def kind(cls):
-        return self.id
+        return cls.id
 
     @classmethod
     def properties(cls):
--- a/goa/dbmyams.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/dbmyams.py	Wed Apr 15 17:36:09 2009 +0200
@@ -109,6 +109,7 @@
         super(GaeSchemaLoader, self).__init__(*args, **kwargs)
         self.defined = {}
         self.created = []
+        self.loaded_files = []
         self._instantiate_handlers()
         
     def finalize(self, register_base_types=False):
--- a/goa/goactl.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/goactl.py	Wed Apr 15 17:36:09 2009 +0200
@@ -211,12 +211,12 @@
         # link every supported components
         packagesdir = join(appldir, 'cubes')
         create_init_file(join(appldir, 'cubes'), 'cubes')
-        cubesdir = CubicWebConfiguration.cubes_dir()
-        for include in ('addressbook','basket', 'blog','classfolders',
-                        'classtags', 'comment', 'file', 'link',
+        for include in ('addressbook','basket', 'blog','folder',
+                        'tag', 'comment', 'file', 'link',
                         'mailinglist', 'person', 'task', 'zone',
                         ):
-            create_symlink(join(cubesdir, include), join(packagesdir, include))
+            create_symlink(CubicWebConfiguration.cube_dir(include),
+                           join(packagesdir, include))
         # generate sample config
         from cubicweb.goa.goaconfig import GAEConfiguration
         from cubicweb.common.migration import MigrationHelper
--- a/goa/overrides/rqlannotation.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/overrides/rqlannotation.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,4 +1,4 @@
-def set_qdata(union, noinvariant):
+def set_qdata(getrschema, union, noinvariant):
     pass
         
 class SQLGenAnnotator(object):
--- a/goa/test/unittest_editcontroller.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/test/unittest_editcontroller.py	Wed Apr 15 17:36:09 2009 +0200
@@ -17,7 +17,7 @@
     config.global_set_option('use-google-auth', False)
     config.global_set_option('schema-type', 'yams')
     config.global_set_option('included-cubes', ())
-    config.global_set_option('included-yams-cubes', ('eblog',))
+    config.global_set_option('included-yams-cubes', ('blog',))
     
     MODEL_CLASSES = ()
     from cubicweb.web.views import editcontroller
--- a/goa/testlib.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/testlib.py	Wed Apr 15 17:36:09 2009 +0200
@@ -7,7 +7,7 @@
 # additional monkey patches necessary in regular cubicweb environment
 from cubicweb.server import rqlannotation
 from cubicweb.goa.overrides import rqlannotation as goarqlannotation
-rqlannotation.sqlgen_annotate = goarqlannotation.sqlgen_annotate
+rqlannotation.SQLGenAnnotator = goarqlannotation.SQLGenAnnotator
 rqlannotation.set_qdata = goarqlannotation.set_qdata
 
 try:
@@ -58,7 +58,7 @@
     _DS_TEMPL_FILE = 'tmpdb-template'
 
     def load_schema_hook(self, loader):
-        loader.import_yams_template_schema('data')
+        loader.import_yams_cube_schema('data')
     
     @property
     def DS_FILE(self):
--- a/goa/tools/i18n.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/goa/tools/i18n.py	Wed Apr 15 17:36:09 2009 +0200
@@ -221,7 +221,7 @@
     os.chdir(appdirectory)
     potfiles = []
     if osp.exists(osp.join('i18n', 'entities.pot')):
-        potfiles = potfiles.append( osp.join('i18n', scfile) )
+        potfiles = potfiles.append( osp.join('i18n', 'entities.pot') )
     print '******** extract schema messages'
     schemapot = osp.join(tempdir, 'schema.pot')
     potfiles.append(schemapot)
--- a/i18n/en.po	Thu Jan 15 10:13:25 2009 +0100
+++ b/i18n/en.po	Wed Apr 15 17:36:09 2009 +0200
@@ -47,10 +47,26 @@
 msgstr ""
 
 #, python-format
+msgid "%d days"
+msgstr ""
+
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#, python-format
 msgid "%d months"
 msgstr ""
 
 #, python-format
+msgid "%d seconds"
+msgstr ""
+
+#, python-format
 msgid "%d weeks"
 msgstr ""
 
@@ -59,7 +75,31 @@
 msgstr ""
 
 #, python-format
-msgid "%s days"
+msgid "%d&nbsp;days"
+msgstr ""
+
+#, python-format
+msgid "%d&nbsp;hours"
+msgstr ""
+
+#, python-format
+msgid "%d&nbsp;minutes"
+msgstr ""
+
+#, python-format
+msgid "%d&nbsp;months"
+msgstr ""
+
+#, python-format
+msgid "%d&nbsp;seconds"
+msgstr ""
+
+#, python-format
+msgid "%d&nbsp;weeks"
+msgstr ""
+
+#, python-format
+msgid "%d&nbsp;years"
 msgstr ""
 
 #, python-format
@@ -67,14 +107,6 @@
 msgstr ""
 
 #, python-format
-msgid "%s hours"
-msgstr ""
-
-#, python-format
-msgid "%s minutes"
-msgstr ""
-
-#, python-format
 msgid "%s not estimated"
 msgstr ""
 
@@ -83,10 +115,6 @@
 msgstr ""
 
 #, python-format
-msgid "%s seconds"
-msgstr ""
-
-#, python-format
 msgid "%s software version of the database"
 msgstr ""
 
@@ -618,6 +646,12 @@
 msgid "actions_delete_description"
 msgstr ""
 
+msgid "actions_download_as_owl"
+msgstr ""
+
+msgid "actions_download_as_owl_description"
+msgstr ""
+
 msgid "actions_edit"
 msgstr "modify"
 
@@ -717,6 +751,9 @@
 msgid "add"
 msgstr ""
 
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr "bookmark"
+
 msgid "add EEType add_permission RQLExpression subject"
 msgstr "rql expression for the add permission"
 
@@ -1311,6 +1348,9 @@
 msgid "created_by_object"
 msgstr "has created"
 
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr "creating bookmark for %(linkto)s"
+
 msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
 msgstr "creating constraint for attribute %(linkto)s"
 
@@ -1400,6 +1440,10 @@
 msgid "csv export"
 msgstr ""
 
+#, python-format
+msgid "currently attached file: %s"
+msgstr ""
+
 msgid "data directory url"
 msgstr ""
 
@@ -1512,7 +1556,8 @@
 msgid "destination_state_object"
 msgstr "destination of"
 
-msgid "detach attached file"
+#, python-format
+msgid "detach attached file %s"
 msgstr ""
 
 msgid "detailed schema view"
@@ -1547,6 +1592,9 @@
 msgid "download icon"
 msgstr ""
 
+msgid "download schema as owl"
+msgstr ""
+
 msgid "edit bookmarks"
 msgstr ""
 
@@ -1668,12 +1716,18 @@
 msgid "february"
 msgstr ""
 
+msgid "file tree view"
+msgstr ""
+
 msgid "final"
 msgstr ""
 
 msgid "firstname"
 msgstr ""
 
+msgid "foaf"
+msgstr ""
+
 msgid "follow"
 msgstr ""
 
@@ -1991,12 +2045,20 @@
 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 ""
 
 msgid "list"
 msgstr ""
 
+msgid "loading"
+msgstr ""
+
 msgid "log in"
 msgstr ""
 
@@ -2025,6 +2087,9 @@
 msgid "manage bookmarks"
 msgstr ""
 
+msgid "manage permissions"
+msgstr ""
+
 msgid "manage security"
 msgstr ""
 
@@ -2137,6 +2202,9 @@
 msgid "not authorized"
 msgstr ""
 
+msgid "not selected"
+msgstr ""
+
 msgid "not specified"
 msgstr ""
 
@@ -2173,6 +2241,12 @@
 msgid "ordernum"
 msgstr "order"
 
+msgid "owl"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
 msgid "owned_by"
 msgstr "owned by"
 
@@ -2216,6 +2290,9 @@
 msgid "pkey"
 msgstr "key"
 
+msgid "planned_delivery"
+msgstr "planned delivery"
+
 msgid "please correct errors below"
 msgstr ""
 
@@ -2416,6 +2493,9 @@
 msgid "select this entity"
 msgstr ""
 
+msgid "selected"
+msgstr ""
+
 msgid "semantic description of this attribute"
 msgstr ""
 
@@ -2617,6 +2697,9 @@
 msgid "transition_of_object"
 msgstr "use transitions"
 
+msgid "tree view"
+msgstr ""
+
 msgid "tuesday"
 msgstr ""
 
--- a/i18n/es.po	Thu Jan 15 10:13:25 2009 +0100
+++ b/i18n/es.po	Wed Apr 15 17:36:09 2009 +0200
@@ -52,10 +52,26 @@
 msgstr "%(subject)s %(etype)s #%(eid)s (%(login)s)"
 
 #, python-format
+msgid "%d days"
+msgstr "%d días"
+
+#, python-format
+msgid "%d hours"
+msgstr "%d horas"
+
+#, python-format
+msgid "%d minutes"
+msgstr "%d minutos"
+
+#, python-format
 msgid "%d months"
 msgstr "%d meses"
 
 #, python-format
+msgid "%d seconds"
+msgstr "%d segundos"
+
+#, python-format
 msgid "%d weeks"
 msgstr "%d semanas"
 
@@ -64,22 +80,38 @@
 msgstr "%d años"
 
 #, python-format
-msgid "%s days"
-msgstr "%d días"
+msgid "%d&nbsp;days"
+msgstr "%d&nbsp;días"
+
+#, python-format
+msgid "%d&nbsp;hours"
+msgstr "%d&nbsp;horas"
+
+#, python-format
+msgid "%d&nbsp;minutes"
+msgstr "%d&nbsp;minutos"
+
+#, python-format
+msgid "%d&nbsp;months"
+msgstr "%d&nbsp;meses"
+
+#, python-format
+msgid "%d&nbsp;seconds"
+msgstr "%d&nbsp;segundos"
+
+#, python-format
+msgid "%d&nbsp;weeks"
+msgstr "%d&nbsp;semanas"
+
+#, python-format
+msgid "%d&nbsp;years"
+msgstr ""
 
 #, python-format
 msgid "%s error report"
 msgstr "%s reporte de errores"
 
 #, python-format
-msgid "%s hours"
-msgstr "%s horas"
-
-#, python-format
-msgid "%s minutes"
-msgstr "%s minutos"
-
-#, python-format
 msgid "%s not estimated"
 msgstr "%s no estimado(s)"
 
@@ -88,10 +120,6 @@
 msgstr "%s resultados de la demanda"
 
 #, python-format
-msgid "%s seconds"
-msgstr "%s segundos"
-
-#, python-format
 msgid "%s software version of the database"
 msgstr "version sistema de la base para %s"
 
@@ -639,6 +667,12 @@
 msgid "actions_delete_description"
 msgstr ""
 
+msgid "actions_download_as_owl"
+msgstr ""
+
+msgid "actions_download_as_owl_description"
+msgstr ""
+
 msgid "actions_edit"
 msgstr "modificar"
 
@@ -738,6 +772,9 @@
 msgid "add"
 msgstr "agregar"
 
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr ""
+
 msgid "add EEType add_permission RQLExpression subject"
 msgstr "Definir una expresión RQL de agregación"
 
@@ -1359,6 +1396,9 @@
 msgid "created_by_object"
 msgstr "ha creado"
 
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr ""
+
 msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
 msgstr "creación condicionada por el atributo %(linkto)s"
 
@@ -1457,6 +1497,10 @@
 msgid "csv export"
 msgstr "exportar CSV"
 
+#, python-format
+msgid "currently attached file: %s"
+msgstr ""
+
 msgid "data directory url"
 msgstr "url del repertorio de datos"
 
@@ -1582,8 +1626,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 ""
 
 msgid "detailed schema view"
 msgstr "vista detallada del esquema"
@@ -1619,6 +1664,9 @@
 msgid "download icon"
 msgstr "ícono de descarga"
 
+msgid "download schema as owl"
+msgstr ""
+
 msgid "edit bookmarks"
 msgstr "editar los atajos"
 
@@ -1745,12 +1793,18 @@
 msgid "february"
 msgstr "febrero"
 
+msgid "file tree view"
+msgstr ""
+
 msgid "final"
 msgstr "final"
 
 msgid "firstname"
 msgstr "nombre"
 
+msgid "foaf"
+msgstr ""
+
 msgid "follow"
 msgstr "seguir la liga"
 
@@ -2084,12 +2138,20 @@
 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"
 
 msgid "list"
 msgstr "liste"
 
+msgid "loading"
+msgstr ""
+
 msgid "log in"
 msgstr "s'identifier"
 
@@ -2118,6 +2180,9 @@
 msgid "manage bookmarks"
 msgstr "gÈrer les signets"
 
+msgid "manage permissions"
+msgstr ""
+
 msgid "manage security"
 msgstr "gestion de la sÈcuritÈ"
 
@@ -2232,6 +2297,9 @@
 msgid "not authorized"
 msgstr "non autorisÈ"
 
+msgid "not selected"
+msgstr ""
+
 msgid "not specified"
 msgstr "non spÈcifiÈ"
 
@@ -2268,6 +2336,12 @@
 msgid "ordernum"
 msgstr "ordre"
 
+msgid "owl"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
 msgid "owned_by"
 msgstr "appartient ‡"
 
@@ -2312,6 +2386,9 @@
 msgid "pkey"
 msgstr "clÈ"
 
+msgid "planned_delivery"
+msgstr ""
+
 msgid "please correct errors below"
 msgstr "veuillez corriger les erreurs ci-dessous"
 
@@ -2521,6 +2598,9 @@
 msgid "select this entity"
 msgstr "sÈlectionner cette entitÈ"
 
+msgid "selected"
+msgstr ""
+
 msgid "semantic description of this attribute"
 msgstr "description sÈmantique de cet attribut"
 
@@ -2726,6 +2806,9 @@
 msgid "transition_of_object"
 msgstr "a pour transition"
 
+msgid "tree view"
+msgstr ""
+
 msgid "tuesday"
 msgstr "mardi"
 
@@ -2940,6 +3023,9 @@
 #~ "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"
 
--- a/i18n/fr.po	Thu Jan 15 10:13:25 2009 +0100
+++ b/i18n/fr.po	Wed Apr 15 17:36:09 2009 +0200
@@ -52,10 +52,26 @@
 msgstr "%(subject)s %(etype)s #%(eid)s (%(login)s)"
 
 #, python-format
+msgid "%d days"
+msgstr "%d jours"
+
+#, python-format
+msgid "%d hours"
+msgstr "%d heures"
+
+#, python-format
+msgid "%d minutes"
+msgstr "%d minutes"
+
+#, python-format
 msgid "%d months"
 msgstr "%d mois"
 
 #, python-format
+msgid "%d seconds"
+msgstr "%d secondes"
+
+#, python-format
 msgid "%d weeks"
 msgstr "%d semaines"
 
@@ -64,22 +80,38 @@
 msgstr "%d années"
 
 #, python-format
-msgid "%s days"
-msgstr "%d jours"
+msgid "%d&nbsp;days"
+msgstr "%d&nbsp;jours"
+
+#, python-format
+msgid "%d&nbsp;hours"
+msgstr "%d&nbsp;heures"
+
+#, python-format
+msgid "%d&nbsp;minutes"
+msgstr "%d&nbsp;minutes"
+
+#, python-format
+msgid "%d&nbsp;months"
+msgstr "%d&nbsp;mois"
+
+#, python-format
+msgid "%d&nbsp;seconds"
+msgstr "%d&nbsp;secondes"
+
+#, python-format
+msgid "%d&nbsp;weeks"
+msgstr "%d&nbsp;semaines"
+
+#, python-format
+msgid "%d&nbsp;years"
+msgstr "%d&nbsp;années"
 
 #, python-format
 msgid "%s error report"
 msgstr "%s rapport d'erreur"
 
 #, python-format
-msgid "%s hours"
-msgstr "%s heures"
-
-#, python-format
-msgid "%s minutes"
-msgstr "%s minutes"
-
-#, python-format
 msgid "%s not estimated"
 msgstr "%s non estimé(s)"
 
@@ -88,10 +120,6 @@
 msgstr "%s résultats pour la requête"
 
 #, python-format
-msgid "%s seconds"
-msgstr "%s secondes"
-
-#, python-format
 msgid "%s software version of the database"
 msgstr "version logicielle de la base pour %s"
 
@@ -641,6 +669,12 @@
 msgid "actions_delete_description"
 msgstr ""
 
+msgid "actions_download_as_owl"
+msgstr ""
+
+msgid "actions_download_as_owl_description"
+msgstr ""
+
 msgid "actions_edit"
 msgstr "modifier"
 
@@ -740,6 +774,9 @@
 msgid "add"
 msgstr "ajouter"
 
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr "signet"
+
 msgid "add EEType add_permission RQLExpression subject"
 msgstr "définir une expression RQL d'ajout"
 
@@ -887,7 +924,7 @@
 "s #%(toeid)s"
 
 msgid "address"
-msgstr "adresse"
+msgstr "adresse électronique"
 
 msgid "alias"
 msgstr "alias"
@@ -1197,7 +1234,7 @@
 msgstr "la barre de requête rql, dans l'en-tête de page"
 
 msgid "components_rss_feed_url"
-msgstr ""
+msgstr "syndication rss"
 
 msgid "components_rss_feed_url_description"
 msgstr ""
@@ -1361,14 +1398,17 @@
 msgid "created_by_object"
 msgstr "a créé"
 
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr "création d'un signet pour %(linkto)s"
+
 msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
-msgstr "création contrainte pour l'attribut %(linkto)s"
+msgstr "création d'une contrainte pour l'attribut %(linkto)s"
 
 msgid "creating EConstraint (ENFRDef %(linkto)s constrained_by EConstraint)"
-msgstr "création contrainte pour la relation %(linkto)s"
+msgstr "création d'une contrainte pour la relation %(linkto)s"
 
 msgid "creating EFRDef (EFRDef relation_type ERType %(linkto)s)"
-msgstr "création attribut %(linkto)s"
+msgstr "création d'un attribut %(linkto)s"
 
 msgid "creating ENFRDef (ENFRDef relation_type ERType %(linkto)s)"
 msgstr "création relation %(linkto)s"
@@ -1458,6 +1498,10 @@
 msgid "csv export"
 msgstr "export CSV"
 
+#, python-format
+msgid "currently attached file: %s"
+msgstr "fichie actuellement attaché %s"
+
 msgid "data directory url"
 msgstr "url du répertoire de données"
 
@@ -1582,8 +1626,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"
 
 msgid "detailed schema view"
 msgstr "vue détaillée du schéma"
@@ -1619,6 +1664,9 @@
 msgid "download icon"
 msgstr "icône de téléchargement"
 
+msgid "download schema as owl"
+msgstr ""
+
 msgid "edit bookmarks"
 msgstr "éditer les signets"
 
@@ -1744,12 +1792,18 @@
 msgid "february"
 msgstr "février"
 
+msgid "file tree view"
+msgstr "arborescence (fichiers)"
+
 msgid "final"
 msgstr "final"
 
 msgid "firstname"
 msgstr "prénom"
 
+msgid "foaf"
+msgstr "foaf"
+
 msgid "follow"
 msgstr "suivre le lien"
 
@@ -2085,12 +2139,20 @@
 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"
 
 msgid "list"
 msgstr "liste"
 
+msgid "loading"
+msgstr "chargement"
+
 msgid "log in"
 msgstr "s'identifier"
 
@@ -2119,6 +2181,9 @@
 msgid "manage bookmarks"
 msgstr "gérer les signets"
 
+msgid "manage permissions"
+msgstr "gestion des permissions"
+
 msgid "manage security"
 msgstr "gestion de la sécurité"
 
@@ -2233,6 +2298,9 @@
 msgid "not authorized"
 msgstr "non autorisé"
 
+msgid "not selected"
+msgstr "non sélectionné"
+
 msgid "not specified"
 msgstr "non spécifié"
 
@@ -2269,6 +2337,12 @@
 msgid "ordernum"
 msgstr "ordre"
 
+msgid "owl"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
 msgid "owned_by"
 msgstr "appartient à"
 
@@ -2313,6 +2387,9 @@
 msgid "pkey"
 msgstr "clé"
 
+msgid "planned_delivery"
+msgstr "livraison prévue"
+
 msgid "please correct errors below"
 msgstr "veuillez corriger les erreurs ci-dessous"
 
@@ -2522,6 +2599,9 @@
 msgid "select this entity"
 msgstr "sélectionner cette entité"
 
+msgid "selected"
+msgstr "sélectionné"
+
 msgid "semantic description of this attribute"
 msgstr "description sémantique de cet attribut"
 
@@ -2727,6 +2807,9 @@
 msgid "transition_of_object"
 msgstr "a pour transition"
 
+msgid "tree view"
+msgstr "arborescence"
+
 msgid "tuesday"
 msgstr "mardi"
 
@@ -2941,6 +3024,9 @@
 #~ "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"
 
--- a/interfaces.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/interfaces.py	Wed Apr 15 17:36:09 2009 +0200
@@ -238,3 +238,34 @@
     def rss_feed_url(self):
         """return an url which layout sub-entities item
         """
+class ISiocItem(Interface):
+    """interface for entities (which are item
+    in sioc specification) with sioc views"""
+    
+    def isioc_content(self):
+        """return content entity"""
+
+    def isioc_container(self):
+        """return container entity"""
+
+    def isioc_type(self):
+        """return container type (post, BlogPost, MailMessage)"""
+
+    def isioc_replies(self):
+        """return replies items"""       
+
+    def isioc_topics(self):
+        """return topics items"""
+            
+class ISiocContainer(Interface):
+    """interface for entities (which are container
+    in sioc specification) with sioc views"""
+
+    def isioc_type(self):
+        """return container type (forum, Weblog, MailingList)"""
+
+    def isioc_items(self):
+        """return contained items"""
+
+   
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.1.5_Any.py	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,1 @@
+synchronize_permissions('condition')
--- a/rset.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/rset.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """The `ResultSet` class which is returned as result of a rql query
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -60,11 +60,15 @@
     def __repr__(self):
         if not self.rows:
             return '<empty resultset for %r>' % self.rql
+        rows = self.rows
+        if len(rows) > 10:
+            rows = rows[:10] + ['...']
         if not self.description:
-            return '<resultset %r: %s>' % (self.rql, '\n'.join(str(r) for r in self.rows))
-        return '<resultset %r: %s>' % (self.rql,
-                                       '\n'.join('%s (%s)' % (r, d)
-                                                 for r, d in zip(self.rows, self.description)))
+            return '<resultset %r (%s rows): %s>' % (self.rql, len(self.rows),
+                                                     '\n'.join(str(r) for r in rows))
+        return '<resultset %r (%s rows): %s>' % (self.rql, len(self.rows),
+                                                 '\n'.join('%s (%s)' % (r, d)
+                                                           for r, d in zip(rows, self.description)))
 
     @cached
     def possible_actions(self):
@@ -464,7 +468,8 @@
         rqlst = self.syntax_tree()
         etype = self.description[row][col]
         if self.vreg.schema.eschema(etype).is_final():
-            # final type, find a better (ambiguous) one
+            # final type, find a better one to locate the correct subquery
+            # (ambiguous if possible) 
             for i in xrange(len(rqlst.children[0].selection)):
                 if i == col:
                     continue
@@ -476,18 +481,17 @@
                     locate_query_col = i
                     if len(self.column_types(i)) > 1:
                         break
-        # UNION query, find the subquery from which this entity has been
-        # found
+        # UNION query, find the subquery from which this entity has been found
         select = rqlst.locate_subquery(locate_query_col, etype, self.args)
         try:
             myvar = select.selection[col].variable
         except AttributeError:
-            # no .selection attribute is available
+            # not a variable
             return None, None
         rel = myvar.main_relation()
         if rel is not None:
             index = rel.children[0].variable.selected_index()
-            if index is not None:
+            if index is not None and self.rows[row][index]:
                 return self.get_entity(row, index), rel.r_type
         return None, None
 
--- a/schema.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/schema.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """classes to define schemas for CubicWeb
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
--- a/schemas/base.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/schemas/base.py	Wed Apr 15 17:36:09 2009 +0200
@@ -212,6 +212,10 @@
     """link a state to one or more entity type"""
 class transition_of(MetaRelationType):
     """link a transition to one or more entity type"""
+class condition(MetaRelationType):
+    """link a transition to one or more rql expression allowing to go through
+    this transition
+    """
     
 class initial_state(MetaRelationType):
     """indicate which state should be used by default when an entity using
--- a/server/__init__.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/__init__.py	Wed Apr 15 17:36:09 2009 +0200
@@ -113,6 +113,8 @@
     for eid, etype in needisfix:
         handler.session.unsafe_execute('SET X is E WHERE X eid %(x)s, E name %(name)s',
                                        {'x': eid, 'name': etype}, 'x')
+        handler.session.unsafe_execute('SET X is_instance_of E WHERE X eid %(x)s, E name %(name)s',
+                                       {'x': eid, 'name': etype}, 'x')
     # insert versions
     handler.cmd_add_entity('EProperty', pkey=u'system.version.cubicweb',
                            value=unicode(config.cubicweb_version()))
--- a/server/checkintegrity.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/checkintegrity.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 is checked.
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -12,6 +12,8 @@
 from mx.DateTime import now
 from logilab.common.shellutils import ProgressBar
 
+from cubicweb.server.sqlutils import SQL_PREFIX
+
 def has_eid(sqlcursor, eid, eids):
     """return true if the eid is a valid eid"""
     if eids.has_key(eid):
@@ -26,7 +28,8 @@
         # XXX what to do...
         eids[eid] = True
         return True
-    sqlcursor.execute('SELECT * FROM %s WHERE eid=%s' % (etype, eid))
+    sqlcursor.execute('SELECT * FROM %s%s WHERE %seid=%s' % (SQL_PREFIX, etype,
+                                                             SQL_PREFIX, eid))
     result = sqlcursor.fetchall()
     if len(result) == 0:
         eids[eid] = False
@@ -71,6 +74,7 @@
                             'before_update_entity', '')
     repo.hm.unregister_hook(uniquecstrcheck_before_modification,
                             'before_update_entity', '')
+    repo.do_fti = True  # ensure full-text indexation is activated
     etypes = set()
     for eschema in schema.entities():
         if eschema.is_final():
@@ -153,7 +157,9 @@
     for eschema in schema.entities():
         if eschema.is_final():
             continue
-        cursor = session.system_sql('SELECT eid FROM %s;' % eschema.type)
+        table = SQL_PREFIX + eschema.type
+        column = SQL_PREFIX +  'eid'
+        cursor = session.system_sql('SELECT %s FROM %s;' % (column, table))
         for row in cursor.fetchall():
             eid = row[0]
             # eids is full since we have fetched everyting from the entities table,
@@ -162,7 +168,7 @@
                 msg = '  Entity with eid %s exists in the %s table but not in the system table'
                 print >> sys.stderr, msg % (eid, eschema.type),
                 if fix:
-                    session.system_sql('DELETE FROM %s WHERE eid=%s;' % (eschema.type, eid))
+                    session.system_sql('DELETE FROM %s WHERE %s=%s;' % (table, column, eid))
                     print >> sys.stderr, ' [FIXED]'
                 else:
                     print >> sys.stderr
@@ -183,40 +189,41 @@
     for rschema in schema.relations():
         if rschema.is_final():
             continue
-        rtype = rschema.type
-        if rtype == 'identity':
+        if rschema == 'identity':
             continue
         if rschema.inlined:
             for subjtype in rschema.subjects():
+                table = SQL_PREFIX + str(subjtype)
+                column = SQL_PREFIX +  str(rschema)
                 sql = 'SELECT %s FROM %s WHERE %s IS NOT NULL;' % (
-                    rtype, subjtype, rtype)
+                    column, table, column)
                 cursor = session.system_sql(sql)
                 for row in cursor.fetchall():
                     eid = row[0]
                     if not has_eid(cursor, eid, eids):
-                        bad_related_msg(rtype, 'object', eid, fix)
+                        bad_related_msg(rschema, 'object', eid, fix)
                         if fix:
-                            sql = 'UPDATE %s SET %s = NULL WHERE eid=%s;' % (
-                                subjtype, rtype, eid)
+                            sql = 'UPDATE %s SET %s = NULL WHERE %seid=%s;' % (
+                                table, column, SQL_PREFIX, eid)
                             session.system_sql(sql)
             continue
-        cursor = session.system_sql('SELECT eid_from FROM %s_relation;' % rtype)
+        cursor = session.system_sql('SELECT eid_from FROM %s_relation;' % rschema)
         for row in cursor.fetchall():
             eid = row[0]
             if not has_eid(cursor, eid, eids):
-                bad_related_msg(rtype, 'subject', eid, fix)
+                bad_related_msg(rschema, 'subject', eid, fix)
                 if fix:
                     sql = 'DELETE FROM %s_relation WHERE eid_from=%s;' % (
-                        rtype, eid)
+                        rschema, eid)
                     session.system_sql(sql)
-        cursor = session.system_sql('SELECT eid_to FROM %s_relation;' % rtype)
+        cursor = session.system_sql('SELECT eid_to FROM %s_relation;' % rschema)
         for row in cursor.fetchall():
             eid = row[0]
             if not has_eid(cursor, eid, eids):
-                bad_related_msg(rtype, 'object', eid, fix)
+                bad_related_msg(rschema, 'object', eid, fix)
                 if fix:
                     sql = 'DELETE FROM %s_relation WHERE eid_to=%s;' % (
-                        rtype, eid)
+                        rschema, eid)
                     session.system_sql(sql)
 
 
@@ -227,21 +234,26 @@
     """
     print 'Checking metadata'
     cursor = session.system_sql("SELECT DISTINCT type FROM entities;")
+    eidcolumn = SQL_PREFIX + 'eid'
     for etype, in cursor.fetchall():
+        table = SQL_PREFIX + etype
         for rel, default in ( ('creation_date', now()),
                               ('modification_date', now()), ):
-            cursor = session.system_sql("SELECT eid FROM %s "
-                                        "WHERE %s is NULL" % (etype, rel))
+            column = SQL_PREFIX + rel
+            cursor = session.system_sql("SELECT %s FROM %s WHERE %s is NULL"
+                                        % (eidcolumn, table, column))
             for eid, in cursor.fetchall():
                 msg = '  %s with eid %s has no %s'
                 print >> sys.stderr, msg % (etype, eid, rel),
                 if fix:
-                    session.system_sql("UPDATE %s SET %s=%(default)s WHERE eid=%s ;"
-                                       % (etype, rel, eid), {'default': default})
+                    session.system_sql("UPDATE %s SET %s=%%(v)s WHERE %s=%s ;"
+                                       % (table, column, eidcolumn, eid),
+                                       {'v': default})
                     print >> sys.stderr, ' [FIXED]'
                 else:
                     print >> sys.stderr
-    cursor = session.system_sql('SELECT MIN(eid) FROM euser;')
+    cursor = session.system_sql('SELECT MIN(%s) FROM %sEUser;' % (eidcolumn,
+                                                                  SQL_PREFIX))
     default_user_eid = cursor.fetchone()[0]
     assert default_user_eid is not None, 'no user defined !'
     for rel, default in ( ('owned_by', default_user_eid), ):
--- a/server/hooks.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/hooks.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 entities...
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -62,6 +62,8 @@
 
 def setis_after_add_entity(session, entity):
     """create a new entity -> set is relation"""
+    if hasattr(entity, '_cw_recreating'):
+        return
     session.unsafe_execute('SET X is E WHERE X eid %(x)s, E name %(name)s',
                            {'x': entity.eid, 'name': entity.id}, 'x')
     # XXX < 2.50 bw compat
--- a/server/migractions.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/migractions.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,7 +11,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -34,10 +34,46 @@
 try:
     from cubicweb.server import schemaserial as ss
     from cubicweb.server.utils import manager_userpasswd
-    from cubicweb.server.sqlutils import sqlexec
+    from cubicweb.server.sqlutils import sqlexec, SQL_PREFIX
 except ImportError: # LAX
     pass
 
+def set_sql_prefix(prefix):
+    """3.1.5 migration function: allow to unset/reset SQL_PREFIX"""
+    for module in ('checkintegrity', 'migractions', 'schemahooks',
+                   'sources.rql2sql', 'sources.native'):
+        try:
+            sys.modules['cubicweb.server.%s' % module].SQL_PREFIX = prefix
+            print 'changed SQL_PREFIX for %s' % module
+        except KeyError:
+            pass
+        
+def update_database(repo):
+    """3.1.3 migration function: update database schema by adding SQL_PREFIX to
+    entity type tables and columns
+    """
+    pool = repo._get_pool()
+    source = repo.system_source
+    sqlcu = pool['system']
+    for etype in repo.schema.entities():
+        if etype.is_final():
+            continue
+        try:
+            sqlcu.execute('ALTER TABLE %s RENAME TO cw_%s' % (etype, etype))
+            print 'renamed %s table' % etype
+        except:
+            pass
+        for rschema in etype.subject_relations():
+            if rschema == 'has_text':
+                continue
+            if rschema.is_final() or rschema.inlined:
+                sqlcu.execute('ALTER TABLE cw_%s RENAME %s TO cw_%s'
+                              % (etype, rschema, rschema))
+                print 'renamed %s.%s column' % (etype, rschema)
+    pool.commit()
+    repo._free_pool(pool)
+
+        
 class ServerMigrationHelper(MigrationHelper):
     """specific migration helper for server side  migration scripts,
     providind actions related to schema/data migration
@@ -57,12 +93,22 @@
             self.repo_connect()
         if not schema:
             schema = config.load_schema(expand_cubes=True)
-        self.new_schema = schema
+        self.fs_schema = schema
         self._synchronized = set()
 
     @cached
     def repo_connect(self):
-        self.repo = get_repository(method='inmemory', config=self.config)
+        try:
+            self.repo = get_repository(method='inmemory', config=self.config)
+        except:
+            import traceback
+            traceback.print_exc()
+            print '3.1.5 migration'
+            # XXX 3.1.5 migration
+            set_sql_prefix('')
+            self.repo = get_repository(method='inmemory', config=self.config)
+            update_database(self.repo)
+            set_sql_prefix('cw_')
         return self.repo
     
     def shutdown(self):
@@ -106,7 +152,9 @@
                 if answer == 1: # 1: continue, 2: retry
                     break
             else:
+                from cubicweb.toolsutils import restrict_perms_to_user
                 print 'database backup:', backupfile
+                restrict_perms_to_user(backupfile, self.info)
                 break
         
     def restore_database(self, backupfile, drop=True):
@@ -194,7 +242,10 @@
     @cached
     def rqlcursor(self):
         """lazy rql cursor"""
-        return self.cnx.cursor(self.session)    
+        # should not give session as cnx.cursor(), else we may try to execute
+        # some query while no pool is set on the session (eg on entity attribute
+        # access for instance)
+        return self.cnx.cursor()
     
     def commit(self):
         if hasattr(self, '_cnx'):
@@ -217,7 +268,9 @@
                         'rql': self.rqlexec,
                         'rqliter': self.rqliter,
                         'schema': self.repo.schema,
-                        'newschema': self.new_schema,
+                        # XXX deprecate
+                        'newschema': self.fs_schema,
+                        'fsschema': self.fs_schema,
                         'cnx': self.cnx,
                         'session' : self.session,
                         'repo' : self.repo,
@@ -264,13 +317,15 @@
             self.commit()
 
     def cmd_add_cube(self, cube, update_database=True):
+        self.cmd_add_cubes( (cube,), update_database)
+    
+    def cmd_add_cubes(self, cubes, update_database=True):
         """update_database is telling if the database schema should be updated
         or if only the relevant eproperty should be inserted (for the case where
         a cube has been extracted from an existing application, so the
         cube schema is already in there)
         """
-        newcubes = super(ServerMigrationHelper, self).cmd_add_cube(
-            cube)
+        newcubes = super(ServerMigrationHelper, self).cmd_add_cubes(cubes)
         if not newcubes:
             return
         for pack in newcubes:
@@ -279,22 +334,22 @@
         if not update_database:
             self.commit()
             return
-        self.new_schema = self.config.load_schema()
+        newcubes_schema = self.config.load_schema()
         new = set()
         # execute pre-create files
         for pack in reversed(newcubes):
             self.exec_event_script('precreate', self.config.cube_dir(pack))
         # add new entity and relation types
-        for rschema in self.new_schema.relations():
+        for rschema in newcubes_schema.relations():
             if not rschema in self.repo.schema:
                 self.cmd_add_relation_type(rschema.type)
                 new.add(rschema.type)
-        for eschema in self.new_schema.entities():
+        for eschema in newcubes_schema.entities():
             if not eschema in self.repo.schema:
                 self.cmd_add_entity_type(eschema.type)
                 new.add(eschema.type)
         # check if attributes has been added to existing entities
-        for rschema in self.new_schema.relations():
+        for rschema in newcubes_schema.relations():
             existingschema = self.repo.schema.rschema(rschema.type)
             for (fromtype, totype) in rschema.iter_rdefs():
                 if existingschema.has_rdef(fromtype, totype):
@@ -313,25 +368,25 @@
         removedcubes = super(ServerMigrationHelper, self).cmd_remove_cube(cube)
         if not removedcubes:
             return
-        oldschema = self.new_schema
-        self.new_schema = newschema = self.config.load_schema()
+        fsschema = self.fs_schema
+        removedcubes_schema = self.config.load_schema()
         reposchema = self.repo.schema
         # execute pre-remove files
         for pack in reversed(removedcubes):
             self.exec_event_script('preremove', self.config.cube_dir(pack))
         # remove cubes'entity and relation types
-        for rschema in oldschema.relations():
-            if not rschema in newschema and rschema in reposchema:
+        for rschema in fsschema.relations():
+            if not rschema in removedcubes_schema and rschema in reposchema:
                 self.cmd_drop_relation_type(rschema.type)
-        for eschema in oldschema.entities():
-            if not eschema in newschema and eschema in reposchema:
+        for eschema in fsschema.entities():
+            if not eschema in removedcubes_schema and eschema in reposchema:
                 self.cmd_drop_entity_type(eschema.type)
-        for rschema in oldschema.relations():
-            if rschema in newschema and rschema in reposchema: 
+        for rschema in fsschema.relations():
+            if rschema in removedcubes_schema and rschema in reposchema: 
                 # check if attributes/relations has been added to entities from 
                 # other cubes
                 for fromtype, totype in rschema.iter_rdefs():
-                    if not newschema[rschema.type].has_rdef(fromtype, totype) and \
+                    if not removedcubes_schema[rschema.type].has_rdef(fromtype, totype) and \
                            reposchema[rschema.type].has_rdef(fromtype, totype):
                         self.cmd_drop_relation_definition(
                             str(fromtype), rschema.type, str(totype))
@@ -347,7 +402,7 @@
     def cmd_add_attribute(self, etype, attrname, attrtype=None, commit=True):
         """add a new attribute on the given entity type"""
         if attrtype is None:
-            rschema = self.new_schema.rschema(attrname)
+            rschema = self.fs_schema.rschema(attrname)
             attrtype = rschema.objects(etype)[0]
         self.cmd_add_relation_definition(etype, attrname, attrtype, commit=commit)
         
@@ -366,7 +421,7 @@
         `oldname` is a string giving the name of the existing attribute
         `newname` is a string giving the name of the renamed attribute
         """
-        eschema = self.new_schema.eschema(etype)
+        eschema = self.fs_schema.eschema(etype)
         attrtype = eschema.destination(newname)
         # have to commit this first step anyway to get the definition
         # actually in the schema
@@ -391,7 +446,7 @@
             if eschema.is_final():
                 applschema.del_entity_type(etype)
         else:
-            eschema = self.new_schema.eschema(etype)
+            eschema = self.fs_schema.eschema(etype)
         confirm = self.verbosity >= 2
         # register the entity into EEType
         self.rqlexecall(ss.eschema2rql(eschema), ask_confirm=confirm)
@@ -497,7 +552,7 @@
         committing depends on the `commit` argument value).
         
         """
-        rschema = self.new_schema.rschema(rtype)
+        rschema = self.fs_schema.rschema(rtype)
         # register the relation into ERType and insert necessary relation
         # definitions
         self.rqlexecall(ss.rschema2rql(rschema, addrdef=False),
@@ -535,7 +590,7 @@
         """register a new relation definition, from its definition found in the
         schema definition file
         """
-        rschema = self.new_schema.rschema(rtype)
+        rschema = self.fs_schema.rschema(rtype)
         if not rtype in self.repo.schema:
             self.cmd_add_relation_type(rtype, addrdef=False, commit=True)
         self.rqlexecall(ss.rdef2rql(rschema, subjtype, objtype),
@@ -562,7 +617,7 @@
         """permission synchronization for an entity or relation type"""
         if ertype in ('eid', 'has_text', 'identity'):
             return
-        newrschema = self.new_schema[ertype]
+        newrschema = self.fs_schema[ertype]
         teid = self.repo.schema[ertype].eid
         if 'update' in newrschema.ACTIONS or newrschema.is_final():
             # entity type
@@ -642,7 +697,7 @@
         if rtype in self._synchronized:
             return
         self._synchronized.add(rtype)
-        rschema = self.new_schema.rschema(rtype)
+        rschema = self.fs_schema.rschema(rtype)
         self.rqlexecall(ss.updaterschema2rql(rschema),
                         ask_confirm=self.verbosity>=2)
         reporschema = self.repo.schema.rschema(rtype)
@@ -672,18 +727,18 @@
         self._synchronized.add(etype)
         repoeschema = self.repo.schema.eschema(etype)
         try:
-            eschema = self.new_schema.eschema(etype)
+            eschema = self.fs_schema.eschema(etype)
         except KeyError:
             return
         repospschema = repoeschema.specializes()
         espschema = eschema.specializes()
         if repospschema and not espschema:
             self.rqlexec('DELETE X specializes Y WHERE X is EEType, X name %(x)s',
-                         {'x': str(repoechema)})
+                         {'x': str(repoeschema)})
         elif not repospschema and espschema:
             self.rqlexec('SET X specializes Y WHERE X is EEType, X name %(x)s, '
                          'Y is EEType, Y name %(y)s',
-                         {'x': str(repoechema), 'y': str(epschema)})
+                         {'x': str(repoeschema), 'y': str(espschema)})
         self.rqlexecall(ss.updateeschema2rql(eschema),
                         ask_confirm=self.verbosity >= 2)
         for rschema, targettypes, x in eschema.relation_definitions(True):
@@ -717,7 +772,7 @@
         * constraints
         """
         subjtype, objtype = str(subjtype), str(objtype)
-        rschema = self.new_schema.rschema(rtype)
+        rschema = self.fs_schema.rschema(rtype)
         reporschema = self.repo.schema.rschema(rschema)
         if (subjtype, rschema, objtype) in self._synchronized:
             return
@@ -901,6 +956,13 @@
         if commit:
             self.commit()
 
+    def cmd_set_state(self, eid, statename, commit=False):
+        self.session.set_pool() # ensure pool is set
+        entity = self.session.eid_rset(eid).get_entity(0, 0)
+        entity.change_state(entity.wf_state(statename).eid)
+        if commit:
+            self.commit()
+        
     # EProperty handling ######################################################
 
     def cmd_property_value(self, pkey):
@@ -1018,7 +1080,8 @@
         and a sql database
         """
         dbhelper = self.repo.system_source.dbhelper
-        tablesql = eschema2sql(dbhelper, self.repo.schema.eschema(etype))
+        tablesql = eschema2sql(dbhelper, self.repo.schema.eschema(etype),
+                               prefix=SQL_PREFIX)
         for sql in tablesql.split(';'):
             if sql.strip():
                 self.sqlexec(sql)
--- a/server/msplanner.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/msplanner.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,32 +1,54 @@
 """plan execution of rql queries on multiple sources
 
-the best way to understand what are we trying to acheive here is to read
-the unit-tests in unittest_querier_planner.py
+the best way to understand what are we trying to acheive here is to read the
+unit-tests in unittest_msplanner.py
 
 
+What you need to know
+~~~~~~~~~~~~~~~~~~~~~
+1. The system source is expected  to support every entity and relation types
 
-Split and execution specifications
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+2. Given "X relation Y":
+
+   * if relation, X and Y types are supported by the external source, we suppose
+     by default that X and Y should both come from the same source as the
+     relation. You can specify otherwise by adding relation into the
+     "cross_relations" set in the source's mapping file and it that case, we'll
+     consider that we can also find in the system source some relation between
+     X and Y coming from different sources.
+     
+   * if "relation" isn't supported by the external source but X or Y
+     types (or both) are, we suppose by default that can find in the system
+     source some relation where X and/or Y come from the external source. You
+     can specify otherwise by adding relation into the "dont_cross_relations"
+     set in the source's mapping file and it that case, we'll consider that we
+     can only find in the system source some relation between X and Y coming
+     the system source.
+
+
+Implementation
+~~~~~~~~~~~~~~
+XXX explain algorithm
+
+
+Exemples of multi-sources query execution
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 For a system source and a ldap user source (only EUser and its attributes
 is supported, no group or such):
 
-
 :EUser X:
 1. fetch EUser X from both sources and return concatenation of results
 
-
 :EUser X WHERE X in_group G, G name 'users':
 * catch 1
-  1. fetch EUser X from both sources, store concatenation of results
-     into a temporary table
-  2. return the result of TMP X WHERE X in_group G, G name 'users' from
-     the system source
-     
+  1. fetch EUser X from both sources, store concatenation of results into a
+     temporary table
+  2. return the result of TMP X WHERE X in_group G, G name 'users' from the
+     system source
 * catch 2
-  1. return the result of EUser X WHERE X in_group G, G name 'users'
-     from system source, that's enough (optimization of the sql querier
-     will avoid join on EUser, so we will directly get local eids)
-
+  1. return the result of EUser X WHERE X in_group G, G name 'users' from system
+     source, that's enough (optimization of the sql querier will avoid join on
+     EUser, so we will directly get local eids)
     
 :EUser X,L WHERE X in_group G, X login L, G name 'users':
 1. fetch Any X,L WHERE X is EUser, X login L from both sources, store
@@ -37,19 +59,18 @@
 
 :Any X WHERE X owned_by Y:
 * catch 1
-  1. fetch EUser X from both sources, store concatenation of results
-     into a temporary table
-  2. return the result of Any X WHERE X owned_by Y, Y is TMP from
-     the system source
-     
+  1. fetch EUser X from both sources, store concatenation of results into a
+     temporary table
+  2. return the result of Any X WHERE X owned_by Y, Y is TMP from the system
+     source
 * catch 2
-  1. return the result of Any X WHERE X owned_by Y
-     from system source, that's enough (optimization of the sql querier
-     will avoid join on EUser, so we will directly get local eids)
+  1. return the result of Any X WHERE X owned_by Y from system source, that's
+     enough (optimization of the sql querier will avoid join on EUser, so we
+     will directly get local eids)
 
 
 :organization: Logilab
-:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -66,7 +87,8 @@
 from cubicweb import server
 from cubicweb.common.utils import make_uid
 from cubicweb.server.utils import cleanup_solutions
-from cubicweb.server.ssplanner import SSPlanner, OneFetchStep, add_types_restriction
+from cubicweb.server.ssplanner import (SSPlanner, OneFetchStep,
+                                       add_types_restriction)
 from cubicweb.server.mssteps import *
 from cubicweb.server.sources import AbstractSource
 
@@ -77,14 +99,6 @@
 
 AbstractSource.dont_cross_relations = ()
 AbstractSource.cross_relations = ()
-
-def allequals(solutions):
-    """return true if all solutions are identical"""
-    sol = solutions.next()
-    for sol_ in solutions:
-        if sol_ != sol:
-            return False
-    return True
     
 def need_aggr_step(select, sources, stepdefs=None):
     """return True if a temporary table is necessary to store some partial
@@ -114,24 +128,6 @@
                 fstepsolindices.update(stepdef[2])
     return False
 
-def copy_node(newroot, node, subparts=()):
-    newnode = node.__class__(*node.initargs(newroot))
-    for part in subparts:
-        newnode.append(part)
-    return newnode
-        
-def same_scope(var):
-    """return true if the variable is always used in the same scope"""
-    try:
-        return var.stinfo['samescope']
-    except KeyError:
-        for rel in var.stinfo['relations']:
-            if not rel.scope is var.scope:
-                var.stinfo['samescope'] = False
-                return False
-        var.stinfo['samescope'] = True
-        return True
-
 def select_group_sort(select): # XXX something similar done in rql2sql
     # add variables used in groups and sort terms to the selection
     # if necessary
@@ -149,66 +145,139 @@
                 select.append_selected(vref.copy(select))
                 if select.groupby and not vref in select.groupby:
                     select.add_group_var(vref.copy(select))
-            
+
+def allequals(solutions):
+    """return true if all solutions are identical"""
+    sol = solutions.next()
+    noconstsol = None
+    for sol_ in solutions:
+        if sol_ != sol:
+            return False
+    return True
+
+# XXX move functions below to rql ##############################################
+
+def is_ancestor(n1, n2):
+    p = n1.parent
+    while p is not None:
+        if p is n2:
+            return True
+        p = p.parent
+    return False
+
+def copy_node(newroot, node, subparts=()):
+    newnode = node.__class__(*node.initargs(newroot))
+    for part in subparts:
+        newnode.append(part)
+    return newnode
+        
+def same_scope(var):
+    """return true if the variable is always used in the same scope"""
+    try:
+        return var.stinfo['samescope']
+    except KeyError:
+        for rel in var.stinfo['relations']:
+            if not rel.scope is var.scope:
+                var.stinfo['samescope'] = False
+                return False
+        var.stinfo['samescope'] = True
+        return True
+    
+################################################################################
 
 class PartPlanInformation(object):
     """regroups necessary information to execute some part of a "global" rql
     query ("global" means as received by the querier, which may result in
-    several internal queries, e.g. parts, due to security insertions)
+    several internal queries, e.g. parts, due to security insertions). Actually
+    a PPI is created for each subquery and for each query in a union.
 
-    it exposes as well some methods helping in executing this part on a
+    It exposes as well some methods helping in executing this part on a
     multi-sources repository, modifying its internal structure during the
-    process
+    process.
 
-    :attr solutions: a list of mappings (varname -> vartype)
-    :attr sourcesvars:
-      a dictionnary telling for each source which variable/solution are
-      supported, of the form {source : {varname: [solution index, ]}}
+    :attr plan:
+      the execution plan
+    :attr rqlst:
+      the original rql syntax tree handled by this part
+      
+    :attr needsplit:
+      bool telling if the query has to be split into multiple steps for
+      execution or if it can be executed at once
+      
+    :attr temptable:
+      a SQL temporary table name or None, if necessary to handle aggregate /
+      sorting for this part of the query
+      
+    :attr finaltable:
+      a SQL table name or None, if results for this part of the query should be
+      written into a temporary table (usually shared by multiple PPI)
+      
+    :attr sourcesterms:
+      a dictionary {source : {term: set([solution index, ])}} telling for each
+      source which terms are supported for which solutions. A "term" may be
+      either a rql Variable, Constant or Relation node.
     """
     def __init__(self, plan, rqlst, rqlhelper=None):
+        self.plan = plan
+        self.rqlst = rqlst
         self.needsplit = False
         self.temptable = None
         self.finaltable = None
-        self.plan = plan
-        self.rqlst = rqlst
+        # shortcuts
+        self._schema = plan.schema
         self._session = plan.session
+        self._repo = self._session.repo
         self._solutions = rqlst.solutions
         self._solindices = range(len(self._solutions))
-        # source : {var: [solution index, ]}
-        self.sourcesvars = self._sourcesvars = {}
+        self.system_source = self._repo.system_source
+        # source : {term: [solution index, ]}
+        self.sourcesterms = self._sourcesterms = {}
         # source : {relation: set(child variable and constant)}
         self._crossrelations = {}
-        # dictionnary of variables which are linked to each other using a non
-        # final relation which is supported by multiple sources
-        self._linkedvars = {}
-        self._crosslinkedvars = {}
+        # dictionary of variables and constants which are linked to each other
+        # using a non final relation supported by multiple sources (crossed or
+        # not).
+        self._linkedterms = {}
         # processing
-        self._compute_sourcesvars()
-        self._remove_invalid_sources()
+        termssources = self._compute_sourcesterms()
+        self._remove_invalid_sources(termssources)
         self._compute_needsplit()
-        self.sourcesvars = {}
-        for k, v in self._sourcesvars.iteritems():
-            self.sourcesvars[k] = {}
+        # after initialisation, .sourcesterms contains the same thing as
+        # ._sourcesterms though during plan construction, ._sourcesterms will
+        # be modified while .sourcesterms will be kept unmodified
+        self.sourcesterms = {}
+        for k, v in self._sourcesterms.iteritems():
+            self.sourcesterms[k] = {}
             for k2, v2 in v.iteritems():
-                self.sourcesvars[k][k2] = v2.copy()
+                self.sourcesterms[k][k2] = v2.copy()
+        # cleanup linked var
+        for var, linkedrelsinfo in self._linkedterms.iteritems():
+            self._linkedterms[var] = frozenset(x[0] for x in linkedrelsinfo)
+        # map output of a step to input of a following step
         self._inputmaps = {}
+        # record input map conflicts to resolve them on final step generation
+        self._conflicts = []
         if rqlhelper is not None: # else test
             self._insert_identity_variable = rqlhelper._annotator.rewrite_shared_optional
-
+        if server.DEBUG:
+            print 'sourcesterms:'
+            for source, terms in self.sourcesterms.items():
+                print source, terms
+            
     def copy_solutions(self, solindices):
         return [self._solutions[solidx].copy() for solidx in solindices]
     
     @property
     @cached
     def part_sources(self):
-        if self._sourcesvars:
-            return tuple(sorted(self._sourcesvars))
-        return (self._session.repo.system_source,)
+        if self._sourcesterms:
+            return tuple(sorted(self._sourcesterms))
+        return (self.system_source,)
     
     @property
     @cached
     def _sys_source_set(self):
-        return frozenset((self._session.repo.system_source, solindex)
+        return frozenset((self.system_source, solindex)
                          for solindex in self._solindices)        
        
     @cached
@@ -216,20 +285,18 @@
         """return a set of (source, solindex) where source doesn't support the
         relation
         """
-        return frozenset((source, solidx) for source in self._session.repo.sources
+        return frozenset((source, solidx) for source in self._repo.sources
                          for solidx in self._solindices
-                         if not ((source.support_relation(relation.r_type) and
-                                  not self.crossed_relation(source, relation))
+                         if not ((source.support_relation(relation.r_type))
                                  or relation.r_type in source.dont_cross_relations))
 
-
-    def _compute_sourcesvars(self):
-        """compute for each variable/solution in the rqlst which sources support
-        them
+    def _compute_sourcesterms(self):
+        """compute for each term (variable, rewritten constant, relation) and
+        for each solution in the rqlst which sources support them
         """
-        repo = self._session.repo
-        eschema = repo.schema.eschema
-        sourcesvars = self._sourcesvars
+        repo = self._repo
+        eschema = self._schema.eschema
+        sourcesterms = self._sourcesterms
         # find for each source which variable/solution are supported
         for varname, varobj in self.rqlst.defined_vars.items():
             # if variable has an eid specified, we can get its source directly
@@ -237,22 +304,22 @@
             if varobj.stinfo['uidrels']:
                 vrels = varobj.stinfo['relations'] - varobj.stinfo['uidrels']
                 for rel in varobj.stinfo['uidrels']:
-                    if  rel.neged(strict=True) or rel.operator() != '=':
+                    if rel.neged(strict=True) or rel.operator() != '=':
                         continue
                     for const in rel.children[1].get_nodes(Constant):
                         eid = const.eval(self.plan.args)
                         source = self._session.source_from_eid(eid)
                         if vrels and not any(source.support_relation(r.r_type)
                                              for r in vrels):
-                            self._set_source_for_var(repo.system_source, varobj)
+                            self._set_source_for_term(self.system_source, varobj)
                         else:
-                            self._set_source_for_var(source, varobj)
+                            self._set_source_for_term(source, varobj)
                 continue
             rels = varobj.stinfo['relations']
             if not rels and not varobj.stinfo['typerels']:
                 # (rare) case where the variable has no type specified nor
                 # relation accessed ex. "Any MAX(X)"
-                self._set_source_for_var(repo.system_source, varobj)
+                self._set_source_for_term(self.system_source, varobj)
                 continue
             for i, sol in enumerate(self._solutions):
                 vartype = sol[varname]
@@ -268,60 +335,35 @@
                         if not varobj._q_invariant or \
                                any(imap(source.support_relation,
                                         (r.r_type for r in rels if r.r_type != 'eid'))):
-                            sourcesvars.setdefault(source, {}).setdefault(varobj, set()).add(i)
+                            sourcesterms.setdefault(source, {}).setdefault(varobj, set()).add(i)
                         # if variable is not invariant and is used by a relation
                         # not supported by this source, we'll have to split the
                         # query
                         if not varobj._q_invariant and any(ifilterfalse(
                             source.support_relation, (r.r_type for r in rels))):
                             self.needsplit = True               
-
-    def _handle_cross_relation(self, rel, relsources, vsources):
-        crossvars = None
-        for source in relsources:
-            if rel.r_type in source.cross_relations:
-                crossvars = set(x.variable for x in rel.get_nodes(VariableRef))
-                crossvars.update(frozenset(x for x in rel.get_nodes(Constant)))
-                assert len(crossvars) == 2
-                ssource = self._session.repo.system_source
-                needsplit = True
-                flag = 0
-                for v in crossvars:
-                    if isinstance(v, Constant):
-                        self._sourcesvars[ssource][v] = set(self._solindices)
-                    if len(vsources[v]) == 1:
-                        if iter(vsources[v]).next()[0].uri == 'system':
-                            flag = 1
-                            for ov in crossvars:
-                                if ov is not v and ov._q_invariant:
-                                    ssset = frozenset((ssource,))
-                                    self._remove_sources(ov, vsources[ov] - ssset)
-                        else:
-                            for ov in crossvars:
-                                if ov is not v and ov._q_invariant:
-                                    needsplit = False
-                                    break
-                            else:
-                                continue
-                        if not rel.neged(strict=True):
-                            break
-                else:
-                    self._crossrelations.setdefault(source, {})[rel] = crossvars
-                    if not flag:
-                        self._sourcesvars.setdefault(source, {})[rel] = set(self._solindices)
-                    self._sourcesvars.setdefault(ssource, {})[rel] = set(self._solindices)
-                    if needsplit:
-                        self.needsplit = True
-        return crossvars is None
-        
-    def _remove_invalid_sources(self):
-        """removes invalid sources from `sourcesvars` member according to
-        traversed relations and their properties (which sources support them,
-        can they cross sources, etc...)
-        """
-        repo = self._session.repo
-        rschema = repo.schema.rschema
-        vsources = {}
+        # add source for rewritten constants to sourcesterms
+        for vconsts in self.rqlst.stinfo['rewritten'].itervalues():
+            const = vconsts[0]
+            source = self._session.source_from_eid(const.eval(self.plan.args))
+            if source is self.system_source:
+                for const in vconsts:
+                    self._set_source_for_term(source, const)
+            elif source in self._sourcesterms:
+                source_scopes = frozenset(t.scope for t in self._sourcesterms[source])
+                for const in vconsts:
+                    if const.scope in source_scopes:
+                        self._set_source_for_term(source, const)
+                        # if system source is used, add every rewritten constant
+                        # to its supported terms even when associated entity
+                        # doesn't actually comes from it so we get a changes
+                        # that allequals will return True as expected when
+                        # computing needsplit
+                        if self.system_source in sourcesterms:
+                            self._set_source_for_term(self.system_source, const)
+        # add source for relations
+        rschema = self._schema.rschema
+        termssources = {}
         for rel in self.rqlst.iget_nodes(Relation):
             # process non final relations only
             # note: don't try to get schema for 'is' relation (not available
@@ -334,7 +376,6 @@
                 # XXX code below don't deal if some source allow relation
                 #     crossing but not another one
                 relsources = repo.rel_type_sources(rel.r_type)
-                crossvars = None
                 if len(relsources) < 2:
                     # filter out sources being there because they have this
                     # relation in their dont_cross_relations attribute
@@ -343,25 +384,54 @@
                     if relsources:
                         # this means the relation is using a variable inlined as
                         # a constant and another unsupported variable, in which
-                        # case we put the relation in sourcesvars
-                        self._sourcesvars.setdefault(relsources[0], {})[rel] = set(self._solindices)
+                        # case we put the relation in sourcesterms
+                        self._sourcesterms.setdefault(relsources[0], {})[rel] = set(self._solindices)
                     continue
                 lhs, rhs = rel.get_variable_parts()
                 lhsv, rhsv = getattr(lhs, 'variable', lhs), getattr(rhs, 'variable', rhs)
-                # update dictionnary of sources supporting lhs and rhs vars
-                if not lhsv in vsources:
-                    vsources[lhsv] = self._term_sources(lhs)
-                if not rhsv in vsources:
-                    vsources[rhsv] = self._term_sources(rhs)
-                if self._handle_cross_relation(rel, relsources, vsources):
-                    self._linkedvars.setdefault(lhsv, set()).add((rhsv, rel))
-                    self._linkedvars.setdefault(rhsv, set()).add((lhsv, rel))
+                # update dictionary of sources supporting lhs and rhs vars
+                if not lhsv in termssources:
+                    termssources[lhsv] = self._term_sources(lhs)
+                if not rhsv in termssources:
+                    termssources[rhsv] = self._term_sources(rhs)
+                self._handle_cross_relation(rel, relsources, termssources)
+                self._linkedterms.setdefault(lhsv, set()).add((rhsv, rel))
+                self._linkedterms.setdefault(rhsv, set()).add((lhsv, rel))
+        return termssources
+            
+    def _handle_cross_relation(self, rel, relsources, termssources):
+        for source in relsources:
+            if rel.r_type in source.cross_relations:
+                ssource = self.system_source
+                crossvars = set(x.variable for x in rel.get_nodes(VariableRef))
+                for const in rel.get_nodes(Constant):
+                    if source.uri != 'system' and not const in self._sourcesterms.get(source, ()):
+                        continue
+                    crossvars.add(const)
+                self._crossrelations.setdefault(source, {})[rel] = crossvars
+                if len(crossvars) < 2:
+                    # this means there is a constant in the relation which is
+                    # not supported by the source, so we can stop here
+                    continue
+                self._sourcesterms.setdefault(ssource, {})[rel] = set(self._solindices)
+                for term in crossvars:
+                    if len(termssources[term]) == 1 and iter(termssources[term]).next()[0].uri == 'system':
+                        for ov in crossvars:
+                            if ov is not term and (isinstance(ov, Constant) or ov._q_invariant):
+                                ssset = frozenset((ssource,))
+                                self._remove_sources(ov, termssources[ov] - ssset)
+                        break
                 else:
-                    self._crosslinkedvars.setdefault(lhsv, set()).add((rhsv, rel))
-                    self._crosslinkedvars.setdefault(rhsv, set()).add((lhsv, rel))
-        for term in self._linkedvars:
-            self._remove_sources_until_stable(term, vsources)
-        if len(self._sourcesvars) > 1 and hasattr(self.plan.rqlst, 'main_relations'):
+                    self._sourcesterms.setdefault(source, {})[rel] = set(self._solindices)
+    
+    def _remove_invalid_sources(self, termssources):
+        """removes invalid sources from `sourcesterms` member according to
+        traversed relations and their properties (which sources support them,
+        can they cross sources, etc...)
+        """
+        for term in self._linkedterms:
+            self._remove_sources_until_stable(term, termssources)
+        if len(self._sourcesterms) > 1 and hasattr(self.plan.rqlst, 'main_relations'):
             # the querier doesn't annotate write queries, need to do it here
             self.plan.annotate_rqlst()
             # insert/update/delete queries, we may get extra information from
@@ -371,6 +441,8 @@
                                 for etype, vref in self.plan.rqlst.main_variables)
             else:
                 inserted = {}
+            repo = self._repo
+            rschema = self._schema.rschema
             for rel in self.plan.rqlst.main_relations:
                 if not rschema(rel.r_type).is_final():
                     # nothing to do if relation is not supported by multiple sources
@@ -378,88 +450,88 @@
                         continue
                     lhs, rhs = rel.get_variable_parts()
                     try:
-                        lhsv = self._extern_term(lhs, vsources, inserted)
-                        rhsv = self._extern_term(rhs, vsources, inserted)
+                        lhsv = self._extern_term(lhs, termssources, inserted)
+                        rhsv = self._extern_term(rhs, termssources, inserted)
                     except KeyError, ex:
                         continue
-                    norelsup = self._norel_support_set(rel)
-                    self._remove_var_sources(lhsv, norelsup, rhsv, vsources)
-                    self._remove_var_sources(rhsv, norelsup, lhsv, vsources)
-        # cleanup linked var
-        for var, linkedrelsinfo in self._linkedvars.iteritems():
-            self._linkedvars[var] = frozenset(x[0] for x in linkedrelsinfo)
-        # if there are other sources than the system source, consider simplified
-        # variables'source
-        if self._sourcesvars and self._sourcesvars.keys() != [self._session.repo.system_source]:
-            # add source for rewritten constants to sourcesvars
-            for vconsts in self.rqlst.stinfo['rewritten'].itervalues():
-                const = vconsts[0]
-                eid = const.eval(self.plan.args)
-                source = self._session.source_from_eid(eid)
-                if source is self._session.repo.system_source:
-                    for const in vconsts:
-                        self._set_source_for_var(source, const)
-                elif source in self._sourcesvars:
-                    source_scopes = frozenset(v.scope for v in self._sourcesvars[source])
-                    for const in vconsts:
-                        if const.scope in source_scopes:
-                            self._set_source_for_var(source, const)
-                            
-    def _extern_term(self, term, vsources, inserted):
+                    self._remove_term_sources(lhsv, rel, rhsv, termssources)
+                    self._remove_term_sources(rhsv, rel, lhsv, termssources)
+                                    
+    def _extern_term(self, term, termssources, inserted):
         var = term.variable
         if var.stinfo['constnode']:
             termv = var.stinfo['constnode']
-            vsources[termv] = self._term_sources(termv)
+            termssources[termv] = self._term_sources(termv)
         elif var in inserted:
             termv = var
-            source = self._session.repo.locate_etype_source(inserted[var])
-            vsources[termv] = set((source, solindex) for solindex in self._solindices)
+            source = self._repo.locate_etype_source(inserted[var])
+            termssources[termv] = set((source, solindex)
+                                      for solindex in self._solindices)
         else:
             termv = self.rqlst.defined_vars[var.name]
-            if not termv in vsources:
-                vsources[termv] = self._term_sources(termv)
+            if not termv in termssources:
+                termssources[termv] = self._term_sources(termv)
         return termv
         
-    def _remove_sources_until_stable(self, var, vsources):
-        sourcesvars = self._sourcesvars
-        for ovar, rel in self._linkedvars.get(var, ()):
-            if not var.scope is ovar.scope and rel.scope.neged(strict=True):
+    def _remove_sources_until_stable(self, term, termssources):
+        sourcesterms = self._sourcesterms
+        for oterm, rel in self._linkedterms.get(term, ()):
+            if not term.scope is oterm.scope and rel.scope.neged(strict=True):
                 # can't get information from relation inside a NOT exists
-                # where variables don't belong to the same scope
+                # where terms don't belong to the same scope
                 continue
-            if not (var.scope is rel.scope and ovar.scope is rel.scope) and rel.ored():
-                continue
-            relsources = self._session.repo.rel_type_sources(rel.r_type)
+            need_ancestor_scope = False
+            if not (term.scope is rel.scope and oterm.scope is rel.scope):
+                if rel.ored():
+                    continue
+                if rel.ored(traverse_scope=True):
+                    # if relation has some OR as parent, constraints should only
+                    # propagate from parent scope to child scope, nothing else
+                    need_ancestor_scope = True
+            relsources = self._repo.rel_type_sources(rel.r_type)
             if rel.neged(strict=True) and (
                 len(relsources) < 2
-                or not isinstance(ovar, Variable)
-                or ovar.valuable_references() != 1
-                or any(sourcesvars[source][var] != sourcesvars[source][ovar]
+                or not isinstance(oterm, Variable)
+                or oterm.valuable_references() != 1
+                or any(sourcesterms[source][term] != sourcesterms[source][oterm]
                        for source in relsources
-                       if var in sourcesvars.get(source, ())
-                       and ovar in sourcesvars.get(source, ()))):
-                # neged relation doesn't allow to infer variable sources unless we're
-                # on a multisource relation for a variable only used by this relation
-                # (eg "Any X WHERE NOT X multisource_rel Y" and over is Y), iif 
+                       if term in sourcesterms.get(source, ())
+                       and oterm in sourcesterms.get(source, ()))):
+                # neged relation doesn't allow to infer term sources unless
+                # we're on a multisource relation for a term only used by this
+                # relation (eg "Any X WHERE NOT X multisource_rel Y" and over is
+                # Y)
                 continue
-            norelsup = self._norel_support_set(rel)
-            # compute invalid sources for variables and remove them
-            self._remove_var_sources(var, norelsup, ovar, vsources)
-            self._remove_var_sources(ovar, norelsup, var, vsources)
+            # compute invalid sources for terms and remove them
+            if not need_ancestor_scope or is_ancestor(term.scope, oterm.scope):
+                self._remove_term_sources(term, rel, oterm, termssources)
+            if not need_ancestor_scope or is_ancestor(oterm.scope, term.scope):
+                self._remove_term_sources(oterm, rel, term, termssources)
     
-    def _remove_var_sources(self, var, norelsup, ovar, vsources):
-        """remove invalid sources for var according to ovar's sources and the
-        relation between those two variables. 
+    def _remove_term_sources(self, term, rel, oterm, termssources):
+        """remove invalid sources for term according to oterm's sources and the
+        relation between those two terms. 
         """
-        varsources = vsources[var]
-        invalid_sources = varsources - (vsources[ovar] | norelsup)
+        norelsup = self._norel_support_set(rel)
+        termsources = termssources[term]
+        invalid_sources = termsources - (termssources[oterm] | norelsup)
+        if invalid_sources and self._repo.can_cross_relation(rel.r_type):
+            invalid_sources -= self._sys_source_set
+            if invalid_sources and isinstance(term, Variable) \
+                   and self._need_ext_source_access(term, rel):
+                # if the term is a not invariant variable, we should filter out
+                # source where the relation is a cross relation from invalid
+                # sources
+                invalid_sources = frozenset((s, solidx) for s, solidx in invalid_sources
+                                            if not (s in self._crossrelations and
+                                                    rel in self._crossrelations[s]))
         if invalid_sources:
-            self._remove_sources(var, invalid_sources)
-            varsources -= invalid_sources
-            self._remove_sources_until_stable(var, vsources)
+            self._remove_sources(term, invalid_sources)
+            termsources -= invalid_sources
+            self._remove_sources_until_stable(term, termssources)
         
     def _compute_needsplit(self):
-        """tell according to sourcesvars if the rqlst has to be splitted for
+        """tell according to sourcesterms if the rqlst has to be splitted for
         execution among multiple sources
         
         the execution has to be split if
@@ -471,20 +543,43 @@
           be fetched from some source
         """
         # NOTE: < 2 since may be 0 on queries such as Any X WHERE X eid 2
-        if len(self._sourcesvars) < 2: 
+        if len(self._sourcesterms) < 2: 
             self.needsplit = False
         elif not self.needsplit:
-            if not allequals(self._sourcesvars.itervalues()):
+            if not allequals(self._sourcesterms.itervalues()):
                 self.needsplit = True
             else:
-                sample = self._sourcesvars.itervalues().next()
-                if len(sample) > 1 and any(v for v in sample
-                                           if not v in self._linkedvars
-                                           and not v in self._crosslinkedvars):
-                    self.needsplit = True
-            
-    def _set_source_for_var(self, source, var):
-        self._sourcesvars.setdefault(source, {})[var] = set(self._solindices)
+                sample = self._sourcesterms.itervalues().next()
+                if len(sample) > 1:
+                    for term in sample:
+                        # need split if unlinked variable
+                        if isinstance(term, Variable) and not term in self._linkedterms:
+                            self.needsplit = True
+                            break
+                    else:
+                        # need split if there are some cross relation on non
+                        # invariant variable or if the variable is used in
+                        # multi-sources relation
+                        if self._crossrelations:
+                            for reldict in self._crossrelations.itervalues():
+                                for rel, terms in reldict.iteritems():
+                                    for term in terms:
+                                        if isinstance(term, Variable) \
+                                               and self._need_ext_source_access(term, rel):
+                                            self.needsplit = True
+                                            return
+
+    @cached
+    def _need_ext_source_access(self, var, rel):
+        if not var._q_invariant:
+            return True
+        if  any(r for x, r in self._linkedterms[var]
+                if not r is rel and self._repo.is_multi_sources_relation(r.r_type)):
+            return True
+        return False
+        
+    def _set_source_for_term(self, source, term):
+        self._sourcesterms.setdefault(source, {})[term] = set(self._solindices)
 
     def _term_sources(self, term):
         """returns possible sources for terms `term`"""
@@ -493,27 +588,27 @@
             return set((source, solindex) for solindex in self._solindices)
         else:
             var = getattr(term, 'variable', term)
-            sources = [source for source, varobjs in self.sourcesvars.iteritems()
+            sources = [source for source, varobjs in self.sourcesterms.iteritems()
                        if var in varobjs]
             return set((source, solindex) for source in sources
-                       for solindex in self.sourcesvars[source][var])
+                       for solindex in self.sourcesterms[source][var])
 
-    def _remove_sources(self, var, sources):
-        """removes invalid sources (`sources`) from `sourcesvars`
+    def _remove_sources(self, term, sources):
+        """removes invalid sources (`sources`) from `sourcesterms`
 
         :param sources: the list of sources to remove
-        :param var: the analyzed variable
+        :param term: the analyzed term
         """
-        sourcesvars = self._sourcesvars
+        sourcesterms = self._sourcesterms
         for source, solindex in sources:
             try:
-                sourcesvars[source][var].remove(solindex)
+                sourcesterms[source][term].remove(solindex)
             except KeyError:
                 return # may occur with subquery column alias
-            if not sourcesvars[source][var]:
-                del sourcesvars[source][var]
-                if not sourcesvars[source]:
-                    del sourcesvars[source]
+            if not sourcesterms[source][term]:
+                del sourcesterms[source][term]
+                if not sourcesterms[source]:
+                    del sourcesterms[source]
 
     def crossed_relation(self, source, relation):
         return relation in self._crossrelations.get(source, ())
@@ -525,45 +620,97 @@
         """
         steps = []
         select = self.rqlst
-        rschema = self.plan.schema.rschema
+        rschema = self._schema.rschema
         for source in self.part_sources:
-            sourcevars = self._sourcesvars[source]
-            while sourcevars:
-                # take a variable randomly, and all variables supporting the
+            try:
+                sourceterms = self._sourcesterms[source]
+            except KeyError:
+                continue # already proceed
+            while sourceterms:
+                # take a term randomly, and all terms supporting the
                 # same solutions
-                var, solindices = self._choose_var(sourcevars)
+                term, solindices = self._choose_term(sourceterms)
                 if source.uri == 'system':
                     # ensure all variables are available for the latest step
                     # (missing one will be available from temporary tables
                     # of previous steps)
                     scope = select
-                    variables = scope.defined_vars.values() + scope.aliases.values()
-                    sourcevars.clear()
+                    terms = scope.defined_vars.values() + scope.aliases.values()
+                    sourceterms.clear()
+                    sources = [source]
                 else:
-                    scope = var.scope
-                    variables = self._expand_vars(var, source, sourcevars, scope, solindices)
-                    if not sourcevars:
-                        del self._sourcesvars[source]
-                # find which sources support the same variables/solutions
-                sources = self._expand_sources(source, variables, solindices)
-                # suppose this is a final step until the contrary is proven
-                final = scope is select
-                # set of variables which should be additionaly selected when
+                    scope = term.scope
+                    # find which sources support the same term and solutions
+                    sources = self._expand_sources(source, term, solindices)
+                    # no try to get as much terms as possible
+                    terms = self._expand_terms(term, sources, sourceterms,
+                                               scope, solindices)
+                    if len(terms) == 1 and isinstance(terms[0], Constant):
+                        # we can't generate anything interesting with a single
+                        # constant term (will generate an empty "Any" query),
+                        # go to the next iteration directly!
+                        continue
+                    if not sourceterms:
+                         try:
+                             del self._sourcesterms[source]
+                         except KeyError:
+                             # XXX already cleaned
+                             pass
+                # set of terms which should be additionaly selected when
                 # possible
                 needsel = set()
-                # add attribute variables and mark variables which should be
-                # additionaly selected when possible
-                for var in select.defined_vars.itervalues():
-                    if not var in variables:
-                        stinfo = var.stinfo
-                        for ovar, rtype in stinfo['attrvars']:
-                            if ovar in variables:
+                if not self._sourcesterms:
+                    terms += scope.defined_vars.values() + scope.aliases.values()
+                    final = True
+                else:
+                    # suppose this is a final step until the contrary is proven
+                    final = scope is select
+                    # add attribute variables and mark variables which should be
+                    # additionaly selected when possible
+                    for var in select.defined_vars.itervalues():
+                        if not var in terms:
+                            stinfo = var.stinfo
+                            for ovar, rtype in stinfo['attrvars']:
+                                if ovar in terms:
+                                    needsel.add(var.name)
+                                    terms.append(var)
+                                    break
+                            else:
                                 needsel.add(var.name)
-                                variables.append(var)
+                                final = False
+                    # check where all relations are supported by the sources
+                    for rel in scope.iget_nodes(Relation):
+                        if rel.is_types_restriction():
+                            continue
+                        # take care not overwriting the existing "source" identifier
+                        for _source in sources:
+                            if not _source.support_relation(rel.r_type) or (
+                                self.crossed_relation(_source, rel) and not rel in terms):
+                                for vref in rel.iget_nodes(VariableRef):
+                                    needsel.add(vref.name)
+                                final = False
                                 break
                         else:
-                            needsel.add(var.name)
-                            final = False
+                            if not scope is select:
+                                self._exists_relation(rel, terms, needsel)
+                            # if relation is supported by all sources and some of
+                            # its lhs/rhs variable isn't in "terms", and the
+                            # other end *is* in "terms", mark it have to be
+                            # selected
+                            if source.uri != 'system' and not rschema(rel.r_type).is_final():
+                                lhs, rhs = rel.get_variable_parts()
+                                try:
+                                    lhsvar = lhs.variable
+                                except AttributeError:
+                                    lhsvar = lhs
+                                try:
+                                    rhsvar = rhs.variable
+                                except AttributeError:
+                                    rhsvar = rhs
+                                if lhsvar in terms and not rhsvar in terms:
+                                    needsel.add(lhsvar.name)
+                                elif rhsvar in terms and not lhsvar in terms:
+                                    needsel.add(rhsvar.name)
                 if final and source.uri != 'system':
                     # check rewritten constants
                     for vconsts in select.stinfo['rewritten'].itervalues():
@@ -571,62 +718,25 @@
                         eid = const.eval(self.plan.args)
                         _source = self._session.source_from_eid(eid)
                         if len(sources) > 1 or not _source in sources:
-                            # if there is some rewriten constant used by a
-                            # not neged relation while there are some source
-                            # not supporting the associated entity, this step
-                            # can't be final (unless the relation is explicitly
-                            # in `variables`, eg cross relations)
+                            # if there is some rewriten constant used by a not
+                            # neged relation while there are some source not
+                            # supporting the associated entity, this step can't
+                            # be final (unless the relation is explicitly in
+                            # `terms`, eg cross relations)
                             for c in vconsts:
                                 rel = c.relation()
-                                if rel is None or not (rel in variables or rel.neged(strict=True)):
-                                #if rel is not None and rel.r_type == 'identity' and not rel.neged(strict=True):
+                                if rel is None or not (rel in terms or rel.neged(strict=True)):
                                     final = False
                                     break
                             break
-                # check where all relations are supported by the sources
-                for rel in scope.iget_nodes(Relation):
-                    if rel.is_types_restriction():
-                        continue
-                    # take care not overwriting the existing "source" identifier
-                    for _source in sources:
-                        if not _source.support_relation(rel.r_type):
-                            for vref in rel.iget_nodes(VariableRef):
-                                needsel.add(vref.name)
-                            final = False
-                            break
-                        elif self.crossed_relation(_source, rel) and not rel in variables:
-                            final = False
-                            break
-                    else:
-                        if not scope is select:
-                            self._exists_relation(rel, variables, needsel)
-                        # if relation is supported by all sources and some of
-                        # its lhs/rhs variable isn't in "variables", and the
-                        # other end *is* in "variables", mark it have to be
-                        # selected
-                        if source.uri != 'system' and not rschema(rel.r_type).is_final():
-                            lhs, rhs = rel.get_variable_parts()
-                            try:
-                                lhsvar = lhs.variable
-                            except AttributeError:
-                                lhsvar = lhs
-                            try:
-                                rhsvar = rhs.variable
-                            except AttributeError:
-                                rhsvar = rhs
-                            if lhsvar in variables and not rhsvar in variables:
-                                needsel.add(lhsvar.name)
-                            elif rhsvar in variables and not lhsvar in variables:
-                                needsel.add(rhsvar.name)
                 if final:
-                    self._cleanup_sourcesvars(sources, solindices)
-                # XXX rename: variables may contain Relation and Constant nodes...
-                steps.append( (sources, variables, solindices, scope, needsel,
-                               final) )
+                    self._cleanup_sourcesterms(sources, solindices)
+                steps.append((sources, terms, solindices, scope, needsel, final)
+                             )
         return steps
 
-    def _exists_relation(self, rel, variables, needsel):
-        rschema = self.plan.schema.rschema(rel.r_type)
+    def _exists_relation(self, rel, terms, needsel):
+        rschema = self._schema.rschema(rel.r_type)
         lhs, rhs = rel.get_variable_parts()
         try:
             lhsvar, rhsvar = lhs.variable, rhs.variable
@@ -638,135 +748,165 @@
             # variable is refed by an outer scope and should be substituted
             # using an 'identity' relation (else we'll get a conflict of
             # temporary tables)
-            if rhsvar in variables and not lhsvar in variables:
-                self._identity_substitute(rel, lhsvar, variables, needsel)
-            elif lhsvar in variables and not rhsvar in variables:
-                self._identity_substitute(rel, rhsvar, variables, needsel)
+            if rhsvar in terms and not lhsvar in terms:
+                self._identity_substitute(rel, lhsvar, terms, needsel)
+            elif lhsvar in terms and not rhsvar in terms:
+                self._identity_substitute(rel, rhsvar, terms, needsel)
 
-    def _identity_substitute(self, relation, var, variables, needsel):
+    def _identity_substitute(self, relation, var, terms, needsel):
         newvar = self._insert_identity_variable(relation.scope, var)
         if newvar is not None:
             # ensure relation is using '=' operator, else we rely on a
             # sqlgenerator side effect (it won't insert an inequality operator
             # in this case)
             relation.children[1].operator = '=' 
-            variables.append(newvar)
+            terms.append(newvar)
             needsel.add(newvar.name)
         
-    def _choose_var(self, sourcevars):
+    def _choose_term(self, sourceterms):
+        """pick one term among terms supported by a source, which will be used
+        as a base to generate an execution step
+        """
         secondchoice = None
-        if len(self._sourcesvars) > 1:
+        if len(self._sourcesterms) > 1:
             # priority to variable from subscopes
-            for var in sourcevars:
-                if not var.scope is self.rqlst:
-                    if isinstance(var, Variable):
-                        return var, sourcevars.pop(var)
-                    secondchoice = var, sourcevars.pop(var)
+            for term in sourceterms:
+                if not term.scope is self.rqlst:
+                    if isinstance(term, Variable):
+                        return term, sourceterms.pop(term)
+                    secondchoice = term
         else:
-            # priority to variable outer scope
-            for var in sourcevars:
-                if var.scope is self.rqlst:
-                    if isinstance(var, Variable):
-                        return var, sourcevars.pop(var)
-                    secondchoice = var
+            # priority to variable from outer scope
+            for term in sourceterms:
+                if term.scope is self.rqlst:
+                    if isinstance(term, Variable):
+                        return term, sourceterms.pop(term)
+                    secondchoice = term
         if secondchoice is not None:
-            return secondchoice, sourcevars.pop(secondchoice)
-        # priority to variable
-        for var in sourcevars:
-            if isinstance(var, Variable):
-                return var, sourcevars.pop(var)
-        # whatever
-        var = iter(sourcevars).next()
-        return var, sourcevars.pop(var)
-            
+            return secondchoice, sourceterms.pop(secondchoice)
+        # priority to variable with the less solutions supported and with the
+        # most valuable refs. Add variable name for test predictability
+        variables = sorted([(var, sols) for (var, sols) in sourceterms.items()
+                            if isinstance(var, Variable)],
+                           key=lambda (v, s): (len(s), -v.valuable_references(), v.name))
+        if variables:
+            var = variables[0][0]
+            return var, sourceterms.pop(var)
+        # priority to constant
+        for term in sourceterms:
+            if isinstance(term, Constant):
+                return term, sourceterms.pop(term)
+        # whatever (relation)
+        term = iter(sourceterms).next()
+        return term, sourceterms.pop(term)
             
-    def _expand_vars(self, var, source, sourcevars, scope, solindices):
-        variables = [var]
+    def _expand_sources(self, selected_source, term, solindices):
+        """return all sources supporting given term / solindices"""
+        sources = [selected_source]
+        sourcesterms = self._sourcesterms
+        for source in sourcesterms.keys():
+            if source is selected_source:
+                continue
+            if not (term in sourcesterms[source] and 
+                    solindices.issubset(sourcesterms[source][term])):
+                continue
+            sources.append(source)
+            if source.uri != 'system' or not (isinstance(term, Variable) and not term in self._linkedterms):
+                termsolindices = sourcesterms[source][term]
+                termsolindices -= solindices
+                if not termsolindices:
+                    del sourcesterms[source][term]
+                    if not sourcesterms[source]:
+                        del sourcesterms[source]
+        return sources
+            
+    def _expand_terms(self, term, sources, sourceterms, scope, solindices):
+        terms = [term]
+        sources = sorted(sources)
+        sourcesterms = self._sourcesterms
         nbunlinked = 1
-        linkedvars = self._linkedvars
-        # variable has to belong to the same scope if there is more
+        linkedterms = self._linkedterms
+        # term has to belong to the same scope if there is more
         # than the system source remaining
-        if len(self._sourcesvars) > 1 and not scope is self.rqlst:
-            candidates = (v for v in sourcevars.keys() if scope is v.scope)
+        if len(sourcesterms) > 1 and not scope is self.rqlst:
+            candidates = (t for t in sourceterms.keys() if scope is t.scope)
         else:
-            candidates = sourcevars #.iterkeys()
-        # we only want one unlinked variable in each generated query
-        candidates = [v for v in candidates
-                      if isinstance(v, Constant) or
-                      (solindices.issubset(sourcevars[v]) and v in linkedvars)]
-        accept_var = lambda x: (isinstance(x, Constant) or any(v for v in variables if v in linkedvars.get(x, ())))
-        source_cross_rels = self._crossrelations.get(source, ())
-        if isinstance(var, Relation) and var in source_cross_rels:
-            cross_vars = source_cross_rels.pop(var)
-            base_accept_var = accept_var
-            accept_var = lambda x: (base_accept_var(x) or x in cross_vars)
-            for refed in cross_vars:
+            candidates = sourceterms #.iterkeys()
+        # we only want one unlinked term in each generated query
+        candidates = [t for t in candidates
+                      if isinstance(t, (Constant, Relation)) or
+                      (solindices.issubset(sourceterms[t]) and t in linkedterms)]
+        cross_rels = {}
+        for source in sources:
+            cross_rels.update(self._crossrelations.get(source, {}))
+        exclude = {}
+        for rel, crossvars in cross_rels.iteritems():
+            vars = [t for t in crossvars if isinstance(t, Variable)]
+            try:
+                exclude[vars[0]] = vars[1]
+                exclude[vars[1]] = vars[0]
+            except IndexError:
+                pass
+        accept_term = lambda x: (not any(s for s in sources if not x in sourcesterms.get(s, ()))
+                                 and any(t for t in terms if t in linkedterms.get(x, ()))
+                                 and not exclude.get(x) in terms)
+        if isinstance(term, Relation) and term in cross_rels:
+            cross_terms = cross_rels.pop(term)
+            base_accept_term = accept_term
+            accept_term = lambda x: (base_accept_term(x) or x in cross_terms)
+            for refed in cross_terms:
                 if not refed in candidates:
-                    candidates.append(refed)
-        else:
-            cross_vars = ()
-        # repeat until no variable can't be added, since addition of a new
-        # variable may permit to another one to be added
+                    terms.append(refed)
+        # repeat until no term can't be added, since addition of a new
+        # term may permit to another one to be added
         modified = True
         while modified and candidates:
             modified = False
-            for var in candidates[:]:
-                if accept_var(var):
-                    variables.append(var)
-                    try:
-                        # constant nodes should be systematically deleted
-                        if isinstance(var, Constant):
-                            del sourcevars[var]
-                        else:
-                            # variable nodes should be deleted once all possible
-                            # solutions indices have been consumed
-                            sourcevars[var] -= solindices
-                            if not sourcevars[var]:
-                                del sourcevars[var]
-                    except KeyError:
-                        assert var in cross_vars
-                    candidates.remove(var)
+            for term in candidates[:]:
+                if isinstance(term, Constant):
+                    relation = term.relation()
+                    if sorted(set(x[0] for x in self._term_sources(term))) != sources:
+                        continue
+                    terms.append(term)
+                    candidates.remove(term)
                     modified = True
-        return variables
+                    del sourceterms[term]
+                elif accept_term(term):
+                    terms.append(term)
+                    candidates.remove(term)
+                    modified = True
+                    self._cleanup_sourcesterms(sources, solindices, term)
+        return terms
     
-    def _expand_sources(self, selected_source, vars, solindices):
-        sources = [selected_source]
-        sourcesvars = self._sourcesvars
-        for source in sourcesvars:
-            if source is selected_source:
-                continue
-            for var in vars:
-                if not (var in sourcesvars[source] and 
-                        solindices.issubset(sourcesvars[source][var])):
-                    break
-            else:
-                sources.append(source)
-                if source.uri != 'system':
-                    for var in vars:
-                        varsolindices = sourcesvars[source][var]
-                        varsolindices -= solindices
-                        if not varsolindices:
-                            del sourcesvars[source][var]                
-        return sources
-    
-    def _cleanup_sourcesvars(self, sources, solindices):
-        """on final parts, remove solutions so we know they are already processed"""
+    def _cleanup_sourcesterms(self, sources, solindices, term=None):
+        """remove solutions so we know they are already processed"""
         for source in sources:
             try:
-                sourcevars = self._sourcesvars[source]
+                sourceterms = self._sourcesterms[source]
             except KeyError:
                 continue
-            for var, varsolindices in sourcevars.items():
-                if isinstance(var, Relation) and self.crossed_relation(source, var):
-                    continue
-                varsolindices -= solindices
-                if not varsolindices:
-                    del sourcevars[var]
-                    
+            if term is None:
+                for term, termsolindices in sourceterms.items():
+                    if isinstance(term, Relation) and self.crossed_relation(source, term):
+                        continue
+                    termsolindices -= solindices
+                    if not termsolindices:
+                        del sourceterms[term]
+            else:
+                try:
+                    sourceterms[term] -= solindices
+                    if not sourceterms[term]:
+                        del sourceterms[term]
+                except KeyError:
+                    pass
+                    #assert term in cross_terms
+            if not sourceterms:
+                del self._sourcesterms[source]
+                
     def merge_input_maps(self, allsolindices):
-        """inputmaps is a dictionary with tuple of solution indices as key with an
-        associateed input map as value. This function compute for each solution 
-        its necessary input map and return them grouped
+        """inputmaps is a dictionary with tuple of solution indices as key with
+        an associated input map as value. This function compute for each
+        solution its necessary input map and return them grouped
 
         ex:
         inputmaps = {(0, 1, 2): {'A': 't1.login1', 'U': 't1.C0', 'U.login': 't1.login1'},
@@ -802,26 +942,38 @@
 
     def build_final_part(self, select, solindices, inputmap,  sources,
                          insertedvars):
-        plan = self.plan
-        rqlst = plan.finalize(select, [self._solutions[i] for i in solindices],
-                              insertedvars)
+        solutions = [self._solutions[i] for i in solindices]
+        if self._conflicts:
+            for varname, mappedto in self._conflicts:
+                var = select.defined_vars[varname]
+                newvar = select.make_variable()
+                # XXX should use var.scope but scope hasn't been computed yet
+                select.add_relation(var, 'identity', newvar)
+                for sol in solutions:
+                    sol[newvar.name] = sol[varname]
+                inputmap[newvar.name] = mappedto
+        rqlst = self.plan.finalize(select, solutions, insertedvars)
         if self.temptable is None and self.finaltable is None:
-            return OneFetchStep(plan, rqlst, sources, inputmap=inputmap)
+            return OneFetchStep(self.plan, rqlst, sources, inputmap=inputmap)
         table = self.temptable or self.finaltable
-        return FetchStep(plan, rqlst, sources, table, True, inputmap)
+        return FetchStep(self.plan, rqlst, sources, table, True, inputmap)
 
     def build_non_final_part(self, select, solindices, sources, insertedvars,
                              table):
         """non final step, will have to store results in a temporary table"""
-        plan = self.plan
-        rqlst = plan.finalize(select, [self._solutions[i] for i in solindices],
-                              insertedvars)
-        step = FetchStep(plan, rqlst, sources, table, False)
+        solutions = [self._solutions[i] for i in solindices]
+        rqlst = self.plan.finalize(select, solutions, insertedvars)
+        step = FetchStep(self.plan, rqlst, sources, table, False)
         # update input map for following steps, according to processed solutions
         inputmapkey = tuple(sorted(solindices))
         inputmap = self._inputmaps.setdefault(inputmapkey, {})
+        for varname, mapping in step.outputmap.iteritems():
+            if varname in inputmap and \
+                   not (mapping == inputmap[varname] or
+                        self._schema.eschema(solutions[0][varname]).is_final()):
+                self._conflicts.append((varname, inputmap[varname]))
         inputmap.update(step.outputmap)
-        plan.add_step(step)
+        self.plan.add_step(step)
 
 
 class MSPlanner(SSPlanner):
@@ -895,7 +1047,7 @@
             byinputmap = {}
             for ppi in cppis:
                 select = ppi.rqlst
-                if sources != (plan.session.repo.system_source,):
+                if sources != (ppi.system_source,):
                     add_types_restriction(self.schema, select)
                 # part plan info for subqueries
                 inputmap = self._ppi_subqueries(ppi)
@@ -952,10 +1104,10 @@
             atemptable = None
             selection = select.selection
         ppi.temptable = atemptable
-        vfilter = VariablesFiltererVisitor(self.schema, ppi)
+        vfilter = TermsFiltererVisitor(self.schema, ppi)
         steps = []
-        for sources, variables, solindices, scope, needsel, final in stepdefs:
-            # extract an executable query using only the specified variables
+        for sources, terms, solindices, scope, needsel, final in stepdefs:
+            # extract an executable query using only the specified terms
             if sources[0].uri == 'system':
                 # in this case we have to merge input maps before call to
                 # filter so already processed restriction are correctly
@@ -963,7 +1115,7 @@
                 solsinputmaps = ppi.merge_input_maps(solindices)
                 for solindices, inputmap in solsinputmaps:
                     minrqlst, insertedvars = vfilter.filter(
-                        sources, variables, scope, set(solindices), needsel, final)
+                        sources, terms, scope, set(solindices), needsel, final)
                     if inputmap is None:
                         inputmap = subinputmap
                     else:
@@ -972,10 +1124,10 @@
                                                       sources, insertedvars))
             else:
                 # this is a final part (i.e. retreiving results for the
-                # original query part) if all variable / sources have been
+                # original query part) if all term / sources have been
                 # treated or if this is the last shot for used solutions
                 minrqlst, insertedvars = vfilter.filter(
-                    sources, variables, scope, solindices, needsel, final)
+                    sources, terms, scope, solindices, needsel, final)
                 if final:
                     solsinputmaps = ppi.merge_input_maps(solindices)
                     for solindices, inputmap in solsinputmaps:
@@ -983,10 +1135,17 @@
                             inputmap = subinputmap
                         else:
                             inputmap.update(subinputmap)
-                        steps.append(ppi.build_final_part(minrqlst, solindices, inputmap,
-                                                  sources, insertedvars))
+                        if inputmap and len(sources) > 1:
+                            sources.remove(ppi.system_source)
+                            steps.append(ppi.build_final_part(minrqlst, solindices, None,
+                                                              sources, insertedvars))
+                            steps.append(ppi.build_final_part(minrqlst, solindices, inputmap,
+                                                              [ppi.system_source], insertedvars))
+                        else:
+                            steps.append(ppi.build_final_part(minrqlst, solindices, inputmap,
+                                                              sources, insertedvars))
                 else:
-                    table = '_T%s%s' % (''.join(sorted(v._ms_table_key() for v in variables)),
+                    table = '_T%s%s' % (''.join(sorted(v._ms_table_key() for v in terms)),
                                         ''.join(sorted(str(i) for i in solindices)))
                     ppi.build_non_final_part(minrqlst, solindices, sources,
                                              insertedvars, table)
@@ -995,7 +1154,9 @@
             step = AggrStep(plan, selection, select, atemptable, temptable)
             step.children = steps
         elif len(steps) > 1:
-            if select.need_intersect:
+            if select.need_intersect or any(select.need_intersect
+                                            for step in steps
+                                            for select in step.union.children):
                 if temptable:
                     step = IntersectFetchStep(plan)
                 else:
@@ -1017,7 +1178,7 @@
     pass
 
 
-class VariablesFiltererVisitor(object):
+class TermsFiltererVisitor(object):
     def __init__(self, schema, ppi):
         self.schema = schema
         self.ppi = ppi
@@ -1026,9 +1187,9 @@
         self.extneedsel = frozenset(vref.name for sortterm in ppi.rqlst.orderby
                                     for vref in sortterm.iget_nodes(VariableRef))
         
-    def _rqlst_accept(self, rqlst, node, newroot, variables, setfunc=None):
+    def _rqlst_accept(self, rqlst, node, newroot, terms, setfunc=None):
         try:
-            newrestr, node_ = node.accept(self, newroot, variables[:])
+            newrestr, node_ = node.accept(self, newroot, terms[:])
         except UnsupportedBranch:
             return rqlst
         if setfunc is not None and newrestr is not None:
@@ -1037,18 +1198,18 @@
             rqlst = node.parent
         return rqlst
 
-    def filter(self, sources, variables, rqlst, solindices, needsel, final):
+    def filter(self, sources, terms, rqlst, solindices, needsel, final):
         if server.DEBUG:
-            print 'filter', final and 'final' or '', sources, variables, rqlst, solindices, needsel
+            print 'filter', final and 'final' or '', sources, terms, rqlst, solindices, needsel
         newroot = Select()
         self.sources = sorted(sources)
-        self.variables = variables
+        self.terms = terms
         self.solindices = solindices
         self.final = final
-        # variables which appear in unsupported branches
+        # terms which appear in unsupported branches
         needsel |= self.extneedsel
         self.needsel = needsel
-        # variables which appear in supported branches
+        # terms which appear in supported branches
         self.mayneedsel = set()
         # new inserted variables
         self.insertedvars = []
@@ -1057,36 +1218,36 @@
         self.use_only_defined = False
         self.scopes = {rqlst: newroot}
         if rqlst.where:
-            rqlst = self._rqlst_accept(rqlst, rqlst.where, newroot, variables,
+            rqlst = self._rqlst_accept(rqlst, rqlst.where, newroot, terms,
                                        newroot.set_where)
         if isinstance(rqlst, Select):
             self.use_only_defined = True
             if rqlst.groupby:
                 groupby = []
                 for node in rqlst.groupby:
-                    rqlst = self._rqlst_accept(rqlst, node, newroot, variables,
+                    rqlst = self._rqlst_accept(rqlst, node, newroot, terms,
                                                groupby.append)
                 if groupby:
                     newroot.set_groupby(groupby)
             if rqlst.having:
                 having = []
                 for node in rqlst.having:
-                    rqlst = self._rqlst_accept(rqlst, node, newroot, variables,
+                    rqlst = self._rqlst_accept(rqlst, node, newroot, terms,
                                                having.append)
                 if having:
                     newroot.set_having(having)
             if final and rqlst.orderby and not self.hasaggrstep:
                 orderby = []
                 for node in rqlst.orderby:
-                    rqlst = self._rqlst_accept(rqlst, node, newroot, variables,
+                    rqlst = self._rqlst_accept(rqlst, node, newroot, terms,
                                                orderby.append)
                 if orderby:
                     newroot.set_orderby(orderby)
-            self.process_selection(newroot, variables, rqlst)
+            self.process_selection(newroot, terms, rqlst)
         elif not newroot.where:
-            # no restrictions have been copied, just select variables and add
+            # no restrictions have been copied, just select terms and add
             # type restriction (done later by add_types_restriction)
-            for v in variables:
+            for v in terms:
                 if not isinstance(v, Variable):
                     continue
                 newroot.append_selected(VariableRef(newroot.get_variable(v.name)))
@@ -1134,12 +1295,12 @@
             print '--->', newroot
         return newroot, self.insertedvars
         
-    def visit_and(self, node, newroot, variables):
+    def visit_and(self, node, newroot, terms):
         subparts = []
         for i in xrange(len(node.children)):
             child = node.children[i]
             try:
-                newchild, child_ = child.accept(self, newroot, variables)
+                newchild, child_ = child.accept(self, newroot, terms)
                 if not child_ is child:
                     node = child_.parent
                 if newchild is None:
@@ -1158,10 +1319,10 @@
     def _relation_supported(self, relation):
         rtype = relation.r_type
         for source in self.sources:
-            if not source.support_relation(rtype) \
-                   or (rtype in source.cross_relations and not relation in self.variables):#self.ppi.crossed_relation(source, relation):
+            if not source.support_relation(rtype) or (
+                rtype in source.cross_relations and not relation in self.terms):
                 return False
-        if not self.final:
+        if not self.final and not relation in self.terms:
             rschema = self.schema.rschema(relation.r_type)
             if not rschema.is_final():
                 for term in relation.get_nodes((VariableRef, Constant)):
@@ -1171,7 +1332,7 @@
                         return False
         return True
         
-    def visit_relation(self, node, newroot, variables):
+    def visit_relation(self, node, newroot, terms):
         if not node.is_types_restriction():
             if node in self.skip and self.solindices.issubset(self.skip[node]):
                 if not self.schema.rschema(node.r_type).is_final():
@@ -1192,12 +1353,15 @@
         # copy a type restriction while the variable is not actually used)
         elif not any(self._relation_supported(rel)
                      for rel in node.children[0].variable.stinfo['relations']):
-            rel, node = self.visit_default(node, newroot, variables)
+            rel, node = self.visit_default(node, newroot, terms)
             return rel, node
         else:
             raise UnsupportedBranch()
         rschema = self.schema.rschema(node.r_type)
-        res = self.visit_default(node, newroot, variables)[0]
+        try:
+            res = self.visit_default(node, newroot, terms)[0]
+        except Exception, ex:
+            raise
         ored = node.ored()
         if rschema.is_final() or rschema.inlined:
             vrefs = node.children[1].get_nodes(VariableRef)
@@ -1211,13 +1375,13 @@
                 vref = vrefs[0]
                 # XXX check operator ?
                 self.hasvar[(node.children[0].name, rschema)] = vref
-                if self._may_skip_attr_rel(rschema, node, vref, ored, variables, res):
+                if self._may_skip_attr_rel(rschema, node, vref, ored, terms, res):
                     self.skip.setdefault(node, set()).update(self.solindices)
         elif not ored:
             self.skip.setdefault(node, set()).update(self.solindices)
         return res, node
 
-    def _may_skip_attr_rel(self, rschema, rel, vref, ored, variables, res):
+    def _may_skip_attr_rel(self, rschema, rel, vref, ored, terms, res):
         var = vref.variable
         if ored:
             return False
@@ -1225,35 +1389,35 @@
             return False
         if not same_scope(var):
             return False
-        if any(v for v,_ in var.stinfo['attrvars'] if not v.name in variables):
+        if any(v for v,_ in var.stinfo['attrvars'] if not v.name in terms):
             return False
         return True
         
-    def visit_exists(self, node, newroot, variables):
+    def visit_exists(self, node, newroot, terms):
         newexists = node.__class__()
         self.scopes = {node: newexists}
-        subparts, node = self._visit_children(node, newroot, variables)
+        subparts, node = self._visit_children(node, newroot, terms)
         if not subparts:
             return None, node
         newexists.set_where(subparts[0])
         return newexists, node
     
-    def visit_not(self, node, newroot, variables):
-        subparts, node = self._visit_children(node, newroot, variables)
+    def visit_not(self, node, newroot, terms):
+        subparts, node = self._visit_children(node, newroot, terms)
         if not subparts:
             return None, node
         return copy_node(newroot, node, subparts), node
     
-    def visit_group(self, node, newroot, variables):
+    def visit_group(self, node, newroot, terms):
         if not self.final:
             return None, node
-        return self.visit_default(node, newroot, variables)
+        return self.visit_default(node, newroot, terms)
             
-    def visit_variableref(self, node, newroot, variables):
+    def visit_variableref(self, node, newroot, terms):
         if self.use_only_defined:
             if not node.variable.name in newroot.defined_vars:
                 raise UnsupportedBranch(node.name)
-        elif not node.variable in variables:
+        elif not node.variable in terms:
             raise UnsupportedBranch(node.name)
         self.mayneedsel.add(node.name)
         # set scope so we can insert types restriction properly
@@ -1261,28 +1425,28 @@
         newvar.stinfo['scope'] = self.scopes.get(node.variable.scope, newroot)
         return VariableRef(newvar), node
 
-    def visit_constant(self, node, newroot, variables):
+    def visit_constant(self, node, newroot, terms):
         return copy_node(newroot, node), node
     
-    def visit_default(self, node, newroot, variables):
-        subparts, node = self._visit_children(node, newroot, variables)
+    def visit_default(self, node, newroot, terms):
+        subparts, node = self._visit_children(node, newroot, terms)
         return copy_node(newroot, node, subparts), node
         
     visit_comparison = visit_mathexpression = visit_constant = visit_function = visit_default
     visit_sort = visit_sortterm = visit_default
     
-    def _visit_children(self, node, newroot, variables):
+    def _visit_children(self, node, newroot, terms):
         subparts = []
         for i in xrange(len(node.children)):
             child = node.children[i]
-            newchild, child_ = child.accept(self, newroot, variables)
+            newchild, child_ = child.accept(self, newroot, terms)
             if not child is child_:
                 node = child_.parent
             if newchild is not None:
                 subparts.append(newchild)
         return subparts, node
     
-    def process_selection(self, newroot, variables, rqlst):
+    def process_selection(self, newroot, terms, rqlst):
         if self.final:
             for term in rqlst.selection:
                 newroot.append_selected(term.copy(newroot))
@@ -1295,7 +1459,7 @@
                 supportedvars = []
                 for vref in vrefs:
                     var = vref.variable
-                    if var in variables:
+                    if var in terms:
                         supportedvars.append(vref)
                         continue
                     else:
@@ -1309,9 +1473,9 @@
                     if not vref in newroot.get_selected_variables():
                         newroot.append_selected(VariableRef(newroot.get_variable(vref.name)))
             
-    def add_necessary_selection(self, newroot, variables):
+    def add_necessary_selection(self, newroot, terms):
         selected = tuple(newroot.get_selected_variables())
-        for varname in variables:
+        for varname in terms:
             var = newroot.defined_vars[varname]
             for vref in var.references():
                 rel = vref.relation()
--- a/server/mssteps.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/mssteps.py	Wed Apr 15 17:36:09 2009 +0200
@@ -6,7 +6,7 @@
   for now)
 
 :organization: Logilab
-:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -274,9 +274,9 @@
             result &= frozenset(step.execute())
         result = list(result)
         if self.offset:
-            result = result[offset:]
+            result = result[self.offset:]
         if self.limit:
-            result = result[:limit]
+            result = result[:self.limit]
         return result
 
 
--- a/server/querier.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/querier.py	Wed Apr 15 17:36:09 2009 +0200
@@ -196,7 +196,7 @@
             self._insert_security(union, noinvariant)
         self.rqlhelper.simplify(union)
         self.sqlannotate(union)
-        set_qdata(union, noinvariant)
+        set_qdata(self.schema.rschema, union, noinvariant)
         if union.has_text_query:
             self.cache_key = None
 
--- a/server/repository.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/repository.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,7 +11,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -144,6 +144,8 @@
         self.schema = CubicWebSchema(config.appid)
         # querier helper, need to be created after sources initialization
         self.querier = QuerierHelper(self, self.schema)
+        # should we reindex in changes?
+        self.do_fti = not config['delay-full-text-indexation']
         # sources
         self.sources = []
         self.sources_by_uri = {}
@@ -211,7 +213,7 @@
         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):
@@ -490,7 +492,7 @@
         session = self.internal_session()
         try:
             if session.execute('EUser X WHERE X login %(login)s', {'login': login}):
-                return
+                return False
             # we have to create the user
             user = self.vreg.etype_class('EUser')(session, None)
             if isinstance(password, unicode):
@@ -505,6 +507,7 @@
             session.commit()
         finally:
             session.close()
+        return True
         
     def connect(self, login, password, cnxprops=None):
         """open a connection for a given user
@@ -767,7 +770,8 @@
             raise UnknownEid(eid)
         return extid
 
-    def extid2eid(self, source, lid, etype, session=None, insert=True):
+    def extid2eid(self, source, lid, etype, session=None, insert=True,
+                  recreate=False):
         """get eid from a local id. An eid is attributed if no record is found"""
         cachekey = (str(lid), source.uri)
         try:
@@ -782,6 +786,15 @@
         if eid is not None:
             self._extid_cache[cachekey] = eid
             self._type_source_cache[eid] = (etype, source.uri, lid)
+            if recreate:
+                entity = source.before_entity_insertion(session, lid, etype, eid)
+                entity._cw_recreating = True
+                if source.should_call_hooks:
+                    self.hm.call_hooks('before_add_entity', etype, session, entity)
+                # XXX add fti op ?
+                source.after_entity_insertion(session, lid, entity)
+                if source.should_call_hooks:
+                    self.hm.call_hooks('after_add_entity', etype, session, entity)
             if reset_pool:
                 session.reset_pool()
             return eid
@@ -791,7 +804,7 @@
         # since the current session user may not have required permissions to
         # do necessary stuff and we don't want to commit user session.
         #
-        # More other, even if session is already an internal session but is
+        # Moreover, even if session is already an internal session but is
         # processing a commit, we have to use another one
         if not session.is_internal_session:
             session = self.internal_session()
@@ -803,6 +816,7 @@
             entity = source.before_entity_insertion(session, lid, etype, eid)
             if source.should_call_hooks:
                 self.hm.call_hooks('before_add_entity', etype, session, entity)
+            # XXX call add_info with complete=False ?
             self.add_info(session, entity, source, lid)
             source.after_entity_insertion(session, lid, entity)
             if source.should_call_hooks:
@@ -827,7 +841,8 @@
             entity.complete(entity.e_schema.indexable_attributes())
         session.add_query_data('neweids', entity.eid)
         # now we can update the full text index
-        FTIndexEntityOp(session, entity=entity)
+        if self.do_fti:
+            FTIndexEntityOp(session, entity=entity)
         CleanupEidTypeCacheOp(session)
         
     def delete_info(self, session, eid):
@@ -896,11 +911,6 @@
             source = subjsource
         return source
     
-    @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]
-    
     def locate_etype_source(self, etype):
         for source in self.sources:
             if source.support_entity(etype, 1):
@@ -993,7 +1003,7 @@
                                     entity)
         source.update_entity(session, entity)
         if not only_inline_rels:
-            if need_fti_update:
+            if need_fti_update and self.do_fti:
                 # reindex the entity only if this query is updating at least
                 # one indexable attribute
                 FTIndexEntityOp(session, entity=entity)
@@ -1094,6 +1104,26 @@
                 pass
         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/rqlannotation.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/rqlannotation.py	Wed Apr 15 17:36:09 2009 +0200
@@ -20,7 +20,7 @@
     #if server.DEBUG:
     #    print '-------- sql annotate', repr(rqlst)
     getrschema = annotator.schema.rschema
-    has_text_query = need_intersect = False
+    has_text_query = False
     need_distinct = rqlst.distinct
     for rel in rqlst.iget_nodes(Relation):
         if rel.neged(strict=True):
@@ -29,13 +29,6 @@
             else:
                 rschema = getrschema(rel.r_type)
                 if not rschema.is_final():
-                    # if one of the relation's variable is ambiguous, an intersection
-                    # will be necessary
-                    for vref in rel.get_nodes(VariableRef):
-                        var = vref.variable
-                        if not var.stinfo['selected'] and len(var.stinfo['possibletypes']) > 1:
-                            need_intersect = True
-                            break
                     if rschema.inlined:
                         try:
                             var = rel.children[1].children[0].variable
@@ -147,23 +140,23 @@
             except CantSelectPrincipal:
                 stinfo['invariant'] = False
     rqlst.need_distinct = need_distinct
-    rqlst.need_intersect = need_intersect
     return has_text_query
 
 
 
 class CantSelectPrincipal(Exception): pass
 
-def _select_principal(sqlscope, relations):
+def _select_principal(sqlscope, relations, _sort=lambda x:x):
     """given a list of rqlst relations, select one which will be used to
     represent an invariant variable (e.g. using on extremity of the relation
     instead of the variable's type table
     """
+    # _sort argument is there for test
     diffscope_rels = {}
     has_same_scope_rel = False
     ored_rels = set()
     diffscope_rels = set()
-    for rel in relations:
+    for rel in _sort(relations):
         # note: only eid and has_text among all final relations may be there
         if rel.r_type in ('eid', 'identity'):
             has_same_scope_rel = rel.sqlscope is sqlscope
@@ -183,18 +176,17 @@
                 if isinstance(common_parent(rel1, rel2), Or):
                     ored_rels.discard(rel1)
                     ored_rels.discard(rel2)
-    for rel in ored_rels:
+    for rel in _sort(ored_rels):
         if rel.sqlscope is sqlscope:
             return rel
         diffscope_rels.add(rel)
     # if DISTINCT query, can use variable from a different scope as principal
     # since introduced duplicates will be removed
     if sqlscope.stmt.distinct and diffscope_rels:
-        return iter(diffscope_rels).next()
+        return iter(_sort(diffscope_rels)).next()
     # XXX  could use a relation for a different scope if it can't generate
     # duplicates, so we would have to check cardinality
-    raise CantSelectPrincipal()
-    
+    raise CantSelectPrincipal()    
 
 def _select_main_var(relations):
     """given a list of rqlst relations, select one which will be used as main
@@ -207,12 +199,12 @@
     return principal
 
 
-def set_qdata(union, noinvariant):
+def set_qdata(getrschema, union, noinvariant):
     """recursive function to set querier data on variables in the syntax tree
     """
     for select in union.children:
         for subquery in select.with_:
-            set_qdata(subquery.query, noinvariant)
+            set_qdata(getrschema, subquery.query, noinvariant)
         for var in select.defined_vars.itervalues():
             if var.stinfo['invariant']:
                 if var in noinvariant and not var.stinfo['principal'].r_type == 'has_text':
@@ -221,6 +213,23 @@
                     var._q_invariant = True
             else:
                 var._q_invariant = False
+        for rel in select.iget_nodes(Relation):
+            if rel.neged(strict=True) and not rel.is_types_restriction():
+                rschema = getrschema(rel.r_type)
+                if not rschema.is_final():
+                    # if one of the relation's variable is ambiguous but not
+                    # invariant, an intersection will be necessary
+                    for vref in rel.get_nodes(VariableRef):
+                        var = vref.variable
+                        if (not var._q_invariant and var.valuable_references() == 1
+                            and len(var.stinfo['possibletypes']) > 1):
+                            select.need_intersect = True
+                            break
+                    else:
+                        continue
+                    break
+        else:
+            select.need_intersect = False
 
 
 class SQLGenAnnotator(object):
@@ -251,7 +260,6 @@
                 has_text_query = True
         return has_text_query
 
-
     def is_ambiguous(self, var):
         # ignore has_text relation
         if len([rel for rel in var.stinfo['relations']
@@ -328,7 +336,7 @@
                 except KeyError:
                     # no relation to deambiguify
                     continue
-
+        
     def _debug_print(self):
         print 'varsols', dict((x, sorted(str(v) for v in values))
                                for x, values in self.varsols.iteritems())
@@ -366,8 +374,9 @@
             otheretypes = (other.uidtype,)
             deambiguifier = None
         if otheretypes is not None:
-            # unless types for variable are already non-ambigous, check
-            # if this relation has some type ambiguity
+            # to restrict, we must check that for all type in othertypes,
+            # possible types on the other end of the relation are matching
+            # variable's possible types
             rschema = self.rschema(rel.r_type)
             if onlhs:
                 rtypefunc = rschema.subjects
@@ -377,7 +386,8 @@
                 reltypes = frozenset(rtypefunc(otheretype))
                 if var.stinfo['possibletypes'] != reltypes:
                     break
-                self.restrict(var, reltypes)
+            else:
+                self.restrict(var, var.stinfo['possibletypes'])
                 self.deambification_map[var] = deambiguifier
                 return True
         return False
--- a/server/schemahooks.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/schemahooks.py	Wed Apr 15 17:36:09 2009 +0200
@@ -6,7 +6,7 @@
 checking for schema consistency is done in hooks.py
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -17,6 +17,7 @@
 
 from cubicweb import ValidationError, RepositoryError
 from cubicweb.server import schemaserial as ss
+from cubicweb.server.sqlutils import SQL_PREFIX
 from cubicweb.server.pool import Operation, SingleLastOperation, PreCommitOperation
 from cubicweb.server.hookhelper import (entity_attr, entity_name,
                                      check_internal_entity)
@@ -44,19 +45,22 @@
 
 def add_inline_relation_column(session, etype, rtype):
     """add necessary column and index for an inlined relation"""
+    table = SQL_PREFIX + etype
+    column = SQL_PREFIX + rtype
     try:
         session.system_sql(str('ALTER TABLE %s ADD COLUMN %s integer'
-                               % (etype, rtype)))
-        session.info('added column %s to table %s', rtype, etype)
+                               % (table, column)))
+        session.info('added column %s to table %s', column, table)
     except:
         # silent exception here, if this error has not been raised because the 
         # column already exists, index creation will fail anyway
-        session.exception('error while adding column %s to table %s', etype, rtype)
+        session.exception('error while adding column %s to table %s',
+                          table, column)
     # create index before alter table which may expectingly fail during test
     # (sqlite) while index creation should never fail (test for index existence
     # is done by the dbhelper)
-    session.pool.source('system').create_index(session, etype, rtype)
-    session.info('added index on %s(%s)', etype, rtype)
+    session.pool.source('system').create_index(session, table, column)
+    session.info('added index on %s(%s)', table, column)
     session.add_query_data('createdattrs', '%s.%s' % (etype, rtype))
 
 
@@ -148,7 +152,7 @@
     name = check_internal_entity(session, eid, CORE_ETYPES)
     # delete every entities of this type
     session.unsafe_execute('DELETE %s X' % name)
-    DropTableOp(session, table=name)
+    DropTableOp(session, table=SQL_PREFIX + name)
     DeleteEETypeOp(session, name)
 
 def after_del_eetype(session, eid):
@@ -223,7 +227,8 @@
                        'R eid %%(x)s, X from_entity E, E name %%(name)s'
                        % rdeftype, {'x': rteid, 'name': str(subjschema)})
         if rset[0][0] == 0 and not subjschema.eid in pendings:
-            DropColumnOp(session, table=subjschema.type, column=rschema.type)
+            DropColumnOp(session, table=SQL_PREFIX + subjschema.type,
+                         column=SQL_PREFIX + rschema.type)
     elif lastrel:
         DropTableOp(session, table='%s_relation' % rschema.type)
     # if this is the last instance, drop associated relation type
@@ -270,7 +275,8 @@
     eschema = schema.add_entity_type(etype)
     eschema.set_default_groups()
     # generate table sql and rql to add metadata
-    tablesql = eschema2sql(session.pool.source('system').dbhelper, eschema)
+    tablesql = eschema2sql(session.pool.source('system').dbhelper, eschema,
+                           prefix=SQL_PREFIX)
     relrqls = []
     for rtype in ('is', 'is_instance_of', 'creation_date', 'modification_date',
                   'created_by', 'owned_by'):
@@ -393,22 +399,24 @@
             extra_unique_index = False
         # added some str() wrapping query since some backend (eg psycopg) don't
         # allow unicode queries
+        table = SQL_PREFIX + subj
+        column = SQL_PREFIX + rtype
         try:
             session.system_sql(str('ALTER TABLE %s ADD COLUMN %s %s'
-                                   % (subj, rtype, attrtype)))
-            self.info('added column %s to table %s', rtype, subj)
+                                   % (table, column, attrtype)))
+            self.info('added column %s to table %s', table, column)
         except Exception, ex:
             # the column probably already exists. this occurs when
             # the entity's type has just been added or if the column
             # has not been previously dropped
-            self.error('error while altering table %s: %s', subj, ex)
+            self.error('error while altering table %s: %s', table, ex)
         if extra_unique_index or entity.indexed:
             try:
-                sysource.create_index(session, subj, rtype,
+                sysource.create_index(session, table, column,
                                       unique=extra_unique_index)
             except Exception, ex:
                 self.error('error while creating index for %s.%s: %s',
-                           subj, rtype, ex)
+                           table, column, ex)
         # postgres doesn't implement, so do it in two times
         # ALTER TABLE %s ADD COLUMN %s %s SET DEFAULT %s
         if default is not None:
@@ -416,12 +424,12 @@
                 default = default.encode(sysource.encoding)
             try:
                 session.system_sql('ALTER TABLE %s ALTER COLUMN %s SET DEFAULT '
-                                   '%%(default)s' % (subj, rtype),
+                                   '%%(default)s' % (table, column),
                                    {'default': default})
             except Exception, ex:
                 # not supported by sqlite for instance
-                self.error('error while altering table %s: %s', subj, ex)
-            session.system_sql('UPDATE %s SET %s=%%(default)s' % (subj, rtype),
+                self.error('error while altering table %s: %s', table, ex)
+            session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column),
                                {'default': default})
         AddErdefOp(session, rdef)
 
@@ -534,7 +542,8 @@
     def precommit_event(self):
         # we need sql to operate physical changes on the system database
         sqlexec = self.session.system_sql
-        sqlexec('ALTER TABLE %s RENAME TO %s' % (self.oldname, self.newname))
+        sqlexec('ALTER TABLE %s%s RENAME TO %s%s' % (SQL_PREFIX, self.oldname,
+                                                     SQL_PREFIX, self.newname))
         self.info('renamed table %s to %s', self.oldname, self.newname)
         sqlexec('UPDATE entities SET type=%s WHERE type=%s',
                 (self.newname, self.oldname))
@@ -551,7 +560,9 @@
     def precommit_event(self):
         if 'indexed' in self.values:
             sysource = self.session.pool.source('system')
-            table, column = self.kobj[0], self.rschema.type
+            etype, rtype = self.kobj[0], self.rschema.type
+            table = SQL_PREFIX + etype
+            column = SQL_PREFIX + rtype
             if self.values['indexed']:
                 sysource.create_index(self.session, table, column)
             else:
@@ -561,6 +572,7 @@
         # structure should be clean, not need to remove entity's relations
         # at this point
         self.rschema._rproperties[self.kobj].update(self.values)
+
     
 def after_update_erdef(session, entity):
     desttype = entity.to_entity[0].name
@@ -593,6 +605,7 @@
         # inlined changed, make necessary physical changes!
         sqlexec = self.session.system_sql
         rtype = rschema.type
+        eidcolumn = SQL_PREFIX + 'eid'
         if not inlined:
             # need to create the relation if it has not been already done by another
             # event of the same transaction
@@ -604,12 +617,15 @@
                         sqlexec(sql)
                 session.add_query_data('createdtables', rschema.type)
             # copy existant data
+            column = SQL_PREFIX + rtype
             for etype in rschema.subjects():
-                sqlexec('INSERT INTO %s_relation SELECT eid, %s FROM %s WHERE NOT %s IS NULL'
-                        % (rtype, rtype, etype, rtype))
+                table = SQL_PREFIX + str(etype)
+                sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL'
+                        % (rtype, eidcolumn, column, table, column))
             # drop existant columns
             for etype in rschema.subjects():
-                DropColumnOp(session, table=str(etype), column=rtype)
+                DropColumnOp(session, table=SQL_PREFIX + str(etype),
+                             column=SQL_PREFIX + rtype)
         else:
             for etype in rschema.subjects():
                 try:
@@ -625,13 +641,15 @@
                 #        'FROM %(rtype)s_relation '
                 #        'WHERE %(etype)s.eid=%(rtype)s_relation.eid_from'
                 #        % locals())
-                cursor = sqlexec('SELECT eid_from, eid_to FROM %(etype)s, '
-                                 '%(rtype)s_relation WHERE %(etype)s.eid='
+                table = SQL_PREFIX + str(etype)
+                cursor = sqlexec('SELECT eid_from, eid_to FROM %(table)s, '
+                                 '%(rtype)s_relation WHERE %(table)s.%(eidcolumn)s='
                                  '%(rtype)s_relation.eid_from' % locals())
                 args = [{'val': eid_to, 'x': eid} for eid, eid_to in cursor.fetchall()]
                 if args:
-                    cursor.executemany('UPDATE %s SET %s=%%(val)s WHERE eid=%%(x)s'
-                                       % (etype, rtype), args)
+                    column = SQL_PREFIX + rtype
+                    cursor.executemany('UPDATE %s SET %s=%%(val)s WHERE %s=%%(x)s'
+                                       % (table, column, eidcolumn), args)
                 # drop existant table
                 DropTableOp(session, table='%s_relation' % rtype)
 
@@ -677,20 +695,22 @@
         self.cstr = rtype.constraint_by_type(subjtype, objtype, cstrtype)
         self._cstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
         self._cstr.eid = self.entity.eid
+        table = SQL_PREFIX + str(subjtype)
+        column = SQL_PREFIX + str(rtype)
         # alter the physical schema on size constraint changes
         if self._cstr.type() == 'SizeConstraint' and (
             self.cstr is None or self.cstr.max != self._cstr.max):
             try:
                 session.system_sql('ALTER TABLE %s ALTER COLUMN %s TYPE VARCHAR(%s)'
-                                   % (subjtype, rtype, self._cstr.max))
+                                   % (table, column, self._cstr.max))
                 self.info('altered column %s of table %s: now VARCHAR(%s)',
-                          rtype, subjtype, self._cstr.max)
+                          column, table, self._cstr.max)
             except Exception, ex:
                 # not supported by sqlite for instance
-                self.error('error while altering table %s: %s', subjtype, ex)
+                self.error('error while altering table %s: %s', table, ex)
         elif cstrtype == 'UniqueConstraint':
             session.pool.source('system').create_index(
-                self.session, str(subjtype), str(rtype), unique=True)
+                self.session, table, column, unique=True)
         
     def commit_event(self):
         if self.cancelled:
@@ -700,32 +720,35 @@
             self.constraints.remove(self.cstr)
         self.constraints.append(self._cstr)
 
+
 def after_add_econstraint(session, entity):
     ConstraintOp(session, entity=entity)
 
 def after_update_econstraint(session, entity):
     ConstraintOp(session, entity=entity)
 
+
 class DelConstraintOp(ConstraintOp):
     """actually remove a constraint of a relation definition"""
     
     def precommit_event(self):
         self.prepare_constraints(self.rtype, self.subjtype, self.objtype)
         cstrtype = self.cstr.type()
+        table = SQL_PREFIX + str(self.subjtype)
+        column = SQL_PREFIX + str(self.rtype)
         # alter the physical schema on size/unique constraint changes
         if cstrtype == 'SizeConstraint':
             try:
                 self.session.system_sql('ALTER TABLE %s ALTER COLUMN %s TYPE TEXT'
-                                        % (self.subjtype, self.rtype))
+                                        % (table, column))
                 self.info('altered column %s of table %s: now TEXT', 
-                          self.rtype,  self.subjtype)
+                          column, table)
             except Exception, ex:
                 # not supported by sqlite for instance
-                self.error('error while altering table %s: %s', 
-                           self.subjtype, ex)
+                self.error('error while altering table %s: %s', table, ex)
         elif cstrtype == 'UniqueConstraint':
             self.session.pool.source('system').drop_index(
-                self.session, str(self.subjtype), str(self.rtype), unique=True)
+                self.session, table, column, unique=True)
                 
     def commit_event(self):
         self.constraints.remove(self.cstr)
--- a/server/securityhooks.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/securityhooks.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 the user connected to a session
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -54,6 +54,7 @@
             entity.check_perm('update')
             check_entity_attributes(session, entity)
         except Unauthorized:
+            entity.clear_local_perm_cache('update')
             CheckEntityPermissionOp(session, entity=entity, action='update')
         
 def before_del_entity(session, eid):
--- a/server/serverconfig.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/serverconfig.py	Wed Apr 15 17:36:09 2009 +0200
@@ -73,6 +73,15 @@
           'help': 'size of the parsed rql cache size.',
           'group': 'main', 'inputlevel': 1,
           }),
+        ('delay-full-text-indexation',
+         {'type' : 'yn', 'default': False,
+          'help': 'When full text indexation of entity has a too important cost'
+          ' to be done when entity are added/modified by users, activate this '
+          'option and setup a job using cubicweb-ctl db-rebuild-fti on your '
+          'system (using cron for instance).',
+          'group': 'main', 'inputlevel': 1,
+          }),
+        
         # email configuration
         ('default-recipients-mode',
          {'type' : 'choice',
--- a/server/serverctl.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/serverctl.py	Wed Apr 15 17:36:09 2009 +0200
@@ -475,7 +475,8 @@
         raise ExecutionError('Error while retrieving the dump')
     rmcmd = 'ssh -t %s "rm -f /tmp/%s.dump"' % (host, appid)
     print rmcmd
-    if os.system(rmcmd) and not confirm('an error occured while deleting remote dump. Continue anyway?'):
+    if os.system(rmcmd) and not confirm(
+        'an error occured while deleting remote dump. Continue anyway?'):
         raise ExecutionError('Error while deleting remote dump')
 
 def _local_dump(appid, output):
--- a/server/session.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/session.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """Repository users' and internal' sessions.
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -21,6 +21,18 @@
 from cubicweb.common.utils import make_uid
 from cubicweb.server.rqlrewrite import RQLRewriter
 
+_ETYPE_PYOBJ_MAP = { bool: 'Boolean',
+                     int: 'Int',
+                     long: 'Int',
+                     float: 'Float',
+                     Decimal: 'Decimal',
+                     unicode: 'String',
+                     NoneType: None,
+                     Binary: 'Bytes',
+                     DateTimeType: 'Datetime',
+                     DateTimeDeltaType: 'Interval',
+                     }
+
 def etype_from_pyobj(value):
     """guess yams type from python value"""
     # note:
@@ -28,17 +40,7 @@
     # * use type(value) and not value.__class__ since mx instances have no
     #   __class__ attribute
     # * XXX Date, Time
-    return {bool: 'Boolean',
-            int: 'Int',
-            long: 'Int',
-            float: 'Float',
-            Decimal: 'Decimal',
-            unicode: 'String',
-            NoneType: None,
-            Binary: 'Bytes',
-            DateTimeType: 'Datetime',
-            DateTimeDeltaType: 'Interval',
-            }[type(value)]
+    return _ETYPE_PYOBJ_MAP[type(value)]
 
 def is_final(rqlst, variable, args):
     # try to find if this is a final var or not
@@ -58,35 +60,8 @@
         description.append(term.get_type(solution, args))
     return description
 
-#XXX rql <= 0.18.3 bw compat
 from rql import stmts
-if not hasattr(stmts.Union, 'get_variable_variables'):
-    def _union_get_variable_variables(self):
-        """return the set of variable names which take different type according to
-        the solution
-        """
-        change = set()
-        values = {}
-        for select in self.children:
-            change.update(select.get_variable_variables(values))
-        return change
-    stmts.Union.get_variable_variables = _union_get_variable_variables
-                        
-    def _select_get_variable_variables(self, _values=None):
-        """return the set of variable names which take different type according to
-        the solution
-        """
-        change = set()
-        if _values is None:
-            _values = {}
-        for solution in self.solutions:
-            for vname, etype in solution.iteritems():
-                if not vname in _values:
-                    _values[vname] = etype
-                elif _values[vname] != etype:
-                    change.add(vname)
-        return change
-    stmts.Select.get_variable_variables = _select_get_variable_variables
+assert hasattr(stmts.Union, 'get_variable_variables'), "You need RQL > 0.18.3"
 
 class Session(RequestSessionMixIn):
     """tie session id, user, connections pool and other session data all
@@ -469,10 +444,14 @@
                     # None value inserted by an outer join, no type
                     row_descr[index] = None
                     continue
-                if isfinal:
-                    row_descr[index] = etype_from_pyobj(value)
-                else:
-                    row_descr[index] = etype_from_eid(value)[0]
+                try:
+                    if isfinal:
+                        row_descr[index] = etype_from_pyobj(value)
+                    else:
+                        row_descr[index] = etype_from_eid(value)[0]
+                except UnknownEid:
+                    self.critical('wrong eid in repository, should check database')
+                    row_descr[index] = row[index] = None
             description.append(tuple(row_descr))
         return description
 
--- a/server/sources/__init__.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/sources/__init__.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,14 +1,36 @@
 """cubicweb server sources support
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
 
 from logging import getLogger
 
+from mx.DateTime import now, DateTimeDelta
+
 from cubicweb import set_log_methods
+from cubicweb.server.sqlutils import SQL_PREFIX
+
+
+class TimedCache(dict):
+    def __init__(self, ttlm, ttls=0):
+        # time to live in minutes
+        self.ttl = DateTimeDelta(0, 0, ttlm, ttls)
+        
+    def __setitem__(self, key, value):
+        dict.__setitem__(self, key, (now(), value))
+        
+    def __getitem__(self, key):
+        return dict.__getitem__(self, key)[1]
+    
+    def clear_expired(self):
+        now_ = now()
+        ttl = self.ttl
+        for key, (timestamp, value) in self.items():
+            if now_ - timestamp > ttl:
+                del self[key]
 
 
 class AbstractSource(object):
@@ -58,7 +80,7 @@
         pass
     
     def __repr__(self):
-        return '<%s source>' % self.uri
+        return '<%s source @%#x>' % (self.uri, id(self))
 
     def __cmp__(self, other):
         """simple comparison function to get predictable source order, with the
@@ -117,8 +139,8 @@
     def eid2extid(self, eid, session=None):
         return self.repo.eid2extid(self, eid, session)
 
-    def extid2eid(self, value, etype, session=None, insert=True):
-        return self.repo.extid2eid(self, value, etype, session, insert)
+    def extid2eid(self, value, etype, session=None, **kwargs):
+        return self.repo.extid2eid(self, value, etype, session, **kwargs)
 
     PUBLIC_KEYS = ('adapter', 'uri')
     def remove_sensitive_information(self, sourcedef):
@@ -139,15 +161,18 @@
         if not myeids:
             return
         # delete relations referencing one of those eids
+        eidcolum = SQL_PREFIX + 'eid'
         for rschema in self.schema.relations():
             if rschema.is_final() or rschema.type == 'identity':
                 continue
             if rschema.inlined:
+                column = SQL_PREFIX + rschema.type
                 for subjtype in rschema.subjects():
+                    table = SQL_PREFIX + str(subjtype)
                     for objtype in rschema.objects(subjtype):
                         if self.support_entity(objtype):
-                            sql = 'UPDATE %s SET %s = NULL WHERE eid IN (%s);' % (
-                                subjtype, rschema.type, myeids)
+                            sql = 'UPDATE %s SET %s=NULL WHERE %s IN (%s);' % (
+                                table, column, eidcolum, myeids)
                             session.system_sql(sql)
                             break
                 continue
--- a/server/sources/extlite.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/sources/extlite.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """provide an abstract class for external sources using a sqlite database helper
 
 :organization: Logilab
-:copyright: 2007-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -12,7 +12,7 @@
 from os.path import join, exists
 
 from cubicweb import server
-from cubicweb.server.sqlutils import sqlexec, SQLAdapterMixIn
+from cubicweb.server.sqlutils import SQL_PREFIX, sqlexec, SQLAdapterMixIn
 from cubicweb.server.sources import AbstractSource, native
 from cubicweb.server.sources.rql2sql import SQLGenerator
 
@@ -122,7 +122,7 @@
         for etype in self.support_entities:
             eschema = schema.eschema(etype)
             createsqls = eschema2sql(self.sqladapter.dbhelper, eschema,
-                                     skip_relations=('data',))
+                                     skip_relations=('data',), prefix=SQL_PREFIX)
             sqlexec(createsqls, cu, withpb=False)
         for rtype in self.support_relations:
             rschema = schema.rschema(rtype)
@@ -141,7 +141,7 @@
         
     def set_schema(self, schema):
         super(SQLiteAbstractSource, self).set_schema(schema)
-        if self._need_sql_create and self._is_schema_complete():
+        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)
                 
@@ -196,7 +196,7 @@
         """
         cu = session.pool[self.uri]
         attrs = self.sqladapter.preprocess_entity(entity)
-        sql = self.sqladapter.sqlgen.insert(str(entity.e_schema), attrs)
+        sql = self.sqladapter.sqlgen.insert(SQL_PREFIX + str(entity.e_schema), attrs)
         cu.execute(sql, attrs)
         
     def add_entity(self, session, entity):
@@ -212,7 +212,7 @@
         """
         cu = session.pool[self.uri]
         attrs = self.sqladapter.preprocess_entity(entity)
-        sql = self.sqladapter.sqlgen.update(str(entity.e_schema), attrs, ['eid'])
+        sql = self.sqladapter.sqlgen.update(SQL_PREFIX + str(entity.e_schema), attrs, ['eid'])
         cu.execute(sql, attrs)
         
     def update_entity(self, session, entity):
@@ -227,8 +227,8 @@
         entity is deleted.
         """
         sqlcursor = session.pool[self.uri]        
-        attrs = {'eid': eid}
-        sql = self.sqladapter.sqlgen.delete(etype, attrs)
+        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):
@@ -237,8 +237,9 @@
         if rschema.inlined:
             if subject in session.query_data('pendingeids', ()):
                 return
-            etype = session.describe(subject)[0]
-            sql = 'UPDATE %s SET %s=NULL WHERE eid=%%(eid)s' % (etype, rtype)
+            table = SQL_PREFIX + session.describe(subject)[0]
+            column = SQL_PREFIX + rtype
+            sql = 'UPDATE %s SET %s=NULL WHERE %seid=%%(eid)s' % (table, column, SQL_PREFIX)
             attrs = {'eid' : subject}
         else:
             attrs = {'eid_from': subject, 'eid_to': object}
--- a/server/sources/ldapuser.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/sources/ldapuser.py	Wed Apr 15 17:36:09 2009 +0200
@@ -3,7 +3,7 @@
 this source is for now limited to a read-only EUser source
 
 :organization: Logilab
-:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 
 
@@ -20,8 +20,6 @@
 FOR A PARTICULAR PURPOSE.
 """
 
-from mx.DateTime import now, DateTimeDelta
-
 from logilab.common.textutils import get_csv
 from rql.nodes import Relation, VariableRef, Constant, Function
 
@@ -30,9 +28,10 @@
 from ldap.filter import filter_format, escape_filter_chars
 from ldapurl import LDAPUrl
 
-from cubicweb.common import AuthenticationError, UnknownEid, RepositoryError
-from cubicweb.server.sources import AbstractSource, TrFunc, GlobTrFunc, ConnectionWrapper
+from cubicweb import AuthenticationError, UnknownEid, RepositoryError
 from cubicweb.server.utils import cartesian_product
+from cubicweb.server.sources import (AbstractSource, TrFunc, GlobTrFunc,
+                                     ConnectionWrapper, TimedCache)
 
 # search scopes
 BASE = ldap.SCOPE_BASE
@@ -49,24 +48,6 @@
     1: (636, 'ldaps'),
     2: (0,   'ldapi'),
     }
-
-class TimedCache(dict):
-    def __init__(self, ttlm, ttls=0):
-        # time to live in minutes
-        self.ttl = DateTimeDelta(0, 0, ttlm, ttls)
-        
-    def __setitem__(self, key, value):
-        dict.__setitem__(self, key, (now(), value))
-        
-    def __getitem__(self, key):
-        return dict.__getitem__(self, key)[1]
-    
-    def clear_expired(self):
-        now_ = now()
-        ttl = self.ttl
-        for key, (timestamp, value) in self.items():
-            if now_ - timestamp > ttl:
-                del self[key]
                 
 class LDAPUserSource(AbstractSource):
     """LDAP read-only EUser source"""
@@ -176,6 +157,10 @@
         external repository
         """
         self.info('synchronizing ldap source %s', self.uri)
+        try:
+            ldap_emailattr = self.user_rev_attrs['email']
+        except KeyError:
+            return # no email in ldap, we're done
         session = self.repo.internal_session()
         try:
             cursor = session.system_sql("SELECT eid, extid FROM entities WHERE "
@@ -184,7 +169,7 @@
                 # if no result found, _search automatically delete entity information
                 res = self._search(session, extid, BASE)
                 if res: 
-                    ldapemailaddr = res[0].get(self.user_rev_attrs['email'])
+                    ldapemailaddr = res[0].get(ldap_emailattr)
                     if ldapemailaddr:
                         rset = session.execute('EmailAddress X,A WHERE '
                                                'U use_email X, U eid %(u)s',
@@ -628,7 +613,10 @@
             filter = '(%s%s)' % (self._ldap_attrs[relation.r_type],
                                  rhs.accept(self))
         except KeyError:
-            assert relation.r_type == 'password' # 2.38 migration
+            # unsupported attribute
+            self.source.warning('%s source can\'t handle relation %s, no '
+                                'results will be returned from this source',
+                                self.source.uri, relation)
             raise UnknownEid # trick to return no result
         return filter
 
--- a/server/sources/native.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/sources/native.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """Adapters for native cubicweb sources.
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -18,7 +18,7 @@
 
 from cubicweb import UnknownEid, AuthenticationError, Binary, server
 from cubicweb.server.utils import crypt_password
-from cubicweb.server.sqlutils import SQLAdapterMixIn
+from cubicweb.server.sqlutils import SQL_PREFIX, SQLAdapterMixIn
 from cubicweb.server.rqlannotation import set_qdata
 from cubicweb.server.sources import AbstractSource
 from cubicweb.server.sources.rql2sql import SQLGenerator
@@ -188,7 +188,7 @@
         rqlst.restricted_vars = ()
         rqlst.children[0].solutions = self._sols
         self.repo.querier.sqlgen_annotate(rqlst)
-        set_qdata(rqlst, ())
+        set_qdata(self.schema.rschema, rqlst, ())
         return rqlst
     
     def set_schema(self, schema):
@@ -367,19 +367,19 @@
     def add_entity(self, session, entity):
         """add a new entity to the source"""
         attrs = self.preprocess_entity(entity)
-        sql = self.sqlgen.insert(str(entity.e_schema), attrs)
+        sql = self.sqlgen.insert(SQL_PREFIX + str(entity.e_schema), attrs)
         self.doexec(session.pool[self.uri], sql, attrs)
         
     def update_entity(self, session, entity):
         """replace an entity in the source"""
         attrs = self.preprocess_entity(entity)
-        sql = self.sqlgen.update(str(entity.e_schema), attrs, ['eid'])
+        sql = self.sqlgen.update(SQL_PREFIX + str(entity.e_schema), attrs, [SQL_PREFIX + 'eid'])
         self.doexec(session.pool[self.uri], sql, attrs)
 
     def delete_entity(self, session, etype, eid):
         """delete an entity from the source"""
-        attrs = {'eid': eid}
-        sql = self.sqlgen.delete(etype, attrs)
+        attrs = {SQL_PREFIX + 'eid': eid}
+        sql = self.sqlgen.delete(SQL_PREFIX + etype, attrs)
         self.doexec(session.pool[self.uri], sql, attrs)
 
     def add_relation(self, session, subject, rtype, object):
@@ -392,8 +392,10 @@
         """delete a relation from the source"""
         rschema = self.schema.rschema(rtype)
         if rschema.inlined:
-            etype = session.describe(subject)[0]
-            sql = 'UPDATE %s SET %s=NULL WHERE eid=%%(eid)s' % (etype, rtype)
+            table = SQL_PREFIX + session.describe(subject)[0]
+            column = SQL_PREFIX + rtype
+            sql = 'UPDATE %s SET %s=NULL WHERE %seid=%%(eid)s' % (table, column,
+                                                                  SQL_PREFIX)
             attrs = {'eid' : subject}
         else:
             attrs = {'eid_from': subject, 'eid_to': object}
@@ -451,6 +453,7 @@
         try:
             res = session.system_sql(sql).fetchone()
         except:
+            assert session.pool, 'session has no pool set'
             raise UnknownEid(eid)
         if res is None:
             raise UnknownEid(eid)
--- a/server/sources/pyrorql.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/sources/pyrorql.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """Source to query another RQL repository using pyro
 
 :organization: Logilab
-:copyright: 2007-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -21,7 +21,7 @@
 from cubicweb import dbapi, server
 from cubicweb import BadConnectionId, UnknownEid, ConnectionError
 from cubicweb.cwconfig import register_persistent_options
-from cubicweb.server.sources import AbstractSource, ConnectionWrapper
+from cubicweb.server.sources import AbstractSource, ConnectionWrapper, TimedCache
 
 class ReplaceByInOperator:
     def __init__(self, eids):
@@ -129,6 +129,7 @@
                        'group': 'sources', 
                        }),)
         register_persistent_options(myoptions)
+        self._query_cache = TimedCache(30)
 
     def last_update_time(self):
         pkey = u'sources.%s.latest-update-time' % self.uri
@@ -153,13 +154,15 @@
         """method called by the repository once ready to handle request"""
         interval = int(self.config.get('synchronization-interval', 5*60))
         self.repo.looping_task(interval, self.synchronize) 
+        self.repo.looping_task(self._query_cache.ttl.seconds/10, self._query_cache.clear_expired) 
 
     def synchronize(self, mtime=None):
         """synchronize content known by this repository with content in the
         external repository
         """
         self.info('synchronizing pyro source %s', self.uri)
-        extrepo = self.get_connection()._repo
+        cnx = self.get_connection()
+        extrepo = cnx._repo
         etypes = self.support_entities.keys()
         if mtime is None:
             mtime = self.last_update_time()
@@ -170,11 +173,13 @@
         try:
             for etype, extid in modified:
                 try:
-                    eid = self.extid2eid(extid, etype, session)
-                    rset = session.eid_rset(eid, etype)
-                    entity = rset.get_entity(0, 0)
-                    entity.complete(entity.e_schema.indexable_attributes())
-                    repo.index_entity(session, entity)
+                    exturi = cnx.describe(extid)[1]
+                    if exturi == 'system' or not exturi in repo.sources_by_uri:
+                        eid = self.extid2eid(extid, etype, session)
+                        rset = session.eid_rset(eid, etype)
+                        entity = rset.get_entity(0, 0)
+                        entity.complete(entity.e_schema.indexable_attributes())
+                        repo.index_entity(session, entity)
                 except:
                     self.exception('while updating %s with external id %s of source %s',
                                    etype, extid, self.uri)
@@ -237,9 +242,18 @@
         # try to reconnect
         return self.get_connection()
         
-    
     def syntax_tree_search(self, session, union, args=None, cachekey=None,
                            varmap=None):
+        #assert not varmap, (varmap, union)
+        rqlkey = union.as_string(kwargs=args)
+        try:
+            results = self._query_cache[rqlkey]
+        except KeyError:
+            results = self._syntax_tree_search(session, union, args)
+            self._query_cache[rqlkey] = results
+        return results
+    
+    def _syntax_tree_search(self, session, union, args):
         """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
@@ -277,18 +291,28 @@
         descr = rset.description
         if rset:
             needtranslation = []
+            rows = rset.rows
             for i, etype in enumerate(descr[0]):
                 if (etype is None or not self.schema.eschema(etype).is_final() or
                     getattr(union.locate_subquery(i, etype, args).selection[i], 'uidtype', None)):
                     needtranslation.append(i)
             if needtranslation:
-                for rowindex, row in enumerate(rset):
+                cnx = session.pool.connection(self.uri)
+                for rowindex in xrange(rset.rowcount - 1, -1, -1):
+                    row = rows[rowindex]
                     for colindex in needtranslation:
                         if row[colindex] is not None: # optional variable
                             etype = descr[rowindex][colindex]
-                            eid = self.extid2eid(row[colindex], etype, session)
-                            row[colindex] = eid
-            results = rset.rows
+                            exttype, exturi, extid = cnx.describe(row[colindex])
+                            if exturi == 'system' or not exturi in self.repo.sources_by_uri:
+                                eid = self.extid2eid(row[colindex], etype, session)
+                                row[colindex] = eid
+                            else:
+                                # skip this row
+                                del rows[rowindex]
+                                del descr[rowindex]
+                                break
+            results = rows
         else:
             results = []
         if server.DEBUG:
--- a/server/sources/rql2sql.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/sources/rql2sql.py	Wed Apr 15 17:36:09 2009 +0200
@@ -25,7 +25,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -38,6 +38,7 @@
                        Variable, ColumnAlias, Relation, SubQuery, Exists)
 
 from cubicweb import server
+from cubicweb.server.sqlutils import SQL_PREFIX
 from cubicweb.server.utils import cleanup_solutions
 
 def _new_var(select, varname): 
@@ -488,7 +489,8 @@
                 sql.insert(1, 'FROM (SELECT 1) AS _T')
             sqls.append('\n'.join(sql))
         if select.need_intersect:
-            if distinct:
+            # XXX use getattr for lgc bw compat, remove once 0.37.3 is out
+            if distinct or not getattr(self.dbms_helper, 'intersect_all_support', True):
                 return '\nINTERSECT\n'.join(sqls)
             else:
                 return '\nINTERSECT ALL\n'.join(sqls)
@@ -764,7 +766,7 @@
             if '%s.%s' % (lhs.name, attr) in self._varmap:
                 lhssql = self._varmap['%s.%s' % (lhs.name, attr)]
             else:
-                lhssql = '%s.%s' % (self._var_table(lhs.variable), attr)
+                lhssql = '%s.%s%s' % (self._var_table(lhs.variable), SQL_PREFIX, attr)
             if not rhsvar is None:
                 t2 = self._var_table(rhsvar)
                 if t2 is None:
@@ -801,11 +803,12 @@
             else:
                 join += ')'
         if not rhsconst:
-            rhstable = self._var_table(rhsvar)
+            rhstable = rhsvar._q_sqltable
             if rhstable:
                 assert rhstable is not None, rhsvar
                 join += ' %s OUTER JOIN %s ON (%s.%s=%s)' % (
-                    outertype, self._state.tables[rhstable][1], rid, restrattr, rhssql)
+                    outertype, self._state.tables[rhstable][1], rid, restrattr,
+                    rhssql)
                 toreplace.append(rhstable)
         self.replace_tables_by_outer_join(join, maintable, *toreplace)
         return ''
@@ -845,7 +848,10 @@
             try:
                 lhssql = self._varmap['%s.%s' % (lhs.name, relation.r_type)]
             except KeyError:
-                lhssql = '%s.%s' % (table, relation.r_type)
+                if relation.r_type == 'eid':
+                    lhssql = lhs.variable._q_sql
+                else:
+                    lhssql = '%s.%s%s' % (table, SQL_PREFIX, relation.r_type)
         try:
             if relation._q_needcast == 'TODAY':
                 sql = 'DATE(%s)%s' % (lhssql, rhssql)
@@ -966,7 +972,10 @@
         """get the sql name for a subquery column alias"""
         if colalias.name in self._varmap:
             sql = self._varmap[colalias.name]
-            self.add_table(sql.split('.', 1)[0])
+            table = sql.split('.', 1)[0]
+            colalias._q_sqltable = table
+            colalias._q_sql = sql
+            self.add_table(table)
             return sql
         return colalias._q_sql
     
@@ -989,7 +998,7 @@
             principal = variable.stinfo['principal']
             if principal is None:
                 vtablename = variable.name
-                self.add_table('entities AS %s' % variable.name, vtablename)
+                self.add_table('entities AS %s' % vtablename, vtablename)
                 sql = '%s.eid' % vtablename
                 if variable.stinfo['typerels']:
                     # add additional restriction on entities.type column
@@ -1054,8 +1063,8 @@
             if self.schema.eschema(etype).is_final():
                 raise BadRQLQuery(var.stmt.root)
             table = var.name
-            sql = '%s.eid' % table
-            self.add_table('%s AS %s' % (etype, table), table, scope=scope)
+            sql = '%s.%seid' % (table, SQL_PREFIX)
+            self.add_table('%s%s AS %s' % (SQL_PREFIX, etype, table), table, scope=scope)
         return sql, table
     
     def _inlined_var_sql(self, var, rtype):
@@ -1064,7 +1073,7 @@
             scope = var.sqlscope is var.stmt and 0 or -1
             self.add_table(sql.split('.', 1)[0], scope=scope)
         except KeyError:
-            sql = '%s.%s' % (self._var_table(var), rtype)
+            sql = '%s.%s%s' % (self._var_table(var), SQL_PREFIX, rtype)
             #self._state.done.add(var.name)
         return sql
         
@@ -1087,7 +1096,7 @@
             sql = self._varmap['%s.%s' % (linkedvar.name, rel.r_type)]
         except KeyError:
             linkedvar.accept(self)            
-            sql = '%s.%s' % (linkedvar._q_sqltable, rel.r_type)
+            sql = '%s.%s%s' % (linkedvar._q_sqltable, SQL_PREFIX, rel.r_type)
         return sql
 
     # tables handling #########################################################
--- a/server/sqlutils.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/sqlutils.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """SQL utilities functions and classes.
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -18,6 +18,7 @@
 from cubicweb.server import SQL_CONNECT_HOOKS
 from cubicweb.server.utils import crypt_password, cartesian_product
 
+SQL_PREFIX = 'cw_'
 
 def sqlexec(sqlstmts, cursor_or_execute, withpb=True, delimiter=';'):
     """execute sql statements ignoring DROP/ CREATE GROUP or USER statements
@@ -58,7 +59,7 @@
         indexer = get_indexer(driver)
         w(indexer.sql_grant_user(user))
         w('')
-    w(grant_schema(schema, user, set_owner, skip_entities=skip_entities))
+    w(grant_schema(schema, user, set_owner, skip_entities=skip_entities, prefix=SQL_PREFIX))
     return '\n'.join(output)
 
                   
@@ -79,7 +80,7 @@
         w(indexer.sql_init_fti())
         w('')
     dbhelper = get_adv_func_helper(driver)
-    w(schema2sql(dbhelper, schema, 
+    w(schema2sql(dbhelper, schema, prefix=SQL_PREFIX, 
                  skip_entities=skip_entities, skip_relations=skip_relations))
     if dbhelper.users_support and user:
         w('')
@@ -101,7 +102,7 @@
         indexer = get_indexer(driver)
         w(indexer.sql_drop_fti())
         w('')
-    w(dropschema2sql(schema,
+    w(dropschema2sql(schema, prefix=SQL_PREFIX,
                      skip_entities=skip_entities, skip_relations=skip_relations))
     return '\n'.join(output)
 
@@ -179,7 +180,7 @@
 
     def preprocess_entity(self, entity):
         """return a dictionary to use as extra argument to cursor.execute
-        to insert/update an entity
+        to insert/update an entity into a SQL database
         """
         attrs = {}
         eschema = entity.e_schema
@@ -198,7 +199,7 @@
                         value = crypt_password(value)
                 elif isinstance(value, Binary):
                     value = self.binary(value.getvalue())
-            attrs[str(attr)] = value
+            attrs[SQL_PREFIX+str(attr)] = value
         return attrs
 
 
--- a/server/test/data/schema/relations.rel	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/data/schema/relations.rel	Wed Apr 15 17:36:09 2009 +0200
@@ -43,3 +43,6 @@
 EPermission require_state State
 
 Note migrated_from Note
+
+Note attachment File
+Note attachment Image
--- a/server/test/data/sources_multi	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/data/sources_multi	Wed Apr 15 17:36:09 2009 +0200
@@ -15,6 +15,13 @@
 cubicweb-password = gingkow
 mapping-file = extern_mapping.py
 
+[extern-multi]
+adapter = pyrorql
+pyro-ns-id = extern-multi
+cubicweb-user = admin
+cubicweb-password = gingkow
+mapping-file = extern_mapping.py
+
 [admin]
 login = admin
 password = gingkow
--- a/server/test/unittest_hooks.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_hooks.py	Wed Apr 15 17:36:09 2009 +0200
@@ -7,8 +7,9 @@
 from logilab.common.testlib import TestCase, unittest_main
 from cubicweb.devtools.apptest import RepositoryBasedTC, get_versions
 
-from cubicweb.common import ConnectionError, RepositoryError, ValidationError
-from cubicweb.server.repository import *
+from cubicweb import ConnectionError, RepositoryError, ValidationError, AuthenticationError, BadConnectionId
+from cubicweb.server.sqlutils import SQL_PREFIX
+from cubicweb.server.repository import Repository
 
 orig_get_versions = Repository.get_versions
 
@@ -250,7 +251,12 @@
             repo.config._cubes = None
             repo.fill_schema()
         RepositoryBasedTC.setUp(self)
-            
+
+    def index_exists(self, etype, attr, unique=False):
+        dbhelper = self.session.pool.source('system').dbhelper    
+        sqlcursor = self.session.pool['system']
+        return dbhelper.index_exists(sqlcursor, SQL_PREFIX + etype, SQL_PREFIX + attr, unique=unique)
+        
     def test_base(self):
         schema = self.repo.schema
         dbhelper = self.session.pool.source('system').dbhelper    
@@ -281,11 +287,11 @@
                      'WHERE RT name "comments", E name "Societe2", C name "Comment"')
         self.failIf('nom' in schema['Societe2'].subject_relations())
         self.failIf('concerne2' in schema['Societe2'].subject_relations())
-        self.failIf(dbhelper.index_exists(sqlcursor, 'Societe2', 'nom'))
+        self.failIf(self.index_exists('Societe2', 'nom'))
         self.commit()
         self.failUnless('nom' in schema['Societe2'].subject_relations())
         self.failUnless('concerne2' in schema['Societe2'].subject_relations())
-        self.failUnless(dbhelper.index_exists(sqlcursor, 'Societe2', 'nom'))
+        self.failUnless(self.index_exists('Societe2', 'nom'))
         # now we should be able to insert and query Societe2
         s2eid = self.execute('INSERT Societe2 X: X nom "logilab"')[0][0]
         self.execute('Societe2 X WHERE X nom "logilab"')
@@ -304,11 +310,11 @@
         # schema should be cleaned on delete (after commit)
         self.execute('DELETE EEType X WHERE X name "Societe2"')
         self.execute('DELETE ERType X WHERE X name "concerne2"')
-        self.failUnless(dbhelper.index_exists(sqlcursor, 'Societe2', 'nom'))
+        self.failUnless(self.index_exists('Societe2', 'nom'))
         self.failUnless(schema.has_entity('Societe2'))
         self.failUnless(schema.has_relation('concerne2'))
         self.commit()
-        self.failIf(dbhelper.index_exists(sqlcursor, 'Societe2', 'nom'))
+        self.failIf(self.index_exists('Societe2', 'nom'))
         self.failIf(schema.has_entity('Societe2'))
         self.failIf(schema.has_entity('concerne2'))
 
@@ -385,7 +391,7 @@
                 self.failUnless(self.schema['inline2'].inlined)
                 self.commit()
                 self.failIf(self.schema['inline2'].inlined)
-                self.failIf(dbhelper.index_exists(sqlcursor, 'Personne', 'inline2'))
+                self.failIf(self.index_exists('Personne', 'inline2'))
                 rset = self.execute('Any X, Y WHERE X inline2 Y')
                 self.assertEquals(len(rset), 1)
                 self.assertEquals(rset.rows[0], [peid, aeid])
@@ -398,7 +404,7 @@
             self.failIf(self.schema['inline2'].inlined)
             self.commit()
             self.failUnless(self.schema['inline2'].inlined)
-            self.failUnless(dbhelper.index_exists(sqlcursor, 'Personne', 'inline2'))
+            self.failUnless(self.index_exists('Personne', 'inline2'))
             rset = self.execute('Any X, Y WHERE X inline2 Y')
             self.assertEquals(len(rset), 1)
             self.assertEquals(rset.rows[0], [peid, aeid])
@@ -409,39 +415,44 @@
         try:
             self.execute('SET X indexed TRUE WHERE X relation_type R, R name "sujet"')
             self.failIf(self.schema['sujet'].rproperty('Affaire', 'String', 'indexed'))
-            self.failIf(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet'))
+            self.failIf(self.index_exists('Affaire', 'sujet'))
             self.commit()
             self.failUnless(self.schema['sujet'].rproperty('Affaire', 'String', 'indexed'))
-            self.failUnless(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet'))
+            self.failUnless(self.index_exists('Affaire', 'sujet'))
         finally:
             self.execute('SET X indexed FALSE WHERE X relation_type R, R name "sujet"')
             self.failUnless(self.schema['sujet'].rproperty('Affaire', 'String', 'indexed'))
-            self.failUnless(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet'))
+            self.failUnless(self.index_exists('Affaire', 'sujet'))
             self.commit()
             self.failIf(self.schema['sujet'].rproperty('Affaire', 'String', 'indexed'))
-            self.failIf(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet'))
+            self.failIf(self.index_exists('Affaire', 'sujet'))
 
     def test_unique_change(self):
         dbhelper = self.session.pool.source('system').dbhelper    
         sqlcursor = self.session.pool['system']
         try:
-            self.execute('INSERT EConstraint X: X cstrtype CT, DEF constrained_by X '
-                         'WHERE CT name "UniqueConstraint", DEF relation_type RT, DEF from_entity E,'
-                         'RT name "sujet", E name "Affaire"')
-            self.failIf(self.schema['Affaire'].has_unique_values('sujet'))
-            self.failIf(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet', unique=True))
-            self.commit()
-            self.failUnless(self.schema['Affaire'].has_unique_values('sujet'))
-            self.failUnless(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet', unique=True))
+            try:
+                self.execute('INSERT EConstraint X: X cstrtype CT, DEF constrained_by X '
+                             'WHERE CT name "UniqueConstraint", DEF relation_type RT, DEF from_entity E,'
+                             'RT name "sujet", E name "Affaire"')
+                self.failIf(self.schema['Affaire'].has_unique_values('sujet'))
+                self.failIf(self.index_exists('Affaire', 'sujet', unique=True))
+                self.commit()
+                self.failUnless(self.schema['Affaire'].has_unique_values('sujet'))
+                self.failUnless(self.index_exists('Affaire', 'sujet', unique=True))
+            except:
+                import traceback
+                traceback.print_exc()
+                raise
         finally:
             self.execute('DELETE DEF constrained_by X WHERE X cstrtype CT, '
                          'CT name "UniqueConstraint", DEF relation_type RT, DEF from_entity E,'
                          'RT name "sujet", E name "Affaire"')
             self.failUnless(self.schema['Affaire'].has_unique_values('sujet'))
-            self.failUnless(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet', unique=True))
+            self.failUnless(self.index_exists('Affaire', 'sujet', unique=True))
             self.commit()
             self.failIf(self.schema['Affaire'].has_unique_values('sujet'))
-            self.failIf(dbhelper.index_exists(sqlcursor, 'Affaire', 'sujet', unique=True))
+            self.failIf(self.index_exists('Affaire', 'sujet', unique=True))
         
 
 class WorkflowHooksTC(RepositoryBasedTC):
--- a/server/test/unittest_ldapuser.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_ldapuser.py	Wed Apr 15 17:36:09 2009 +0200
@@ -33,8 +33,8 @@
 repo, cnx = init_test_database('sqlite', config=config)
 
 class LDAPUserSourceTC(RepositoryBasedTC):
-    repo = repo
-        
+    repo, cnx = repo, cnx
+    
     def patch_authenticate(self):
         self._orig_authenticate = LDAPUserSource.authenticate
         LDAPUserSource.authenticate = nopwd_authenticate
@@ -242,7 +242,10 @@
                                               ['users', 'cochon'],
                                               ['users', 'syt']])
         
-
+    def test_cd_restriction(self):
+        rset = self.execute('EUser X WHERE X creation_date > "2009-02-01"')
+        self.assertEquals(len(rset), 2) # admin/anon but no ldap user since it doesn't support creation_date
+        
     def test_union(self):
         afeids = self.execute('State X')
         ueids = self.execute('EUser X')
@@ -276,32 +279,39 @@
         rset = cu.execute('Any F WHERE X has_text "iaminguestsgrouponly", X firstname F')
         self.assertEquals(rset.rows, [[None]])
 
-    def test_nonregr_1(self):
+    def test_nonregr1(self):
         self.execute('Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E owned_by X, '
                      'X modification_date AA',
                      {'x': cnx.user(self.session).eid})
 
-    def test_nonregr_2(self):
+    def test_nonregr2(self):
         self.execute('Any X,L,AA WHERE E eid %(x)s, E owned_by X, '
                      'X login L, X modification_date AA',
                      {'x': cnx.user(self.session).eid})
 
-    def test_nonregr_3(self):
+    def test_nonregr3(self):
         self.execute('Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, '
                      'X modification_date AA',
                      {'x': cnx.user(self.session).eid})
 
-    def test_nonregr_4(self):
+    def test_nonregr4(self):
         emaileid = self.execute('INSERT EmailAddress X: X address "toto@logilab.org"')[0][0]
         self.execute('Any X,AA WHERE X use_email Y, Y eid %(x)s, X modification_date AA',
                      {'x': emaileid})
         
-    def test_nonregr_5(self):
+    def test_nonregr5(self):
         # original jpl query:
         # Any X, NOW - CD, P WHERE P is Project, U interested_in P, U is EUser, U login "sthenault", X concerns P, X creation_date CD ORDERBY CD DESC LIMIT 5
         rql = 'Any X, NOW - CD, P ORDERBY CD DESC LIMIT 5 WHERE P bookmarked_by U, U login "%s", P is X, X creation_date CD' % self.session.user.login
         self.execute(rql, )#{'x': })
         
+    def test_nonregr6(self):
+        self.execute('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File '
+                     'WITH U,UL BEING (Any U,UL WHERE ME eid %(x)s, (EXISTS(U identity ME) '
+                     'OR (EXISTS(U in_group G, G name IN("managers", "staff")))) '
+                     'OR (EXISTS(U in_group H, ME in_group H, NOT H name "users")), U login UL, U is EUser)',
+                     {'x': self.session.user.eid})
+
 
 class GlobTrFuncTC(TestCase):
 
--- a/server/test/unittest_migractions.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_migractions.py	Wed Apr 15 17:36:09 2009 +0200
@@ -6,6 +6,8 @@
 from logilab.common.testlib import TestCase, unittest_main
 from cubicweb.devtools.apptest import RepositoryBasedTC, get_versions
 
+from cubicweb.schema import CubicWebSchemaLoader
+from cubicweb.server.sqlutils import SQL_PREFIX
 from cubicweb.server.repository import Repository
 from cubicweb.server.migractions import *
 
@@ -29,7 +31,6 @@
             repo.config._cubes = None
             repo.fill_schema()
             # hack to read the schema from data/migrschema
-            from cubicweb.schema import CubicWebSchemaLoader
             CubicWebSchemaLoader.main_schema_directory = 'migrschema'
             global migrschema
             migrschema = self.repo.config.load_schema()
@@ -40,6 +41,8 @@
         self.mh = ServerMigrationHelper(self.repo.config, migrschema,
                                         repo=self.repo, cnx=self.cnx,
                                         interactive=False)
+        assert self.cnx is self.mh._cnx
+        assert self.session is self.mh.session, (self.session.id, self.mh.session.id)
         
     def test_add_attribute_int(self):
         self.failIf('whatever' in self.schema)
@@ -66,9 +69,9 @@
         self.assertEquals(self.schema['shortpara'].subjects(), ('Note', ))
         self.assertEquals(self.schema['shortpara'].objects(), ('String', ))
         # test created column is actually a varchar(64)
-        notesql = self.mh.sqlexec("SELECT sql FROM sqlite_master WHERE type='table' and name='Note'")[0][0]
+        notesql = self.mh.sqlexec("SELECT sql FROM sqlite_master WHERE type='table' and name='%sNote'" % SQL_PREFIX)[0][0]
         fields = dict(x.strip().split()[:2] for x in notesql.split('(', 1)[1].rsplit(')', 1)[0].split(','))
-        self.assertEquals(fields['shortpara'], 'varchar(64)')
+        self.assertEquals(fields['%sshortpara' % SQL_PREFIX], 'varchar(64)')
         self.mh.rollback()
         
     def test_add_datetime_with_default_value_attribute(self):
@@ -134,7 +137,7 @@
         self.assertEquals([str(rs) for rs in self.schema['Folder2'].object_relations()],
                           ['filed_under2', 'identity'])
         self.assertEquals(sorted(str(e) for e in self.schema['filed_under2'].subjects()),
-                          ['Affaire', 'Card', 'Division', 'ECache', 'Email', 'EmailThread', 'File', 
+                          ['Affaire', 'Card', 'Division', 'Email', 'EmailThread', 'File', 
                            'Folder2', 'Image', 'Note', 'Personne', 'Societe', 'SubDivision'])
         self.assertEquals(self.schema['filed_under2'].objects(), ('Folder2',))
         eschema = self.schema.eschema('Folder2')
@@ -161,7 +164,7 @@
         self.mh.cmd_add_relation_type('filed_under2')
         self.failUnless('filed_under2' in self.schema)
         self.assertEquals(sorted(str(e) for e in self.schema['filed_under2'].subjects()),
-                          ['Affaire', 'Card', 'Division', 'ECache', 'Email', 'EmailThread', 'File', 
+                          ['Affaire', 'Card', 'Division', 'Email', 'EmailThread', 'File', 
                            'Folder2', 'Image', 'Note', 'Personne', 'Societe', 'SubDivision'])
         self.assertEquals(self.schema['filed_under2'].objects(), ('Folder2',))
 
@@ -364,23 +367,36 @@
     def test_add_remove_cube(self):
         cubes = set(self.config.cubes())
         schema = self.repo.schema
+        self.assertEquals(sorted(schema['see_also']._rproperties.keys()),
+                          sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'),
+                                  ('Bookmark', 'Bookmark'), ('Bookmark', 'Note'),
+                                  ('Note', 'Note'), ('Note', 'Bookmark')]))
         try:
-            self.mh.cmd_remove_cube('email')
-            # file was there because it's an email dependancy, should have been removed
-            cubes.remove('email')
-            cubes.remove('file')
-            self.assertEquals(set(self.config.cubes()), cubes)
-            for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', 'Image', 
-                           'sender', 'in_thread', 'reply_to', 'data_format'):
-                self.failIf(ertype in schema, ertype)
-            self.assertEquals(sorted(schema['see_also']._rproperties.keys()),
-                              [('Folder', 'Folder')])
-            self.assertEquals(schema['see_also'].subjects(), ('Folder',))
-            self.assertEquals(schema['see_also'].objects(), ('Folder',))
-            self.assertEquals(self.execute('Any X WHERE X pkey "system.version.email"').rowcount, 0)
-            self.assertEquals(self.execute('Any X WHERE X pkey "system.version.file"').rowcount, 0)
-            self.failIf('email' in self.config.cubes())
-            self.failIf('file' in self.config.cubes())
+            try:
+                self.mh.cmd_remove_cube('email')
+                # file was there because it's an email dependancy, should have been removed
+                cubes.remove('email')
+                cubes.remove('file')
+                self.assertEquals(set(self.config.cubes()), cubes)
+                for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', 'Image', 
+                               'sender', 'in_thread', 'reply_to', 'data_format'):
+                    self.failIf(ertype in schema, ertype)
+                self.assertEquals(sorted(schema['see_also']._rproperties.keys()),
+                                  sorted([('Folder', 'Folder'),
+                                          ('Bookmark', 'Bookmark'),
+                                          ('Bookmark', 'Note'),
+                                          ('Note', 'Note'),
+                                          ('Note', 'Bookmark')]))
+                self.assertEquals(sorted(schema['see_also'].subjects()), ['Bookmark', 'Folder', 'Note'])
+                self.assertEquals(sorted(schema['see_also'].objects()), ['Bookmark', 'Folder', 'Note'])
+                self.assertEquals(self.execute('Any X WHERE X pkey "system.version.email"').rowcount, 0)
+                self.assertEquals(self.execute('Any X WHERE X pkey "system.version.file"').rowcount, 0)
+                self.failIf('email' in self.config.cubes())
+                self.failIf('file' in self.config.cubes())
+            except :
+                import traceback
+                traceback.print_exc()
+                raise
         finally:
             self.mh.cmd_add_cube('email')
             cubes.add('email')
@@ -390,9 +406,13 @@
                            'sender', 'in_thread', 'reply_to', 'data_format'):
                 self.failUnless(ertype in schema, ertype)
             self.assertEquals(sorted(schema['see_also']._rproperties.keys()),
-                              [('EmailThread', 'EmailThread'), ('Folder', 'Folder')])
-            self.assertEquals(sorted(schema['see_also'].subjects()), ['EmailThread', 'Folder'])
-            self.assertEquals(sorted(schema['see_also'].objects()), ['EmailThread', 'Folder'])
+                              sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'),
+                                      ('Bookmark', 'Bookmark'),
+                                      ('Bookmark', 'Note'),
+                                      ('Note', 'Note'),
+                                      ('Note', 'Bookmark')]))
+            self.assertEquals(sorted(schema['see_also'].subjects()), ['Bookmark', 'EmailThread', 'Folder', 'Note'])
+            self.assertEquals(sorted(schema['see_also'].objects()), ['Bookmark', 'EmailThread', 'Folder', 'Note'])
             from cubes.email.__pkginfo__ import version as email_version
             from cubes.file.__pkginfo__ import version as file_version
             self.assertEquals(self.execute('Any V WHERE X value V, X pkey "system.version.email"')[0][0],
@@ -407,6 +427,16 @@
             # why this commit is necessary is unclear to me (though without it
             # next test may fail complaining of missing tables
             self.commit() 
+
+    def test_set_state(self):
+        user = self.session.user
+        self.set_debug(True)
+        self.mh.set_state(user.eid, 'deactivated')
+        user.clear_related_cache('in_state', 'subject')
+        try:
+            self.assertEquals(user.state, 'deactivated')
+        finally:
+            self.set_debug(False)
         
 if __name__ == '__main__':
     unittest_main()
--- a/server/test/unittest_msplanner.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_msplanner.py	Wed Apr 15 17:36:09 2009 +0200
@@ -48,6 +48,12 @@
                      {'X': 'Societe'}, {'X': 'State'}, {'X': 'SubDivision'},
                      {'X': 'Tag'}, {'X': 'TrInfo'}, {'X': 'Transition'}])
 
+def clear_ms_caches(repo):
+    clear_cache(repo, 'rel_type_sources')
+    clear_cache(repo, 'can_cross_relation')
+    clear_cache(repo, 'is_multi_sources_relation')
+    # XXX source_defs
+    
 # keep cnx so it's not garbage collected and the associated session is closed
 repo, cnx = init_test_database('sqlite')
 
@@ -90,6 +96,7 @@
         repo.sources_by_uri['cards'] = self.sources[-1]
         self.rql = self.sources[-1]
         do_monkey_patch()
+        clear_ms_caches(repo)
         
     def tearDown(self):
         undo_monkey_patch()
@@ -118,19 +125,19 @@
 
     def _test(self, rql, *args):
         if len(args) == 3:
-            kwargs, sourcesvars, needsplit = args
+            kwargs, sourcesterms, needsplit = args
         else:
-            sourcesvars, needsplit = args
+            sourcesterms, needsplit = args
             kwargs = None
         plan = self._prepare_plan(rql, kwargs)
         union = plan.rqlst
         plan.preprocess(union)
         ppi = PartPlanInformation(plan, union.children[0])
-        for sourcevars in ppi._sourcesvars.itervalues():
+        for sourcevars in ppi._sourcesterms.itervalues():
             for var in sourcevars.keys():
                 solindices = sourcevars.pop(var)
                 sourcevars[var._ms_table_key()] = solindices
-        self.assertEquals(ppi._sourcesvars, sourcesvars)
+        self.assertEquals(ppi._sourcesterms, sourcesterms)
         self.assertEquals(ppi.needsplit, needsplit)
 
         
@@ -163,7 +170,7 @@
         """
         ueid = self.session.user.eid
         self._test('Any X WHERE X eid %(x)s', {'x': ueid},
-                   {}, False)
+                   {self.system: {'x': s[0]}}, False)
         
     def test_simple_invariant(self):
         """retrieve EUser X from system source only (X is invariant and in_group not supported by ldap source)
@@ -241,8 +248,11 @@
     def test_complex_optional(self):
         ueid = self.session.user.eid
         self._test('Any U WHERE WF wf_info_for X, X eid %(x)s, WF owned_by U?, WF from_state FS', {'x': ueid},
-                   {self.system: {'WF': s[0], 'FS': s[0], 'U': s[0], 'from_state': s[0], 'owned_by': s[0], 'wf_info_for': s[0]}}, False)
-
+                   {self.system: {'WF': s[0], 'FS': s[0], 'U': s[0],
+                                  'from_state': s[0], 'owned_by': s[0], 'wf_info_for': s[0],
+                                  'x': s[0]}},
+                   False)
+        
     def test_exists4(self):
         """
         State S could come from both rql source and system source,
@@ -253,29 +263,99 @@
                    'EXISTS(X copain T, T login L, T login in ("comme", "cochon")) OR '
                    'EXISTS(X in_state S, S name "pascontent", NOT X copain T2, T2 login "billy")',
                    {self.system: {'X': s[0], 'S': s[0], 'T2': s[0], 'T': s[0], 'G': s[0], 'copain': s[0], 'in_group': s[0]}, 
-                    self.ldap: {'X': s[0], 'T2': s[0], 'T': s[0]}}, True)
+                    self.ldap: {'X': s[0], 'T2': s[0], 'T': s[0]}},
+                   True)
 
     def test_relation_need_split(self):
         self._test('Any X, S WHERE X in_state S',
                    {self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2]},
-                     self.rql: {'X': s[2], 'S': s[2]}}, True)
+                    self.rql: {'X': s[2], 'S': s[2]}},
+                   True)
+        
+    def test_not_relation_need_split(self):
+        self._test('Any SN WHERE NOT X in_state S, S name SN',
+                   {self.rql: {'X': s[2], 'S': s[0, 1, 2]},
+                    self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2]}},
+                   True)
+        
+    def test_not_relation_no_split_external(self):
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        # similar to the above test but with an eid coming from the external source.
+        # the same plan may be used, since we won't find any record in the system source
+        # linking 9999999 to a state 
+        self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
+                   {'x': 999999},
+                   {self.rql: {'x': s[0], 'S': s[0]},
+                    self.system: {'x': s[0], 'S': s[0]}},
+                   False)
 
     def test_relation_restriction_ambigous_need_split(self):
         self._test('Any X,T WHERE X in_state S, S name "pending", T tags X',
                    {self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2], 'T': s[0, 1, 2], 'tags': s[0, 1, 2]},
-                    self.rql: {'X': s[2], 'S': s[2]}}, True)
+                    self.rql: {'X': s[2], 'S': s[2]}},
+                   True)
 
     def test_simplified_var(self):
         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
         self._test('Any U WHERE U in_group G, (G name IN ("managers", "logilab") OR (X require_permission P?, P name "bla", P require_group G)), X eid %(x)s, U eid %(u)s',
                    {'x': 999999, 'u': self.session.user.eid},
-                   {self.system: {'P': s[0], 'G': s[0], 'X': s[0], 'require_permission': s[0], 'in_group': s[0], 'P': s[0], 'require_group': s[0]}}, False)
+                   {self.system: {'P': s[0], 'G': s[0], 'X': s[0],
+                                  'require_permission': s[0], 'in_group': s[0], 'P': s[0], 'require_group': s[0],
+                                  'u': s[0]}},
+                   False)
         
     def test_delete_relation1(self):
         ueid = self.session.user.eid
         self._test('Any X, Y WHERE X created_by Y, X eid %(x)s, NOT Y eid %(y)s',
                    {'x': ueid, 'y': ueid},
-                   {self.system: {'Y': s[0], 'created_by': s[0]}}, False)
+                   {self.system: {'Y': s[0], 'created_by': s[0], 'x': s[0]}},
+                   False)
+
+    def test_crossed_relation_eid_1_needattr(self):
+        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        ueid = self.session.user.eid
+        self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
+                   {'x': 999999,},
+                   {self.rql: {'Y': s[0]}, self.system: {'Y': s[0], 'x': s[0]}},
+                   True)
+        
+    def test_crossed_relation_eid_1_invariant(self):
+        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
+                   {'x': 999999},
+                   {self.system: {'Y': s[0], 'x': s[0]}},
+                   False)
+
+    def test_crossed_relation_eid_2_invariant(self):
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
+                   {'x': 999999,},
+                   {self.rql: {'Y': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]},
+                    self.system: {'Y': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]}},
+                   False)
+
+    def test_version_crossed_depends_on_1(self):
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
+                   {'x': 999999},
+                   {self.rql: {'X': s[0], 'AD': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]},
+                    self.system: {'X': s[0], 'AD': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]}},
+                   True)
+        
+    def test_version_crossed_depends_on_2(self):
+        repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
+                   {'x': 999999},
+                   {self.rql: {'X': s[0], 'AD': s[0]},
+                    self.system: {'X': s[0], 'AD': s[0], 'x': s[0]}},
+                    True)
+
+    def test_simplified_var_3(self):
+        repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        repo._type_source_cache[999998] = ('State', 'cards', 999998)
+        self._test('Any S,T WHERE S eid %(s)s, N eid %(n)s, N type T, N is Note, S is State',
+                   {'n': 999999, 's': 999998},
+                   {self.rql: {'s': s[0], 'N': s[0]}}, False)
                    
 
         
@@ -1142,50 +1222,40 @@
         # in the source where %(x)s is not coming from and will be removed during rql
         # generation for the external source
         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
-                   [('OneFetchStep', [('Any SN WHERE NOT 5 in_state S, S name SN, S is State', [{'S': 'State', 'SN': 'String'}])], 
+                   [('OneFetchStep', [('Any SN WHERE NOT 5 in_state S, S name SN, S is State',
+                                       [{'S': 'State', 'SN': 'String'}])], 
                      None, None, [self.rql, self.system], {}, [])],
                    {'x': ueid})
 
     def test_not_relation_no_split_external(self):
         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        # similar to the above test but with an eid coming from the external source
+        # similar to the above test but with an eid coming from the external source.
+        # the same plan may be used, since we won't find any record in the system source
+        # linking 9999999 to a state 
         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
-                   [('UnionStep', None, None,
-                     [('OneFetchStep',
-                       [('Any SN WHERE NOT 999999 in_state S, S name SN, S is State',
-                         [{'S': 'State', 'SN': 'String'}])],
-                       None, None, [self.rql], {},
-                       []),
-                      ('OneFetchStep',
-                       [('Any SN WHERE S name SN, S is State',
-                         [{'S': 'State', 'SN': 'String'}])],
-                       None, None, [self.system], {},
-                       [])]
-                     )],
+                   [('OneFetchStep', [('Any SN WHERE NOT 999999 in_state S, S name SN, S is State',
+                                       [{'S': 'State', 'SN': 'String'}])], 
+                     None, None, [self.rql, self.system], {}, [])],
                    {'x': 999999})
 
     def test_not_relation_need_split(self):
-        ueid = self.session.user.eid
         self._test('Any SN WHERE NOT X in_state S, S name SN',
-                   [('FetchStep', [('Any SN,S WHERE S name SN, S is State', [{'S': 'State', 'SN': 'String'}])],
+                   [('FetchStep', [('Any SN,S WHERE S name SN, S is State',
+                                    [{'S': 'State', 'SN': 'String'}])],
                      [self.rql, self.system], None, {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
                      []),
-                    ('FetchStep', [('Any X WHERE X is Note', [{'X': 'Note'}])],
-                     [self.rql, self.system], None, {'X': 'table1.C0'},
-                     []),
                     ('IntersectStep', None, None,
                      [('OneFetchStep',
+                       [('Any SN WHERE NOT X in_state S, S name SN, S is State, X is Note',
+                         [{'S': 'State', 'SN': 'String', 'X': 'Note'}])],
+                       None, None, [self.rql, self.system], {},
+                       []),
+                      ('OneFetchStep',
                        [('Any SN WHERE NOT X in_state S, S name SN, S is State, X is IN(Affaire, EUser)',
                          [{'S': 'State', 'SN': 'String', 'X': 'Affaire'},
                           {'S': 'State', 'SN': 'String', 'X': 'EUser'}])],
                        None, None, [self.system], {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
-                       []),
-                      ('OneFetchStep',
-                       [('Any SN WHERE NOT X in_state S, S name SN, S is State, X is Note',
-                         [{'S': 'State', 'SN': 'String', 'X': 'Note'}])],
-                       None, None, [self.system], {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0',
-                                                   'X': 'table1.C0'},
-                       [])]
+                       []),]
                      )])
             
     def test_external_attributes_and_relation(self):
@@ -1372,7 +1442,6 @@
     
     def test_crossed_relation_eid_1_invariant(self):
         repo._type_source_cache[999999] = ('Note', 'system', 999999)
-        ueid = self.session.user.eid
         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
                    [('OneFetchStep', [('Any Y WHERE 999999 multisource_crossed_rel Y', [{u'Y': 'Note'}])],
                       None, None, [self.system], {}, [])
@@ -1381,7 +1450,6 @@
 
     def test_crossed_relation_eid_1_needattr(self):
         repo._type_source_cache[999999] = ('Note', 'system', 999999)
-        ueid = self.session.user.eid
         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
                    [('FetchStep', [('Any Y,T WHERE Y type T, Y is Note', [{'T': 'String', 'Y': 'Note'}])],
                      [self.rql, self.system], None,
@@ -1395,7 +1463,6 @@
 
     def test_crossed_relation_eid_2_invariant(self):
         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        ueid = self.session.user.eid
         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
                    [('OneFetchStep', [('Any Y WHERE 999999 multisource_crossed_rel Y, Y is Note', [{'Y': 'Note'}])],
                       None, None, [self.rql, self.system], {}, [])
@@ -1404,22 +1471,25 @@
 
     def test_crossed_relation_eid_2_needattr(self):
         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-        ueid = self.session.user.eid
-        self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
+        self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',                   
                    [('FetchStep', [('Any Y,T WHERE Y type T, Y is Note', [{'T': 'String', 'Y': 'Note'}])],
                      [self.rql, self.system], None,
                      {'T': 'table0.C1', 'Y': 'table0.C0', 'Y.type': 'table0.C1'}, []),
-                    ('OneFetchStep', [('Any Y,T WHERE 999999 multisource_crossed_rel Y, Y type T, Y is Note',
-                                       [{'T': 'String', 'Y': 'Note'}])],
-                     None, None, [self.rql, self.system],
-                     {'T': 'table0.C1', 'Y': 'table0.C0', 'Y.type': 'table0.C1'},
-                     [])
-                    ],
+                    ('UnionStep', None, None,
+                     [('OneFetchStep', [('Any Y,T WHERE 999999 multisource_crossed_rel Y, Y type T, Y is Note',
+                                         [{'T': 'String', 'Y': 'Note'}])],
+                       None, None, [self.rql], None,
+                       []),
+                      ('OneFetchStep', [('Any Y,T WHERE 999999 multisource_crossed_rel Y, Y type T, Y is Note',
+                                         [{'T': 'String', 'Y': 'Note'}])],
+                       None, None, [self.system],
+                       {'T': 'table0.C1', 'Y': 'table0.C0', 'Y.type': 'table0.C1'},
+                       [])]
+                     )],
                    {'x': 999999,})
 
     def test_crossed_relation_eid_not_1(self):
         repo._type_source_cache[999999] = ('Note', 'system', 999999)
-        ueid = self.session.user.eid
         self._test('Any Y WHERE X eid %(x)s, NOT X multisource_crossed_rel Y',
                    [('FetchStep', [('Any Y WHERE Y is Note', [{'Y': 'Note'}])],
                      [self.rql, self.system], None, {'Y': 'table0.C0'}, []),
@@ -1431,14 +1501,12 @@
 
 #     def test_crossed_relation_eid_not_2(self):
 #         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
-#         ueid = self.session.user.eid
 #         self._test('Any Y WHERE X eid %(x)s, NOT X multisource_crossed_rel Y',
 #                    [],
 #                    {'x': 999999,})
 
-    def test_crossed_relation_base(self):
+    def test_crossed_relation_base_XXXFIXME(self):
         repo._type_source_cache[999999] = ('Note', 'system', 999999)
-        ueid = self.session.user.eid
         self._test('Any X,Y,T WHERE X multisource_crossed_rel Y, Y type T, X type T',
                    [('FetchStep', [('Any X,T WHERE X type T, X is Note', [{'T': 'String', 'X': 'Note'}])],
                      [self.rql, self.system], None,
@@ -1446,12 +1514,18 @@
                     ('FetchStep',  [('Any Y,T WHERE Y type T, Y is Note', [{'T': 'String', 'Y': 'Note'}])],
                      [self.rql, self.system], None,
                      {'T': 'table1.C1', 'Y': 'table1.C0', 'Y.type': 'table1.C1'},  []),
-                    ('OneFetchStep', [('Any X,Y,T WHERE X multisource_crossed_rel Y, Y type T, X type T, X is Note, Y is Note',
-                                       [{'T': 'String', 'X': 'Note', 'Y': 'Note'}])],
-                     None, None, [self.rql, self.system],
-                     {'T': 'table1.C1', 'X': 'table0.C0', 'X.type': 'table0.C1',
-                      'Y': 'table1.C0', 'Y.type': 'table1.C1'},
-                    [])],
+                    ('UnionStep', None,  None,
+                     [('OneFetchStep', [('Any X,Y,T WHERE X multisource_crossed_rel Y, Y type T, X type T, X is Note, Y is Note',
+                                         [{'T': 'String', 'X': 'Note', 'Y': 'Note'}])],
+                       None, None, [self.rql], None,
+                       []),
+                      ('OneFetchStep', [('Any X,Y,T WHERE X multisource_crossed_rel Y, Y type T, X type T, X is Note, Y is Note',
+                                         [{'T': 'String', 'X': 'Note', 'Y': 'Note'}])],
+                       None, None, [self.system],
+                       {'T': 'table1.C1', 'X': 'table0.C0', 'X.type': 'table0.C1',
+                        'Y': 'table1.C0', 'Y.type': 'table1.C1'},
+                       [])]
+                     )],
                     {'x': 999999,})
         
     # edition queries tests ###################################################
@@ -1768,8 +1842,8 @@
                    [('FetchStep',
                      [('Any X,AA,AB WHERE X login AA, X modification_date AB, X is EUser',
                        [{'AA': 'String', 'AB': 'Datetime', 'X': 'EUser'}])],
-                     [self.ldap], None, {'AA': 'table0.C1', 'AB': 'table0.C2',
-                                         'X': 'table0.C0', 'X.login': 'table0.C1', 'X.modification_date': 'table0.C2'},
+                     [self.ldap, self.system], None, {'AA': 'table0.C1', 'AB': 'table0.C2',
+                                                      'X': 'table0.C0', 'X.login': 'table0.C1', 'X.modification_date': 'table0.C2'},
                      []),
                     ('OneFetchStep',
                      [('Any X,AA,AB ORDERBY AA WHERE 999999 owned_by X, X login AA, X modification_date AB, X is EUser',
@@ -1799,7 +1873,7 @@
         self._test('Any X ORDERBY Z DESC WHERE X modification_date Z, E eid %(x)s, E see_also X',
                    [('FetchStep', [('Any X,Z WHERE X modification_date Z, X is Note',
                                     [{'X': 'Note', 'Z': 'Datetime'}])],
-                     [self.rql], None, {'X': 'table0.C0', 'X.modification_date': 'table0.C1', 'Z': 'table0.C1'},
+                     [self.rql, self.system], None, {'X': 'table0.C0', 'X.modification_date': 'table0.C1', 'Z': 'table0.C1'},
                      []),
                     ('AggrStep', 'Any X ORDERBY Z DESC',
                      None, None, 'table1', None,
@@ -1818,16 +1892,74 @@
                       )],
                    {'x': 999999})
 
+    def test_nonregr13_1(self):
+        # identity wrapped into exists:
+        # should'nt propagate constraint that U is in the same source as ME
+        self._test('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File '
+                   'WITH U,UL BEING (Any U,UL WHERE ME eid %(x)s, (EXISTS(U identity ME) '
+                   'OR (EXISTS(U in_group G, G name IN("managers", "staff")))) '
+                   'OR (EXISTS(U in_group H, ME in_group H, NOT H name "users")), U login UL, U is EUser)',
+                   [('FetchStep', [('Any U,UL WHERE U login UL, U is EUser',
+                                    [{'U': 'EUser', 'UL': 'String'}])],
+                     [self.ldap, self.system], None,
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     []),
+                    ('FetchStep', [('Any U,UL WHERE ((EXISTS(U identity 5)) OR (EXISTS(U in_group G, G name IN("managers", "staff"), G is EGroup))) OR (EXISTS(U in_group H, 5 in_group H, NOT H name "users", H is EGroup)), U login UL, U is EUser',
+                                    [{'G': 'EGroup', 'H': 'EGroup', 'U': 'EUser', 'UL': 'String'}])],
+                     [self.system],
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     {'U': 'table1.C0', 'U.login': 'table1.C1', 'UL': 'table1.C1'},
+                     []),
+                    ('OneFetchStep', [('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File',
+                                       [{'B': 'File', 'U': 'EUser', 'UL': 'String'}])],
+                     None, None, [self.system],
+                     {'U': 'table1.C0', 'UL': 'table1.C1'},
+                     [])],
+                   {'x': self.session.user.eid})
+        
+    def test_nonregr13_2(self):
+        # identity *not* wrapped into exists.
+        #
+        # XXX this test fail since in this case, in "U identity 5" U and 5 are
+        # from the same scope so constraints are applied (telling the U should
+        # come from the same source as user with eid 5).
+        #
+        # IMO this is normal, unless we introduce a special case for the
+        # identity relation. BUT I think it's better to leave it as is and to
+        # explain constraint propagation rules, and so why this should be
+        # wrapped in exists() if used in multi-source
+        self.skip('take a look at me if you wish')
+        self._test('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File '
+                   'WITH U,UL BEING (Any U,UL WHERE ME eid %(x)s, (U identity ME '
+                   'OR (EXISTS(U in_group G, G name IN("managers", "staff")))) '
+                   'OR (EXISTS(U in_group H, ME in_group H, NOT H name "users")), U login UL, U is EUser)',
+                   [('FetchStep', [('Any U,UL WHERE U login UL, U is EUser',
+                                    [{'U': 'EUser', 'UL': 'String'}])],
+                     [self.ldap, self.system], None,
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     []),
+                    ('FetchStep', [('Any U,UL WHERE ((U identity 5) OR (EXISTS(U in_group G, G name IN("managers", "staff"), G is EGroup))) OR (EXISTS(U in_group H, 5 in_group H, NOT H name "users", H is EGroup)), U login UL, U is EUser',
+                                    [{'G': 'EGroup', 'H': 'EGroup', 'U': 'EUser', 'UL': 'String'}])],
+                     [self.system],
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     {'U': 'table1.C0', 'U.login': 'table1.C1', 'UL': 'table1.C1'},
+                     []),
+                    ('OneFetchStep', [('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File',
+                                       [{'B': 'File', 'U': 'EUser', 'UL': 'String'}])],
+                     None, None, [self.system],
+                     {'U': 'table1.C0', 'UL': 'table1.C1'},
+                     [])],
+                   {'x': self.session.user.eid})
+
 
 class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC):
     """test planner related feature on a 3-sources repository:
     
-    * 2 rql source supporting Card
+    * 2 rql sources supporting Card
     """
     repo = repo
     
     def setUp(self):
-        #_QuerierTC.setUp(self)
         self.o = repo.querier
         self.session = repo._sessions.values()[0]
         self.pool = self.session.set_pool()
@@ -1844,7 +1976,11 @@
         self.rql2 = self.sources[-1]
         do_monkey_patch()
         self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
-
+        assert repo.sources_by_uri['cards2'].support_relation('multisource_crossed_rel')
+        assert 'multisource_crossed_rel' in repo.sources_by_uri['cards2'].cross_relations
+        assert repo.sources_by_uri['cards'].support_relation('multisource_crossed_rel')
+        assert 'multisource_crossed_rel' in repo.sources_by_uri['cards'].cross_relations
+        clear_ms_caches(repo)
     _test = test_plan
         
     def tearDown(self):
@@ -1869,7 +2005,92 @@
                      {'X': 'table0.C0', 'X.title': 'table0.C1', 'XT': 'table0.C1'},
                      [])],
                    {'t': 999999})
- 
+
+    def test_version_depends_on(self):
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self._test('Any X,AD,AE WHERE E eid %(x)s, E migrated_from X, X in_state AD, AD name AE',
+                   [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
+                                    [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                     [self.rql, self.rql2, self.system],
+                     None, {'AD': 'table0.C1', 'AD.name': 'table0.C2',
+                            'AE': 'table0.C2', 'X': 'table0.C0'},
+                     []),
+                    ('OneFetchStep', [('Any X,AD,AE WHERE 999999 migrated_from X, AD name AE, AD is State, X is Note',
+                                       [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                     None, None, [self.system],
+                     {'AD': 'table0.C1', 'AD.name': 'table0.C2', 'AE': 'table0.C2', 'X': 'table0.C0'},
+                     [])],
+                   {'x': 999999})
+
+    def test_version_crossed_depends_on_1(self):
+        self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
+        self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
+                   [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
+                                    [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                     [self.rql, self.rql2, self.system],
+                     None, {'AD': 'table0.C1', 'AD.name': 'table0.C2',
+                            'AE': 'table0.C2', 'X': 'table0.C0'},
+                     []),
+                    ('UnionStep', None, None,
+                     [('OneFetchStep', [('Any X,AD,AE WHERE 999999 multisource_crossed_rel X, AD name AE, AD is State, X is Note',
+                                         [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                       None, None, [self.rql], None,
+                       []),
+                      ('OneFetchStep', [('Any X,AD,AE WHERE 999999 multisource_crossed_rel X, AD name AE, AD is State, X is Note',
+                                         [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                       None, None, [self.system],
+                       {'AD': 'table0.C1', 'AD.name': 'table0.C2',
+                        'AE': 'table0.C2', 'X': 'table0.C0'},
+                       [])]
+                     )],
+                   {'x': 999999})
+
+    def test_version_crossed_depends_on_2(self):
+        self.repo._type_source_cache[999999] = ('Note', 'system', 999999)
+        self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
+                   [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
+                                    [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                     [self.rql, self.rql2, self.system],
+                     None, {'AD': 'table0.C1', 'AD.name': 'table0.C2',
+                            'AE': 'table0.C2', 'X': 'table0.C0'},
+                     []),
+                    ('OneFetchStep', [('Any X,AD,AE WHERE 999999 multisource_crossed_rel X, AD name AE, AD is State, X is Note',
+                                       [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                     None, None, [self.system],
+                     {'AD': 'table0.C1', 'AD.name': 'table0.C2', 'AE': 'table0.C2', 'X': 'table0.C0'},
+                     [])],
+                   {'x': 999999})
+
+    def test_version_crossed_depends_on_3(self):
+        self._test('Any X,AD,AE WHERE E multisource_crossed_rel X, X in_state AD, AD name AE, E is Note',
+                   [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
+                                    [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
+                     [self.rql, self.rql2, self.system],
+                     None, {'AD': 'table0.C1', 'AD.name': 'table0.C2',
+                            'AE': 'table0.C2', 'X': 'table0.C0'},
+                     []),
+                    ('FetchStep', [('Any E WHERE E is Note', [{'E': 'Note'}])],
+                     [self.rql, self.rql2, self.system],
+                     None, {'E': 'table1.C0'},
+                     []),
+                    ('UnionStep', None, None,
+                     [('OneFetchStep', [('Any X,AD,AE WHERE E multisource_crossed_rel X, AD name AE, AD is State, E is Note, X is Note',
+                                         [{'AD': 'State', 'AE': 'String', 'E': 'Note', 'X': 'Note'}])],
+                       None, None, [self.rql, self.rql2], None,
+                       []),
+                      ('OneFetchStep', [('Any X,AD,AE WHERE E multisource_crossed_rel X, AD name AE, AD is State, E is Note, X is Note',
+                                         [{'AD': 'State', 'AE': 'String', 'E': 'Note', 'X': 'Note'}])],
+                       None, None, [self.system],
+                       {'AD': 'table0.C1',
+                        'AD.name': 'table0.C2',
+                        'AE': 'table0.C2',
+                        'E': 'table1.C0',
+                        'X': 'table0.C0'},
+                       [])]
+                     )]
+                   )
+
+
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()
--- a/server/test/unittest_multisources.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_multisources.py	Wed Apr 15 17:36:09 2009 +0200
@@ -10,10 +10,13 @@
     sourcefile = 'sources_multi'
 
         
-class ExternalSourceConfiguration(TestServerConfiguration):
+class ExternalSource1Configuration(TestServerConfiguration):
     sourcefile = 'sources_extern'
+        
+class ExternalSource2Configuration(TestServerConfiguration):
+    sourcefile = 'sources_multi2'
 
-repo2, cnx2 = init_test_database('sqlite', config=ExternalSourceConfiguration('data'))
+repo2, cnx2 = init_test_database('sqlite', config=ExternalSource1Configuration('data'))
 cu = cnx2.cursor()
 ec1 = cu.execute('INSERT Card X: X title "C3: An external card", X wikiid "aaa"')[0][0]
 cu.execute('INSERT Card X: X title "C4: Ze external card", X wikiid "zzz"')
@@ -22,9 +25,11 @@
 
 MTIME = now() - 0.1
 
+repo3, cnx3 = init_test_database('sqlite', config=ExternalSource2Configuration('data'))
+
 # XXX, access existing connection, no pyro connection
 from cubicweb.server.sources.pyrorql import PyroRQLSource
-PyroRQLSource.get_connection = lambda x: cnx2
+PyroRQLSource.get_connection = lambda x: x.uri == 'extern-multi' and cnx3 or cnx2
 # necessary since the repository is closing its initial connections pool though
 # we want to keep cnx2 valid
 from cubicweb.dbapi import Connection
@@ -84,12 +89,12 @@
         self.assertEquals(rset.rows, rsetbase.rows[2:4])
 
     def test_has_text(self):
-        self.repo.sources[-1].synchronize(MTIME) # in case fti_update has been run before
+        self.repo.sources_by_uri['extern'].synchronize(MTIME) # in case fti_update has been run before
         self.failUnless(self.execute('Any X WHERE X has_text "affref"'))
         self.failUnless(self.execute('Affaire X WHERE X has_text "affref"'))
 
     def test_anon_has_text(self):
-        self.repo.sources[-1].synchronize(MTIME) # in case fti_update has been run before
+        self.repo.sources_by_uri['extern'].synchronize(MTIME) # in case fti_update has been run before
         self.execute('INSERT Affaire X: X ref "no readable card"')[0][0]
         aff1 = self.execute('INSERT Affaire X: X ref "card"')[0][0]
         # grant read access
@@ -98,7 +103,7 @@
         cnx = self.login('anon')
         cu = cnx.cursor()
         rset = cu.execute('Any X WHERE X has_text "card"')
-        self.assertEquals(len(rset), 5)
+        self.assertEquals(len(rset), 5, zip(rset.rows, rset.description))
 
     def test_synchronization(self):
         cu = cnx2.cursor()
@@ -107,13 +112,14 @@
         cnx2.commit()
         try:
             # force sync
-            self.repo.sources[-1].synchronize(MTIME)
+            self.repo.sources_by_uri['extern'].synchronize(MTIME)
             self.failUnless(self.execute('Any X WHERE X has_text "blah"'))
             self.failUnless(self.execute('Any X WHERE X has_text "affreux"'))
             cu.execute('DELETE Affaire X WHERE X eid %(x)s', {'x': aff2})
             cnx2.commit()
-            self.repo.sources[-1].synchronize(MTIME)
-            self.failIf(self.execute('Any X WHERE X has_text "affreux"'))
+            self.repo.sources_by_uri['extern'].synchronize(MTIME)
+            rset = self.execute('Any X WHERE X has_text "affreux"')
+            self.failIf(rset)
         finally:
             # restore state
             cu.execute('SET X ref "AFFREF" WHERE X eid %(x)s', {'x': aff1}, 'x')
@@ -139,7 +145,8 @@
         self.execute('Any X ORDERBY DUMB_SORT(RF) WHERE X title RF')
 
     def test_in_eid(self):
-        iec1 = self.repo.extid2eid(self.repo.sources[-1], ec1, 'Card', self.session)
+        iec1 = self.repo.extid2eid(self.repo.sources_by_uri['extern'], ec1,
+                                   'Card', self.session)
         rset = self.execute('Any X WHERE X eid IN (%s, %s)' % (iec1, self.ic1))
         self.assertEquals(sorted(r[0] for r in rset.rows), sorted([iec1, self.ic1]))
         
--- a/server/test/unittest_querier.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_querier.py	Wed Apr 15 17:36:09 2009 +0200
@@ -9,7 +9,9 @@
 
 from mx.DateTime import today, now, DateTimeType
 from rql import BadRQLQuery, RQLSyntaxError
+
 from cubicweb import QueryError, Unauthorized
+from cubicweb.server.sqlutils import SQL_PREFIX
 from cubicweb.server.utils import crypt_password
 from cubicweb.server.sources.native import make_schema
 
@@ -454,7 +456,7 @@
                             'WHERE RT name N, RDEF relation_type RT '
                             'HAVING COUNT(RDEF) > 10')
         self.assertListEquals(rset.rows,
-                              [[u'description', 11], ['in_basket', 12],
+                              [[u'description', 11], ['in_basket', 11],
                                [u'name', 13], [u'created_by', 33],
                                [u'creation_date', 33], [u'is', 33], [u'is_instance_of', 33],
                                [u'modification_date', 33], [u'owned_by', 33]])
@@ -468,6 +470,7 @@
         self.assertEquals(rset.rows[0][0], self.ueid)
 
     def test_select_complex_sort(self):
+        self.skip('retry me once http://www.sqlite.org/cvstrac/tktview?tn=3773 is fixed')
         rset = self.execute('Any X ORDERBY X,D LIMIT 5 WHERE X creation_date D')
         result = rset.rows
         result.sort()
@@ -1072,7 +1075,8 @@
         self.assertRaises(Unauthorized,
                           self.execute, "Any P WHERE X is EUser, X login 'bob', X upassword P")
         cursor = self.pool['system']
-        cursor.execute("SELECT upassword from EUser WHERE login='bob'")
+        cursor.execute("SELECT %supassword from %sEUser WHERE %slogin='bob'"
+                       % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
         passwd = cursor.fetchone()[0].getvalue()
         self.assertEquals(passwd, crypt_password('toto', passwd[:2])) 
         rset = self.execute("Any X WHERE X is EUser, X login 'bob', X upassword '%s'" % passwd)
@@ -1085,7 +1089,8 @@
         self.assertEquals(rset.description[0][0], 'EUser')
         rset = self.execute("SET X upassword %(pwd)s WHERE X is EUser, X login 'bob'",
                             {'pwd': 'tutu'})
-        cursor.execute("SELECT upassword from EUser WHERE login='bob'")
+        cursor.execute("SELECT %supassword from %sEUser WHERE %slogin='bob'"
+                       % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
         passwd = cursor.fetchone()[0].getvalue()
         self.assertEquals(passwd, crypt_password('tutu', passwd[:2])) 
         rset = self.execute("Any X WHERE X is EUser, X login 'bob', X upassword '%s'" % passwd)
@@ -1212,6 +1217,7 @@
         cause: old variable ref inserted into a fresh rqlst copy
         (in RQLSpliter._complex_select_plan)
         """
+        self.skip('retry me once http://www.sqlite.org/cvstrac/tktview?tn=3773 is fixed')
         self.execute('Any X ORDERBY D DESC WHERE X creation_date D')
     
     def test_nonregr_extra_joins(self):
--- a/server/test/unittest_repository.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_repository.py	Wed Apr 15 17:36:09 2009 +0200
@@ -8,17 +8,18 @@
 from copy import deepcopy
 
 from mx.DateTime import DateTimeType, now
+
 from logilab.common.testlib import TestCase, unittest_main
-from cubicweb.devtools.apptest import RepositoryBasedTC
-from cubicweb.devtools.repotest import tuplify
 
 from yams.constraints import UniqueConstraint
 
 from cubicweb import BadConnectionId, RepositoryError, ValidationError, UnknownEid, AuthenticationError
 from cubicweb.schema import CubicWebSchema, RQLConstraint
 from cubicweb.dbapi import connect, repo_connect
-
+from cubicweb.devtools.apptest import RepositoryBasedTC
+from cubicweb.devtools.repotest import tuplify
 from cubicweb.server import repository 
+from cubicweb.server.sqlutils import SQL_PREFIX
 
 
 # start name server anyway, process will fail if already running
@@ -46,11 +47,16 @@
         self.repo.config._cubes = None # avoid assertion error
         self.repo.fill_schema()
         pool = self.repo._get_pool()
+        table = SQL_PREFIX + 'EEType'
+        namecol = SQL_PREFIX + 'name'
+        finalcol = SQL_PREFIX + 'final'
         try:
             sqlcursor = pool['system']
-            sqlcursor.execute('SELECT name FROM EEType WHERE final is NULL')
+            sqlcursor.execute('SELECT %s FROM %s WHERE %s is NULL' % (
+                namecol, table, finalcol))
             self.assertEquals(sqlcursor.fetchall(), [])
-            sqlcursor.execute('SELECT name FROM EEType WHERE final=%(final)s ORDER BY name', {'final': 'TRUE'})
+            sqlcursor.execute('SELECT %s FROM %s WHERE %s=%%(final)s ORDER BY %s'
+                              % (namecol, table, finalcol, namecol), {'final': 'TRUE'})
             self.assertEquals(sqlcursor.fetchall(), [(u'Boolean',), (u'Bytes',),
                                                      (u'Date',), (u'Datetime',),
                                                      (u'Decimal',),(u'Float',),
--- a/server/test/unittest_rql2sql.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_rql2sql.py	Wed Apr 15 17:36:09 2009 +0200
@@ -31,111 +31,111 @@
 
 PARSER = [
     (r"Personne P WHERE P nom 'Zig\'oto';",
-     '''SELECT P.eid
-FROM Personne AS P
-WHERE P.nom=Zig\'oto'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE P.cw_nom=Zig\'oto'''),
 
     (r'Personne P WHERE P nom ~= "Zig\"oto%";',
-     '''SELECT P.eid
-FROM Personne AS P
-WHERE P.nom ILIKE Zig"oto%'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE P.cw_nom ILIKE Zig"oto%'''),
     ]
 
 BASIC = [
-    
+
     ("Any X WHERE X is Affaire",
-     '''SELECT X.eid
-FROM Affaire AS X'''),
+     '''SELECT X.cw_eid
+FROM cw_Affaire AS X'''),
     
     ("Any X WHERE X eid 0",
      '''SELECT 0'''),
     
     ("Personne P",
-     '''SELECT P.eid
-FROM Personne AS P'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P'''),
 
     ("Personne P WHERE P test TRUE",
-     '''SELECT P.eid
-FROM Personne AS P
-WHERE P.test=True'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE P.cw_test=True'''),
 
     ("Personne P WHERE P test false",
-     '''SELECT P.eid
-FROM Personne AS P
-WHERE P.test=False'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE P.cw_test=False'''),
 
     ("Personne P WHERE P eid -1",
      '''SELECT -1'''),
 
     ("Personne P LIMIT 20 OFFSET 10",
-     '''SELECT P.eid
-FROM Personne AS P
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
 LIMIT 20
 OFFSET 10'''),
 
     ("Personne P WHERE S is Societe, P travaille S, S nom 'Logilab';",
      '''SELECT rel_travaille0.eid_from
-FROM Societe AS S, travaille_relation AS rel_travaille0
-WHERE rel_travaille0.eid_to=S.eid AND S.nom=Logilab'''),
+FROM cw_Societe AS S, travaille_relation AS rel_travaille0
+WHERE rel_travaille0.eid_to=S.cw_eid AND S.cw_nom=Logilab'''),
 
     ("Personne P WHERE P concerne A, A concerne S, S nom 'Logilab', S is Societe;",
      '''SELECT rel_concerne0.eid_from
-FROM Societe AS S, concerne_relation AS rel_concerne0, concerne_relation AS rel_concerne1
-WHERE rel_concerne0.eid_to=rel_concerne1.eid_from AND rel_concerne1.eid_to=S.eid AND S.nom=Logilab'''),
+FROM concerne_relation AS rel_concerne0, concerne_relation AS rel_concerne1, cw_Societe AS S
+WHERE rel_concerne0.eid_to=rel_concerne1.eid_from AND rel_concerne1.eid_to=S.cw_eid AND S.cw_nom=Logilab'''),
 
     ("Note N WHERE X evaluee N, X nom 'Logilab';",
      '''SELECT rel_evaluee0.eid_to
-FROM Division AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom=Logilab
+FROM cw_Division AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom=Logilab
 UNION ALL
 SELECT rel_evaluee0.eid_to
-FROM Personne AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom=Logilab
+FROM cw_Personne AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom=Logilab
 UNION ALL
 SELECT rel_evaluee0.eid_to
-FROM Societe AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom=Logilab
+FROM cw_Societe AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom=Logilab
 UNION ALL
 SELECT rel_evaluee0.eid_to
-FROM SubDivision AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom=Logilab'''),
+FROM cw_SubDivision AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom=Logilab'''),
 
     ("Note N WHERE X evaluee N, X nom in ('Logilab', 'Caesium');",
      '''SELECT rel_evaluee0.eid_to
-FROM Division AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom IN(Logilab, Caesium)
+FROM cw_Division AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom IN(Logilab, Caesium)
 UNION ALL
 SELECT rel_evaluee0.eid_to
-FROM Personne AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom IN(Logilab, Caesium)
+FROM cw_Personne AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom IN(Logilab, Caesium)
 UNION ALL
 SELECT rel_evaluee0.eid_to
-FROM Societe AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom IN(Logilab, Caesium)
+FROM cw_Societe AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom IN(Logilab, Caesium)
 UNION ALL
 SELECT rel_evaluee0.eid_to
-FROM SubDivision AS X, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=X.eid AND X.nom IN(Logilab, Caesium)'''),
+FROM cw_SubDivision AS X, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=X.cw_eid AND X.cw_nom IN(Logilab, Caesium)'''),
 
     ("Any X WHERE X creation_date TODAY, X is Affaire",
-     '''SELECT X.eid
-FROM Affaire AS X
-WHERE DATE(X.creation_date)=CURRENT_DATE'''),
+     '''SELECT X.cw_eid
+FROM cw_Affaire AS X
+WHERE DATE(X.cw_creation_date)=CURRENT_DATE'''),
 
     ("Any N WHERE G is EGroup, G name N, E eid 12, E read_permission G",
-     '''SELECT G.name
-FROM EGroup AS G, read_permission_relation AS rel_read_permission0
-WHERE rel_read_permission0.eid_from=12 AND rel_read_permission0.eid_to=G.eid'''),
+     '''SELECT G.cw_name
+FROM cw_EGroup AS G, read_permission_relation AS rel_read_permission0
+WHERE rel_read_permission0.eid_from=12 AND rel_read_permission0.eid_to=G.cw_eid'''),
 
     ('Any Y WHERE U login "admin", U login Y', # stupid but valid...
-     """SELECT U.login
-FROM EUser AS U
-WHERE U.login=admin"""),
+     """SELECT U.cw_login
+FROM cw_EUser AS U
+WHERE U.cw_login=admin"""),
 
     ('Any T WHERE T tags X, X is State',
      '''SELECT rel_tags0.eid_from
-FROM State AS X, tags_relation AS rel_tags0
-WHERE rel_tags0.eid_to=X.eid'''),
+FROM cw_State AS X, tags_relation AS rel_tags0
+WHERE rel_tags0.eid_to=X.cw_eid'''),
 
     ('Any X,Y WHERE X eid 0, Y eid 1, X concerne Y',
      '''SELECT 0, 1
@@ -144,45 +144,40 @@
 
     ("Any X WHERE X prenom 'lulu',"
      "EXISTS(X owned_by U, U in_group G, G name 'lulufanclub' OR G name 'managers');",
-     '''SELECT X.eid
-FROM Personne AS X
-WHERE X.prenom=lulu AND EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, in_group_relation AS rel_in_group1, EGroup AS G WHERE rel_owned_by0.eid_from=X.eid AND rel_in_group1.eid_from=rel_owned_by0.eid_to AND rel_in_group1.eid_to=G.eid AND ((G.name=lulufanclub) OR (G.name=managers)))'''),
+     '''SELECT X.cw_eid
+FROM cw_Personne AS X
+WHERE X.cw_prenom=lulu AND EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, in_group_relation AS rel_in_group1, cw_EGroup AS G WHERE rel_owned_by0.eid_from=X.cw_eid AND rel_in_group1.eid_from=rel_owned_by0.eid_to AND rel_in_group1.eid_to=G.cw_eid AND ((G.cw_name=lulufanclub) OR (G.cw_name=managers)))'''),
 
     ("Any X WHERE X prenom 'lulu',"
      "NOT EXISTS(X owned_by U, U in_group G, G name 'lulufanclub' OR G name 'managers');",
-     '''SELECT X.eid
-FROM Personne AS X
-WHERE X.prenom=lulu AND NOT EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, in_group_relation AS rel_in_group1, EGroup AS G WHERE rel_owned_by0.eid_from=X.eid AND rel_in_group1.eid_from=rel_owned_by0.eid_to AND rel_in_group1.eid_to=G.eid AND ((G.name=lulufanclub) OR (G.name=managers)))'''),
+     '''SELECT X.cw_eid
+FROM cw_Personne AS X
+WHERE X.cw_prenom=lulu AND NOT EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, in_group_relation AS rel_in_group1, cw_EGroup AS G WHERE rel_owned_by0.eid_from=X.cw_eid AND rel_in_group1.eid_from=rel_owned_by0.eid_to AND rel_in_group1.eid_to=G.cw_eid AND ((G.cw_name=lulufanclub) OR (G.cw_name=managers)))'''),
 ]
 
 ADVANCED= [
-    ('Any X WHERE X is ET, ET eid 2',
-     '''SELECT rel_is0.eid_from
-FROM is_relation AS rel_is0
-WHERE rel_is0.eid_to=2'''),
-
 
     ("Societe S WHERE S nom 'Logilab' OR S nom 'Caesium'",
-     '''SELECT S.eid
-FROM Societe AS S
-WHERE ((S.nom=Logilab) OR (S.nom=Caesium))'''),
+     '''SELECT S.cw_eid
+FROM cw_Societe AS S
+WHERE ((S.cw_nom=Logilab) OR (S.cw_nom=Caesium))'''),
     
     ('Any X WHERE X nom "toto", X eid IN (9700, 9710, 1045, 674)',
-    '''SELECT X.eid
-FROM Division AS X
-WHERE X.nom=toto AND X.eid IN(9700, 9710, 1045, 674)
+    '''SELECT X.cw_eid
+FROM cw_Division AS X
+WHERE X.cw_nom=toto AND X.cw_eid IN(9700, 9710, 1045, 674)
 UNION ALL
-SELECT X.eid
-FROM Personne AS X
-WHERE X.nom=toto AND X.eid IN(9700, 9710, 1045, 674)
+SELECT X.cw_eid
+FROM cw_Personne AS X
+WHERE X.cw_nom=toto AND X.cw_eid IN(9700, 9710, 1045, 674)
 UNION ALL
-SELECT X.eid
-FROM Societe AS X
-WHERE X.nom=toto AND X.eid IN(9700, 9710, 1045, 674)
+SELECT X.cw_eid
+FROM cw_Societe AS X
+WHERE X.cw_nom=toto AND X.cw_eid IN(9700, 9710, 1045, 674)
 UNION ALL
-SELECT X.eid
-FROM SubDivision AS X
-WHERE X.nom=toto AND X.eid IN(9700, 9710, 1045, 674)'''),
+SELECT X.cw_eid
+FROM cw_SubDivision AS X
+WHERE X.cw_nom=toto AND X.cw_eid IN(9700, 9710, 1045, 674)'''),
 
     ('Any Y, COUNT(N) GROUPBY Y WHERE Y evaluee N;',
      '''SELECT rel_evaluee0.eid_from, COUNT(rel_evaluee0.eid_to)
@@ -190,34 +185,34 @@
 GROUP BY rel_evaluee0.eid_from'''),
 
     ("Any X WHERE X concerne B or C concerne X",
-     '''SELECT X.eid
-FROM Affaire AS X, concerne_relation AS rel_concerne0, concerne_relation AS rel_concerne1
-WHERE ((rel_concerne0.eid_from=X.eid) OR (rel_concerne1.eid_to=X.eid))'''),
+     '''SELECT X.cw_eid
+FROM concerne_relation AS rel_concerne0, concerne_relation AS rel_concerne1, cw_Affaire AS X
+WHERE ((rel_concerne0.eid_from=X.cw_eid) OR (rel_concerne1.eid_to=X.cw_eid))'''),
 
     ("Any X WHERE X travaille S or X concerne A",
-     '''SELECT X.eid
-FROM Personne AS X, concerne_relation AS rel_concerne1, travaille_relation AS rel_travaille0
-WHERE ((rel_travaille0.eid_from=X.eid) OR (rel_concerne1.eid_from=X.eid))'''),
+     '''SELECT X.cw_eid
+FROM concerne_relation AS rel_concerne1, cw_Personne AS X, travaille_relation AS rel_travaille0
+WHERE ((rel_travaille0.eid_from=X.cw_eid) OR (rel_concerne1.eid_from=X.cw_eid))'''),
 
     ("Any N WHERE A evaluee N or N ecrit_par P",
-     '''SELECT N.eid
-FROM Note AS N, evaluee_relation AS rel_evaluee0
-WHERE ((rel_evaluee0.eid_to=N.eid) OR (N.ecrit_par IS NOT NULL))'''),
+     '''SELECT N.cw_eid
+FROM cw_Note AS N, evaluee_relation AS rel_evaluee0
+WHERE ((rel_evaluee0.eid_to=N.cw_eid) OR (N.cw_ecrit_par IS NOT NULL))'''),
 
     ("Any N WHERE A evaluee N or EXISTS(N todo_by U)",
-     '''SELECT N.eid
-FROM Note AS N, evaluee_relation AS rel_evaluee0
-WHERE ((rel_evaluee0.eid_to=N.eid) OR (EXISTS(SELECT 1 FROM todo_by_relation AS rel_todo_by1 WHERE rel_todo_by1.eid_from=N.eid)))'''),
+     '''SELECT N.cw_eid
+FROM cw_Note AS N, evaluee_relation AS rel_evaluee0
+WHERE ((rel_evaluee0.eid_to=N.cw_eid) OR (EXISTS(SELECT 1 FROM todo_by_relation AS rel_todo_by1 WHERE rel_todo_by1.eid_from=N.cw_eid)))'''),
 
     ("Any N WHERE A evaluee N or N todo_by U",
-     '''SELECT N.eid
-FROM Note AS N, evaluee_relation AS rel_evaluee0, todo_by_relation AS rel_todo_by1
-WHERE ((rel_evaluee0.eid_to=N.eid) OR (rel_todo_by1.eid_from=N.eid))'''),
+     '''SELECT N.cw_eid
+FROM cw_Note AS N, evaluee_relation AS rel_evaluee0, todo_by_relation AS rel_todo_by1
+WHERE ((rel_evaluee0.eid_to=N.cw_eid) OR (rel_todo_by1.eid_from=N.cw_eid))'''),
     
     ("Any X WHERE X concerne B or C concerne X, B eid 12, C eid 13",
-     '''SELECT X.eid
-FROM Affaire AS X, concerne_relation AS rel_concerne0, concerne_relation AS rel_concerne1
-WHERE ((rel_concerne0.eid_from=X.eid AND rel_concerne0.eid_to=12) OR (rel_concerne1.eid_from=13 AND rel_concerne1.eid_to=X.eid))'''),
+     '''SELECT X.cw_eid
+FROM concerne_relation AS rel_concerne0, concerne_relation AS rel_concerne1, cw_Affaire AS X
+WHERE ((rel_concerne0.eid_from=X.cw_eid AND rel_concerne0.eid_to=12) OR (rel_concerne1.eid_from=13 AND rel_concerne1.eid_to=X.cw_eid))'''),
 
     ('Any X WHERE X created_by U, X concerne B OR C concerne X, B eid 12, C eid 13',
      '''SELECT rel_created_by0.eid_from
@@ -225,9 +220,9 @@
 WHERE ((rel_concerne1.eid_from=rel_created_by0.eid_from AND rel_concerne1.eid_to=12) OR (rel_concerne2.eid_from=13 AND rel_concerne2.eid_to=rel_created_by0.eid_from))'''),
 
     ('Any P WHERE P travaille_subdivision S1 OR P travaille_subdivision S2, S1 nom "logilab", S2 nom "caesium"',
-     '''SELECT P.eid
-FROM Personne AS P, SubDivision AS S1, SubDivision AS S2, travaille_subdivision_relation AS rel_travaille_subdivision0, travaille_subdivision_relation AS rel_travaille_subdivision1
-WHERE ((rel_travaille_subdivision0.eid_from=P.eid AND rel_travaille_subdivision0.eid_to=S1.eid) OR (rel_travaille_subdivision1.eid_from=P.eid AND rel_travaille_subdivision1.eid_to=S2.eid)) AND S1.nom=logilab AND S2.nom=caesium'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P, cw_SubDivision AS S1, cw_SubDivision AS S2, travaille_subdivision_relation AS rel_travaille_subdivision0, travaille_subdivision_relation AS rel_travaille_subdivision1
+WHERE ((rel_travaille_subdivision0.eid_from=P.cw_eid AND rel_travaille_subdivision0.eid_to=S1.cw_eid) OR (rel_travaille_subdivision1.eid_from=P.cw_eid AND rel_travaille_subdivision1.eid_to=S2.cw_eid)) AND S1.cw_nom=logilab AND S2.cw_nom=caesium'''),
 
     ('Any X WHERE T tags X',
      '''SELECT rel_tags0.eid_to
@@ -239,31 +234,31 @@
 WHERE rel_in_basket0.eid_to=12'''),
     
     ('Any SEN,RN,OEN WHERE X from_entity SE, SE eid 44, X relation_type R, R eid 139, X to_entity OE, OE eid 42, R name RN, SE name SEN, OE name OEN',
-     '''SELECT SE.name, R.name, OE.name
-FROM EEType AS OE, EEType AS SE, EFRDef AS X, ERType AS R
-WHERE X.from_entity=44 AND SE.eid=44 AND X.relation_type=139 AND R.eid=139 AND X.to_entity=42 AND OE.eid=42
+     '''SELECT SE.cw_name, R.cw_name, OE.cw_name
+FROM cw_EEType AS OE, cw_EEType AS SE, cw_EFRDef AS X, cw_ERType AS R
+WHERE X.cw_from_entity=44 AND SE.cw_eid=44 AND X.cw_relation_type=139 AND R.cw_eid=139 AND X.cw_to_entity=42 AND OE.cw_eid=42
 UNION ALL
-SELECT SE.name, R.name, OE.name
-FROM EEType AS OE, EEType AS SE, ENFRDef AS X, ERType AS R
-WHERE X.from_entity=44 AND SE.eid=44 AND X.relation_type=139 AND R.eid=139 AND X.to_entity=42 AND OE.eid=42'''),
+SELECT SE.cw_name, R.cw_name, OE.cw_name
+FROM cw_EEType AS OE, cw_EEType AS SE, cw_ENFRDef AS X, cw_ERType AS R
+WHERE X.cw_from_entity=44 AND SE.cw_eid=44 AND X.cw_relation_type=139 AND R.cw_eid=139 AND X.cw_to_entity=42 AND OE.cw_eid=42'''),
 
     # Any O WHERE NOT S corrected_in O, S eid %(x)s, S concerns P, O version_of P, O in_state ST, NOT ST name "published", O modification_date MTIME ORDERBY MTIME DESC LIMIT 9
     ('Any O WHERE NOT S ecrit_par O, S eid 1, S inline1 P, O inline2 P',
-     '''SELECT DISTINCT O.eid
-FROM Note AS S, Personne AS O
-WHERE (S.ecrit_par IS NULL OR S.ecrit_par!=O.eid) AND S.eid=1 AND O.inline2=S.inline1'''),
+     '''SELECT DISTINCT O.cw_eid
+FROM cw_Note AS S, cw_Personne AS O
+WHERE (S.cw_ecrit_par IS NULL OR S.cw_ecrit_par!=O.cw_eid) AND S.cw_eid=1 AND O.cw_inline2=S.cw_inline1'''),
 
     ('DISTINCT Any S ORDERBY stockproc(SI) WHERE NOT S ecrit_par O, S para SI',
-     '''SELECT T1.C0 FROM (SELECT DISTINCT S.eid AS C0, STOCKPROC(S.para) AS C1
-FROM Note AS S
-WHERE S.ecrit_par IS NULL
+     '''SELECT T1.C0 FROM (SELECT DISTINCT S.cw_eid AS C0, STOCKPROC(S.cw_para) AS C1
+FROM cw_Note AS S
+WHERE S.cw_ecrit_par IS NULL
 ORDER BY 2) AS T1'''),
 
     ('Any N WHERE N todo_by U, N is Note, U eid 2, N filed_under T, T eid 3',
      # N would actually be invarient if U eid 2 had given a specific type to U
-     '''SELECT N.eid
-FROM Note AS N, filed_under_relation AS rel_filed_under1, todo_by_relation AS rel_todo_by0
-WHERE rel_todo_by0.eid_from=N.eid AND rel_todo_by0.eid_to=2 AND rel_filed_under1.eid_from=N.eid AND rel_filed_under1.eid_to=3'''),
+     '''SELECT N.cw_eid
+FROM cw_Note AS N, filed_under_relation AS rel_filed_under1, todo_by_relation AS rel_todo_by0
+WHERE rel_todo_by0.eid_from=N.cw_eid AND rel_todo_by0.eid_to=2 AND rel_filed_under1.eid_from=N.cw_eid AND rel_filed_under1.eid_to=3'''),
 
     ('Any N WHERE N todo_by U, U eid 2, P evaluee N, P eid 3',
      '''SELECT rel_evaluee1.eid_to
@@ -277,103 +272,103 @@
 WHERE rel_owned_by0.eid_from=1 AND NOT EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by1 WHERE rel_owned_by1.eid_from=2 AND rel_owned_by0.eid_to=rel_owned_by1.eid_to)'''),
 
     ('Any GN WHERE X in_group G, G name GN, (G name "managers" OR EXISTS(X copain T, T login in ("comme", "cochon")))',
-     '''SELECT G.name
-FROM EGroup AS G, in_group_relation AS rel_in_group0
-WHERE rel_in_group0.eid_to=G.eid AND ((G.name=managers) OR (EXISTS(SELECT 1 FROM copain_relation AS rel_copain1, EUser AS T WHERE rel_copain1.eid_from=rel_in_group0.eid_from AND rel_copain1.eid_to=T.eid AND T.login IN(comme, cochon))))'''),
+     '''SELECT G.cw_name
+FROM cw_EGroup AS G, in_group_relation AS rel_in_group0
+WHERE rel_in_group0.eid_to=G.cw_eid AND ((G.cw_name=managers) OR (EXISTS(SELECT 1 FROM copain_relation AS rel_copain1, cw_EUser AS T WHERE rel_copain1.eid_from=rel_in_group0.eid_from AND rel_copain1.eid_to=T.cw_eid AND T.cw_login IN(comme, cochon))))'''),
 
     ('Any C WHERE C is Card, EXISTS(X documented_by C)',
-      """SELECT C.eid
-FROM Card AS C
-WHERE EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by0 WHERE rel_documented_by0.eid_to=C.eid)"""),
+      """SELECT C.cw_eid
+FROM cw_Card AS C
+WHERE EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by0 WHERE rel_documented_by0.eid_to=C.cw_eid)"""),
     
     ('Any C WHERE C is Card, EXISTS(X documented_by C, X eid 12)',
-      """SELECT C.eid
-FROM Card AS C
-WHERE EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by0 WHERE rel_documented_by0.eid_from=12 AND rel_documented_by0.eid_to=C.eid)"""),
+      """SELECT C.cw_eid
+FROM cw_Card AS C
+WHERE EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by0 WHERE rel_documented_by0.eid_from=12 AND rel_documented_by0.eid_to=C.cw_eid)"""),
 
     ('Any T WHERE C is Card, C title T, EXISTS(X documented_by C, X eid 12)',
-      """SELECT C.title
-FROM Card AS C
-WHERE EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by0 WHERE rel_documented_by0.eid_from=12 AND rel_documented_by0.eid_to=C.eid)"""),
+      """SELECT C.cw_title
+FROM cw_Card AS C
+WHERE EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by0 WHERE rel_documented_by0.eid_from=12 AND rel_documented_by0.eid_to=C.cw_eid)"""),
 
     ('Any GN,L WHERE X in_group G, X login L, G name GN, EXISTS(X copain T, T login L, T login IN("comme", "cochon"))',
-     '''SELECT G.name, X.login
-FROM EGroup AS G, EUser AS X, in_group_relation AS rel_in_group0
-WHERE rel_in_group0.eid_from=X.eid AND rel_in_group0.eid_to=G.eid AND EXISTS(SELECT 1 FROM copain_relation AS rel_copain1, EUser AS T WHERE rel_copain1.eid_from=X.eid AND rel_copain1.eid_to=T.eid AND T.login=X.login AND T.login IN(comme, cochon))'''),
+     '''SELECT G.cw_name, X.cw_login
+FROM cw_EGroup AS G, cw_EUser AS X, in_group_relation AS rel_in_group0
+WHERE rel_in_group0.eid_from=X.cw_eid AND rel_in_group0.eid_to=G.cw_eid AND EXISTS(SELECT 1 FROM copain_relation AS rel_copain1, cw_EUser AS T WHERE rel_copain1.eid_from=X.cw_eid AND rel_copain1.eid_to=T.cw_eid AND T.cw_login=X.cw_login AND T.cw_login IN(comme, cochon))'''),
 
     ('Any X,S, MAX(T) GROUPBY X,S ORDERBY S WHERE X is EUser, T tags X, S eid IN(32), X in_state S',
-     '''SELECT X.eid, 32, MAX(rel_tags0.eid_from)
-FROM EUser AS X, tags_relation AS rel_tags0
-WHERE rel_tags0.eid_to=X.eid AND X.in_state=32
-GROUP BY X.eid'''),
+     '''SELECT X.cw_eid, 32, MAX(rel_tags0.eid_from)
+FROM cw_EUser AS X, tags_relation AS rel_tags0
+WHERE rel_tags0.eid_to=X.cw_eid AND X.cw_in_state=32
+GROUP BY X.cw_eid'''),
 
     ('Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 WHERE S is Affaire, C is Societe, S concerne C, C nom CS, (EXISTS(S owned_by 1)) OR (EXISTS(S documented_by N, N title "published"))',
-     '''SELECT COUNT(rel_concerne0.eid_from), C.nom
-FROM Societe AS C, concerne_relation AS rel_concerne0
-WHERE rel_concerne0.eid_to=C.eid AND ((EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by1 WHERE rel_concerne0.eid_from=rel_owned_by1.eid_from AND rel_owned_by1.eid_to=1)) OR (EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by2, Card AS N WHERE rel_concerne0.eid_from=rel_documented_by2.eid_from AND rel_documented_by2.eid_to=N.eid AND N.title=published)))
-GROUP BY C.nom
+     '''SELECT COUNT(rel_concerne0.eid_from), C.cw_nom
+FROM concerne_relation AS rel_concerne0, cw_Societe AS C
+WHERE rel_concerne0.eid_to=C.cw_eid AND ((EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by1 WHERE rel_concerne0.eid_from=rel_owned_by1.eid_from AND rel_owned_by1.eid_to=1)) OR (EXISTS(SELECT 1 FROM documented_by_relation AS rel_documented_by2, cw_Card AS N WHERE rel_concerne0.eid_from=rel_documented_by2.eid_from AND rel_documented_by2.eid_to=N.cw_eid AND N.cw_title=published)))
+GROUP BY C.cw_nom
 ORDER BY 1 DESC
 LIMIT 10'''),
 
     ('Any X WHERE Y evaluee X, Y is EUser',
      '''SELECT rel_evaluee0.eid_to
-FROM EUser AS Y, evaluee_relation AS rel_evaluee0
-WHERE rel_evaluee0.eid_from=Y.eid'''),
+FROM cw_EUser AS Y, evaluee_relation AS rel_evaluee0
+WHERE rel_evaluee0.eid_from=Y.cw_eid'''),
 
     ('Any L WHERE X login "admin", X identity Y, Y login L',
-     '''SELECT Y.login
-FROM EUser AS X, EUser AS Y
-WHERE X.login=admin AND X.eid=Y.eid'''),
+     '''SELECT Y.cw_login
+FROM cw_EUser AS X, cw_EUser AS Y
+WHERE X.cw_login=admin AND X.cw_eid=Y.cw_eid'''),
 
     ('Any L WHERE X login "admin", NOT X identity Y, Y login L',
-     '''SELECT Y.login
-FROM EUser AS X, EUser AS Y
-WHERE X.login=admin AND NOT X.eid=Y.eid'''),
+     '''SELECT Y.cw_login
+FROM cw_EUser AS X, cw_EUser AS Y
+WHERE X.cw_login=admin AND NOT X.cw_eid=Y.cw_eid'''),
     
     ('Any L WHERE X login "admin", X identity Y?, Y login L',
-     '''SELECT Y.login
-FROM EUser AS X LEFT OUTER JOIN EUser AS Y ON (X.eid=Y.eid)
-WHERE X.login=admin'''),
+     '''SELECT Y.cw_login
+FROM cw_EUser AS X LEFT OUTER JOIN cw_EUser AS Y ON (X.cw_eid=Y.cw_eid)
+WHERE X.cw_login=admin'''),
 
     ('Any XN ORDERBY XN WHERE X name XN',
-     '''SELECT X.name
-FROM Basket AS X
+     '''SELECT X.cw_name
+FROM cw_Basket AS X
 UNION ALL
-SELECT X.name
-FROM ECache AS X
+SELECT X.cw_name
+FROM cw_ECache AS X
 UNION ALL
-SELECT X.name
-FROM EConstraintType AS X
+SELECT X.cw_name
+FROM cw_EConstraintType AS X
 UNION ALL
-SELECT X.name
-FROM EEType AS X
+SELECT X.cw_name
+FROM cw_EEType AS X
 UNION ALL
-SELECT X.name
-FROM EGroup AS X
+SELECT X.cw_name
+FROM cw_EGroup AS X
 UNION ALL
-SELECT X.name
-FROM EPermission AS X
+SELECT X.cw_name
+FROM cw_EPermission AS X
 UNION ALL
-SELECT X.name
-FROM ERType AS X
+SELECT X.cw_name
+FROM cw_ERType AS X
 UNION ALL
-SELECT X.name
-FROM File AS X
+SELECT X.cw_name
+FROM cw_File AS X
 UNION ALL
-SELECT X.name
-FROM Folder AS X
+SELECT X.cw_name
+FROM cw_Folder AS X
 UNION ALL
-SELECT X.name
-FROM Image AS X
+SELECT X.cw_name
+FROM cw_Image AS X
 UNION ALL
-SELECT X.name
-FROM State AS X
+SELECT X.cw_name
+FROM cw_State AS X
 UNION ALL
-SELECT X.name
-FROM Tag AS X
+SELECT X.cw_name
+FROM cw_Tag AS X
 UNION ALL
-SELECT X.name
-FROM Transition AS X
+SELECT X.cw_name
+FROM cw_Transition AS X
 ORDER BY 1'''),
 
 #    ('Any XN WHERE X name XN GROUPBY XN',
@@ -383,180 +378,180 @@
 
     # DISTINCT, can use relatin under exists scope as principal
     ('DISTINCT Any X,Y WHERE X name "EGroup", Y eid IN(1, 2, 3), EXISTS(X read_permission Y)',
-     '''SELECT DISTINCT X.eid, rel_read_permission0.eid_to
-FROM EEType AS X, read_permission_relation AS rel_read_permission0
-WHERE X.name=EGroup AND rel_read_permission0.eid_to IN(1, 2, 3) AND EXISTS(SELECT 1 WHERE rel_read_permission0.eid_from=X.eid)
+     '''SELECT DISTINCT X.cw_eid, rel_read_permission0.eid_to
+FROM cw_EEType AS X, read_permission_relation AS rel_read_permission0
+WHERE X.cw_name=EGroup AND rel_read_permission0.eid_to IN(1, 2, 3) AND EXISTS(SELECT 1 WHERE rel_read_permission0.eid_from=X.cw_eid)
 UNION
-SELECT DISTINCT X.eid, rel_read_permission0.eid_to
-FROM ERType AS X, read_permission_relation AS rel_read_permission0
-WHERE X.name=EGroup AND rel_read_permission0.eid_to IN(1, 2, 3) AND EXISTS(SELECT 1 WHERE rel_read_permission0.eid_from=X.eid)'''),
+SELECT DISTINCT X.cw_eid, rel_read_permission0.eid_to
+FROM cw_ERType AS X, read_permission_relation AS rel_read_permission0
+WHERE X.cw_name=EGroup AND rel_read_permission0.eid_to IN(1, 2, 3) AND EXISTS(SELECT 1 WHERE rel_read_permission0.eid_from=X.cw_eid)'''),
 
     # no distinct, Y can't be invariant
     ('Any X,Y WHERE X name "EGroup", Y eid IN(1, 2, 3), EXISTS(X read_permission Y)',
-     '''SELECT X.eid, Y.eid
-FROM EEType AS X, EGroup AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+     '''SELECT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_EGroup AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION ALL
-SELECT X.eid, Y.eid
-FROM EEType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION ALL
-SELECT X.eid, Y.eid
-FROM EGroup AS Y, ERType AS X
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT X.cw_eid, Y.cw_eid
+FROM cw_EGroup AS Y, cw_ERType AS X
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION ALL
-SELECT X.eid, Y.eid
-FROM ERType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)'''),
+SELECT X.cw_eid, Y.cw_eid
+FROM cw_ERType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)'''),
 
     # DISTINCT but NEGED exists, can't be invariant
     ('DISTINCT Any X,Y WHERE X name "EGroup", Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)',
-     '''SELECT DISTINCT X.eid, Y.eid
-FROM EEType AS X, EGroup AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+     '''SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_EGroup AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION
-SELECT DISTINCT X.eid, Y.eid
-FROM EEType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION
-SELECT DISTINCT X.eid, Y.eid
-FROM EGroup AS Y, ERType AS X
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_EGroup AS Y, cw_ERType AS X
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION
-SELECT DISTINCT X.eid, Y.eid
-FROM ERType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)'''),
+SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_ERType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)'''),
 
     # should generate the same query as above
     ('DISTINCT Any X,Y WHERE X name "EGroup", Y eid IN(1, 2, 3), NOT X read_permission Y',
-     '''SELECT DISTINCT X.eid, Y.eid
-FROM EEType AS X, EGroup AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+     '''SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_EGroup AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION
-SELECT DISTINCT X.eid, Y.eid
-FROM EEType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION
-SELECT DISTINCT X.eid, Y.eid
-FROM EGroup AS Y, ERType AS X
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_EGroup AS Y, cw_ERType AS X
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION
-SELECT DISTINCT X.eid, Y.eid
-FROM ERType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)'''),
+SELECT DISTINCT X.cw_eid, Y.cw_eid
+FROM cw_ERType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)'''),
     
     # neged relation, can't be inveriant
     ('Any X,Y WHERE X name "EGroup", Y eid IN(1, 2, 3), NOT X read_permission Y',
-     '''SELECT X.eid, Y.eid
-FROM EEType AS X, EGroup AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+     '''SELECT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_EGroup AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION ALL
-SELECT X.eid, Y.eid
-FROM EEType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT X.cw_eid, Y.cw_eid
+FROM cw_EEType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION ALL
-SELECT X.eid, Y.eid
-FROM EGroup AS Y, ERType AS X
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)
+SELECT X.cw_eid, Y.cw_eid
+FROM cw_EGroup AS Y, cw_ERType AS X
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)
 UNION ALL
-SELECT X.eid, Y.eid
-FROM ERType AS X, RQLExpression AS Y
-WHERE X.name=EGroup AND Y.eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.eid AND rel_read_permission0.eid_to=Y.eid)'''),
+SELECT X.cw_eid, Y.cw_eid
+FROM cw_ERType AS X, cw_RQLExpression AS Y
+WHERE X.cw_name=EGroup AND Y.cw_eid IN(1, 2, 3) AND NOT EXISTS(SELECT 1 FROM read_permission_relation AS rel_read_permission0 WHERE rel_read_permission0.eid_from=X.cw_eid AND rel_read_permission0.eid_to=Y.cw_eid)'''),
 
     ('Any MAX(X)+MIN(X), N GROUPBY N WHERE X name N;',
-     '''SELECT (MAX(T1.C0) + MIN(T1.C0)), T1.C1 FROM (SELECT X.eid AS C0, X.name AS C1
-FROM Basket AS X
+     '''SELECT (MAX(T1.C0) + MIN(T1.C0)), T1.C1 FROM (SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_Basket AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM ECache AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_ECache AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM EConstraintType AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_EConstraintType AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM EEType AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_EEType AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM EGroup AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_EGroup AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM EPermission AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_EPermission AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM ERType AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_ERType AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM File AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_File AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM Folder AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_Folder AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM Image AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_Image AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM State AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_State AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM Tag AS X
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_Tag AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM Transition AS X) AS T1
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_Transition AS X) AS T1
 GROUP BY T1.C1'''),
     
     ('Any MAX(X)+MIN(LENGTH(D)), N GROUPBY N ORDERBY 1, N, DF WHERE X name N, X data D, X data_format DF;',
-     '''SELECT (MAX(T1.C1) + MIN(LENGTH(T1.C0))), T1.C2 FROM (SELECT X.data AS C0, X.eid AS C1, X.name AS C2, X.data_format AS C3
-FROM File AS X
+     '''SELECT (MAX(T1.C1) + MIN(LENGTH(T1.C0))), T1.C2 FROM (SELECT X.cw_data AS C0, X.cw_eid AS C1, X.cw_name AS C2, X.cw_data_format AS C3
+FROM cw_File AS X
 UNION ALL
-SELECT X.data AS C0, X.eid AS C1, X.name AS C2, X.data_format AS C3
-FROM Image AS X) AS T1
+SELECT X.cw_data AS C0, X.cw_eid AS C1, X.cw_name AS C2, X.cw_data_format AS C3
+FROM cw_Image AS X) AS T1
 GROUP BY T1.C2
 ORDER BY 1,2,T1.C3'''),
 
     ('DISTINCT Any S ORDERBY R WHERE A is Affaire, A sujet S, A ref R',
-     '''SELECT T1.C0 FROM (SELECT DISTINCT A.sujet AS C0, A.ref AS C1
-FROM Affaire AS A
+     '''SELECT T1.C0 FROM (SELECT DISTINCT A.cw_sujet AS C0, A.cw_ref AS C1
+FROM cw_Affaire AS A
 ORDER BY 2) AS T1'''),
     
     ('DISTINCT Any MAX(X)+MIN(LENGTH(D)), N GROUPBY N ORDERBY 2, DF WHERE X name N, X data D, X data_format DF;',
-     '''SELECT T1.C0,T1.C1 FROM (SELECT DISTINCT (MAX(T1.C1) + MIN(LENGTH(T1.C0))) AS C0, T1.C2 AS C1, T1.C3 AS C2 FROM (SELECT DISTINCT X.data AS C0, X.eid AS C1, X.name AS C2, X.data_format AS C3
-FROM File AS X
+     '''SELECT T1.C0,T1.C1 FROM (SELECT DISTINCT (MAX(T1.C1) + MIN(LENGTH(T1.C0))) AS C0, T1.C2 AS C1, T1.C3 AS C2 FROM (SELECT DISTINCT X.cw_data AS C0, X.cw_eid AS C1, X.cw_name AS C2, X.cw_data_format AS C3
+FROM cw_File AS X
 UNION
-SELECT DISTINCT X.data AS C0, X.eid AS C1, X.name AS C2, X.data_format AS C3
-FROM Image AS X) AS T1
+SELECT DISTINCT X.cw_data AS C0, X.cw_eid AS C1, X.cw_name AS C2, X.cw_data_format AS C3
+FROM cw_Image AS X) AS T1
 GROUP BY T1.C2,T1.C3
 ORDER BY 2,3) AS T1
 '''),
 
     # ambiguity in EXISTS() -> should union the sub-query
     ('Any T WHERE T is Tag, NOT T name in ("t1", "t2"), EXISTS(T tags X, X is IN (EUser, EGroup))',
-     '''SELECT T.eid
-FROM Tag AS T
-WHERE NOT (T.name IN(t1, t2)) AND EXISTS(SELECT 1 FROM tags_relation AS rel_tags0, EGroup AS X WHERE rel_tags0.eid_from=T.eid AND rel_tags0.eid_to=X.eid UNION SELECT 1 FROM tags_relation AS rel_tags1, EUser AS X WHERE rel_tags1.eid_from=T.eid AND rel_tags1.eid_to=X.eid)'''),
+     '''SELECT T.cw_eid
+FROM cw_Tag AS T
+WHERE NOT (T.cw_name IN(t1, t2)) AND EXISTS(SELECT 1 FROM tags_relation AS rel_tags0, cw_EGroup AS X WHERE rel_tags0.eid_from=T.cw_eid AND rel_tags0.eid_to=X.cw_eid UNION SELECT 1 FROM tags_relation AS rel_tags1, cw_EUser AS X WHERE rel_tags1.eid_from=T.cw_eid AND rel_tags1.eid_to=X.cw_eid)'''),
 
     # must not use a relation in EXISTS scope to inline a variable 
     ('Any U WHERE U eid IN (1,2), EXISTS(X owned_by U)',
-     '''SELECT U.eid
-FROM EUser AS U
-WHERE U.eid IN(1, 2) AND EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0 WHERE rel_owned_by0.eid_to=U.eid)'''),
+     '''SELECT U.cw_eid
+FROM cw_EUser AS U
+WHERE U.cw_eid IN(1, 2) AND EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0 WHERE rel_owned_by0.eid_to=U.cw_eid)'''),
 
     ('Any U WHERE EXISTS(U eid IN (1,2), X owned_by U)',
-     '''SELECT U.eid
-FROM EUser AS U
-WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0 WHERE U.eid IN(1, 2) AND rel_owned_by0.eid_to=U.eid)'''),
+     '''SELECT U.cw_eid
+FROM cw_EUser AS U
+WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0 WHERE U.cw_eid IN(1, 2) AND rel_owned_by0.eid_to=U.cw_eid)'''),
 
     ('Any COUNT(U) WHERE EXISTS (P owned_by U, P is IN (Note, Affaire))',
-     '''SELECT COUNT(U.eid)
-FROM EUser AS U
-WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, Affaire AS P WHERE rel_owned_by0.eid_from=P.eid AND rel_owned_by0.eid_to=U.eid UNION SELECT 1 FROM owned_by_relation AS rel_owned_by1, Note AS P WHERE rel_owned_by1.eid_from=P.eid AND rel_owned_by1.eid_to=U.eid)'''),
+     '''SELECT COUNT(U.cw_eid)
+FROM cw_EUser AS U
+WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, cw_Affaire AS P WHERE rel_owned_by0.eid_from=P.cw_eid AND rel_owned_by0.eid_to=U.cw_eid UNION SELECT 1 FROM owned_by_relation AS rel_owned_by1, cw_Note AS P WHERE rel_owned_by1.eid_from=P.cw_eid AND rel_owned_by1.eid_to=U.cw_eid)'''),
 
     ('Any MAX(X)',
      '''SELECT MAX(X.eid)
 FROM entities AS X'''),
 
     ('Any MAX(X) WHERE X is Note',
-     '''SELECT MAX(X.eid)
-FROM Note AS X'''),
+     '''SELECT MAX(X.cw_eid)
+FROM cw_Note AS X'''),
     
     ('Any X WHERE X eid > 12',
      '''SELECT X.eid
@@ -569,17 +564,17 @@
 WHERE X.type='Note' AND X.eid>12"""),
     
     ('Any X, T WHERE X eid > 12, X title T',
-     """SELECT X.eid, X.title
-FROM Bookmark AS X
-WHERE X.eid>12
+     """SELECT X.cw_eid, X.cw_title
+FROM cw_Bookmark AS X
+WHERE X.cw_eid>12
 UNION ALL
-SELECT X.eid, X.title
-FROM Card AS X
-WHERE X.eid>12
+SELECT X.cw_eid, X.cw_title
+FROM cw_Card AS X
+WHERE X.cw_eid>12
 UNION ALL
-SELECT X.eid, X.title
-FROM EmailThread AS X
-WHERE X.eid>12"""),
+SELECT X.cw_eid, X.cw_title
+FROM cw_EmailThread AS X
+WHERE X.cw_eid>12"""),
 
     ('Any X',
      '''SELECT X.eid
@@ -589,11 +584,11 @@
      '''SELECT 12'''),
     
     ('Any X GROUPBY X ORDERBY Y WHERE X eid 12, X login Y',
-     '''SELECT X.eid
-FROM EUser AS X
-WHERE X.eid=12
-GROUP BY X.eid
-ORDER BY X.login'''),
+     '''SELECT X.cw_eid
+FROM cw_EUser AS X
+WHERE X.cw_eid=12
+GROUP BY X.cw_eid
+ORDER BY X.cw_login'''),
     
     ('Any U,COUNT(X) GROUPBY U WHERE U eid 12, X owned_by U HAVING COUNT(X) > 10',
      '''SELECT rel_owned_by0.eid_to, COUNT(rel_owned_by0.eid_from)
@@ -603,80 +598,80 @@
 HAVING COUNT(rel_owned_by0.eid_from)>10'''),
 
     ('DISTINCT Any X ORDERBY stockproc(X) WHERE U login X',
-     '''SELECT T1.C0 FROM (SELECT DISTINCT U.login AS C0, STOCKPROC(U.login) AS C1
-FROM EUser AS U
+     '''SELECT T1.C0 FROM (SELECT DISTINCT U.cw_login AS C0, STOCKPROC(U.cw_login) AS C1
+FROM cw_EUser AS U
 ORDER BY 2) AS T1'''),
     
     ('DISTINCT Any X ORDERBY Y WHERE B bookmarked_by X, X login Y',
-     '''SELECT T1.C0 FROM (SELECT DISTINCT X.eid AS C0, X.login AS C1
-FROM EUser AS X, bookmarked_by_relation AS rel_bookmarked_by0
-WHERE rel_bookmarked_by0.eid_to=X.eid
+     '''SELECT T1.C0 FROM (SELECT DISTINCT X.cw_eid AS C0, X.cw_login AS C1
+FROM bookmarked_by_relation AS rel_bookmarked_by0, cw_EUser AS X
+WHERE rel_bookmarked_by0.eid_to=X.cw_eid
 ORDER BY 2) AS T1'''),
 
     ('DISTINCT Any X ORDERBY SN WHERE X in_state S, S name SN',
-     '''SELECT T1.C0 FROM (SELECT DISTINCT X.eid AS C0, S.name AS C1
-FROM Affaire AS X, State AS S
-WHERE X.in_state=S.eid
+     '''SELECT T1.C0 FROM (SELECT DISTINCT X.cw_eid AS C0, S.cw_name AS C1
+FROM cw_Affaire AS X, cw_State AS S
+WHERE X.cw_in_state=S.cw_eid
 UNION
-SELECT DISTINCT X.eid AS C0, S.name AS C1
-FROM EUser AS X, State AS S
-WHERE X.in_state=S.eid
+SELECT DISTINCT X.cw_eid AS C0, S.cw_name AS C1
+FROM cw_EUser AS X, cw_State AS S
+WHERE X.cw_in_state=S.cw_eid
 UNION
-SELECT DISTINCT X.eid AS C0, S.name AS C1
-FROM Note AS X, State AS S
-WHERE X.in_state=S.eid
+SELECT DISTINCT X.cw_eid AS C0, S.cw_name AS C1
+FROM cw_Note AS X, cw_State AS S
+WHERE X.cw_in_state=S.cw_eid
 ORDER BY 2) AS T1'''),
 
     ]
 
 MULTIPLE_SEL = [
     ("DISTINCT Any X,Y where P is Personne, P nom X , P prenom Y;",
-     '''SELECT DISTINCT P.nom, P.prenom
-FROM Personne AS P'''),
+     '''SELECT DISTINCT P.cw_nom, P.cw_prenom
+FROM cw_Personne AS P'''),
     ("Any X,Y where P is Personne, P nom X , P prenom Y, not P nom NULL;",
-     '''SELECT P.nom, P.prenom
-FROM Personne AS P
-WHERE NOT (P.nom IS NULL)'''),
+     '''SELECT P.cw_nom, P.cw_prenom
+FROM cw_Personne AS P
+WHERE NOT (P.cw_nom IS NULL)'''),
     ("Personne X,Y where X nom NX, Y nom NX, X eid XE, not Y eid XE",
-     '''SELECT X.eid, Y.eid
-FROM Personne AS X, Personne AS Y
-WHERE Y.nom=X.nom AND NOT (Y.eid=X.eid)''')
+     '''SELECT X.cw_eid, Y.cw_eid
+FROM cw_Personne AS X, cw_Personne AS Y
+WHERE Y.cw_nom=X.cw_nom AND NOT (Y.cw_eid=X.cw_eid)''')
     ]
 
 NEGATIONS = [
     ("Personne X WHERE NOT X evaluee Y;",
-     '''SELECT X.eid
-FROM Personne AS X
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=X.eid)'''),
+     '''SELECT X.cw_eid
+FROM cw_Personne AS X
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=X.cw_eid)'''),
     
     ("Note N WHERE NOT X evaluee N, X eid 0",
-     '''SELECT N.eid
-FROM Note AS N
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=0 AND rel_evaluee0.eid_to=N.eid)'''),
+     '''SELECT N.cw_eid
+FROM cw_Note AS N
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=0 AND rel_evaluee0.eid_to=N.cw_eid)'''),
     
     ('Any X WHERE NOT X travaille S, X is Personne',
-     '''SELECT X.eid
-FROM Personne AS X
-WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_from=X.eid)'''),
+     '''SELECT X.cw_eid
+FROM cw_Personne AS X
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_from=X.cw_eid)'''),
     
     ("Personne P where not P datenaiss TODAY",
-     '''SELECT P.eid
-FROM Personne AS P
-WHERE NOT (DATE(P.datenaiss)=CURRENT_DATE)'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE NOT (DATE(P.cw_datenaiss)=CURRENT_DATE)'''),
     
     ("Personne P where NOT P concerne A",
-     '''SELECT P.eid
-FROM Personne AS P
-WHERE NOT EXISTS(SELECT 1 FROM concerne_relation AS rel_concerne0 WHERE rel_concerne0.eid_from=P.eid)'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE NOT EXISTS(SELECT 1 FROM concerne_relation AS rel_concerne0 WHERE rel_concerne0.eid_from=P.cw_eid)'''),
     
     ("Affaire A where not P concerne A",
-     '''SELECT A.eid
-FROM Affaire AS A
-WHERE NOT EXISTS(SELECT 1 FROM concerne_relation AS rel_concerne0 WHERE rel_concerne0.eid_to=A.eid)'''),
+     '''SELECT A.cw_eid
+FROM cw_Affaire AS A
+WHERE NOT EXISTS(SELECT 1 FROM concerne_relation AS rel_concerne0 WHERE rel_concerne0.eid_to=A.cw_eid)'''),
     ("Personne P where not P concerne A, A sujet ~= 'TEST%'",
-     '''SELECT P.eid
-FROM Affaire AS A, Personne AS P
-WHERE NOT EXISTS(SELECT 1 FROM concerne_relation AS rel_concerne0 WHERE rel_concerne0.eid_from=P.eid AND rel_concerne0.eid_to=A.eid) AND A.sujet ILIKE TEST%'''),
+     '''SELECT P.cw_eid
+FROM cw_Affaire AS A, cw_Personne AS P
+WHERE NOT EXISTS(SELECT 1 FROM concerne_relation AS rel_concerne0 WHERE rel_concerne0.eid_from=P.cw_eid AND rel_concerne0.eid_to=A.cw_eid) AND A.cw_sujet ILIKE TEST%'''),
 
     ('Any S WHERE NOT T eid 28258, T tags S',
      '''SELECT rel_tags0.eid_to
@@ -684,17 +679,17 @@
 WHERE NOT (rel_tags0.eid_from=28258)'''),
     
     ('Any S WHERE T is Tag, T name TN, NOT T eid 28258, T tags S, S name SN',
-     '''SELECT S.eid
-FROM EGroup AS S, Tag AS T, tags_relation AS rel_tags0
-WHERE NOT (T.eid=28258) AND rel_tags0.eid_from=T.eid AND rel_tags0.eid_to=S.eid
+     '''SELECT S.cw_eid
+FROM cw_EGroup AS S, cw_Tag AS T, tags_relation AS rel_tags0
+WHERE NOT (T.cw_eid=28258) AND rel_tags0.eid_from=T.cw_eid AND rel_tags0.eid_to=S.cw_eid
 UNION ALL
-SELECT S.eid
-FROM State AS S, Tag AS T, tags_relation AS rel_tags0
-WHERE NOT (T.eid=28258) AND rel_tags0.eid_from=T.eid AND rel_tags0.eid_to=S.eid
+SELECT S.cw_eid
+FROM cw_State AS S, cw_Tag AS T, tags_relation AS rel_tags0
+WHERE NOT (T.cw_eid=28258) AND rel_tags0.eid_from=T.cw_eid AND rel_tags0.eid_to=S.cw_eid
 UNION ALL
-SELECT S.eid
-FROM Tag AS S, Tag AS T, tags_relation AS rel_tags0
-WHERE NOT (T.eid=28258) AND rel_tags0.eid_from=T.eid AND rel_tags0.eid_to=S.eid'''),
+SELECT S.cw_eid
+FROM cw_Tag AS S, cw_Tag AS T, tags_relation AS rel_tags0
+WHERE NOT (T.cw_eid=28258) AND rel_tags0.eid_from=T.cw_eid AND rel_tags0.eid_to=S.cw_eid'''),
 
     
     ('Any X,Y WHERE X created_by Y, X eid 5, NOT Y eid 6',
@@ -703,260 +698,260 @@
 WHERE rel_created_by0.eid_from=5 AND NOT (rel_created_by0.eid_to=6)'''),
 
     ('Note X WHERE NOT Y evaluee X',
-     '''SELECT X.eid
-FROM Note AS X
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_to=X.eid)'''),
+     '''SELECT X.cw_eid
+FROM cw_Note AS X
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_to=X.cw_eid)'''),
 
     ('Any Y WHERE NOT Y evaluee X',
-     '''SELECT Y.eid
-FROM Division AS Y
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.eid)
+     '''SELECT Y.cw_eid
+FROM cw_Division AS Y
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.cw_eid)
 UNION ALL
-SELECT Y.eid
-FROM EUser AS Y
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.eid)
+SELECT Y.cw_eid
+FROM cw_EUser AS Y
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.cw_eid)
 UNION ALL
-SELECT Y.eid
-FROM Personne AS Y
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.eid)
+SELECT Y.cw_eid
+FROM cw_Personne AS Y
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.cw_eid)
 UNION ALL
-SELECT Y.eid
-FROM Societe AS Y
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.eid)
+SELECT Y.cw_eid
+FROM cw_Societe AS Y
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.cw_eid)
 UNION ALL
-SELECT Y.eid
-FROM SubDivision AS Y
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.eid)'''),
+SELECT Y.cw_eid
+FROM cw_SubDivision AS Y
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0 WHERE rel_evaluee0.eid_from=Y.cw_eid)'''),
 
     ('Any X WHERE NOT Y evaluee X, Y is EUser',
-     '''SELECT X.eid
-FROM Note AS X
-WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0,EUser AS Y WHERE rel_evaluee0.eid_from=Y.eid AND rel_evaluee0.eid_to=X.eid)'''),
+     '''SELECT X.cw_eid
+FROM cw_Note AS X
+WHERE NOT EXISTS(SELECT 1 FROM evaluee_relation AS rel_evaluee0,cw_EUser AS Y WHERE rel_evaluee0.eid_from=Y.cw_eid AND rel_evaluee0.eid_to=X.cw_eid)'''),
     
     ('Any X,T WHERE X title T, NOT X is Bookmark',
-     '''SELECT DISTINCT X.eid, X.title
-FROM Card AS X
+     '''SELECT DISTINCT X.cw_eid, X.cw_title
+FROM cw_Card AS X
 UNION
-SELECT DISTINCT X.eid, X.title
-FROM EmailThread AS X'''),
+SELECT DISTINCT X.cw_eid, X.cw_title
+FROM cw_EmailThread AS X'''),
 
     ('Any K,V WHERE P is EProperty, P pkey K, P value V, NOT P for_user U',
-     '''SELECT DISTINCT P.pkey, P.value
-FROM EProperty AS P
-WHERE P.for_user IS NULL'''),
+     '''SELECT DISTINCT P.cw_pkey, P.cw_value
+FROM cw_EProperty AS P
+WHERE P.cw_for_user IS NULL'''),
 
     ('Any S WHERE NOT X in_state S, X is IN(Affaire, EUser)',
-     '''SELECT DISTINCT S.eid
-FROM Affaire AS X, State AS S
-WHERE (X.in_state IS NULL OR X.in_state!=S.eid)
+     '''SELECT DISTINCT S.cw_eid
+FROM cw_Affaire AS X, cw_State AS S
+WHERE (X.cw_in_state IS NULL OR X.cw_in_state!=S.cw_eid)
 INTERSECT
-SELECT DISTINCT S.eid
-FROM EUser AS X, State AS S
-WHERE (X.in_state IS NULL OR X.in_state!=S.eid)'''),
+SELECT DISTINCT S.cw_eid
+FROM cw_EUser AS X, cw_State AS S
+WHERE (X.cw_in_state IS NULL OR X.cw_in_state!=S.cw_eid)'''),
     ]
 
 OUTER_JOIN = [
     ('Any X,S WHERE X travaille S?',
-     '''SELECT X.eid, rel_travaille0.eid_to
-FROM Personne AS X LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=X.eid)'''
-#SELECT X.eid, S.eid
-#FROM Personne AS X LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=X.eid) LEFT OUTER JOIN Societe AS S ON (rel_travaille0.eid_to=S.eid)'''
+     '''SELECT X.cw_eid, rel_travaille0.eid_to
+FROM cw_Personne AS X LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=X.cw_eid)'''
+#SELECT X.cw_eid, S.cw_eid
+#FROM cw_Personne AS X LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=X.cw_eid) LEFT OUTER JOIN cw_Societe AS S ON (rel_travaille0.eid_to=S.cw_eid)'''
     ),
     ('Any S,X WHERE X? travaille S, S is Societe',
-     '''SELECT S.eid, rel_travaille0.eid_from
-FROM Societe AS S LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_to=S.eid)'''
-#SELECT S.eid, X.eid
-#FROM Societe AS S LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_to=S.eid) LEFT OUTER JOIN Personne AS X ON (rel_travaille0.eid_from=X.eid)'''
+     '''SELECT S.cw_eid, rel_travaille0.eid_from
+FROM cw_Societe AS S LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_to=S.cw_eid)'''
+#SELECT S.cw_eid, X.cw_eid
+#FROM cw_Societe AS S LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_to=S.cw_eid) LEFT OUTER JOIN cw_Personne AS X ON (rel_travaille0.eid_from=X.cw_eid)'''
     ),
 
     ('Any N,A WHERE N inline1 A?',
-     '''SELECT N.eid, N.inline1
-FROM Note AS N'''),
+     '''SELECT N.cw_eid, N.cw_inline1
+FROM cw_Note AS N'''),
 
     ('Any SN WHERE X from_state S?, S name SN',
-     '''SELECT S.name
-FROM TrInfo AS X LEFT OUTER JOIN State AS S ON (X.from_state=S.eid)'''
+     '''SELECT S.cw_name
+FROM cw_TrInfo AS X LEFT OUTER JOIN cw_State AS S ON (X.cw_from_state=S.cw_eid)'''
     ),
 
     ('Any A,N WHERE N? inline1 A',
-     '''SELECT A.eid, N.eid
-FROM Affaire AS A LEFT OUTER JOIN Note AS N ON (N.inline1=A.eid)'''
+     '''SELECT A.cw_eid, N.cw_eid
+FROM cw_Affaire AS A LEFT OUTER JOIN cw_Note AS N ON (N.cw_inline1=A.cw_eid)'''
     ),
 
     ('Any A,B,C,D,E,F,G WHERE A eid 12,A creation_date B,A modification_date C,A comment D,A from_state E?,A to_state F?,A wf_info_for G?',
-    '''SELECT A.eid, A.creation_date, A.modification_date, A.comment, A.from_state, A.to_state, A.wf_info_for
-FROM TrInfo AS A
-WHERE A.eid=12'''),
+    '''SELECT A.cw_eid, A.cw_creation_date, A.cw_modification_date, A.cw_comment, A.cw_from_state, A.cw_to_state, A.cw_wf_info_for
+FROM cw_TrInfo AS A
+WHERE A.cw_eid=12'''),
 
     ('Any FS,TS,C,D,U ORDERBY D DESC WHERE WF wf_info_for X,WF from_state FS?, WF to_state TS, WF comment C,WF creation_date D, WF owned_by U, X eid 1',
-     '''SELECT WF.from_state, WF.to_state, WF.comment, WF.creation_date, rel_owned_by0.eid_to
-FROM TrInfo AS WF, owned_by_relation AS rel_owned_by0
-WHERE WF.wf_info_for=1 AND WF.to_state IS NOT NULL AND rel_owned_by0.eid_from=WF.eid
+     '''SELECT WF.cw_from_state, WF.cw_to_state, WF.cw_comment, WF.cw_creation_date, rel_owned_by0.eid_to
+FROM cw_TrInfo AS WF, owned_by_relation AS rel_owned_by0
+WHERE WF.cw_wf_info_for=1 AND WF.cw_to_state IS NOT NULL AND rel_owned_by0.eid_from=WF.cw_eid
 ORDER BY 4 DESC'''),
 
     ('Any X WHERE X is Affaire, S is Societe, EXISTS(X owned_by U OR (X concerne S?, S owned_by U))',
-     '''SELECT X.eid
-FROM Affaire AS X
-WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, EUser AS U, Affaire AS A LEFT OUTER JOIN concerne_relation AS rel_concerne1 ON (rel_concerne1.eid_from=A.eid) LEFT OUTER JOIN Societe AS S ON (rel_concerne1.eid_to=S.eid), owned_by_relation AS rel_owned_by2 WHERE ((rel_owned_by0.eid_from=A.eid AND rel_owned_by0.eid_to=U.eid) OR (rel_owned_by2.eid_from=S.eid AND rel_owned_by2.eid_to=U.eid)) AND X.eid=A.eid)'''),
+     '''SELECT X.cw_eid
+FROM cw_Affaire AS X
+WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, cw_EUser AS U, cw_Affaire AS A LEFT OUTER JOIN concerne_relation AS rel_concerne1 ON (rel_concerne1.eid_from=A.cw_eid) LEFT OUTER JOIN cw_Societe AS S ON (rel_concerne1.eid_to=S.cw_eid), owned_by_relation AS rel_owned_by2 WHERE ((rel_owned_by0.eid_from=A.cw_eid AND rel_owned_by0.eid_to=U.cw_eid) OR (rel_owned_by2.eid_from=S.cw_eid AND rel_owned_by2.eid_to=U.cw_eid)) AND X.cw_eid=A.cw_eid)'''),
 
     ('Any C,M WHERE C travaille G?, G evaluee M?, G is Societe',
-     '''SELECT C.eid, rel_evaluee1.eid_to
-FROM Personne AS C LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=C.eid) LEFT OUTER JOIN Societe AS G ON (rel_travaille0.eid_to=G.eid) LEFT OUTER JOIN evaluee_relation AS rel_evaluee1 ON (rel_evaluee1.eid_from=G.eid)'''
-#SELECT C.eid, M.eid
-#FROM Personne AS C LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=C.eid) LEFT OUTER JOIN Societe AS G ON (rel_travaille0.eid_to=G.eid) LEFT OUTER JOIN evaluee_relation AS rel_evaluee1 ON (rel_evaluee1.eid_from=G.eid) LEFT OUTER JOIN Note AS M ON (rel_evaluee1.eid_to=M.eid)'''
+     '''SELECT C.cw_eid, rel_evaluee1.eid_to
+FROM cw_Personne AS C LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=C.cw_eid) LEFT OUTER JOIN cw_Societe AS G ON (rel_travaille0.eid_to=G.cw_eid) LEFT OUTER JOIN evaluee_relation AS rel_evaluee1 ON (rel_evaluee1.eid_from=G.cw_eid)'''
+#SELECT C.cw_eid, M.cw_eid
+#FROM cw_Personne AS C LEFT OUTER JOIN travaille_relation AS rel_travaille0 ON (rel_travaille0.eid_from=C.cw_eid) LEFT OUTER JOIN cw_Societe AS G ON (rel_travaille0.eid_to=G.cw_eid) LEFT OUTER JOIN evaluee_relation AS rel_evaluee1 ON (rel_evaluee1.eid_from=G.cw_eid) LEFT OUTER JOIN cw_Note AS M ON (rel_evaluee1.eid_to=M.cw_eid)'''
      ),
 
     ('Any A,C WHERE A documented_by C?, (C is NULL) OR (EXISTS(C require_permission F, '
      'F name "read", F require_group E, U in_group E)), U eid 1',
-     '''SELECT A.eid, rel_documented_by0.eid_to
-FROM Affaire AS A LEFT OUTER JOIN documented_by_relation AS rel_documented_by0 ON (rel_documented_by0.eid_from=A.eid)
-WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.eid AND F.name=read AND rel_require_group2.eid_from=F.eid AND rel_in_group3.eid_from=1 AND rel_in_group3.eid_to=rel_require_group2.eid_to)))'''),
+     '''SELECT A.cw_eid, rel_documented_by0.eid_to
+FROM cw_Affaire AS A LEFT OUTER JOIN documented_by_relation AS rel_documented_by0 ON (rel_documented_by0.eid_from=A.cw_eid)
+WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, cw_EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.cw_eid AND F.cw_name=read AND rel_require_group2.eid_from=F.cw_eid AND rel_in_group3.eid_to=rel_require_group2.eid_to AND rel_in_group3.eid_from=1)))'''),
 
     ("Any X WHERE X eid 12, P? connait X",
-     '''SELECT X.eid
-FROM Personne AS X LEFT OUTER JOIN connait_relation AS rel_connait0 ON (rel_connait0.eid_to=12)
-WHERE X.eid=12'''
+     '''SELECT X.cw_eid
+FROM cw_Personne AS X LEFT OUTER JOIN connait_relation AS rel_connait0 ON (rel_connait0.eid_to=12)
+WHERE X.cw_eid=12'''
 #SELECT 12
-#FROM Personne AS X LEFT OUTER JOIN connait_relation AS rel_connait0 ON (rel_connait0.eid_to=12) LEFT OUTER JOIN Personne AS P ON (rel_connait0.eid_from=P.eid)
-#WHERE X.eid=12'''
+#FROM cw_Personne AS X LEFT OUTER JOIN connait_relation AS rel_connait0 ON (rel_connait0.eid_to=12) LEFT OUTER JOIN Personne AS P ON (rel_connait0.eid_from=P.cw_eid)
+#WHERE X.cw_eid=12'''
     ),
 
     ('Any GN, TN ORDERBY GN WHERE T tags G?, T name TN, G name GN',
-    '''SELECT _T0.C1, T.name
-FROM Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid) LEFT OUTER JOIN (SELECT G.eid AS C0, G.name AS C1
-FROM EGroup AS G
+    '''SELECT _T0.C1, T.cw_name
+FROM cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid) LEFT OUTER JOIN (SELECT G.cw_eid AS C0, G.cw_name AS C1
+FROM cw_EGroup AS G
 UNION ALL
-SELECT G.eid AS C0, G.name AS C1
-FROM State AS G
+SELECT G.cw_eid AS C0, G.cw_name AS C1
+FROM cw_State AS G
 UNION ALL
-SELECT G.eid AS C0, G.name AS C1
-FROM Tag AS G) AS _T0 ON (rel_tags0.eid_to=_T0.C0)
+SELECT G.cw_eid AS C0, G.cw_name AS C1
+FROM cw_Tag AS G) AS _T0 ON (rel_tags0.eid_to=_T0.C0)
 ORDER BY 1'''),
 
 
     # optional variable with additional restriction
     ('Any T,G WHERE T tags G?, G name "hop", G is EGroup',
-     '''SELECT T.eid, G.eid
-FROM Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid) LEFT OUTER JOIN EGroup AS G ON (rel_tags0.eid_to=G.eid AND G.name=hop)'''),
+     '''SELECT T.cw_eid, G.cw_eid
+FROM cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid) LEFT OUTER JOIN cw_EGroup AS G ON (rel_tags0.eid_to=G.cw_eid AND G.cw_name=hop)'''),
 
     # optional variable with additional invariant restriction
     ('Any T,G WHERE T tags G?, G eid 12',
-     '''SELECT T.eid, rel_tags0.eid_to
-FROM Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid AND rel_tags0.eid_to=12)'''),
+     '''SELECT T.cw_eid, rel_tags0.eid_to
+FROM cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid AND rel_tags0.eid_to=12)'''),
 
     # optional variable with additional restriction appearing before the relation
     ('Any T,G WHERE G name "hop", T tags G?, G is EGroup',
-     '''SELECT T.eid, G.eid
-FROM Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid) LEFT OUTER JOIN EGroup AS G ON (rel_tags0.eid_to=G.eid AND G.name=hop)'''),
+     '''SELECT T.cw_eid, G.cw_eid
+FROM cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid) LEFT OUTER JOIN cw_EGroup AS G ON (rel_tags0.eid_to=G.cw_eid AND G.cw_name=hop)'''),
 
     # optional variable with additional restriction on inlined relation
     # XXX the expected result should be as the query below. So what, raise BadRQLQuery ?
     ('Any T,G,S WHERE T tags G?, G in_state S, S name "hop", G is EUser',
-     '''SELECT T.eid, G.eid, S.eid
-FROM State AS S, Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid) LEFT OUTER JOIN EUser AS G ON (rel_tags0.eid_to=G.eid)
-WHERE G.in_state=S.eid AND S.name=hop
+     '''SELECT T.cw_eid, G.cw_eid, S.cw_eid
+FROM cw_State AS S, cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid) LEFT OUTER JOIN cw_EUser AS G ON (rel_tags0.eid_to=G.cw_eid)
+WHERE G.cw_in_state=S.cw_eid AND S.cw_name=hop
 '''),
 
     # optional variable with additional invariant restriction on an inlined relation
     ('Any T,G,S WHERE T tags G, G in_state S?, S eid 1, G is EUser',
-     '''SELECT rel_tags0.eid_from, G.eid, G.in_state
-FROM EUser AS G, tags_relation AS rel_tags0
-WHERE rel_tags0.eid_to=G.eid AND (G.in_state=1 OR G.in_state IS NULL)'''),
+     '''SELECT rel_tags0.eid_from, G.cw_eid, G.cw_in_state
+FROM cw_EUser AS G, tags_relation AS rel_tags0
+WHERE rel_tags0.eid_to=G.cw_eid AND (G.cw_in_state=1 OR G.cw_in_state IS NULL)'''),
 
     # two optional variables with additional invariant restriction on an inlined relation
     ('Any T,G,S WHERE T tags G?, G in_state S?, S eid 1, G is EUser',
-     '''SELECT T.eid, G.eid, G.in_state
-FROM Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid) LEFT OUTER JOIN EUser AS G ON (rel_tags0.eid_to=G.eid AND (G.in_state=1 OR G.in_state IS NULL))'''),
+     '''SELECT T.cw_eid, G.cw_eid, G.cw_in_state
+FROM cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid) LEFT OUTER JOIN cw_EUser AS G ON (rel_tags0.eid_to=G.cw_eid AND (G.cw_in_state=1 OR G.cw_in_state IS NULL))'''),
 
     # two optional variables with additional restriction on an inlined relation
     ('Any T,G,S WHERE T tags G?, G in_state S?, S name "hop", G is EUser',
-     '''SELECT T.eid, G.eid, S.eid
-FROM Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid) LEFT OUTER JOIN EUser AS G ON (rel_tags0.eid_to=G.eid) LEFT OUTER JOIN State AS S ON (G.in_state=S.eid AND S.name=hop)'''),
+     '''SELECT T.cw_eid, G.cw_eid, S.cw_eid
+FROM cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid) LEFT OUTER JOIN cw_EUser AS G ON (rel_tags0.eid_to=G.cw_eid) LEFT OUTER JOIN cw_State AS S ON (G.cw_in_state=S.cw_eid AND S.cw_name=hop)'''),
     
     # two optional variables with additional restriction on an ambigous inlined relation
     ('Any T,G,S WHERE T tags G?, G in_state S?, S name "hop"',
-     '''SELECT T.eid, _T0.C0, _T0.C1
-FROM Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.eid) LEFT OUTER JOIN (SELECT G.eid AS C0, S.eid AS C1
-FROM Affaire AS G LEFT OUTER JOIN State AS S ON (G.in_state=S.eid AND S.name=hop) 
+     '''SELECT T.cw_eid, _T0.C0, _T0.C1
+FROM cw_Tag AS T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_from=T.cw_eid) LEFT OUTER JOIN (SELECT G.cw_eid AS C0, S.cw_eid AS C1
+FROM cw_Affaire AS G LEFT OUTER JOIN cw_State AS S ON (G.cw_in_state=S.cw_eid AND S.cw_name=hop) 
 UNION ALL
-SELECT G.eid AS C0, S.eid AS C1
-FROM EUser AS G LEFT OUTER JOIN State AS S ON (G.in_state=S.eid AND S.name=hop) 
+SELECT G.cw_eid AS C0, S.cw_eid AS C1
+FROM cw_EUser AS G LEFT OUTER JOIN cw_State AS S ON (G.cw_in_state=S.cw_eid AND S.cw_name=hop) 
 UNION ALL
-SELECT G.eid AS C0, S.eid AS C1
-FROM Note AS G LEFT OUTER JOIN State AS S ON (G.in_state=S.eid AND S.name=hop) ) AS _T0 ON (rel_tags0.eid_to=_T0.C0)'''),
+SELECT G.cw_eid AS C0, S.cw_eid AS C1
+FROM cw_Note AS G LEFT OUTER JOIN cw_State AS S ON (G.cw_in_state=S.cw_eid AND S.cw_name=hop) ) AS _T0 ON (rel_tags0.eid_to=_T0.C0)'''),
 
     ]
 
 VIRTUAL_VARS = [
     ("Personne P WHERE P travaille S, S tel T, S fax T, S is Societe;",
      '''SELECT rel_travaille0.eid_from
-FROM Societe AS S, travaille_relation AS rel_travaille0
-WHERE rel_travaille0.eid_to=S.eid AND S.fax=S.tel'''),
+FROM cw_Societe AS S, travaille_relation AS rel_travaille0
+WHERE rel_travaille0.eid_to=S.cw_eid AND S.cw_fax=S.cw_tel'''),
     
     ("Personne P where X eid 0, X creation_date D, P datenaiss < D, X is Affaire",
-     '''SELECT P.eid
-FROM Affaire AS X, Personne AS P
-WHERE X.eid=0 AND P.datenaiss<X.creation_date'''),
+     '''SELECT P.cw_eid
+FROM cw_Affaire AS X, cw_Personne AS P
+WHERE X.cw_eid=0 AND P.cw_datenaiss<X.cw_creation_date'''),
 
     ("Any N,T WHERE N is Note, N type T;",
-     '''SELECT N.eid, N.type
-FROM Note AS N'''),
+     '''SELECT N.cw_eid, N.cw_type
+FROM cw_Note AS N'''),
 
     ("Personne P where X is Personne, X tel T, X fax F, P fax T+F",
-     '''SELECT P.eid
-FROM Personne AS P, Personne AS X
-WHERE P.fax=(X.tel + X.fax)'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P, cw_Personne AS X
+WHERE P.cw_fax=(X.cw_tel + X.cw_fax)'''),
 
     ("Personne P where X tel T, X fax F, P fax IN (T,F)",
-     '''SELECT P.eid
-FROM Division AS X, Personne AS P
-WHERE P.fax IN(X.tel, X.fax)
+     '''SELECT P.cw_eid
+FROM cw_Division AS X, cw_Personne AS P
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax)
 UNION ALL
-SELECT P.eid
-FROM Personne AS P, Personne AS X
-WHERE P.fax IN(X.tel, X.fax)
+SELECT P.cw_eid
+FROM cw_Personne AS P, cw_Personne AS X
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax)
 UNION ALL
-SELECT P.eid
-FROM Personne AS P, Societe AS X
-WHERE P.fax IN(X.tel, X.fax)
+SELECT P.cw_eid
+FROM cw_Personne AS P, cw_Societe AS X
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax)
 UNION ALL
-SELECT P.eid
-FROM Personne AS P, SubDivision AS X
-WHERE P.fax IN(X.tel, X.fax)'''),
+SELECT P.cw_eid
+FROM cw_Personne AS P, cw_SubDivision AS X
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax)'''),
 
     ("Personne P where X tel T, X fax F, P fax IN (T,F,0832542332)",
-     '''SELECT P.eid
-FROM Division AS X, Personne AS P
-WHERE P.fax IN(X.tel, X.fax, 832542332)
+     '''SELECT P.cw_eid
+FROM cw_Division AS X, cw_Personne AS P
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax, 832542332)
 UNION ALL
-SELECT P.eid
-FROM Personne AS P, Personne AS X
-WHERE P.fax IN(X.tel, X.fax, 832542332)
+SELECT P.cw_eid
+FROM cw_Personne AS P, cw_Personne AS X
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax, 832542332)
 UNION ALL
-SELECT P.eid
-FROM Personne AS P, Societe AS X
-WHERE P.fax IN(X.tel, X.fax, 832542332)
+SELECT P.cw_eid
+FROM cw_Personne AS P, cw_Societe AS X
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax, 832542332)
 UNION ALL
-SELECT P.eid
-FROM Personne AS P, SubDivision AS X
-WHERE P.fax IN(X.tel, X.fax, 832542332)'''),
+SELECT P.cw_eid
+FROM cw_Personne AS P, cw_SubDivision AS X
+WHERE P.cw_fax IN(X.cw_tel, X.cw_fax, 832542332)'''),
     ]
 
 FUNCS = [
     ("Any COUNT(P) WHERE P is Personne",
-     '''SELECT COUNT(P.eid)
-FROM Personne AS P'''),
+     '''SELECT COUNT(P.cw_eid)
+FROM cw_Personne AS P'''),
 ##     ("Personne X where X nom upper('TOTO')",
-##      '''SELECT X.eid\nFROM Personne AS X\nWHERE UPPER(X.nom) = TOTO'''),
+##      '''SELECT X.cw_eid\nFROM cw_Personne AS X\nWHERE UPPER(X.cw_nom) = TOTO'''),
 ##     ("Personne X where X nom Y, UPPER(X) prenom upper(Y)",
-##      '''SELECT X.eid\nFROM Personne AS X\nWHERE UPPER(X.prenom) = UPPER(X.nom)'''),
+##      '''SELECT X.cw_eid\nFROM cw_Personne AS X\nWHERE UPPER(X.cw_prenom) = UPPER(X.cw_nom)'''),
     ]
 
 SYMETRIC = [
     ('Any P WHERE X eid 0, X connait P',
-     '''SELECT DISTINCT P.eid
-FROM Personne AS P, connait_relation AS rel_connait0
-WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=P.eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=P.eid)'''
+     '''SELECT DISTINCT P.cw_eid
+FROM connait_relation AS rel_connait0, cw_Personne AS P
+WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=P.cw_eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=P.cw_eid)'''
 #      '''SELECT rel_connait0.eid_to
 # FROM connait_relation AS rel_connait0
 # WHERE rel_connait0.eid_from=0
@@ -967,104 +962,154 @@
      ),
     
     ('Any P WHERE X connait P',
-    '''SELECT DISTINCT P.eid
-FROM Personne AS P, connait_relation AS rel_connait0
-WHERE (rel_connait0.eid_to=P.eid OR rel_connait0.eid_from=P.eid)'''
+    '''SELECT DISTINCT P.cw_eid
+FROM connait_relation AS rel_connait0, cw_Personne AS P
+WHERE (rel_connait0.eid_to=P.cw_eid OR rel_connait0.eid_from=P.cw_eid)'''
     ),
     
     ('Any X WHERE X connait P',
-    '''SELECT DISTINCT X.eid
-FROM Personne AS X, connait_relation AS rel_connait0
-WHERE (rel_connait0.eid_from=X.eid OR rel_connait0.eid_to=X.eid)'''
+    '''SELECT DISTINCT X.cw_eid
+FROM connait_relation AS rel_connait0, cw_Personne AS X
+WHERE (rel_connait0.eid_from=X.cw_eid OR rel_connait0.eid_to=X.cw_eid)'''
      ),
     
     ('Any P WHERE X eid 0, NOT X connait P',
-     '''SELECT P.eid
-FROM Personne AS P
-WHERE NOT EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=P.eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=P.eid))'''),
+     '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE NOT EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=P.cw_eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=P.cw_eid))'''),
     
     ('Any P WHERE NOT X connait P',
-    '''SELECT P.eid
-FROM Personne AS P
-WHERE NOT EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_to=P.eid OR rel_connait0.eid_from=P.eid))'''),
+    '''SELECT P.cw_eid
+FROM cw_Personne AS P
+WHERE NOT EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_to=P.cw_eid OR rel_connait0.eid_from=P.cw_eid))'''),
     
     ('Any X WHERE NOT X connait P',
-    '''SELECT X.eid
-FROM Personne AS X
-WHERE NOT EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_from=X.eid OR rel_connait0.eid_to=X.eid))'''),
+    '''SELECT X.cw_eid
+FROM cw_Personne AS X
+WHERE NOT EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_from=X.cw_eid OR rel_connait0.eid_to=X.cw_eid))'''),
 
     ('Any P WHERE X connait P, P nom "nom"',
-     '''SELECT DISTINCT P.eid
-FROM Personne AS P, connait_relation AS rel_connait0
-WHERE (rel_connait0.eid_to=P.eid OR rel_connait0.eid_from=P.eid) AND P.nom=nom'''),
+     '''SELECT DISTINCT P.cw_eid
+FROM connait_relation AS rel_connait0, cw_Personne AS P
+WHERE (rel_connait0.eid_to=P.cw_eid OR rel_connait0.eid_from=P.cw_eid) AND P.cw_nom=nom'''),
     
     ('Any X WHERE X connait P, P nom "nom"',
-     '''SELECT DISTINCT X.eid
-FROM Personne AS P, Personne AS X, connait_relation AS rel_connait0
-WHERE (rel_connait0.eid_from=X.eid AND rel_connait0.eid_to=P.eid OR rel_connait0.eid_to=X.eid AND rel_connait0.eid_from=P.eid) AND P.nom=nom'''
+     '''SELECT DISTINCT X.cw_eid
+FROM connait_relation AS rel_connait0, cw_Personne AS P, cw_Personne AS X
+WHERE (rel_connait0.eid_from=X.cw_eid AND rel_connait0.eid_to=P.cw_eid OR rel_connait0.eid_to=X.cw_eid AND rel_connait0.eid_from=P.cw_eid) AND P.cw_nom=nom'''
     ),
 
     ('Any X ORDERBY X DESC LIMIT 9 WHERE E eid 0, E connait X',
-    '''SELECT DISTINCT X.eid
-FROM Personne AS X, connait_relation AS rel_connait0
-WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=X.eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=X.eid)
+    '''SELECT DISTINCT X.cw_eid
+FROM connait_relation AS rel_connait0, cw_Personne AS X
+WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=X.cw_eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=X.cw_eid)
 ORDER BY 1 DESC
 LIMIT 9'''
      ),
 
     ('DISTINCT Any P WHERE P connait S OR S connait P, S nom "chouette"',
-     '''SELECT DISTINCT P.eid
-FROM Personne AS P, Personne AS S, connait_relation AS rel_connait0
-WHERE (rel_connait0.eid_from=P.eid AND rel_connait0.eid_to=S.eid OR rel_connait0.eid_to=P.eid AND rel_connait0.eid_from=S.eid) AND S.nom=chouette'''
+     '''SELECT DISTINCT P.cw_eid
+FROM connait_relation AS rel_connait0, cw_Personne AS P, cw_Personne AS S
+WHERE (rel_connait0.eid_from=P.cw_eid AND rel_connait0.eid_to=S.cw_eid OR rel_connait0.eid_to=P.cw_eid AND rel_connait0.eid_from=S.cw_eid) AND S.cw_nom=chouette'''
      )
     ]
 
 INLINE = [
     ('Any P, L WHERE N ecrit_par P, P nom L, N eid 0',
-     '''SELECT P.eid, P.nom
-FROM Note AS N, Personne AS P
-WHERE N.ecrit_par=P.eid AND N.eid=0'''),
+     '''SELECT P.cw_eid, P.cw_nom
+FROM cw_Note AS N, cw_Personne AS P
+WHERE N.cw_ecrit_par=P.cw_eid AND N.cw_eid=0'''),
     
     ('Any N WHERE NOT N ecrit_par P, P nom "toto"',
-     '''SELECT DISTINCT N.eid
-FROM Note AS N, Personne AS P
-WHERE (N.ecrit_par IS NULL OR N.ecrit_par!=P.eid) AND P.nom=toto'''),
+     '''SELECT DISTINCT N.cw_eid
+FROM cw_Note AS N, cw_Personne AS P
+WHERE (N.cw_ecrit_par IS NULL OR N.cw_ecrit_par!=P.cw_eid) AND P.cw_nom=toto'''),
     
     ('Any P WHERE N ecrit_par P, N eid 0',
-    '''SELECT N.ecrit_par
-FROM Note AS N
-WHERE N.ecrit_par IS NOT NULL AND N.eid=0'''),
+    '''SELECT N.cw_ecrit_par
+FROM cw_Note AS N
+WHERE N.cw_ecrit_par IS NOT NULL AND N.cw_eid=0'''),
 
     ('Any P WHERE N ecrit_par P, P is Personne, N eid 0',
-    '''SELECT P.eid
-FROM Note AS N, Personne AS P
-WHERE N.ecrit_par=P.eid AND N.eid=0'''),
+    '''SELECT P.cw_eid
+FROM cw_Note AS N, cw_Personne AS P
+WHERE N.cw_ecrit_par=P.cw_eid AND N.cw_eid=0'''),
 
     ('Any P WHERE NOT N ecrit_par P, P is Personne, N eid 512',
-     '''SELECT DISTINCT P.eid
-FROM Note AS N, Personne AS P
-WHERE (N.ecrit_par IS NULL OR N.ecrit_par!=P.eid) AND N.eid=512'''),
+     '''SELECT DISTINCT P.cw_eid
+FROM cw_Note AS N, cw_Personne AS P
+WHERE (N.cw_ecrit_par IS NULL OR N.cw_ecrit_par!=P.cw_eid) AND N.cw_eid=512'''),
 
     ('Any S,ES,T WHERE S state_of ET, ET name "EUser", ES allowed_transition T, T destination_state S',
-     '''SELECT T.destination_state, rel_allowed_transition1.eid_from, T.eid
-FROM EEType AS ET, Transition AS T, allowed_transition_relation AS rel_allowed_transition1, state_of_relation AS rel_state_of0
-WHERE T.destination_state=rel_state_of0.eid_from AND rel_state_of0.eid_to=ET.eid AND ET.name=EUser AND rel_allowed_transition1.eid_to=T.eid'''),
+     '''SELECT T.cw_destination_state, rel_allowed_transition1.eid_from, T.cw_eid
+FROM allowed_transition_relation AS rel_allowed_transition1, cw_EEType AS ET, cw_Transition AS T, state_of_relation AS rel_state_of0
+WHERE T.cw_destination_state=rel_state_of0.eid_from AND rel_state_of0.eid_to=ET.cw_eid AND ET.cw_name=EUser AND rel_allowed_transition1.eid_to=T.cw_eid'''),
     ('Any O WHERE S eid 0, S in_state O',
-     '''SELECT S.in_state
-FROM Affaire AS S
-WHERE S.eid=0 AND S.in_state IS NOT NULL
+     '''SELECT S.cw_in_state
+FROM cw_Affaire AS S
+WHERE S.cw_eid=0 AND S.cw_in_state IS NOT NULL
 UNION ALL
-SELECT S.in_state
-FROM EUser AS S
-WHERE S.eid=0 AND S.in_state IS NOT NULL
+SELECT S.cw_in_state
+FROM cw_EUser AS S
+WHERE S.cw_eid=0 AND S.cw_in_state IS NOT NULL
 UNION ALL
-SELECT S.in_state
-FROM Note AS S
-WHERE S.eid=0 AND S.in_state IS NOT NULL''')
+SELECT S.cw_in_state
+FROM cw_Note AS S
+WHERE S.cw_eid=0 AND S.cw_in_state IS NOT NULL''')
     
     ]
 
+INTERSECT = [
+    ('Any SN WHERE NOT X in_state S, S name SN',
+     '''SELECT DISTINCT S.cw_name
+FROM cw_Affaire AS X, cw_State AS S
+WHERE (X.cw_in_state IS NULL OR X.cw_in_state!=S.cw_eid)
+INTERSECT
+SELECT DISTINCT S.cw_name
+FROM cw_EUser AS X, cw_State AS S
+WHERE (X.cw_in_state IS NULL OR X.cw_in_state!=S.cw_eid)
+INTERSECT
+SELECT DISTINCT S.cw_name
+FROM cw_Note AS X, cw_State AS S
+WHERE (X.cw_in_state IS NULL OR X.cw_in_state!=S.cw_eid)'''),
 
+    ('Any PN WHERE NOT X travaille S, X nom PN, S is IN(Division, Societe)',
+     '''SELECT X.cw_nom
+FROM cw_Personne AS X
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0,cw_Division AS S WHERE rel_travaille0.eid_from=X.cw_eid AND rel_travaille0.eid_to=S.cw_eid)
+INTERSECT ALL
+SELECT X.cw_nom
+FROM cw_Personne AS X
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0,cw_Societe AS S WHERE rel_travaille0.eid_from=X.cw_eid AND rel_travaille0.eid_to=S.cw_eid)'''),
+    
+    ('Any PN WHERE NOT X travaille S, S nom PN, S is IN(Division, Societe)',
+     '''SELECT S.cw_nom
+FROM cw_Division AS S
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_to=S.cw_eid)
+UNION ALL
+SELECT S.cw_nom
+FROM cw_Societe AS S
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_to=S.cw_eid)'''),
+    
+    ('Personne X WHERE NOT X travaille S, S nom "chouette"',
+     '''SELECT X.cw_eid
+FROM cw_Division AS S, cw_Personne AS X
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_from=X.cw_eid AND rel_travaille0.eid_to=S.cw_eid) AND S.cw_nom=chouette
+UNION ALL
+SELECT X.cw_eid
+FROM cw_Personne AS X, cw_Societe AS S
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_from=X.cw_eid AND rel_travaille0.eid_to=S.cw_eid) AND S.cw_nom=chouette
+UNION ALL
+SELECT X.cw_eid
+FROM cw_Personne AS X, cw_SubDivision AS S
+WHERE NOT EXISTS(SELECT 1 FROM travaille_relation AS rel_travaille0 WHERE rel_travaille0.eid_from=X.cw_eid AND rel_travaille0.eid_to=S.cw_eid) AND S.cw_nom=chouette'''),
+    
+    ('Any X WHERE X is ET, ET eid 2',
+     '''SELECT rel_is0.eid_from
+FROM is_relation AS rel_is0
+WHERE rel_is0.eid_to=2'''),
+
+    ]
 from logilab.common.adbh import ADV_FUNC_HELPER_DIRECTORY
     
 class PostgresSQLGeneratorTC(RQLGeneratorTC):
@@ -1126,13 +1171,13 @@
 
     def test1(self):
         self._checkall('Any count(RDEF) WHERE RDEF relation_type X, X eid %(x)s',
-                       ("""SELECT COUNT(T1.C0) FROM (SELECT RDEF.eid AS C0
-FROM EFRDef AS RDEF
-WHERE RDEF.relation_type=%(x)s
+                       ("""SELECT COUNT(T1.C0) FROM (SELECT RDEF.cw_eid AS C0
+FROM cw_EFRDef AS RDEF
+WHERE RDEF.cw_relation_type=%(x)s
 UNION ALL
-SELECT RDEF.eid AS C0
-FROM ENFRDef AS RDEF
-WHERE RDEF.relation_type=%(x)s) AS T1""", {}),
+SELECT RDEF.cw_eid AS C0
+FROM cw_ENFRDef AS RDEF
+WHERE RDEF.cw_relation_type=%(x)s) AS T1""", {}),
                        )
 
     def test2(self):
@@ -1156,13 +1201,13 @@
     def test_varmap(self):
         self._check('Any X,L WHERE X is EUser, X in_group G, X login L, G name "users"',
                     '''SELECT T00.x, T00.l
-FROM EGroup AS G, T00, in_group_relation AS rel_in_group0
-WHERE rel_in_group0.eid_from=T00.x AND rel_in_group0.eid_to=G.eid AND G.name=users''',
+FROM T00, cw_EGroup AS G, in_group_relation AS rel_in_group0
+WHERE rel_in_group0.eid_from=T00.x AND rel_in_group0.eid_to=G.cw_eid AND G.cw_name=users''',
                     varmap={'X': 'T00.x', 'X.login': 'T00.l'})
         self._check('Any X,L,GN WHERE X is EUser, X in_group G, X login L, G name GN',
-                    '''SELECT T00.x, T00.l, G.name
-FROM EGroup AS G, T00, in_group_relation AS rel_in_group0
-WHERE rel_in_group0.eid_from=T00.x AND rel_in_group0.eid_to=G.eid''',
+                    '''SELECT T00.x, T00.l, G.cw_name
+FROM T00, cw_EGroup AS G, in_group_relation AS rel_in_group0
+WHERE rel_in_group0.eid_from=T00.x AND rel_in_group0.eid_to=G.cw_eid''',
                     varmap={'X': 'T00.x', 'X.login': 'T00.l'})
 
     def test_parser_parse(self):
@@ -1196,18 +1241,22 @@
     def test_negation(self):
         for t in self._parse(NEGATIONS):
             yield t
+        
+    def test_intersection(self):
+        for t in self._parse(INTERSECT):
+            yield t
 
     def test_union(self):
         for t in self._parse((
             ('(Any N ORDERBY 1 WHERE X name N, X is State)'
              ' UNION '
              '(Any NN ORDERBY 1 WHERE XX name NN, XX is Transition)',
-             '''(SELECT X.name
-FROM State AS X
+             '''(SELECT X.cw_name
+FROM cw_State AS X
 ORDER BY 1)
 UNION ALL
-(SELECT XX.name
-FROM Transition AS XX
+(SELECT XX.cw_name
+FROM cw_Transition AS XX
 ORDER BY 1)'''),
             )):
             yield t
@@ -1220,11 +1269,11 @@
              ' UNION '
              '(Any NN WHERE XX name NN, XX is Transition))',
              '''SELECT _T0.C0
-FROM ((SELECT X.name AS C0
-FROM State AS X)
+FROM ((SELECT X.cw_name AS C0
+FROM cw_State AS X)
 UNION ALL
-(SELECT XX.name AS C0
-FROM Transition AS XX)) AS _T0
+(SELECT XX.cw_name AS C0
+FROM cw_Transition AS XX)) AS _T0
 ORDER BY 1'''),
             
             ('Any N,NX ORDERBY NX WITH N,NX BEING '
@@ -1232,40 +1281,40 @@
              ' UNION '
              '(Any N,COUNT(X) GROUPBY N WHERE X name N, X is Transition HAVING COUNT(X)>1))',
              '''SELECT _T0.C0, _T0.C1
-FROM ((SELECT X.name AS C0, COUNT(X.eid) AS C1
-FROM State AS X
-GROUP BY X.name
-HAVING COUNT(X.eid)>1)
+FROM ((SELECT X.cw_name AS C0, COUNT(X.cw_eid) AS C1
+FROM cw_State AS X
+GROUP BY X.cw_name
+HAVING COUNT(X.cw_eid)>1)
 UNION ALL
-(SELECT X.name AS C0, COUNT(X.eid) AS C1
-FROM Transition AS X
-GROUP BY X.name
-HAVING COUNT(X.eid)>1)) AS _T0
+(SELECT X.cw_name AS C0, COUNT(X.cw_eid) AS C1
+FROM cw_Transition AS X
+GROUP BY X.cw_name
+HAVING COUNT(X.cw_eid)>1)) AS _T0
 ORDER BY 2'''),            
 
             ('Any N,COUNT(X) GROUPBY N HAVING COUNT(X)>1 '
              'WITH X, N BEING ((Any X, N WHERE X name N, X is State) UNION '
              '                 (Any X, N WHERE X name N, X is Transition))',
              '''SELECT _T0.C1, COUNT(_T0.C0)
-FROM ((SELECT X.eid AS C0, X.name AS C1
-FROM State AS X)
+FROM ((SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_State AS X)
 UNION ALL
-(SELECT X.eid AS C0, X.name AS C1
-FROM Transition AS X)) AS _T0
+(SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_Transition AS X)) AS _T0
 GROUP BY _T0.C1
 HAVING COUNT(_T0.C0)>1'''),
 
             ('Any ETN,COUNT(X) GROUPBY ETN WHERE X is ET, ET name ETN '
              'WITH X BEING ((Any X WHERE X is Societe) UNION (Any X WHERE X is Affaire, (EXISTS(X owned_by 1)) OR ((EXISTS(D concerne B?, B owned_by 1, X identity D, B is Note)) OR (EXISTS(F concerne E?, E owned_by 1, E is Societe, X identity F)))))',
-             '''SELECT ET.name, COUNT(_T0.C0)
-FROM ((SELECT X.eid AS C0
-FROM Societe AS X)
+             '''SELECT ET.cw_name, COUNT(_T0.C0)
+FROM ((SELECT X.cw_eid AS C0
+FROM cw_Societe AS X)
 UNION ALL
-(SELECT X.eid AS C0
-FROM Affaire AS X
-WHERE ((EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0 WHERE rel_owned_by0.eid_from=X.eid AND rel_owned_by0.eid_to=1)) OR (((EXISTS(SELECT 1 FROM Affaire AS D LEFT OUTER JOIN concerne_relation AS rel_concerne1 ON (rel_concerne1.eid_from=D.eid) LEFT OUTER JOIN Note AS B ON (rel_concerne1.eid_to=B.eid), owned_by_relation AS rel_owned_by2 WHERE rel_owned_by2.eid_from=B.eid AND rel_owned_by2.eid_to=1 AND X.eid=D.eid)) OR (EXISTS(SELECT 1 FROM Affaire AS F LEFT OUTER JOIN concerne_relation AS rel_concerne3 ON (rel_concerne3.eid_from=F.eid) LEFT OUTER JOIN Societe AS E ON (rel_concerne3.eid_to=E.eid), owned_by_relation AS rel_owned_by4 WHERE rel_owned_by4.eid_from=E.eid AND rel_owned_by4.eid_to=1 AND X.eid=F.eid))))))) AS _T0, EEType AS ET, is_relation AS rel_is0
-WHERE rel_is0.eid_from=_T0.C0 AND rel_is0.eid_to=ET.eid
-GROUP BY ET.name'''),
+(SELECT X.cw_eid AS C0
+FROM cw_Affaire AS X
+WHERE ((EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0 WHERE rel_owned_by0.eid_from=X.cw_eid AND rel_owned_by0.eid_to=1)) OR (((EXISTS(SELECT 1 FROM cw_Affaire AS D LEFT OUTER JOIN concerne_relation AS rel_concerne1 ON (rel_concerne1.eid_from=D.cw_eid) LEFT OUTER JOIN cw_Note AS B ON (rel_concerne1.eid_to=B.cw_eid), owned_by_relation AS rel_owned_by2 WHERE rel_owned_by2.eid_from=B.cw_eid AND rel_owned_by2.eid_to=1 AND X.cw_eid=D.cw_eid)) OR (EXISTS(SELECT 1 FROM cw_Affaire AS F LEFT OUTER JOIN concerne_relation AS rel_concerne3 ON (rel_concerne3.eid_from=F.cw_eid) LEFT OUTER JOIN cw_Societe AS E ON (rel_concerne3.eid_to=E.cw_eid), owned_by_relation AS rel_owned_by4 WHERE rel_owned_by4.eid_from=E.cw_eid AND rel_owned_by4.eid_to=1 AND X.cw_eid=F.cw_eid))))))) AS _T0, cw_EEType AS ET, is_relation AS rel_is0
+WHERE rel_is0.eid_from=_T0.C0 AND rel_is0.eid_to=ET.cw_eid
+GROUP BY ET.cw_name'''),
             )):
             yield t
 
@@ -1304,33 +1353,33 @@
 WHERE appears0.words @@ to_tsquery('default', 'hip&hop&momo') AND appears0.uid=X.eid AND X.type='Personne'"""),
             
             ('Any X WHERE X has_text "toto tata", X name "tutu"',
-             """SELECT X.eid
-FROM Basket AS X, appears AS appears0
-WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.eid AND X.name=tutu
+             """SELECT X.cw_eid
+FROM appears AS appears0, cw_Basket AS X
+WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM File AS X, appears AS appears0
-WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_File AS X
+WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Folder AS X, appears AS appears0
-WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Folder AS X
+WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Image AS X, appears AS appears0
-WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Image AS X
+WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM State AS X, appears AS appears0
-WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_State AS X
+WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Tag AS X, appears AS appears0
-WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Tag AS X
+WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Transition AS X, appears AS appears0
-WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.eid AND X.name=tutu"""),
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Transition AS X
+WHERE appears0.words @@ to_tsquery('default', 'toto&tata') AND appears0.uid=X.cw_eid AND X.cw_name=tutu"""),
 
             ('Personne X where X has_text %(text)s, X travaille S, S has_text %(text)s',
              """SELECT X.eid
@@ -1343,7 +1392,7 @@
     def test_from_clause_needed(self):
         queries = [("Any 1 WHERE EXISTS(T is EGroup, T name 'managers')",
                     '''SELECT 1
-WHERE EXISTS(SELECT 1 FROM EGroup AS T WHERE T.name=managers)'''),
+WHERE EXISTS(SELECT 1 FROM cw_EGroup AS T WHERE T.cw_name=managers)'''),
                    ('Any X,Y WHERE NOT X created_by Y, X eid 5, Y eid 6',
                     '''SELECT 5, 6
 WHERE NOT EXISTS(SELECT 1 FROM created_by_relation AS rel_created_by0 WHERE rel_created_by0.eid_from=5 AND rel_created_by0.eid_to=6)'''),
@@ -1354,7 +1403,7 @@
     def test_ambigous_exists_no_from_clause(self):
         self._check('Any COUNT(U) WHERE U eid 1, EXISTS (P owned_by U, P is IN (Note, Affaire))',
                     '''SELECT COUNT(1)
-WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, Affaire AS P WHERE rel_owned_by0.eid_from=P.eid AND rel_owned_by0.eid_to=1 UNION SELECT 1 FROM owned_by_relation AS rel_owned_by1, Note AS P WHERE rel_owned_by1.eid_from=P.eid AND rel_owned_by1.eid_to=1)''')
+WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, cw_Affaire AS P WHERE rel_owned_by0.eid_from=P.cw_eid AND rel_owned_by0.eid_to=1 UNION SELECT 1 FROM owned_by_relation AS rel_owned_by1, cw_Note AS P WHERE rel_owned_by1.eid_from=P.cw_eid AND rel_owned_by1.eid_to=1)''')
 
 
 class SqliteSQLGeneratorTC(PostgresSQLGeneratorTC):
@@ -1370,19 +1419,19 @@
         self.o = SQLGenerator(schema, dbms_helper)
 
     def _norm_sql(self, sql):
-        return sql.strip().replace(' ILIKE ', ' LIKE ')
+        return sql.strip().replace(' ILIKE ', ' LIKE ').replace('\nINTERSECT ALL\n', '\nINTERSECT\n')
 
     def test_union(self):
         for t in self._parse((
             ('(Any N ORDERBY 1 WHERE X name N, X is State)'
              ' UNION '
              '(Any NN ORDERBY 1 WHERE XX name NN, XX is Transition)',
-             '''SELECT X.name
-FROM State AS X
+             '''SELECT X.cw_name
+FROM cw_State AS X
 ORDER BY 1
 UNION ALL
-SELECT XX.name
-FROM Transition AS XX
+SELECT XX.cw_name
+FROM cw_Transition AS XX
 ORDER BY 1'''),
             )):
             yield t
@@ -1397,11 +1446,11 @@
              ' UNION '
              '(Any NN WHERE XX name NN, XX is Transition))',
              '''SELECT _T0.C0
-FROM (SELECT X.name AS C0
-FROM State AS X
+FROM (SELECT X.cw_name AS C0
+FROM cw_State AS X
 UNION ALL
-SELECT XX.name AS C0
-FROM Transition AS XX) AS _T0
+SELECT XX.cw_name AS C0
+FROM cw_Transition AS XX) AS _T0
 ORDER BY 1'''),
             
             ('Any N,NX ORDERBY NX WITH N,NX BEING '
@@ -1409,26 +1458,26 @@
              ' UNION '
              '(Any N,COUNT(X) GROUPBY N WHERE X name N, X is Transition HAVING COUNT(X)>1))',
              '''SELECT _T0.C0, _T0.C1
-FROM (SELECT X.name AS C0, COUNT(X.eid) AS C1
-FROM State AS X
-GROUP BY X.name
-HAVING COUNT(X.eid)>1
+FROM (SELECT X.cw_name AS C0, COUNT(X.cw_eid) AS C1
+FROM cw_State AS X
+GROUP BY X.cw_name
+HAVING COUNT(X.cw_eid)>1
 UNION ALL
-SELECT X.name AS C0, COUNT(X.eid) AS C1
-FROM Transition AS X
-GROUP BY X.name
-HAVING COUNT(X.eid)>1) AS _T0
+SELECT X.cw_name AS C0, COUNT(X.cw_eid) AS C1
+FROM cw_Transition AS X
+GROUP BY X.cw_name
+HAVING COUNT(X.cw_eid)>1) AS _T0
 ORDER BY 2'''),            
 
             ('Any N,COUNT(X) GROUPBY N HAVING COUNT(X)>1 '
              'WITH X, N BEING ((Any X, N WHERE X name N, X is State) UNION '
              '                 (Any X, N WHERE X name N, X is Transition))',
              '''SELECT _T0.C1, COUNT(_T0.C0)
-FROM (SELECT X.eid AS C0, X.name AS C1
-FROM State AS X
+FROM (SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_State AS X
 UNION ALL
-SELECT X.eid AS C0, X.name AS C1
-FROM Transition AS X) AS _T0
+SELECT X.cw_eid AS C0, X.cw_name AS C1
+FROM cw_Transition AS X) AS _T0
 GROUP BY _T0.C1
 HAVING COUNT(_T0.C0)>1'''),
             )):
@@ -1452,33 +1501,33 @@
 WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.type='Personne'"""),
             
             ('Any X WHERE X has_text "toto tata", X name "tutu"',
-             """SELECT X.eid
-FROM Basket AS X, appears AS appears0
-WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.name=tutu
+             """SELECT X.cw_eid
+FROM appears AS appears0, cw_Basket AS X
+WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM File AS X, appears AS appears0
-WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_File AS X
+WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Folder AS X, appears AS appears0
-WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Folder AS X
+WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Image AS X, appears AS appears0
-WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Image AS X
+WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM State AS X, appears AS appears0
-WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_State AS X
+WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Tag AS X, appears AS appears0
-WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Tag AS X
+WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Transition AS X, appears AS appears0
-WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.eid AND X.name=tutu"""),
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Transition AS X
+WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata')) AND appears0.uid=X.cw_eid AND X.cw_name=tutu"""),
             )):
             yield t
 
@@ -1503,7 +1552,7 @@
         queries = [("Any 1 WHERE EXISTS(T is EGroup, T name 'managers')",
                     '''SELECT 1
 FROM (SELECT 1) AS _T
-WHERE EXISTS(SELECT 1 FROM EGroup AS T WHERE T.name=managers)'''),
+WHERE EXISTS(SELECT 1 FROM cw_EGroup AS T WHERE T.cw_name=managers)'''),
                    ('Any X,Y WHERE NOT X created_by Y, X eid 5, Y eid 6',
                     '''SELECT 5, 6
 FROM (SELECT 1) AS _T
@@ -1528,33 +1577,33 @@
 FROM appears AS appears0, entities AS X
 WHERE MATCH (appears0.words) AGAINST ('hip hop momo' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.type='Personne'"""),
             ('Any X WHERE X has_text "toto tata", X name "tutu"',
-             """SELECT X.eid
-FROM Basket AS X, appears AS appears0
-WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.name=tutu
+             """SELECT X.cw_eid
+FROM appears AS appears0, cw_Basket AS X
+WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM File AS X, appears AS appears0
-WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_File AS X
+WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Folder AS X, appears AS appears0
-WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Folder AS X
+WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Image AS X, appears AS appears0
-WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Image AS X
+WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM State AS X, appears AS appears0
-WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_State AS X
+WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Tag AS X, appears AS appears0
-WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.name=tutu
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Tag AS X
+WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.cw_eid AND X.cw_name=tutu
 UNION ALL
-SELECT X.eid
-FROM Transition AS X, appears AS appears0
-WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.eid AND X.name=tutu""")
+SELECT X.cw_eid
+FROM appears AS appears0, cw_Transition AS X
+WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=X.cw_eid AND X.cw_name=tutu""")
             ]
         for t in self._parse(queries):
             yield t
@@ -1564,7 +1613,7 @@
         self._check('Any COUNT(U) WHERE U eid 1, EXISTS (P owned_by U, P is IN (Note, Affaire))',
                     '''SELECT COUNT(1)
 FROM (SELECT 1) AS _T
-WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, Affaire AS P WHERE rel_owned_by0.eid_from=P.eid AND rel_owned_by0.eid_to=1 UNION SELECT 1 FROM owned_by_relation AS rel_owned_by1, Note AS P WHERE rel_owned_by1.eid_from=P.eid AND rel_owned_by1.eid_to=1)''') 
+WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, cw_Affaire AS P WHERE rel_owned_by0.eid_from=P.cw_eid AND rel_owned_by0.eid_to=1 UNION SELECT 1 FROM owned_by_relation AS rel_owned_by1, cw_Note AS P WHERE rel_owned_by1.eid_from=P.cw_eid AND rel_owned_by1.eid_to=1)''') 
            
 
         
--- a/server/test/unittest_rqlannotation.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/server/test/unittest_rqlannotation.py	Wed Apr 15 17:36:09 2009 +0200
@@ -286,6 +286,12 @@
                               '(EXISTS(S owned_by 1)) OR (EXISTS(S documented_by N, N title "published"))')
         self.assertEquals(rqlst.defined_vars['S']._q_invariant, True)
 
+    def test_nonregr_ambiguity(self):        
+        rqlst = self._prepare('Note N WHERE N attachment F')
+        # N may be an image as well, not invariant
+        self.assertEquals(rqlst.defined_vars['N']._q_invariant, False)
+        self.assertEquals(rqlst.defined_vars['F']._q_invariant, True)
+
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()
--- a/skeleton/__pkginfo__.py.tmpl	Thu Jan 15 10:13:25 2009 +0100
+++ b/skeleton/__pkginfo__.py.tmpl	Wed Apr 15 17:36:09 2009 +0200
@@ -1,6 +1,7 @@
 # pylint: disable-msg=W0622
 """%(distname)s application packaging information"""
 
+modname = '%(cubename)s'
 distname = '%(distname)s'
 
 numversion = (0, 1, 0)
@@ -10,8 +11,8 @@
 copyright = '''Copyright (c) %(year)s %(author)s.
 %(author-web-site)s -- mailto:%(author-email)s'''
 
-author = %(author)s'
-author_email = %(author-email)s'
+author = '%(author)s'
+author_email = '%(author-email)s'
 
 short_desc = '%(shortdesc)s'
 long_desc = '''%(longdesc)s'''
--- a/sobjects/notification.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/sobjects/notification.py	Wed Apr 15 17:36:09 2009 +0200
@@ -160,8 +160,8 @@
     def context(self, **kwargs):
         entity = self.entity(0, 0)
         for key, val in kwargs.iteritems():
-            if val and val.strip():
-                kwargs[key] = self.req._(val)
+            if val and isinstance(val, unicode) and val.strip():
+               kwargs[key] = self.req._(val)
         kwargs.update({'user': self.user_login(),
                        'eid': entity.eid,
                        'etype': entity.dc_type(),
--- a/test/unittest_cwconfig.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/test/unittest_cwconfig.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,4 +1,6 @@
+import sys
 import os
+from os.path import dirname, join, abspath
 from tempfile import mktemp
 
 from logilab.common.testlib import TestCase, unittest_main
@@ -8,7 +10,7 @@
 
 def unabsolutize(path):
     parts = path.split(os.sep)
-    for i, part in enumerate(parts):
+    for i, part in reversed(tuple(enumerate(parts))):
         if part in ('cubicweb', 'cubes', 'cubes'):
             return '/'.join(parts[i+1:])
     raise Exception('duh? %s' % path)
@@ -69,6 +71,36 @@
                           ['entities', 'web/views', 'sobjects',
                            'file/entities.py', 'file/views', 'file/hooks.py',
                            'email/entities.py', 'email/views', 'email/hooks.py'])
-            
+
+    def test_cubes_path(self):
+        # make sure we don't import the email cube, but the stdlib email package
+        import email
+        self.assertNotEquals(dirname(email.__file__), self.config.CUBES_DIR)
+        os.environ['CW_CUBES_PATH'] = join(dirname(__file__), 'data', 'cubes')
+        self.assertEquals(self.config.cubes_search_path(),
+                          [abspath(join(dirname(__file__), 'data', 'cubes')),
+                           self.config.CUBES_DIR])
+        os.environ['CW_CUBES_PATH'] = '%s%s%s%s%s' % (join(dirname(__file__), 'data', 'cubes'),
+                                                      os.pathsep, self.config.CUBES_DIR,
+                                                      os.pathsep, 'unexistant')
+        # filter out unexistant and duplicates
+        self.assertEquals(self.config.cubes_search_path(),
+                          [abspath(join(dirname(__file__), 'data', 'cubes')),
+                           self.config.CUBES_DIR])
+        self.failUnless('mycube' in self.config.available_cubes())
+        # test cubes python path
+        self.config.adjust_sys_path()
+        import cubes
+        self.assertEquals(cubes.__path__, self.config.cubes_search_path())
+        # this import should succeed once path is adjusted
+        from cubes import mycube
+        self.assertEquals(mycube.__path__, [abspath(join(dirname(__file__), 'data', 'cubes', 'mycube'))])
+        # file cube should be overriden by the one found in data/cubes
+        sys.modules.pop('cubes.file', None)
+        del cubes.file
+        from cubes import file
+        self.assertEquals(file.__path__, [abspath(join(dirname(__file__), 'data', 'cubes', 'file'))])
+                                       
+                          
 if __name__ == '__main__':
     unittest_main()
--- a/test/unittest_rset.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/test/unittest_rset.py	Wed Apr 15 17:36:09 2009 +0200
@@ -300,7 +300,13 @@
             attr = etype == 'Bookmark' and 'title' or 'name'
             self.assertEquals(entity[attr], n)
         
-    
+    def test_related_entity_optional(self):
+        e = self.add_entity('Bookmark', title=u'aaaa', path=u'path')
+        rset = self.execute('Any B,U,L WHERE B bookmarked_by U?, U login L')
+        entity, rtype = rset.related_entity(0, 2)
+        self.assertEquals(entity, None)
+        self.assertEquals(rtype, None)
+        
     def test_related_entity_union_subquery(self):
         e = self.add_entity('Bookmark', title=u'aaaa', path=u'path')
         rset = self.execute('Any X,N ORDERBY N WITH X,N BEING '
--- a/test/unittest_schema.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/test/unittest_schema.py	Wed Apr 15 17:36:09 2009 +0200
@@ -227,6 +227,7 @@
     def setUp(self):
         self.loader = CubicWebSchemaLoader()
         self.loader.defined = {}
+        self.loader.loaded_files = []
         self.loader._instantiate_handlers()
 
     def _test(self, schemafile, msg):
--- a/toolsutils.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/toolsutils.py	Wed Apr 15 17:36:09 2009 +0200
@@ -273,7 +273,7 @@
       }),
     ("host",
      {'short': 'H', 'type' : 'string', 'metavar': '<hostname>',
-      'default': 'all-in-one',
+      'default': None,
       'help': 'specify the name server\'s host name. Will be detected by \
 broadcast if not provided.',
       }),
--- a/vregistry.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/vregistry.py	Wed Apr 15 17:36:09 2009 +0200
@@ -20,7 +20,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -105,7 +105,10 @@
                             "can't be used together")
         if '__select__' not in classdict and '__selectors__' in classdict:
             selectors = classdict['__selectors__']
-            classdict['__select__'] = classmethod(chainall(*selectors))
+            if len(selectors) > 1:
+                classdict['__select__'] = classmethod(chainall(*selectors))
+            else:
+                classdict['__select__'] = classmethod(selectors[0])
         return super(autoselectors, mcs).__new__(mcs, name, bases, classdict)
 
     def __setattr__(self, attr, value):
--- a/web/application.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/application.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """CubicWeb web client application object
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -317,6 +317,7 @@
             try:
                 ctrlid, rset = self.url_resolver.process(req, path)
                 controller = self.select_controller(ctrlid, req)
+                req.update_search_state()
                 result = controller.publish(rset=rset)
                 if req.cnx is not None:
                     # req.cnx is None if anonymous aren't allowed and we are
--- a/web/box.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/box.py	Wed Apr 15 17:36:09 2009 +0200
@@ -14,9 +14,9 @@
     accepts_registerer, extresources_registerer,
     etype_rtype_priority_registerer)
 from cubicweb.common.selectors import (
-    etype_rtype_selector, one_line_rset, accept_selector, accept_rtype_selector,
-    primaryview_selector, contextprop_selector, has_related_entities,
-    _rqlcondition_selector)
+    etype_rtype_selector, one_line_rset, accept, has_relation,
+    primary_view, match_context_prop, has_related_entities,
+    _rql_condition)
 from cubicweb.common.view import Template
 from cubicweb.common.appobject import ReloadableMixIn
 
@@ -42,7 +42,7 @@
         box.render(self.w)
     """
     __registry__ = 'boxes'
-    __selectors__ = Template.__selectors__ + (contextprop_selector,)
+    __selectors__ = Template.__selectors__ + (match_context_prop,)
     
     categories_in_order = ()
     property_defs = {
@@ -150,17 +150,15 @@
 class EntityBoxTemplate(BoxTemplate):
     """base class for boxes related to a single entity"""
     __registerer__ = accepts_registerer
-    __selectors__ = (one_line_rset, primaryview_selector,
-                     contextprop_selector, etype_rtype_selector,
-                     accept_rtype_selector, accept_selector,
-                     _rqlcondition_selector)
+    __selectors__ = (one_line_rset, primary_view,
+                     match_context_prop, etype_rtype_selector,
+                     has_relation, accept, _rql_condition)
     accepts = ('Any',)
     context = 'incontext'
     condition = None
     
     def call(self, row=0, col=0, **kwargs):
-        """classes inheriting from EntityBoxTemplate should defined cell_call,
-        """
+        """classes inheriting from EntityBoxTemplate should define cell_call"""
         self.cell_call(row, col, **kwargs)
 
 
@@ -185,7 +183,7 @@
     class attributes.
     """
     
-    def cell_call(self, row, col):
+    def cell_call(self, row, col, view=None):
         self.req.add_js('cubicweb.ajax.js')
         entity = self.entity(row, col)
         box = SideBoxWidget(display_name(self.req, self.rtype), self.id)
--- a/web/component.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/component.py	Wed Apr 15 17:36:09 2009 +0200
@@ -56,7 +56,10 @@
     condition = None
     
     def call(self, view):
-        raise RuntimeError()
+        return self.cell_call(0, 0, view)
+
+    def cell_call(self, row, col, view):
+        raise NotImplementedError()
 
     
 class NavigationComponent(VComponent):
@@ -70,6 +73,19 @@
     selected_page_link_templ = u'<span class="selectedSlice"><a href="%s" title="%s">%s</a></span>'
     previous_page_link_templ = next_page_link_templ = page_link_templ
     no_previous_page_link = no_next_page_link = u''
+
+    @classmethod
+    def selected(cls, req, rset, row=None, col=None, page_size=None, **kwargs):
+        """by default web app objects are usually instantiated on
+        selection according to a request, a result set, and optional
+        row and col
+        """
+        instance = super(NavigationComponent, cls).selected(req, rset, row, col, **kwargs)
+        if page_size is not None:
+            instance.page_size = page_size
+        elif 'page_size' in req.form:
+            instance.page_size = int(req.form['page_size'])
+        return instance
     
     def __init__(self, req, rset):
         super(NavigationComponent, self).__init__(req, rset)
@@ -145,17 +161,17 @@
         """
         return None
     
-    def call(self, view=None):
+    def cell_call(self, row, col, view=None):
         rql = self.rql()
         if rql is None:
-            entity = self.rset.get_entity(0, 0)
+            entity = self.rset.get_entity(row, col)
             if self.target == 'object':
                 role = 'subject'
             else:
                 role = 'object'
             rset = entity.related(self.rtype, role)
         else:
-            eid = self.rset[0][0]
+            eid = self.rset[row][col]
             rset = self.req.execute(self.rql(), {'x': eid}, 'x')
         if not rset.rowcount:
             return
--- a/web/controller.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/controller.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,7 +11,7 @@
 
 from cubicweb import typed_eid
 from cubicweb.common.registerers import priority_registerer
-from cubicweb.common.selectors import in_group_selector
+from cubicweb.common.selectors import match_user_group
 from cubicweb.common.appobject import AppObject
 from cubicweb.web import LOGGER, Redirect, RequestError
 
@@ -68,7 +68,7 @@
     """
     __registry__ = 'controllers'
     __registerer__ = priority_registerer
-    __selectors__ = (in_group_selector,)
+    __selectors__ = (match_user_group,)
     require_groups = ()
 
     def __init__(self, *args, **kwargs):
--- a/web/data/cubicweb.ajax.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.ajax.js	Wed Apr 15 17:36:09 2009 +0200
@@ -9,8 +9,29 @@
 
 var JSON_BASE_URL = baseuri() + 'json?';
 
+function postAjaxLoad(node) {
+    // find sortable tables if there are some
+    if (typeof(Sortable) != 'undefined') {
+	Sortable.sortTables(node);
+    }
+    // find textareas and wrap them if there are some
+    if (typeof(FCKeditor) != 'undefined') {
+	buildWysiwygEditors(node);
+    }
+    if (typeof initFacetBoxEvents != 'undefined') {
+	initFacetBoxEvents(node);
+    }
+    if (typeof buildWidgets != 'undefined') {
+	buildWidgets(node);
+    }
+    if (typeof roundedCornersOnLoad != 'undefined') {
+	roundedCornersOnLoad();
+    }
+}
+
 // cubicweb loadxhtml plugin to make jquery handle xhtml response
 jQuery.fn.loadxhtml = function(url, data, reqtype, mode) {
+
     var ajax = null;
     if (reqtype == 'post') {
 	ajax = jQuery.post;
@@ -27,6 +48,7 @@
 	delete data.callback;
     }
     var node = this.get(0); // only consider the first element
+    ajax = jQuery.post;
     ajax(url, data, function(response) {
 	var domnode = getDomFromResponse(response);
 	if (mode == 'swap') {
@@ -40,28 +62,12 @@
 	} else if (mode == 'append') {
 	    jQuery(node).append(domnode);
 	}
-	// find sortable tables if there are some
-	if (typeof(Sortable) != 'undefined') {
-	    Sortable.sortTables(node);
-	}
-	// find textareas and wrap them if there are some
-	if (typeof(FCKeditor) != 'undefined') {
-	    buildWysiwygEditors(node);
-	}
-
-	if (typeof initFacetBoxEvents != 'undefined') {
-	    initFacetBoxEvents(node);
-	}
-
-	if (typeof buildWidgets != 'undefined') {
-	    buildWidgets(node);
-	}
-
+	postAjaxLoad(node);
 	while (jQuery.isFunction(callback)) {
 	    callback = callback.apply(this, [domnode]);
 	}
     });
-}
+};
 
 
 
@@ -69,7 +75,7 @@
  * the associated RQL to build them (Async call)
  */
 function loadDynamicFragments() {
-    var fragments = getElementsByTagAndClassName('div', 'dynamicFragment');
+    var fragments = jQuery('div.dynamicFragment');
     if (fragments.length == 0) {
 	return;
     }
@@ -277,7 +283,7 @@
  * while the page was generated.
  */
 function unregisterUserCallback(cbname) {
-    d = async_remote_exec('unregister_user_callback', cbname);
+    var d = async_remote_exec('unregister_user_callback', cbname);
     d.addCallback(function() {resetCursor();});
     d.addErrback(function(xxx) {
 	updateMessage(_("an error occured"));
--- a/web/data/cubicweb.calendar.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.calendar.css	Wed Apr 15 17:36:09 2009 +0200
@@ -73,10 +73,6 @@
   text-align: right;
 }
 
-table.omcalendar tr td div.calCellTitle div.stopper {
-  clear:pos;
-}
-
 table.omcalendar tr td {
   padding: 3px 0.5em 1em;                         
 }
--- a/web/data/cubicweb.calendar_popup.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.calendar_popup.css	Wed Apr 15 17:36:09 2009 +0200
@@ -45,7 +45,7 @@
 
 table.popupCalendar th.prev,
 table.popupCalendar th.next {
-  color: orangered;
+  color: #ff4500;
   font-size: 50%;
   font-weight: bold;
   padding: 2px 0px;
--- a/web/data/cubicweb.compat.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.compat.js	Wed Apr 15 17:36:09 2009 +0200
@@ -242,7 +242,36 @@
 UL = createDomFunction('ul');
 
 // cubicweb specific
-IFRAME = createDomFunction('iframe');
+//IFRAME = createDomFunction('iframe');
+function IFRAME(params){
+  if ('name' in params){
+    try {
+      var node = document.createElement('<iframe name="'+params['name']+'">');
+      }catch (ex) {
+	 var node = document.createElement('iframe');
+      }
+  }
+  else{
+    var node = document.createElement('iframe');
+  }
+  for (key in params) {
+    if (key != 'name'){
+      var value = params[key];
+      if (key.substring(0, 2) == 'on') {
+	// this is an event handler definition
+	if (typeof value == 'string') {
+	  // litteral definition
+	  value = new Function(value);
+	}
+	node[key] = value;
+      } else { // normal node attribute
+	node.setAttribute(key, params[key]);
+      }
+    }
+  }
+  return node;
+}
+
 
 // dummy ultra minimalist implementation on deferred for jQuery
 function Deferred() {
--- a/web/data/cubicweb.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.css	Wed Apr 15 17:36:09 2009 +0200
@@ -3,10 +3,9 @@
  *  :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
  *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
  */
-
-/******************************************************************************/
-/* main styles                                                                */
-/******************************************************************************/
+/***************************************/
+/* xhtml tags styles                   */
+/***************************************/
 
 *{
   margin:0px;
@@ -23,14 +22,12 @@
   font-family: Verdana, sans-serif;
 }
 
-
 h1 {
   font-size: 188%;
   margin: 0.2em 0px 0.3em;
   border-bottom: 1px solid #000;
 }
 
-
 h2, h3 {
   margin-top: 0.2em;
   margin-bottom: 0.3em;
@@ -57,7 +54,7 @@
   font-size:105%;
 }
 
-a, a:active, a:link, a:visited {
+a, a:active, a:visited, a:link {
   color: #ff4500;
   text-decoration: none;
 }
@@ -66,33 +63,17 @@
   text-decoration: underline;
 }
 
-a.grayedout {
-  display: block;
-  padding-left: 2px;
-  color: #808080;
-}
-
-a.grayedout:visited{
-  color: #808080;
-}
-
-a.grayedout:hover {
-  color: #000;
-}
-
 a img {
   border: none;
   text-align: center;
 }
 
 p {
-  margin-top: 0em;
-  margin-bottom: 0.2em;
+  margin: 0em 0px 0.2em;
   padding-top: 2px;
 }
 
-
-table, td, input, select {
+table, td, input, select{
   font-size: 100%;
 }
 
@@ -107,7 +88,7 @@
 
 table td img {
   vertical-align: middle;
-  margin: 0px 10px 0px 0px;
+  margin-right: 10px;
 }
 
 ol {
@@ -125,29 +106,22 @@
   background: url("bullet_orange.png") 0% 6px no-repeat;
 }
 
-pre {
-  font-family: Courier, "Courier New", Monaco, monospace;
-  font-size: 100%;
-  color: #000;
-  background-color: #f2f2f2;
-  border: 1px solid #ccc;
-  /*overflow:auto; */
+dt {
+  font-size:1.17em;
+  font-weight:600;
 }
 
-blockquote {
-  font-family: Courier, "Courier New", serif;
-  font-size: 120%;
-  margin: 5px 0px;
-  padding: 0.8em;
-  background-color: #f2f2f2;
-  border: 1px solid #ccc;
+dd {
+  margin: 0.6em 0 1.5em 2em;
 }
 
-note, code {
-  font-size: 120%;
-  color: #000;
-  background-color: #f2f2f2;
-  border: 1px solid #ccc;
+fieldset {
+  border: none;
+}
+
+legend {
+  padding: 0px 2px;
+  font: bold 1em Verdana, sans-serif;
 }
 
 input, textarea {
@@ -160,35 +134,41 @@
   border: 1px inset #ff7700;
 }
 
-fieldset {
-  border: none;
-}
-
-legend {
-  padding: 0px 2px;
-  font: bold 1em Verdana, sans-serif;
-}
-
 label, .label {
-  font-weight: bold ! important;
+  font-weight: bold;
 }
 
 iframe {
   border: 0px;
 }
 
-dt {
-	font-size:	1.17em;
-	font-weight:	600;
+pre {
+  font-family: Courier, "Courier New", Monaco, monospace;
+  font-size: 100%;
+  color: #000;
+  background-color: #f2f2f2;
+  border: 1px solid #ccc;
 }
 
-dd {
-	margin: 0.6em 0 1.5em 2em;
+code {
+  font-size: 120%;
+  color: #000;
+  background-color: #f2f2f2;
+  border: 1px solid #ccc;
 }
 
-/******************************************************************************/
-/* generic classes                                                            */
-/******************************************************************************/
+blockquote {
+  font-family: Courier, "Courier New", serif;
+  font-size: 120%;
+  margin: 5px 0px;
+  padding: 0.8em;
+  background-color: #f2f2f2;
+  border: 1px solid #ccc;
+}
+
+/***************************************/
+/* generic classes                     */
+/***************************************/
 
 .odd {
   background-color: #f7f6f1;
@@ -215,77 +195,67 @@
   clear: both;
 }
 
-.noborder {
-  border: none;
-}
-
-.strong{
-  font-weight:bold;
-}
-
-.title {
-  text-align: left;
-  font-size:  large;
-  font-weight: bold;
-}
-
-.titleUnderline {
-  color: #000;
-  clear: left;
-  margin: 0px;
-  padding-top: 0.5em;
-  border-bottom: 1px solid black;
-}
-
-.helper{
-  font-size: 96%;
-  color: #555544;
-}
-
-.helper:hover {
-  color: #000;
-  cursor: default;
-}
-
 .hidden {
   display: none;
   visibility: hidden;
 }
 
-.needsvalidation {
-  font-style: italic;
-  color: grey ! important;
-}
+li.invisible { list-style: none; background: none; padding: 0px 0px
+1px 1px; }
 
-.folder {
-  /* disable odd/even under folder class */
-  background-color: transparent;
-}
-
-li.invisible {
-  list-style: none;
-  background: none;
-  padding: 0px 0px 1px 1px;
-}
-
-li.invisible div {
+li.invisible div{
   display: inline;
 }
 
-div.row {
- clear: both;
- padding-bottom:0.4px
+
+/***************************************/
+/*   LAYOUT                            */
+/***************************************/
+
+/* header */
+
+table#header {
+  background: #ff7700 url("banner.png") left top repeat-x;
+  text-align: left;
+}
+
+table#header td {
+  vertical-align: middle;
+}
+
+table#header a {
+color: #000;
 }
 
-div.row span.label{ 
- padding-right:1em
+span#appliName {
+ font-weight: bold;
+ color: #000;
+ white-space: nowrap;
+}
+
+table#header td#headtext {
+  width: 100%;
 }
 
-div.field {
-  margin-left: 0.2em;
-  display: inline;
+a.help{
+  display: block;
+  margin: 0px 5px 0px 8px;
+  height: 17px;
+  width: 17px;
+  background: url('help.png') 0% 0% no-repeat;
 }
 
+a.help:hover {
+  background-position: 0px -16px;
+  text-decoration: none;
+}
+
+/* FIXME appear with 4px width in IE6 */
+div#stateheader{
+  min-width: 66%;
+}
+
+/* Popup on login box and userActionBox */
 div.popup {
   position: absolute;
   z-index: 400;
@@ -300,42 +270,7 @@
   color: black;
 }
 
-/******************************************************************************/
-/* header / layout                                                            */
-/******************************************************************************/
-
-.logo {
- background: #fff;
- border-left: #f2f2f2;
-}
-
-span#appliName {
- font-weight: bold;
- color: #000;
- white-space: nowrap;
-}
-
-#header {
-  background: #ff7700 url("banner.png") left top repeat-x;
-  text-align: left;
-}
-
-table#header td {
-  vertical-align: middle;
-}
-
-table#header a {
-color: #000;
-}
-
-td#headtext {
-  width: 100%;
-}
-
-/*FIXME appear with 4px width in IE6*/
-div#stateheader{
-  width: 66%;
-}
+/* main zone */
 
 div#page {
   background: #e2e2e2;
@@ -343,16 +278,16 @@
   min-height: 800px;
 }
  
-td#contentcol {
-  padding: 8px 5px 5px 10px;
+table#mainLayout{ 
+ margin:0px 3px;
 }
 
+table#mainLayout td#contentcol {
+  padding: 8px 10px 5px;
+}
 
-div#pageContent {
-  clear: both;
-  padding: 10px 1em 2em;
-  background: #ffffff;
-  border: 1px solid #ccc;
+table#mainLayout td.navcol {
+  width: 16em;
 }
 
 #contentheader {
@@ -364,157 +299,29 @@
   color: #000;
 }
 
-td.firstcolumn {
-  width: 220px;
-}
-
-td.navcol {
-  width: 16em;
-}
-
-div.footer {
-  text-align: center;
-}
-div.footer a {
-  color: #000;
-  text-decoration: none;
+div#pageContent {
+  clear: both;
+  padding: 10px 1em 2em;
+  background: #ffffff;
+  border: 1px solid #ccc;
 }
 
-/******************************************************************************/
-/* help button                                                                */
-/******************************************************************************/
-
-a.help{
-  display: block;
-  margin: 0px 5px 0px 8px;
-  height: 17px;
-  width: 17px;
-  background: url('help.png') 0% 0% no-repeat;
-}
+/* rql bar */
 
-a.help:hover {
-  background-position: 0px -16px;
-  text-decoration: none;
-}
-
-/******************************************************************************/
-/* rql bar                                                                    */
-/******************************************************************************/
-
-div#rqlform {
-  width: 100%;
+div#rqlinput {
+  border: 1px solid #cfceb7;
+  margin-bottom: 8px;
+  padding: 3px;
+  background: #cfceb7;
 }
 
 input#rql{
- width: 80%;
- margin-left: 12px;
-}
-
-/******************************************************************************/
-/* user actions menu                                                          */
-/******************************************************************************/
-
-a.logout, a.logout:visited, a.logout:hover{
-  color: #fff;
-  text-decoration: none;
-}
-
-div#userActionsBox {
-  width: 14em;
-  text-align: right;
-}
-
-div#userActionsBox a.popupMenu {
-  color: black;
-  text-decoration: underline;
-}
-
-/******************************************************************************/
-/* buttons                                                                    */
-/******************************************************************************/
-
-input#rqlboxsubmit, input#rqlboxsubmit2 {
-  background: #fffff8 url("go.png") 50% 50% no-repeat;
-  width: 20px;
-  height: 20px;
-  margin: 0px;
-}
-
-input.button,
-input.formButton,
-input.validateButton,
-input.searchButton,
-input.loginButton {
-  border-top: 1px solid #edecd2;
-  border-left: 1px solid #edecd2;
-  border-right: 1px solid #cfceb7;
-  border-bottom: 1px solid #cfceb7;
-  background: #fffff8 url("button.png") bottom left repeat-x;
-}
-
-input.searchButton {
-  background: #f0eff0 url("gradient-grey-up.png") left top repeat-x;
-}
-
-input.button,
-input.validateButton {
-  margin: 1em 1em 0px 0px ! important;
+  width: 95%;
 }
 
-/******************************************************************************/
-/* primary view                                                               */
-/******************************************************************************/
-
-.mainInfo  {
-  margin-right: 1em;
-  padding: 0.2em;
-}
-
-div.mainRelated {
-  border: none;
-  margin-right: 1em;
-  padding: 0.5em 0.2em 0.2em;
-}
-
-div.sideRelated h4,
-div.sideRelated h5 {
-  margin-top: 0px;
-  margin-bottom: 0px;
-}
-
-div.sideRelated {
-  margin-right: 1em;
-  padding: 12px 0px 12px 12px;
-  min-width: 21em;
-  max-width: 50em;
-}
-
-div.metadata {
-  font-size: 90%;
-  margin: 5px 0px 3px;
-  color: #666;
-  font-style: italic;
-  text-align: right;
-}
-
-div.section {
-  margin-top: 0.5em;
-  width:100%;
-}
-
-div.section a:hover {
-  text-decoration: none;
-}
-
-
-
-/******************************************************************************/
-/* boxes                                                                      */
-/******************************************************************************/
-
+/* boxes */
 div.navboxes {
-  padding-left: 3px;
-  margin-top: 8px;
+ margin-top: 8px; 
 }
 
 div.boxFrame {
@@ -594,12 +401,14 @@
   color: #111100;
 }
 
+
 a.boxMenu {
   background: transparent url("puce_down.png") 98% 6px no-repeat;
   display: block;
   padding: 1px 9px 1px 3px;
 }
 
+
 a.popupMenu {
   background: transparent url("puce_down_black.png") 2% 6px no-repeat;
   padding-left: 2em;
@@ -648,6 +457,12 @@
   background: #eeedd9;
 }
 
+ul.sideBox li{ 
+ list-style: none;
+ background: none; 
+ padding: 0px 0px 1px 1px;
+ }
+
 div.sideBoxBody {
   padding: 0.2em 5px;
 }
@@ -680,48 +495,53 @@
  padding:0px 5px;
 }
 
-/******************************************************************************/
-/* inline edition and generic form classes                                    */
-/******************************************************************************/
-
-div.inlineedit {
-  display: none;
+input.rqlsubmit{
+  background: #fffff8 url("go.png") 50% 50% no-repeat;
+  width: 20px;
+  height: 20px;
+  margin: 0px;
 }
 
-div.editableField {
-  display: inline;
-}
-
-div.editableField:hover,
-div.editableField p:hover {
-  background-color: #eeedd9;
+input#norql{
+  width:13em;
+  margin-right: 2px;
 }
 
-option.separator {
-  font-weight: bold;
-  background: #ccc;
-  text-align: center;
-}
-
-input.error {
-  background: transparent url("error.png") 100% 50% no-repeat;
+/* user actions menu */
+a.logout, a.logout:visited, a.logout:hover{
+  color: #fff;
+  text-decoration: none;
 }
 
-span.error {
-  display: block;
-  font-weight: bold;
-  color: #ed0d0d;
+div#userActionsBox {
+  width: 14em;
+  text-align: right;
 }
 
-/******************************************************************************/
-/* navigation                                                                 */
-/******************************************************************************/
+div#userActionsBox a.popupMenu {
+  color: black;
+  text-decoration: underline;
+}
 
+/**************/
+/* navigation */
+/**************/
 div#etyperestriction {
   margin-bottom: 1ex;
   border-bottom: 1px solid #ccc;
 }
 
+span.slice a:visited,
+span.slice a:hover{
+  color: #555544;
+}
+
+span.selectedSlice a:visited,
+span.selectedSlice a {
+  color: #000;
+}
+
+/* FIXME should be moved to cubes/folder */
 div.navigation a {
   text-align: center;
   text-decoration: none;
@@ -736,25 +556,82 @@
   color: #000;
 }
 
-span.slice a:visited,
-span.slice a:hover{
-  color: #555544;
+/***************************************/
+/* entity views                        */
+/***************************************/
+
+.mainInfo  {
+  margin-right: 1em;
+  padding: 0.2em;
+}
+
+
+div.mainRelated {
+  border: none;
+  margin-right: 1em;
+  padding: 0.5em 0.2em 0.2em;
+}
+
+div.sideRelated h4,
+div.sideRelated h5 {
+  margin-top: 0px;
+  margin-bottom: 0px;
+}
+
+div.primaryRight{
+  float:right;
+  
+ }
+
+div.sideRelated {
+  margin-right: 1em;
+  padding: 12px 0px 12px 12px;
+  min-width: 21em;
+  max-width: 50em;
 }
 
-span.selectedSlice a:visited,
-span.selectedSlice a {
-  color: #000;
+div.metadata {
+  font-size: 90%;
+  margin: 5px 0px 3px;
+  color: #666;
+  font-style: italic;
+  text-align: right;
+}
+
+div.section {
+  margin-top: 0.5em;
+  width:100%;
+}
+
+div.section a:hover {
+  text-decoration: none;
 }
 
-/******************************************************************************/
-/* messages                                                                   */
-/******************************************************************************/
+/* basic entity view */
+
+div.row {
+ clear: both;
+ padding-bottom:0.4px
+}
+
+div.row span.label{ 
+ padding-right:1em
+}
+
+div.field {
+  margin-left: 0.2em;
+  display: inline;
+}
+
+
+/***************************************/
+/* messages                            */
+/***************************************/
 
 .warning,
 .message,
-.errorMessage,
-.searchMessage,
-.statemessage {
+.errorMessage ,
+.searchMessage{
   padding: 0.3em 0.3em 0.3em 1em;
   font-weight: bold;
 }
@@ -772,13 +649,6 @@
   background: #f8f8ee;
 }
 
-div#rqlinput {
-  border: 1px solid #cfceb7;
-  margin-bottom: 8px;
-  padding: 3px;
-  background: #cfceb7;
-}
-
 .message {
   margin: 0px;
   background: #f8f8ee url("information.png") 5px center no-repeat;
@@ -823,9 +693,9 @@
   display: none;
 }
 
-/******************************************************************************/
-/* listing table                                                              */
-/******************************************************************************/
+/***************************************/
+/* listing table                       */
+/***************************************/
 
 table.listing {
  margin: 10px 0em;
@@ -840,6 +710,25 @@
   cursor: pointer;
 }
 
+table.listing tr th {
+  border: 1px solid #dfdfdf;
+  border-right:none;
+  font-size: 8pt;
+  padding: 4px;
+}
+
+table.listing tr .header {
+  border-right: 1px solid #dfdfdf;
+  cursor: pointer;
+}
+
+table.listing td {
+  color: #3D3D3D;
+  padding: 4px;
+  background-color: #FFF;
+  vertical-align: top;
+}
+
 table.listing th,
 table.listing td {
   padding: 3px 0px 3px 5px;
@@ -872,82 +761,10 @@
   top: -1px;
 }
 
-/******************************************************************************/
-/* drag and drop zone (XXX only used in seo for now)                          */
-/******************************************************************************/
 
-div.droppable {
-  border: 1px dashed black;
-  margin: 2px;
-  padding: 2px;
-  height: 15px;
-}
-
-div.drophover {
-  background: #f4f5ed;
-}
-
-/******************************************************************************/
-/* search box                                                                 */
-/******************************************************************************/
-
-input#norql{
-  width:13em;
-  margin-right: 2px;
-}
-
-/******************************************************************************/
-/* filter box                                                                 */
-/******************************************************************************/
-
-#filter_box input {
-  width: 180px;
-}
-#filter_box label {
-  float: left;
-}
-#filter_box select.radio {
-  width: 47px;
-  float: right;
-}
-#filter_box select {
-  width: 185px;
-}
-#filter_box option.disabled {
-  background: lightgray;
-}
-
-/******************************************************************************/
-/* table filter form                                                          */
-/******************************************************************************/
-
-table.filter th {
-  font-weight: bold;
-  background: #ebe8d9 url("button.png") repeat-x;
-  padding: 0.3em;
-  border-bottom: 1px solid #cfceb7;
-  text-align: left;
-}
-
-table.filter div.facet {
-  padding: 0.6em 0.2em;
-  margin: 0em 1em;
-  border: 1px solid #ccc;
-}
-
-table.filter div.facetTitle {
-  font-weight: bold;
-}
-
-
-div#tableActionsBox {
- direction:rtl;
- float:right
-}
-
-/******************************************************************************/
-/* error view (views/management.py)                                           */
-/******************************************************************************/
+/***************************************/
+/* error view (views/management.py)    */
+/***************************************/
 
 div.pycontext { /* html traceback */
   font-family: Verdana, sans-serif;
@@ -961,32 +778,10 @@
   color: #ff0000;
 }
 
-/******************************************************************************/
-/* index view (views/startup.py)                                              */
-/******************************************************************************/
 
-table.startup {
-  width: 100%;
-}
-
-table.startup td {
-  padding: 0.1em 0.2em;
-}
-
-table.startup td.addcol {
-  text-align: right;
-  width: 0.5em;
-}
-
-table.startup th{
-  padding-top: 3px;
-  padding-bottom: 3px;
-  text-align: left;
-}
-
-/******************************************************************************/
-/* addcombobox                                                                */
-/******************************************************************************/
+/***************************************/
+/* addcombobox                         */
+/***************************************/
 
 input#newopt{ 
  width:120px ; 
@@ -1005,3 +800,58 @@
  display:block;
  float:left;
 }
+
+/***************************************/
+/* buttons                             */
+/***************************************/
+
+input.button{  
+  margin: 1em 1em 0px 0px;
+  border: 1px solid #edecd2;
+  border-color:#edecd2 #cfceb7 #cfceb7  #edecd2;
+  background: #fffff8 url("button.png") bottom left repeat-x;
+}
+
+/* FileItemInnerView  jquery.treeview.css */
+.folder {
+  /* disable odd/even under folder class */
+  background-color: transparent;
+}
+
+/***************************************/
+/* footer                              */
+/***************************************/
+
+div.footer {
+  text-align: center;
+}
+div.footer a {
+  color: #000;
+  text-decoration: none;
+}
+
+
+/****************************************/
+/* FIXME must by managed by cubes       */
+/****************************************/
+.needsvalidation {
+  font-style: italic;
+  color: gray;
+}
+
+
+/***************************************/
+/* FIXME : Deprecated ? entity view ?  */
+/***************************************/
+.title {
+  text-align: left;
+  font-size:  large;
+  font-weight: bold;
+}
+
+input.validateButton {  
+  margin: 1em 1em 0px 0px;
+  border: 1px solid #edecd2;
+  border-color:#edecd2 #cfceb7 #cfceb7  #edecd2;
+  background: #fffff8 url("button.png") bottom left repeat-x;
+}
\ No newline at end of file
--- a/web/data/cubicweb.edition.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.edition.js	Wed Apr 15 17:36:09 2009 +0200
@@ -264,7 +264,8 @@
     var d = async_rawremote_exec('inline_creation_form', peid, ptype, ttype, rtype, role);
     d.addCallback(function (response) {
 	var linknode = getNode('add' + rtype + ':' + peid + 'link');
-	var form = jQuery(getDomFromResponse(response));
+        var dom = getDomFromResponse(response);
+	var form = jQuery(dom);
 	form.css('display', 'none');
 	form.insertBefore(linknode.parentNode).slideDown('fast');
 	// setStyle(form, {display: 'none'});
@@ -273,6 +274,7 @@
 	// slideDown(form, {'duration':0.6});
 	reorderTabindex();
 	form.trigger('inlinedform-added');
+        postAjaxLoad(dom);
 	// MochiKit.Signal.signal(CubicWeb, 'inlinedform-added', form);
     });
     d.addErrback(function (xxx) {
@@ -402,9 +404,8 @@
 
 /* disable form buttons while the validation is being done */
 function freezeFormButtons(formid) {
-    var formbuttons = jQuery(formid + ' input.validateButton');
     jQuery('#progress').show();
-    jQuery(formid + ' input.validateButton').attr('disabled', 'disabled');
+    jQuery('#' + formid + ' input.validateButton').attr('disabled', 'disabled');
     return true;
 }
 
--- a/web/data/cubicweb.facets.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.facets.css	Wed Apr 15 17:36:09 2009 +0200
@@ -69,7 +69,7 @@
 }
 
 div#filter_box div.boxTitle {
-  visibility: none;
+  visibility: hidden;
   display: none;
 }
 
--- a/web/data/cubicweb.form.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.form.css	Wed Apr 15 17:36:09 2009 +0200
@@ -9,7 +9,7 @@
   width: 100%;
   font-size : 160%;
   font-weight: bold;
-  color: orangered;
+  color: #ff4500;
   padding-bottom : 0.4em;
   text-transform: capitalize;
   background: url("bg_trame_grise.png") left bottom repeat-x;
@@ -178,6 +178,38 @@
   margin-left: 2em;
 }
 
+/*FIXME inlineedit not used ?*/
+/*
+div.inlineedit {
+  display: none;
+}
+*/
+
+div.editableField {
+  display: inline;
+}
+
+div.editableField:hover,
+div.editableField p:hover {
+  background-color: #eeedd9;
+}
+
+input.error {
+  background: transparent url("error.png") 100% 50% no-repeat;
+}
+
+span.error {
+  display: block;
+  font-weight: bold;
+  color: #ed0d0d;
+}
+
+option.separator {
+  font-weight: bold;
+  background: #ccc;
+  text-align: center;
+}
+
 div.trame_grise {
   background: url("bg_trame_grise.png") left top repeat-x;
 }
@@ -189,3 +221,21 @@
   padding-left: 2em;
   background : #f8f8ee url("information.png") 5px center no-repeat ;
 }
+
+.helper{
+  font-size: 96%;
+  color: #555544;
+}
+
+.helper:hover {
+  color: #000;
+  cursor: default;
+}
+
+input.validateButton {  
+  margin: 1em 1em 0px 0px;
+  border: 1px solid #edecd2;
+  border-color:#edecd2 #cfceb7 #cfceb7  #edecd2;
+  background: #fffff8 url("button.png") bottom left repeat-x;
+}
+
--- a/web/data/cubicweb.formfilter.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.formfilter.js	Wed Apr 15 17:36:09 2009 +0200
@@ -104,16 +104,20 @@
 
 var SELECTED_IMG = baseuri()+"data/black-check.png";
 var UNSELECTED_IMG = baseuri()+"data/no-check-no-border.png";
+var UNSELECTED_BORDER_IMG = baseuri()+"data/black-unchecked.png";
 
-function initFacetBoxEvents(root){
+function initFacetBoxEvents(root) {
+    // facetargs : (divid, vid, paginate, extraargs)
     root = root || document;
     jQuery(root).find('form').each(function () {
 	var form = jQuery(this);
+	// NOTE: don't evaluate facetargs here but in callbacks since its value
+	//       may changes and we must send its value when the callback is
+	//       called, not when the page is initialized
 	var facetargs = form.attr('cubicweb:facetargs');
-	if (facetargs) {
+	if (facetargs !== undefined) {
 	    form.submit(function() {
-		var facetargs = evalJSON(form.attr('cubicweb:facetargs'));
-	        buildRQL.apply(null, facetargs); //(divid, vid, paginate, extraargs);
+	        buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
 	        return false;
 	    });
 	    form.find('div.facet').each(function() {
@@ -122,11 +126,17 @@
 		    this.setAttribute('cubicweb:idx', i);
 		});
 		facet.find('div.facetCheckBox').click(function () {
-		    var facetargs = evalJSON(form.attr('cubicweb:facetargs'));
 		    var $this = jQuery(this);
 		    if ($this.hasClass('facetValueSelected')) {
 			$this.removeClass('facetValueSelected');
-			$this.find('img').attr('src', UNSELECTED_IMG);
+			$this.find('img').each(function (i){
+			if (this.getAttribute('cubicweb:unselimg')){
+			       this.setAttribute('src', UNSELECTED_BORDER_IMG);
+			    }
+			    else{
+                             this.setAttribute('src', UNSELECTED_IMG);
+			    }
+			});
 			var index = parseInt($this.attr('cubicweb:idx'));
 			var shift = jQuery.grep(facet.find('.facetValueSelected'), function (n) {
 			    var nindex = parseInt(n.getAttribute('cubicweb:idx'));
@@ -146,13 +156,13 @@
 			jQuery(this).addClass('facetValueSelected');
 			jQuery(this).find('img').attr('src', SELECTED_IMG);
 		    }
-		    buildRQL.apply(null, facetargs); // (divid, vid, paginate, extraargs);
+		    buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
 		    facet.find('.facetBody').animate({scrollTop: 0}, '');
 		});
 		facet.find('select.facetOperator').change(function() {
 		    var nbselected = facet.find('div.facetValueSelected').length;
 		    if (nbselected >= 2) {
-			buildRQL.apply(null, facetargs); // (divid, vid, paginate, extraargs);
+			buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
 		    }
 		});
 		facet.find('div.facetTitle').click(function() {
@@ -171,8 +181,7 @@
     root = root || document;
     jQuery(root).find('form').each(function () {
 	var form = jQuery(this);
-	var facetargs = form.attr('cubicweb:facetargs');
-	if (facetargs) {
+	if (form.attr('cubicweb:facetargs')) {
 	    form.find('div.facet').each(function() {
 		var facet = jQuery(this);
 		var lastSelected = null;
--- a/web/data/cubicweb.gmap.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.gmap.js	Wed Apr 15 17:36:09 2009 +0200
@@ -26,7 +26,7 @@
       var self = this; // bind this to a local variable
       jQuery.getJSON(jsonurl, function(geodata) {
 	if (geodata.center) {
-	  var zoomLevel = 8; // FIXME arbitrary !
+	  var zoomLevel = geodata.zoomlevel;
 	  map.setCenter(new GLatLng(geodata.center.latitude, geodata.center.longitude),
 		        zoomLevel);
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.lazy.js	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,14 @@
+
+function load_now(eltsel, holesel, reloadable) {
+    var lazydiv = jQuery(eltsel);
+    var hole = lazydiv.children(holesel);
+    if ((hole.length == 0) && !reloadable) {
+	/* the hole is already filled */
+	return;
+    }
+    lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
+}
+
+function trigger_load(divid) {
+    jQuery('#lazy-' + divid).trigger('load_' + divid);
+}
--- a/web/data/cubicweb.login.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.login.css	Wed Apr 15 17:36:09 2009 +0200
@@ -76,7 +76,8 @@
 }
 
 input.loginButton {
-  display:block;
+  border: 1px solid #edecd2;
+  border-color:#edecd2 #cfceb7 #cfceb7  #edecd2;
   margin: 2px 0px 0px;
   background: #f0eff0 url("gradient-grey-up.png") left top repeat-x; 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.manageview.css	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,22 @@
+/***************************************/
+/* Manage view (views/startup.py)      */
+/***************************************/
+
+table.startup {
+  width: 100%;
+}
+
+table.startup td {
+  padding: 0.1em 0.2em;
+}
+
+table.startup td.addcol {
+  text-align: right;
+  width: 0.5em;
+}
+
+table.startup th{
+  padding-top: 3px;
+  padding-bottom: 3px;
+  text-align: left;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.preferences.js	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,10 @@
+/* toggle visibility of an element by its id
+ * & set current visibility status in a cookie
+ * XXX whenever used outside of preferences, don't forget to
+ *     move me in a more appropriate place
+ */
+function toggle_and_remember_visibility(elemId, cookiename) {
+    jqNode(elemId).toggleClass('hidden');
+    async_remote_exec('set_cookie', cookiename,
+                      jQuery('#' + elemId).attr('class'));
+}
--- a/web/data/cubicweb.schema.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.schema.css	Wed Apr 15 17:36:09 2009 +0200
@@ -5,6 +5,16 @@
  *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
  */
 
+
+.titleUnderline {
+  color: #000;
+  clear: left;
+  margin: 0px;
+  padding-top: 0.5em;
+  border-bottom: 1px solid black;
+}
+
+
 div.relationDefinition { 
   float: left;   
   position: relative;
--- a/web/data/cubicweb.tablesorter.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.tablesorter.css	Wed Apr 15 17:36:09 2009 +0200
@@ -8,24 +8,6 @@
 	text-align: left;
 } */
 
-table.listing tr th {
-  border: 1px solid #FFF;
-  font-size: 8pt;
-  padding: 4px;
-}
-
-table.listing tr .header {
-  cursor: pointer;
-}
-
-table.listing td {
-  color: #3D3D3D;
-  padding: 4px;
-  background-color: #FFF;
-  vertical-align: top;
-}
-
-
 table.listing tr .headerSortUp {
   background-image: url(asc.gif);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.tableview.css	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,27 @@
+/***************************************/
+/* filter table form                   */
+/***************************************/
+
+table.filter th {
+  font-weight: bold;
+  background: #ebe8d9 url("button.png") repeat-x;
+  padding: 0.3em;
+  border-bottom: 1px solid #cfceb7;
+  text-align: left;
+}
+
+table.filter div.facet {
+  padding: 0.6em 0.2em;
+  margin: 0em 1em;
+  border: 1px solid #ccc;
+}
+
+table.filter div.facetTitle {
+  font-weight: bold;
+}
+
+
+div#tableActionsBox {
+ direction:rtl;
+ float:right
+}
--- a/web/data/cubicweb.tabs.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.tabs.js	Wed Apr 15 17:36:09 2009 +0200
@@ -1,5 +1,6 @@
-function set_tab(tabname) {
-  // set appropriate cookie
-  // XXX see if we can no just do it with jQuery
-  async_remote_exec('remember_active_tab', tabname);
+function set_tab(tabname, cookiename) {
+    // set appropriate cookie
+    async_remote_exec('set_cookie', cookiename, tabname);
+    // trigger show + tabname event
+    trigger_load(tabname);
 }
--- a/web/data/cubicweb.timeline-bundle.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.timeline-bundle.js	Wed Apr 15 17:36:09 2009 +0200
@@ -1,3980 +1,10123 @@
-
-var SimileAjax = {
-    loaded:                 false,
-    loadingScriptsCount:    0,
-    error:                  null,
-    params:                 { bundle:"true" }
+var SimileAjax_urlPrefix = baseuri() + 'data/';
+var Timeline_urlPrefix = baseuri() + 'data/';
+
+/*==================================================
+ *  Simile Ajax API
+ *
+ *  Include this file in your HTML file as follows:
+ *
+ *    <script src="http://simile.mit.edu/ajax/api/simile-ajax-api.js" type="text/javascript"></script>
+ *
+ *==================================================
+ */
+
+if (typeof SimileAjax == "undefined") {
+    var SimileAjax = {
+        loaded:                 false,
+        loadingScriptsCount:    0,
+        error:                  null,
+        params:                 { bundle:"true" }
+    };
+
+    SimileAjax.Platform = new Object();
+        /*
+            HACK: We need these 2 things here because we cannot simply append
+            a <script> element containing code that accesses SimileAjax.Platform
+            to initialize it because IE executes that <script> code first
+            before it loads ajax.js and platform.js.
+        */
+
+    var getHead = function(doc) {
+        return doc.getElementsByTagName("head")[0];
+    };
+
+    SimileAjax.findScript = function(doc, substring) {
+        var heads = doc.documentElement.getElementsByTagName("head");
+        for (var h = 0; h < heads.length; h++) {
+            var node = heads[h].firstChild;
+            while (node != null) {
+                if (node.nodeType == 1 && node.tagName.toLowerCase() == "script") {
+                    var url = node.src;
+                    var i = url.indexOf(substring);
+                    if (i >= 0) {
+                        return url;
+                    }
+                }
+                node = node.nextSibling;
+            }
+        }
+        return null;
+    };
+    SimileAjax.includeJavascriptFile = function(doc, url, onerror, charset) {
+        onerror = onerror || "";
+        if (doc.body == null) {
+            try {
+                var q = "'" + onerror.replace( /'/g, '&apos' ) + "'"; // "
+                doc.write("<script src='" + url + "' onerror="+ q +
+                          (charset ? " charset='"+ charset +"'" : "") +
+                          " type='text/javascript'>"+ onerror + "</script>");
+                return;
+            } catch (e) {
+                // fall through
+            }
+        }
+
+        var script = doc.createElement("script");
+        if (onerror) {
+            try { script.innerHTML = onerror; } catch(e) {}
+            script.setAttribute("onerror", onerror);
+        }
+        if (charset) {
+            script.setAttribute("charset", charset);
+        }
+        script.type = "text/javascript";
+        script.language = "JavaScript";
+        script.src = url;
+        return getHead(doc).appendChild(script);
+    };
+    SimileAjax.includeJavascriptFiles = function(doc, urlPrefix, filenames) {
+        for (var i = 0; i < filenames.length; i++) {
+            SimileAjax.includeJavascriptFile(doc, urlPrefix + filenames[i]);
+        }
+        SimileAjax.loadingScriptsCount += filenames.length;
+        SimileAjax.includeJavascriptFile(doc, SimileAjax.urlPrefix + "scripts/signal.js?" + filenames.length);
+    };
+    SimileAjax.includeCssFile = function(doc, url) {
+        if (doc.body == null) {
+            try {
+                doc.write("<link rel='stylesheet' href='" + url + "' type='text/css'/>");
+                return;
+            } catch (e) {
+                // fall through
+            }
+        }
+
+        var link = doc.createElement("link");
+        link.setAttribute("rel", "stylesheet");
+        link.setAttribute("type", "text/css");
+        link.setAttribute("href", url);
+        getHead(doc).appendChild(link);
+    };
+    SimileAjax.includeCssFiles = function(doc, urlPrefix, filenames) {
+        for (var i = 0; i < filenames.length; i++) {
+            SimileAjax.includeCssFile(doc, urlPrefix + filenames[i]);
+        }
+    };
+
+    /**
+     * Append into urls each string in suffixes after prefixing it with urlPrefix.
+     * @param {Array} urls
+     * @param {String} urlPrefix
+     * @param {Array} suffixes
+     */
+    SimileAjax.prefixURLs = function(urls, urlPrefix, suffixes) {
+        for (var i = 0; i < suffixes.length; i++) {
+            urls.push(urlPrefix + suffixes[i]);
+        }
+    };
+
+    /**
+     * Parse out the query parameters from a URL
+     * @param {String} url    the url to parse, or location.href if undefined
+     * @param {Object} to     optional object to extend with the parameters
+     * @param {Object} types  optional object mapping keys to value types
+     *        (String, Number, Boolean or Array, String by default)
+     * @return a key/value Object whose keys are the query parameter names
+     * @type Object
+     */
+    SimileAjax.parseURLParameters = function(url, to, types) {
+        to = to || {};
+        types = types || {};
+
+        if (typeof url == "undefined") {
+            url = location.href;
+        }
+        var q = url.indexOf("?");
+        if (q < 0) {
+            return to;
+        }
+        url = (url+"#").slice(q+1, url.indexOf("#")); // toss the URL fragment
+
+        var params = url.split("&"), param, parsed = {};
+        var decode = window.decodeURIComponent || unescape;
+        for (var i = 0; param = params[i]; i++) {
+            var eq = param.indexOf("=");
+            var name = decode(param.slice(0,eq));
+            var old = parsed[name];
+            if (typeof old == "undefined") {
+                old = [];
+            } else if (!(old instanceof Array)) {
+                old = [old];
+            }
+            parsed[name] = old.concat(decode(param.slice(eq+1)));
+        }
+        for (var i in parsed) {
+            if (!parsed.hasOwnProperty(i)) continue;
+            var type = types[i] || String;
+            var data = parsed[i];
+            if (!(data instanceof Array)) {
+                data = [data];
+            }
+            if (type === Boolean && data[0] == "false") {
+                to[i] = false; // because Boolean("false") === true
+            } else {
+                to[i] = type.apply(this, data);
+            }
+        }
+        return to;
+    };
+
+    (function() {
+        var javascriptFiles = [
+            "jquery-1.2.6.js",
+            "platform.js",
+            "debug.js",
+            "xmlhttp.js",
+            "json.js",
+            "dom.js",
+            "graphics.js",
+            "date-time.js",
+            "string.js",
+            "html.js",
+            "data-structure.js",
+            "units.js",
+
+            "ajax.js",
+            "history.js",
+            "window-manager.js"
+        ];
+        var cssFiles = [
+            "graphics.css"
+        ];
+
+        if (typeof SimileAjax_urlPrefix == "string") {
+            SimileAjax.urlPrefix = SimileAjax_urlPrefix;
+        } else {
+            var url = SimileAjax.findScript(document, "simile-ajax-api.js");
+            if (url == null) {
+                SimileAjax.error = new Error("Failed to derive URL prefix for Simile Ajax API code files");
+                return;
+            }
+
+            SimileAjax.urlPrefix = url.substr(0, url.indexOf("simile-ajax-api.js"));
+        }
+
+        SimileAjax.parseURLParameters(url, SimileAjax.params, {bundle:Boolean});
+//         if (SimileAjax.params.bundle) {
+//             SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix, [ "simile-ajax-bundle.js" ]);
+//         } else {
+//             SimileAjax.includeJavascriptFiles(document, SimileAjax.urlPrefix + "scripts/", javascriptFiles);
+//         }
+        SimileAjax.includeCssFiles(document, SimileAjax.urlPrefix + "styles/", cssFiles);
+
+        SimileAjax.loaded = true;
+    })();
+}
+/*==================================================
+ *  Platform Utility Functions and Constants
+ *==================================================
+ */
+
+/*  This must be called after our jQuery has been loaded
+    but before control returns to user-code.
+*/
+SimileAjax.jQuery = jQuery;
+// SimileAjax.jQuery = jQuery.noConflict(true);
+if (typeof window["$"] == "undefined") {
+    window.$ = SimileAjax.jQuery;
+}
+
+SimileAjax.Platform.os = {
+    isMac:   false,
+    isWin:   false,
+    isWin32: false,
+    isUnix:  false
+};
+SimileAjax.Platform.browser = {
+    isIE:           false,
+    isNetscape:     false,
+    isMozilla:      false,
+    isFirefox:      false,
+    isOpera:        false,
+    isSafari:       false,
+
+    majorVersion:   0,
+    minorVersion:   0
+};
+
+(function() {
+    var an = navigator.appName.toLowerCase();
+	var ua = navigator.userAgent.toLowerCase();
+
+    /*
+     *  Operating system
+     */
+	SimileAjax.Platform.os.isMac = (ua.indexOf('mac') != -1);
+	SimileAjax.Platform.os.isWin = (ua.indexOf('win') != -1);
+	SimileAjax.Platform.os.isWin32 = SimileAjax.Platform.isWin && (
+        ua.indexOf('95') != -1 ||
+        ua.indexOf('98') != -1 ||
+        ua.indexOf('nt') != -1 ||
+        ua.indexOf('win32') != -1 ||
+        ua.indexOf('32bit') != -1
+    );
+	SimileAjax.Platform.os.isUnix = (ua.indexOf('x11') != -1);
+
+    /*
+     *  Browser
+     */
+    SimileAjax.Platform.browser.isIE = (an.indexOf("microsoft") != -1);
+    SimileAjax.Platform.browser.isNetscape = (an.indexOf("netscape") != -1);
+    SimileAjax.Platform.browser.isMozilla = (ua.indexOf("mozilla") != -1);
+    SimileAjax.Platform.browser.isFirefox = (ua.indexOf("firefox") != -1);
+    SimileAjax.Platform.browser.isOpera = (an.indexOf("opera") != -1);
+    SimileAjax.Platform.browser.isSafari = (an.indexOf("safari") != -1);
+
+    var parseVersionString = function(s) {
+        var a = s.split(".");
+        SimileAjax.Platform.browser.majorVersion = parseInt(a[0]);
+        SimileAjax.Platform.browser.minorVersion = parseInt(a[1]);
+    };
+    var indexOf = function(s, sub, start) {
+        var i = s.indexOf(sub, start);
+        return i >= 0 ? i : s.length;
+    };
+
+    if (SimileAjax.Platform.browser.isMozilla) {
+        var offset = ua.indexOf("mozilla/");
+        if (offset >= 0) {
+            parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+        }
+    }
+    if (SimileAjax.Platform.browser.isIE) {
+        var offset = ua.indexOf("msie ");
+        if (offset >= 0) {
+            parseVersionString(ua.substring(offset + 5, indexOf(ua, ";", offset)));
+        }
+    }
+    if (SimileAjax.Platform.browser.isNetscape) {
+        var offset = ua.indexOf("rv:");
+        if (offset >= 0) {
+            parseVersionString(ua.substring(offset + 3, indexOf(ua, ")", offset)));
+        }
+    }
+    if (SimileAjax.Platform.browser.isFirefox) {
+        var offset = ua.indexOf("firefox/");
+        if (offset >= 0) {
+            parseVersionString(ua.substring(offset + 8, indexOf(ua, " ", offset)));
+        }
+    }
+
+    if (!("localeCompare" in String.prototype)) {
+        String.prototype.localeCompare = function (s) {
+            if (this < s) return -1;
+            else if (this > s) return 1;
+            else return 0;
+        };
+    }
+})();
+
+SimileAjax.Platform.getDefaultLocale = function() {
+    return SimileAjax.Platform.clientLocale;
+};/*==================================================
+ *  Debug Utility Functions
+ *==================================================
+ */
+
+SimileAjax.Debug = {
+    silent: false
+};
+
+SimileAjax.Debug.log = function(msg) {
+    var f;
+    if ("console" in window && "log" in window.console) { // FireBug installed
+        f = function(msg2) {
+            console.log(msg2);
+        }
+    } else {
+        f = function(msg2) {
+            if (!SimileAjax.Debug.silent) {
+                alert(msg2);
+            }
+        }
+    }
+    SimileAjax.Debug.log = f;
+    f(msg);
+};
+
+SimileAjax.Debug.warn = function(msg) {
+    var f;
+    if ("console" in window && "warn" in window.console) { // FireBug installed
+        f = function(msg2) {
+            console.warn(msg2);
+        }
+    } else {
+        f = function(msg2) {
+            if (!SimileAjax.Debug.silent) {
+                alert(msg2);
+            }
+        }
+    }
+    SimileAjax.Debug.warn = f;
+    f(msg);
+};
+
+SimileAjax.Debug.exception = function(e, msg) {
+    var f, params = SimileAjax.parseURLParameters();
+    if (params.errors == "throw" || SimileAjax.params.errors == "throw") {
+        f = function(e2, msg2) {
+            throw(e2); // do not hide from browser's native debugging features
+        };
+    } else if ("console" in window && "error" in window.console) { // FireBug installed
+        f = function(e2, msg2) {
+            if (msg2 != null) {
+                console.error(msg2 + " %o", e2);
+            } else {
+                console.error(e2);
+            }
+            throw(e2); // do not hide from browser's native debugging features
+        };
+    } else {
+        f = function(e2, msg2) {
+            if (!SimileAjax.Debug.silent) {
+                alert("Caught exception: " + msg2 + "\n\nDetails: " + ("description" in e2 ? e2.description : e2));
+            }
+            throw(e2); // do not hide from browser's native debugging features
+        };
+    }
+    SimileAjax.Debug.exception = f;
+    f(e, msg);
+};
+
+SimileAjax.Debug.objectToString = function(o) {
+    return SimileAjax.Debug._objectToString(o, "");
+};
+
+SimileAjax.Debug._objectToString = function(o, indent) {
+    var indent2 = indent + " ";
+    if (typeof o == "object") {
+        var s = "{";
+        for (n in o) {
+            s += indent2 + n + ": " + SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
+        }
+        s += indent + "}";
+        return s;
+    } else if (typeof o == "array") {
+        var s = "[";
+        for (var n = 0; n < o.length; n++) {
+            s += SimileAjax.Debug._objectToString(o[n], indent2) + "\n";
+        }
+        s += indent + "]";
+        return s;
+    } else {
+        return o;
+    }
+};
+/**
+ * @fileOverview XmlHttp utility functions
+ * @name SimileAjax.XmlHttp
+ */
+
+SimileAjax.XmlHttp = new Object();
+
+/**
+ *  Callback for XMLHttp onRequestStateChange.
+ */
+SimileAjax.XmlHttp._onReadyStateChange = function(xmlhttp, fError, fDone) {
+    switch (xmlhttp.readyState) {
+    // 1: Request not yet made
+    // 2: Contact established with server but nothing downloaded yet
+    // 3: Called multiple while downloading in progress
+
+    // Download complete
+    case 4:
+        try {
+            if (xmlhttp.status == 0     // file:// urls, works on Firefox
+             || xmlhttp.status == 200   // http:// urls
+            ) {
+                if (fDone) {
+                    fDone(xmlhttp);
+                }
+            } else {
+                if (fError) {
+                    fError(
+                        xmlhttp.statusText,
+                        xmlhttp.status,
+                        xmlhttp
+                    );
+                }
+            }
+        } catch (e) {
+            SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange", e);
+        }
+        break;
+    }
+};
+
+/**
+ *  Creates an XMLHttpRequest object. On the first run, this
+ *  function creates a platform-specific function for
+ *  instantiating an XMLHttpRequest object and then replaces
+ *  itself with that function.
+ */
+SimileAjax.XmlHttp._createRequest = function() {
+    if (SimileAjax.Platform.browser.isIE) {
+        var programIDs = [
+        "Msxml2.XMLHTTP",
+        "Microsoft.XMLHTTP",
+        "Msxml2.XMLHTTP.4.0"
+        ];
+        for (var i = 0; i < programIDs.length; i++) {
+            try {
+                var programID = programIDs[i];
+                var f = function() {
+                    return new ActiveXObject(programID);
+                };
+                var o = f();
+
+                // We are replacing the SimileAjax._createXmlHttpRequest
+                // function with this inner function as we've
+                // found out that it works. This is so that we
+                // don't have to do all the testing over again
+                // on subsequent calls.
+                SimileAjax.XmlHttp._createRequest = f;
+
+                return o;
+            } catch (e) {
+                // silent
+            }
+        }
+        // fall through to try new XMLHttpRequest();
+    }
+
+    try {
+        var f = function() {
+            return new XMLHttpRequest();
+        };
+        var o = f();
+
+        // We are replacing the SimileAjax._createXmlHttpRequest
+        // function with this inner function as we've
+        // found out that it works. This is so that we
+        // don't have to do all the testing over again
+        // on subsequent calls.
+        SimileAjax.XmlHttp._createRequest = f;
+
+        return o;
+    } catch (e) {
+        throw new Error("Failed to create an XMLHttpRequest object");
+    }
+};
+
+/**
+ * Performs an asynchronous HTTP GET.
+ *
+ * @param {Function} fError a function of the form
+     function(statusText, statusCode, xmlhttp)
+ * @param {Function} fDone a function of the form function(xmlhttp)
+ */
+SimileAjax.XmlHttp.get = function(url, fError, fDone) {
+    var xmlhttp = SimileAjax.XmlHttp._createRequest();
+
+    xmlhttp.open("GET", url, true);
+    xmlhttp.onreadystatechange = function() {
+        SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+    };
+    xmlhttp.send(null);
+};
+
+/**
+ * Performs an asynchronous HTTP POST.
+ *
+ * @param {Function} fError a function of the form
+     function(statusText, statusCode, xmlhttp)
+ * @param {Function} fDone a function of the form function(xmlhttp)
+ */
+SimileAjax.XmlHttp.post = function(url, body, fError, fDone) {
+    var xmlhttp = SimileAjax.XmlHttp._createRequest();
+
+    xmlhttp.open("POST", url, true);
+    xmlhttp.onreadystatechange = function() {
+        SimileAjax.XmlHttp._onReadyStateChange(xmlhttp, fError, fDone);
+    };
+    xmlhttp.send(body);
+};
+
+SimileAjax.XmlHttp._forceXML = function(xmlhttp) {
+    try {
+        xmlhttp.overrideMimeType("text/xml");
+    } catch (e) {
+        xmlhttp.setrequestheader("Content-Type", "text/xml");
+    }
+};/*
+ *  Copied directly from http://www.json.org/json.js.
+ */
+
+/*
+    json.js
+    2006-04-28
+
+    This file adds these methods to JavaScript:
+
+        object.toJSONString()
+
+            This method produces a JSON text from an object. The
+            object must not contain any cyclical references.
+
+        array.toJSONString()
+
+            This method produces a JSON text from an array. The
+            array must not contain any cyclical references.
+
+        string.parseJSON()
+
+            This method parses a JSON text to produce an object or
+            array. It will return false if there is an error.
+*/
+
+SimileAjax.JSON = new Object();
+
+(function () {
+    var m = {
+        '\b': '\\b',
+        '\t': '\\t',
+        '\n': '\\n',
+        '\f': '\\f',
+        '\r': '\\r',
+        '"' : '\\"',
+        '\\': '\\\\'
+    };
+    var s = {
+        array: function (x) {
+            var a = ['['], b, f, i, l = x.length, v;
+            for (i = 0; i < l; i += 1) {
+                v = x[i];
+                f = s[typeof v];
+                if (f) {
+                    v = f(v);
+                    if (typeof v == 'string') {
+                        if (b) {
+                            a[a.length] = ',';
+                        }
+                        a[a.length] = v;
+                        b = true;
+                    }
+                }
+            }
+            a[a.length] = ']';
+            return a.join('');
+        },
+        'boolean': function (x) {
+            return String(x);
+        },
+        'null': function (x) {
+            return "null";
+        },
+        number: function (x) {
+            return isFinite(x) ? String(x) : 'null';
+        },
+        object: function (x) {
+            if (x) {
+                if (x instanceof Array) {
+                    return s.array(x);
+                }
+                var a = ['{'], b, f, i, v;
+                for (i in x) {
+                    v = x[i];
+                    f = s[typeof v];
+                    if (f) {
+                        v = f(v);
+                        if (typeof v == 'string') {
+                            if (b) {
+                                a[a.length] = ',';
+                            }
+                            a.push(s.string(i), ':', v);
+                            b = true;
+                        }
+                    }
+                }
+                a[a.length] = '}';
+                return a.join('');
+            }
+            return 'null';
+        },
+        string: function (x) {
+            if (/["\\\x00-\x1f]/.test(x)) {
+                x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
+                    var c = m[b];
+                    if (c) {
+                        return c;
+                    }
+                    c = b.charCodeAt();
+                    return '\\u00' +
+                        Math.floor(c / 16).toString(16) +
+                        (c % 16).toString(16);
+                });
+            }
+            return '"' + x + '"';
+        }
+    };
+
+    SimileAjax.JSON.toJSONString = function(o) {
+        if (o instanceof Object) {
+            return s.object(o);
+        } else if (o instanceof Array) {
+            return s.array(o);
+        } else {
+            return o.toString();
+        }
+    };
+
+    SimileAjax.JSON.parseJSON = function () {
+        try {
+            return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
+                    this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
+                eval('(' + this + ')');
+        } catch (e) {
+            return false;
+        }
+    };
+})();
+/*==================================================
+ *  DOM Utility Functions
+ *==================================================
+ */
+
+SimileAjax.DOM = new Object();
+
+SimileAjax.DOM.registerEventWithObject = function(elmt, eventName, obj, handlerName) {
+    SimileAjax.DOM.registerEvent(elmt, eventName, function(elmt2, evt, target) {
+        return obj[handlerName].call(obj, elmt2, evt, target);
+    });
+};
+
+SimileAjax.DOM.registerEvent = function(elmt, eventName, handler) {
+    var handler2 = function(evt) {
+        evt = (evt) ? evt : ((event) ? event : null);
+        if (evt) {
+            var target = (evt.target) ?
+                evt.target : ((evt.srcElement) ? evt.srcElement : null);
+            if (target) {
+                target = (target.nodeType == 1 || target.nodeType == 9) ?
+                    target : target.parentNode;
+            }
+
+            return handler(elmt, evt, target);
+        }
+        return true;
+    }
+
+    if (SimileAjax.Platform.browser.isIE) {
+        elmt.attachEvent("on" + eventName, handler2);
+    } else {
+        elmt.addEventListener(eventName, handler2, false);
+    }
+};
+
+SimileAjax.DOM.getPageCoordinates = function(elmt) {
+    var left = 0;
+    var top = 0;
+
+    if (elmt.nodeType != 1) {
+        elmt = elmt.parentNode;
+    }
+
+    var elmt2 = elmt;
+    while (elmt2 != null) {
+        left += elmt2.offsetLeft;
+        top += elmt2.offsetTop;
+        elmt2 = elmt2.offsetParent;
+    }
+
+    var body = document.body;
+    while (elmt != null && elmt != body) {
+        if ("scrollLeft" in elmt) {
+            left -= elmt.scrollLeft;
+            top -= elmt.scrollTop;
+        }
+        elmt = elmt.parentNode;
+    }
+
+    return { left: left, top: top };
+};
+
+SimileAjax.DOM.getSize = function(elmt) {
+	var w = this.getStyle(elmt,"width");
+	var h = this.getStyle(elmt,"height");
+	if (w.indexOf("px") > -1) w = w.replace("px","");
+	if (h.indexOf("px") > -1) h = h.replace("px","");
+	return {
+		w: w,
+		h: h
+	}
+}
+
+SimileAjax.DOM.getStyle = function(elmt, styleProp) {
+    if (elmt.currentStyle) { // IE
+        var style = elmt.currentStyle[styleProp];
+    } else if (window.getComputedStyle) { // standard DOM
+        var style = document.defaultView.getComputedStyle(elmt, null).getPropertyValue(styleProp);
+    } else {
+    	var style = "";
+    }
+    return style;
+}
+
+SimileAjax.DOM.getEventRelativeCoordinates = function(evt, elmt) {
+    if (SimileAjax.Platform.browser.isIE) {
+      if (evt.type == "mousewheel") {
+        var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+        return {
+          x: evt.clientX - coords.left,
+          y: evt.clientY - coords.top
+        };
+      } else {
+        return {
+          x: evt.offsetX,
+          y: evt.offsetY
+        };
+      }
+    } else {
+        var coords = SimileAjax.DOM.getPageCoordinates(elmt);
+
+        if ((evt.type == "DOMMouseScroll") &&
+          SimileAjax.Platform.browser.isFirefox &&
+          (SimileAjax.Platform.browser.majorVersion == 2)) {
+          // Due to: https://bugzilla.mozilla.org/show_bug.cgi?id=352179
+
+          return {
+            x: evt.screenX - coords.left,
+            y: evt.screenY - coords.top
+          };
+        } else {
+          return {
+              x: evt.pageX - coords.left,
+              y: evt.pageY - coords.top
+          };
+        }
+    }
+};
+
+SimileAjax.DOM.getEventPageCoordinates = function(evt) {
+    if (SimileAjax.Platform.browser.isIE) {
+        return {
+            x: evt.clientX + document.body.scrollLeft,
+            y: evt.clientY + document.body.scrollTop
+        };
+    } else {
+        return {
+            x: evt.pageX,
+            y: evt.pageY
+        };
+    }
+};
+
+SimileAjax.DOM.hittest = function(x, y, except) {
+    return SimileAjax.DOM._hittest(document.body, x, y, except);
+};
+
+SimileAjax.DOM._hittest = function(elmt, x, y, except) {
+    var childNodes = elmt.childNodes;
+    outer: for (var i = 0; i < childNodes.length; i++) {
+        var childNode = childNodes[i];
+        for (var j = 0; j < except.length; j++) {
+            if (childNode == except[j]) {
+                continue outer;
+            }
+        }
+
+        if (childNode.offsetWidth == 0 && childNode.offsetHeight == 0) {
+            /*
+             *  Sometimes SPAN elements have zero width and height but
+             *  they have children like DIVs that cover non-zero areas.
+             */
+            var hitNode = SimileAjax.DOM._hittest(childNode, x, y, except);
+            if (hitNode != childNode) {
+                return hitNode;
+            }
+        } else {
+            var top = 0;
+            var left = 0;
+
+            var node = childNode;
+            while (node) {
+                top += node.offsetTop;
+                left += node.offsetLeft;
+                node = node.offsetParent;
+            }
+
+            if (left <= x && top <= y && (x - left) < childNode.offsetWidth && (y - top) < childNode.offsetHeight) {
+                return SimileAjax.DOM._hittest(childNode, x, y, except);
+            } else if (childNode.nodeType == 1 && childNode.tagName == "TR") {
+                /*
+                 *  Table row might have cells that span several rows.
+                 */
+                var childNode2 = SimileAjax.DOM._hittest(childNode, x, y, except);
+                if (childNode2 != childNode) {
+                    return childNode2;
+                }
+            }
+        }
+    }
+    return elmt;
+};
+
+SimileAjax.DOM.cancelEvent = function(evt) {
+    evt.returnValue = false;
+    evt.cancelBubble = true;
+    if ("preventDefault" in evt) {
+        evt.preventDefault();
+    }
+};
+
+SimileAjax.DOM.appendClassName = function(elmt, className) {
+    var classes = elmt.className.split(" ");
+    for (var i = 0; i < classes.length; i++) {
+        if (classes[i] == className) {
+            return;
+        }
+    }
+    classes.push(className);
+    elmt.className = classes.join(" ");
+};
+
+SimileAjax.DOM.createInputElement = function(type) {
+    var div = document.createElement("div");
+    div.innerHTML = "<input type='" + type + "' />";
+
+    return div.firstChild;
+};
+
+SimileAjax.DOM.createDOMFromTemplate = function(template) {
+    var result = {};
+    result.elmt = SimileAjax.DOM._createDOMFromTemplate(template, result, null);
+
+    return result;
+};
+
+SimileAjax.DOM._createDOMFromTemplate = function(templateNode, result, parentElmt) {
+    if (templateNode == null) {
+        /*
+        var node = doc.createTextNode("--null--");
+        if (parentElmt != null) {
+            parentElmt.appendChild(node);
+        }
+        return node;
+        */
+        return null;
+    } else if (typeof templateNode != "object") {
+        var node = document.createTextNode(templateNode);
+        if (parentElmt != null) {
+            parentElmt.appendChild(node);
+        }
+        return node;
+    } else {
+        var elmt = null;
+        if ("tag" in templateNode) {
+            var tag = templateNode.tag;
+            if (parentElmt != null) {
+                if (tag == "tr") {
+                    elmt = parentElmt.insertRow(parentElmt.rows.length);
+                } else if (tag == "td") {
+                    elmt = parentElmt.insertCell(parentElmt.cells.length);
+                }
+            }
+            if (elmt == null) {
+                elmt = tag == "input" ?
+                    SimileAjax.DOM.createInputElement(templateNode.type) :
+                    document.createElement(tag);
+
+                if (parentElmt != null) {
+                    parentElmt.appendChild(elmt);
+                }
+            }
+        } else {
+            elmt = templateNode.elmt;
+            if (parentElmt != null) {
+                parentElmt.appendChild(elmt);
+            }
+        }
+
+        for (var attribute in templateNode) {
+            var value = templateNode[attribute];
+
+            if (attribute == "field") {
+                result[value] = elmt;
+
+            } else if (attribute == "className") {
+                elmt.className = value;
+            } else if (attribute == "id") {
+                elmt.id = value;
+            } else if (attribute == "title") {
+                elmt.title = value;
+            } else if (attribute == "type" && elmt.tagName == "input") {
+                // do nothing
+            } else if (attribute == "style") {
+                for (n in value) {
+                    var v = value[n];
+                    if (n == "float") {
+                        n = SimileAjax.Platform.browser.isIE ? "styleFloat" : "cssFloat";
+                    }
+                    elmt.style[n] = v;
+                }
+            } else if (attribute == "children") {
+                for (var i = 0; i < value.length; i++) {
+                    SimileAjax.DOM._createDOMFromTemplate(value[i], result, elmt);
+                }
+            } else if (attribute != "tag" && attribute != "elmt") {
+                elmt.setAttribute(attribute, value);
+            }
+        }
+        return elmt;
+    }
+}
+
+SimileAjax.DOM._cachedParent = null;
+SimileAjax.DOM.createElementFromString = function(s) {
+    if (SimileAjax.DOM._cachedParent == null) {
+        SimileAjax.DOM._cachedParent = document.createElement("div");
+    }
+    SimileAjax.DOM._cachedParent.innerHTML = s;
+    return SimileAjax.DOM._cachedParent.firstChild;
+};
+
+SimileAjax.DOM.createDOMFromString = function(root, s, fieldElmts) {
+    var elmt = typeof root == "string" ? document.createElement(root) : root;
+    elmt.innerHTML = s;
+
+    var dom = { elmt: elmt };
+    SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts != null ? fieldElmts : {} );
+
+    return dom;
+};
+
+SimileAjax.DOM._processDOMConstructedFromString = function(dom, elmt, fieldElmts) {
+    var id = elmt.id;
+    if (id != null && id.length > 0) {
+        elmt.removeAttribute("id");
+        if (id in fieldElmts) {
+            var parentElmt = elmt.parentNode;
+            parentElmt.insertBefore(fieldElmts[id], elmt);
+            parentElmt.removeChild(elmt);
+
+            dom[id] = fieldElmts[id];
+            return;
+        } else {
+            dom[id] = elmt;
+        }
+    }
+
+    if (elmt.hasChildNodes()) {
+        SimileAjax.DOM._processDOMChildrenConstructedFromString(dom, elmt, fieldElmts);
+    }
+};
+
+SimileAjax.DOM._processDOMChildrenConstructedFromString = function(dom, elmt, fieldElmts) {
+    var node = elmt.firstChild;
+    while (node != null) {
+        var node2 = node.nextSibling;
+        if (node.nodeType == 1) {
+            SimileAjax.DOM._processDOMConstructedFromString(dom, node, fieldElmts);
+        }
+        node = node2;
+    }
+};
+/**
+ * @fileOverview Graphics utility functions and constants
+ * @name SimileAjax.Graphics
+ */
+
+SimileAjax.Graphics = new Object();
+
+/**
+ * A boolean value indicating whether PNG translucency is supported on the
+ * user's browser or not.
+ *
+ * @type Boolean
+ */
+SimileAjax.Graphics.pngIsTranslucent = (!SimileAjax.Platform.browser.isIE) || (SimileAjax.Platform.browser.majorVersion > 6);
+if (!SimileAjax.Graphics.pngIsTranslucent) {
+    SimileAjax.includeCssFile(document, SimileAjax.urlPrefix + "styles/graphics-ie6.css");
+}
+
+/*==================================================
+ *  Opacity, translucency
+ *==================================================
+ */
+SimileAjax.Graphics._createTranslucentImage1 = function(url, verticalAlign) {
+    var elmt = document.createElement("img");
+    elmt.setAttribute("src", url);
+    if (verticalAlign != null) {
+        elmt.style.verticalAlign = verticalAlign;
+    }
+    return elmt;
+};
+SimileAjax.Graphics._createTranslucentImage2 = function(url, verticalAlign) {
+    var elmt = document.createElement("img");
+    elmt.style.width = "1px";  // just so that IE will calculate the size property
+    elmt.style.height = "1px";
+    elmt.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image')";
+    elmt.style.verticalAlign = (verticalAlign != null) ? verticalAlign : "middle";
+    return elmt;
+};
+
+/**
+ * Creates a DOM element for an <code>img</code> tag using the URL given. This
+ * is a convenience method that automatically includes the necessary CSS to
+ * allow for translucency, even on IE.
+ *
+ * @function
+ * @param {String} url the URL to the image
+ * @param {String} verticalAlign the CSS value for the image's vertical-align
+ * @return {Element} a DOM element containing the <code>img</code> tag
+ */
+SimileAjax.Graphics.createTranslucentImage = SimileAjax.Graphics.pngIsTranslucent ?
+    SimileAjax.Graphics._createTranslucentImage1 :
+    SimileAjax.Graphics._createTranslucentImage2;
+
+SimileAjax.Graphics._createTranslucentImageHTML1 = function(url, verticalAlign) {
+    return "<img src=\"" + url + "\"" +
+        (verticalAlign != null ? " style=\"vertical-align: " + verticalAlign + ";\"" : "") +
+        " />";
+};
+SimileAjax.Graphics._createTranslucentImageHTML2 = function(url, verticalAlign) {
+    var style =
+        "width: 1px; height: 1px; " +
+        "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + url +"', sizingMethod='image');" +
+        (verticalAlign != null ? " vertical-align: " + verticalAlign + ";" : "");
+
+    return "<img src='" + url + "' style=\"" + style + "\" />";
+};
+
+/**
+ * Creates an HTML string for an <code>img</code> tag using the URL given.
+ * This is a convenience method that automatically includes the necessary CSS
+ * to allow for translucency, even on IE.
+ *
+ * @function
+ * @param {String} url the URL to the image
+ * @param {String} verticalAlign the CSS value for the image's vertical-align
+ * @return {String} a string containing the <code>img</code> tag
+ */
+SimileAjax.Graphics.createTranslucentImageHTML = SimileAjax.Graphics.pngIsTranslucent ?
+    SimileAjax.Graphics._createTranslucentImageHTML1 :
+    SimileAjax.Graphics._createTranslucentImageHTML2;
+
+/**
+ * Sets the opacity on the given DOM element.
+ *
+ * @param {Element} elmt the DOM element to set the opacity on
+ * @param {Number} opacity an integer from 0 to 100 specifying the opacity
+ */
+SimileAjax.Graphics.setOpacity = function(elmt, opacity) {
+    if (SimileAjax.Platform.browser.isIE) {
+        elmt.style.filter = "progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity=" + opacity + ")";
+    } else {
+        var o = (opacity / 100).toString();
+        elmt.style.opacity = o;
+        elmt.style.MozOpacity = o;
+    }
+};
+
+/*==================================================
+ *  Bubble
+ *==================================================
+ */
+
+SimileAjax.Graphics.bubbleConfig = {
+    containerCSSClass:              "simileAjax-bubble-container",
+    innerContainerCSSClass:         "simileAjax-bubble-innerContainer",
+    contentContainerCSSClass:       "simileAjax-bubble-contentContainer",
+
+    borderGraphicSize:              50,
+    borderGraphicCSSClassPrefix:    "simileAjax-bubble-border-",
+
+    arrowGraphicTargetOffset:       33,  // from tip of arrow to the side of the graphic that touches the content of the bubble
+    arrowGraphicLength:             100, // dimension of arrow graphic along the direction that the arrow points
+    arrowGraphicWidth:              49,  // dimension of arrow graphic perpendicular to the direction that the arrow points
+    arrowGraphicCSSClassPrefix:     "simileAjax-bubble-arrow-",
+
+    closeGraphicCSSClass:           "simileAjax-bubble-close",
+
+    extraPadding:                   20
+};
+
+/**
+ * Creates a nice, rounded bubble popup with the given content in a div,
+ * page coordinates and a suggested width. The bubble will point to the
+ * location on the page as described by pageX and pageY.  All measurements
+ * should be given in pixels.
+ *
+ * @param {Element} the content div
+ * @param {Number} pageX the x coordinate of the point to point to
+ * @param {Number} pageY the y coordinate of the point to point to
+ * @param {Number} contentWidth a suggested width of the content
+ * @param {String} orientation a string ("top", "bottom", "left", or "right")
+ *   that describes the orientation of the arrow on the bubble
+ * @param {Number} maxHeight. Add a scrollbar div if bubble would be too tall.
+ *   Default of 0 or null means no maximum
+ */
+SimileAjax.Graphics.createBubbleForContentAndPoint = function(
+       div, pageX, pageY, contentWidth, orientation, maxHeight) {
+    if (typeof contentWidth != "number") {
+        contentWidth = 300;
+    }
+    if (typeof maxHeight != "number") {
+        maxHeight = 0;
+    }
+
+    div.style.position = "absolute";
+    div.style.left = "-5000px";
+    div.style.top = "0px";
+    div.style.width = contentWidth + "px";
+    document.body.appendChild(div);
+
+    window.setTimeout(function() {
+        var width = div.scrollWidth + 10;
+        var height = div.scrollHeight + 10;
+        var scrollDivW = 0; // width of the possible inner container when we want vertical scrolling
+        if (maxHeight > 0 && height > maxHeight) {
+          height = maxHeight;
+          scrollDivW = width - 25;
+        }
+
+        var bubble = SimileAjax.Graphics.createBubbleForPoint(pageX, pageY, width, height, orientation);
+
+        document.body.removeChild(div);
+        div.style.position = "static";
+        div.style.left = "";
+        div.style.top = "";
+
+        // create a scroll div if needed
+        if (scrollDivW > 0) {
+          var scrollDiv = document.createElement("div");
+          div.style.width = "";
+          scrollDiv.style.width = scrollDivW + "px";
+          scrollDiv.appendChild(div);
+          bubble.content.appendChild(scrollDiv);
+        } else {
+          div.style.width = width + "px";
+          bubble.content.appendChild(div);
+        }
+    }, 200);
+};
+
+/**
+ * Creates a nice, rounded bubble popup with the given page coordinates and
+ * content dimensions.  The bubble will point to the location on the page
+ * as described by pageX and pageY.  All measurements should be given in
+ * pixels.
+ *
+ * @param {Number} pageX the x coordinate of the point to point to
+ * @param {Number} pageY the y coordinate of the point to point to
+ * @param {Number} contentWidth the width of the content box in the bubble
+ * @param {Number} contentHeight the height of the content box in the bubble
+ * @param {String} orientation a string ("top", "bottom", "left", or "right")
+ *   that describes the orientation of the arrow on the bubble
+ * @return {Element} a DOM element for the newly created bubble
+ */
+SimileAjax.Graphics.createBubbleForPoint = function(pageX, pageY, contentWidth, contentHeight, orientation) {
+    contentWidth = parseInt(contentWidth, 10); // harden against bad input bugs
+    contentHeight = parseInt(contentHeight, 10); // getting numbers-as-strings
+
+    var bubbleConfig = SimileAjax.Graphics.bubbleConfig;
+    var pngTransparencyClassSuffix =
+        SimileAjax.Graphics.pngIsTranslucent ? "pngTranslucent" : "pngNotTranslucent";
+
+    var bubbleWidth = contentWidth + 2 * bubbleConfig.borderGraphicSize;
+    var bubbleHeight = contentHeight + 2 * bubbleConfig.borderGraphicSize;
+
+    var generatePngSensitiveClass = function(className) {
+        return className + " " + className + "-" + pngTransparencyClassSuffix;
+    };
+
+    /*
+     *  Render container divs
+     */
+    var div = document.createElement("div");
+    div.className = generatePngSensitiveClass(bubbleConfig.containerCSSClass);
+    div.style.width = contentWidth + "px";
+    div.style.height = contentHeight + "px";
+
+    var divInnerContainer = document.createElement("div");
+    divInnerContainer.className = generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass);
+    div.appendChild(divInnerContainer);
+
+    /*
+     *  Create layer for bubble
+     */
+    var close = function() {
+        if (!bubble._closed) {
+            document.body.removeChild(bubble._div);
+            bubble._doc = null;
+            bubble._div = null;
+            bubble._content = null;
+            bubble._closed = true;
+        }
+    }
+    var bubble = { _closed: false };
+    var layer = SimileAjax.WindowManager.pushLayer(close, true, div);
+    bubble._div = div;
+    bubble.close = function() { SimileAjax.WindowManager.popLayer(layer); }
+
+    /*
+     *  Render border graphics
+     */
+    var createBorder = function(classNameSuffix) {
+        var divBorderGraphic = document.createElement("div");
+        divBorderGraphic.className = generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix + classNameSuffix);
+        divInnerContainer.appendChild(divBorderGraphic);
+    };
+    createBorder("top-left");
+    createBorder("top-right");
+    createBorder("bottom-left");
+    createBorder("bottom-right");
+    createBorder("left");
+    createBorder("right");
+    createBorder("top");
+    createBorder("bottom");
+
+    /*
+     *  Render content
+     */
+    var divContentContainer = document.createElement("div");
+    divContentContainer.className = generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass);
+    divInnerContainer.appendChild(divContentContainer);
+    bubble.content = divContentContainer;
+
+    /*
+     *  Render close button
+     */
+    var divClose = document.createElement("div");
+    divClose.className = generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass);
+    divInnerContainer.appendChild(divClose);
+    SimileAjax.WindowManager.registerEventWithObject(divClose, "click", bubble, "close");
+
+    (function() {
+        var dims = SimileAjax.Graphics.getWindowDimensions();
+        var docWidth = dims.w;
+        var docHeight = dims.h;
+
+        var halfArrowGraphicWidth = Math.ceil(bubbleConfig.arrowGraphicWidth / 2);
+
+        var createArrow = function(classNameSuffix) {
+            var divArrowGraphic = document.createElement("div");
+            divArrowGraphic.className = generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix + "point-" + classNameSuffix);
+            divInnerContainer.appendChild(divArrowGraphic);
+            return divArrowGraphic;
+        };
+
+        if (pageX - halfArrowGraphicWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0 &&
+            pageX + halfArrowGraphicWidth + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docWidth) {
+
+            /*
+             *  Bubble can be positioned above or below the target point.
+             */
+
+            var left = pageX - Math.round(contentWidth / 2);
+            left = pageX < (docWidth / 2) ?
+                Math.max(left, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
+                Math.min(left, docWidth - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentWidth);
+
+            if ((orientation && orientation == "top") ||
+                (!orientation &&
+                    (pageY
+                        - bubbleConfig.arrowGraphicTargetOffset
+                        - contentHeight
+                        - bubbleConfig.borderGraphicSize
+                        - bubbleConfig.extraPadding > 0))) {
+
+                /*
+                 *  Position bubble above the target point.
+                 */
+
+                var divArrow = createArrow("down");
+                divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
+
+                div.style.left = left + "px";
+                div.style.top = (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight) + "px";
+
+                return;
+            } else if ((orientation && orientation == "bottom") ||
+                (!orientation &&
+                    (pageY
+                        + bubbleConfig.arrowGraphicTargetOffset
+                        + contentHeight
+                        + bubbleConfig.borderGraphicSize
+                        + bubbleConfig.extraPadding < docHeight))) {
+
+                /*
+                 *  Position bubble below the target point.
+                 */
+
+                var divArrow = createArrow("up");
+                divArrow.style.left = (pageX - halfArrowGraphicWidth - left) + "px";
+
+                div.style.left = left + "px";
+                div.style.top = (pageY + bubbleConfig.arrowGraphicTargetOffset) + "px";
+
+                return;
+            }
+        }
+
+        var top = pageY - Math.round(contentHeight / 2);
+        top = pageY < (docHeight / 2) ?
+            Math.max(top, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
+            Math.min(top, docHeight - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentHeight);
+
+        if ((orientation && orientation == "left") ||
+            (!orientation &&
+                (pageX
+                    - bubbleConfig.arrowGraphicTargetOffset
+                    - contentWidth
+                    - bubbleConfig.borderGraphicSize
+                    - bubbleConfig.extraPadding > 0))) {
+
+            /*
+             *  Position bubble left of the target point.
+             */
+
+            var divArrow = createArrow("right");
+            divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
+
+            div.style.top = top + "px";
+            div.style.left = (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth) + "px";
+        } else {
+
+            /*
+             *  Position bubble right of the target point, as the last resort.
+             */
+
+            var divArrow = createArrow("left");
+            divArrow.style.top = (pageY - halfArrowGraphicWidth - top) + "px";
+
+            div.style.top = top + "px";
+            div.style.left = (pageX + bubbleConfig.arrowGraphicTargetOffset) + "px";
+        }
+    })();
+
+    document.body.appendChild(div);
+
+    return bubble;
+};
+
+SimileAjax.Graphics.getWindowDimensions = function() {
+    if (typeof window.innerHeight == 'number') {
+        return { w:window.innerWidth, h:window.innerHeight }; // Non-IE
+    } else if (document.documentElement && document.documentElement.clientHeight) {
+        return { // IE6+, in "standards compliant mode"
+            w:document.documentElement.clientWidth,
+            h:document.documentElement.clientHeight
+        };
+    } else if (document.body && document.body.clientHeight) {
+        return { // IE 4 compatible
+            w:document.body.clientWidth,
+            h:document.body.clientHeight
+        };
+    }
 };
 
 
 /**
- * Parse out the query parameters from a URL
- * @param {String} url    the url to parse, or location.href if undefined
- * @param {Object} to     optional object to extend with the parameters
- * @param {Object} types  optional object mapping keys to value types
- *        (String, Number, Boolean or Array, String by default)
- * @return a key/value Object whose keys are the query parameter names
- * @type Object
+ * Creates a floating, rounded message bubble in the center of the window for
+ * displaying modal information, e.g. "Loading..."
+ *
+ * @param {Document} doc the root document for the page to render on
+ * @param {Object} an object with two properties, contentDiv and containerDiv,
+ *   consisting of the newly created DOM elements
+ */
+SimileAjax.Graphics.createMessageBubble = function(doc) {
+    var containerDiv = doc.createElement("div");
+    if (SimileAjax.Graphics.pngIsTranslucent) {
+        var topDiv = doc.createElement("div");
+        topDiv.style.height = "33px";
+        topDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-left.png) top left no-repeat";
+        topDiv.style.paddingLeft = "44px";
+        containerDiv.appendChild(topDiv);
+
+        var topRightDiv = doc.createElement("div");
+        topRightDiv.style.height = "33px";
+        topRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-top-right.png) top right no-repeat";
+        topDiv.appendChild(topRightDiv);
+
+        var middleDiv = doc.createElement("div");
+        middleDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-left.png) top left repeat-y";
+        middleDiv.style.paddingLeft = "44px";
+        containerDiv.appendChild(middleDiv);
+
+        var middleRightDiv = doc.createElement("div");
+        middleRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-right.png) top right repeat-y";
+        middleRightDiv.style.paddingRight = "44px";
+        middleDiv.appendChild(middleRightDiv);
+
+        var contentDiv = doc.createElement("div");
+        middleRightDiv.appendChild(contentDiv);
+
+        var bottomDiv = doc.createElement("div");
+        bottomDiv.style.height = "55px";
+        bottomDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-left.png) bottom left no-repeat";
+        bottomDiv.style.paddingLeft = "44px";
+        containerDiv.appendChild(bottomDiv);
+
+        var bottomRightDiv = doc.createElement("div");
+        bottomRightDiv.style.height = "55px";
+        bottomRightDiv.style.background = "url(" + SimileAjax.urlPrefix + "images/message-bottom-right.png) bottom right no-repeat";
+        bottomDiv.appendChild(bottomRightDiv);
+    } else {
+        containerDiv.style.border = "2px solid #7777AA";
+        containerDiv.style.padding = "20px";
+        containerDiv.style.background = "white";
+        SimileAjax.Graphics.setOpacity(containerDiv, 90);
+
+        var contentDiv = doc.createElement("div");
+        containerDiv.appendChild(contentDiv);
+    }
+
+    return {
+        containerDiv:   containerDiv,
+        contentDiv:     contentDiv
+    };
+};
+
+/*==================================================
+ *  Animation
+ *==================================================
+ */
+
+/**
+ * Creates an animation for a function, and an interval of values.  The word
+ * "animation" here is used in the sense of repeatedly calling a function with
+ * a current value from within an interval, and a delta value.
+ *
+ * @param {Function} f a function to be called every 50 milliseconds throughout
+ *   the animation duration, of the form f(current, delta), where current is
+ *   the current value within the range and delta is the current change.
+ * @param {Number} from a starting value
+ * @param {Number} to an ending value
+ * @param {Number} duration the duration of the animation in milliseconds
+ * @param {Function} [cont] an optional function that is called at the end of
+ *   the animation, i.e. a continuation.
+ * @return {SimileAjax.Graphics._Animation} a new animation object
+ */
+SimileAjax.Graphics.createAnimation = function(f, from, to, duration, cont) {
+    return new SimileAjax.Graphics._Animation(f, from, to, duration, cont);
+};
+
+SimileAjax.Graphics._Animation = function(f, from, to, duration, cont) {
+    this.f = f;
+    this.cont = (typeof cont == "function") ? cont : function() {};
+
+    this.from = from;
+    this.to = to;
+    this.current = from;
+
+    this.duration = duration;
+    this.start = new Date().getTime();
+    this.timePassed = 0;
+};
+
+/**
+ * Runs this animation.
+ */
+SimileAjax.Graphics._Animation.prototype.run = function() {
+    var a = this;
+    window.setTimeout(function() { a.step(); }, 50);
+};
+
+/**
+ * Increments this animation by one step, and then continues the animation with
+ * <code>run()</code>.
+ */
+SimileAjax.Graphics._Animation.prototype.step = function() {
+    this.timePassed += 50;
+
+    var timePassedFraction = this.timePassed / this.duration;
+    var parameterFraction = -Math.cos(timePassedFraction * Math.PI) / 2 + 0.5;
+    var current = parameterFraction * (this.to - this.from) + this.from;
+
+    try {
+        this.f(current, current - this.current);
+    } catch (e) {
+    }
+    this.current = current;
+
+    if (this.timePassed < this.duration) {
+        this.run();
+    } else {
+        this.f(this.to, 0);
+        this["cont"]();
+    }
+};
+
+/*==================================================
+ *  CopyPasteButton
+ *
+ *  Adapted from http://spaces.live.com/editorial/rayozzie/demo/liveclip/liveclipsample/techPreview.html.
+ *==================================================
+ */
+
+/**
+ * Creates a button and textarea for displaying structured data and copying it
+ * to the clipboard.  The data is dynamically generated by the given
+ * createDataFunction parameter.
+ *
+ * @param {String} image an image URL to use as the background for the
+ *   generated box
+ * @param {Number} width the width in pixels of the generated box
+ * @param {Number} height the height in pixels of the generated box
+ * @param {Function} createDataFunction a function that is called with no
+ *   arguments to generate the structured data
+ * @return a new DOM element
+ */
+SimileAjax.Graphics.createStructuredDataCopyButton = function(image, width, height, createDataFunction) {
+    var div = document.createElement("div");
+    div.style.position = "relative";
+    div.style.display = "inline";
+    div.style.width = width + "px";
+    div.style.height = height + "px";
+    div.style.overflow = "hidden";
+    div.style.margin = "2px";
+
+    if (SimileAjax.Graphics.pngIsTranslucent) {
+        div.style.background = "url(" + image + ") no-repeat";
+    } else {
+        div.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + image +"', sizingMethod='image')";
+    }
+
+    var style;
+    if (SimileAjax.Platform.browser.isIE) {
+        style = "filter:alpha(opacity=0)";
+    } else {
+        style = "opacity: 0";
+    }
+    div.innerHTML = "<textarea rows='1' autocomplete='off' value='none' style='" + style + "' />";
+
+    var textarea = div.firstChild;
+    textarea.style.width = width + "px";
+    textarea.style.height = height + "px";
+    textarea.onmousedown = function(evt) {
+        evt = (evt) ? evt : ((event) ? event : null);
+        if (evt.button == 2) {
+            textarea.value = createDataFunction();
+            textarea.select();
+        }
+    };
+
+    return div;
+};
+
+/*==================================================
+ *  getWidthHeight
+ *==================================================
+ */
+SimileAjax.Graphics.getWidthHeight = function(el) {
+    // RETURNS hash {width:  w, height: h} in pixels
+
+    var w, h;
+    // offsetWidth rounds on FF, so doesn't work for us.
+    // See https://bugzilla.mozilla.org/show_bug.cgi?id=458617
+    if (el.getBoundingClientRect == null) {
+    	// use offsetWidth
+      w = el.offsetWidth;
+      h = el.offsetHeight;
+    } else {
+    	// use getBoundingClientRect
+      var rect = el.getBoundingClientRect();
+      w = Math.ceil(rect.right - rect.left);
+    	h = Math.ceil(rect.bottom - rect.top);
+    }
+    return {
+        width:  w,
+        height: h
+    };
+};
+
+
+/*==================================================
+ *  FontRenderingContext
+ *==================================================
  */
-SimileAjax.parseURLParameters = function(url, to, types) {
-    to = to || {};
-    types = types || {};
-
-    if (typeof url == "undefined") {
-        url = location.href;
-    }
-    var q = url.indexOf("?");
-    if (q < 0) {
-        return to;
-    }
-    url = (url+"#").slice(q+1, url.indexOf("#")); // toss the URL fragment
-
-    var params = url.split("&"), param, parsed = {};
-    var decode = window.decodeURIComponent || unescape;
-    for (var i = 0; param = params[i]; i++) {
-        var eq = param.indexOf("=");
-        var name = decode(param.slice(0,eq));
-        var old = parsed[name];
-        if (typeof old == "undefined") {
-            old = [];
-        } else if (!(old instanceof Array)) {
-            old = [old];
-        }
-        parsed[name] = old.concat(decode(param.slice(eq+1)));
-    }
-    for (var i in parsed) {
-        if (!parsed.hasOwnProperty(i)) continue;
-        var type = types[i] || String;
-        var data = parsed[i];
-        if (!(data instanceof Array)) {
-            data = [data];
-        }
-        if (type === Boolean && data[0] == "false") {
-            to[i] = false; // because Boolean("false") === true
+SimileAjax.Graphics.getFontRenderingContext = function(elmt, width) {
+    return new SimileAjax.Graphics._FontRenderingContext(elmt, width);
+};
+
+SimileAjax.Graphics._FontRenderingContext = function(elmt, width) {
+    this._elmt = elmt;
+    this._elmt.style.visibility = "hidden";
+    if (typeof width == "string") {
+        this._elmt.style.width = width;
+    } else if (typeof width == "number") {
+        this._elmt.style.width = width + "px";
+    }
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.dispose = function() {
+    this._elmt = null;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.update = function() {
+    this._elmt.innerHTML = "A";
+    this._lineHeight = this._elmt.offsetHeight;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.computeSize = function(text, className) {
+    // className arg is optional
+    var el = this._elmt;
+    el.innerHTML = text;
+    el.className = className === undefined ? '' : className;
+    var wh = SimileAjax.Graphics.getWidthHeight(el);
+    el.className = ''; // reset for the next guy
+
+    return wh;
+};
+
+SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight = function() {
+    return this._lineHeight;
+};
+
+/**
+ * @fileOverview A collection of date/time utility functions
+ * @name SimileAjax.DateTime
+ */
+
+SimileAjax.DateTime = new Object();
+
+SimileAjax.DateTime.MILLISECOND    = 0;
+SimileAjax.DateTime.SECOND         = 1;
+SimileAjax.DateTime.MINUTE         = 2;
+SimileAjax.DateTime.HOUR           = 3;
+SimileAjax.DateTime.DAY            = 4;
+SimileAjax.DateTime.WEEK           = 5;
+SimileAjax.DateTime.MONTH          = 6;
+SimileAjax.DateTime.YEAR           = 7;
+SimileAjax.DateTime.DECADE         = 8;
+SimileAjax.DateTime.CENTURY        = 9;
+SimileAjax.DateTime.MILLENNIUM     = 10;
+
+SimileAjax.DateTime.EPOCH          = -1;
+SimileAjax.DateTime.ERA            = -2;
+
+/**
+ * An array of unit lengths, expressed in milliseconds, of various lengths of
+ * time.  The array indices are predefined and stored as properties of the
+ * SimileAjax.DateTime object, e.g. SimileAjax.DateTime.YEAR.
+ * @type Array
+ */
+SimileAjax.DateTime.gregorianUnitLengths = [];
+    (function() {
+        var d = SimileAjax.DateTime;
+        var a = d.gregorianUnitLengths;
+
+        a[d.MILLISECOND] = 1;
+        a[d.SECOND]      = 1000;
+        a[d.MINUTE]      = a[d.SECOND] * 60;
+        a[d.HOUR]        = a[d.MINUTE] * 60;
+        a[d.DAY]         = a[d.HOUR] * 24;
+        a[d.WEEK]        = a[d.DAY] * 7;
+        a[d.MONTH]       = a[d.DAY] * 31;
+        a[d.YEAR]        = a[d.DAY] * 365;
+        a[d.DECADE]      = a[d.YEAR] * 10;
+        a[d.CENTURY]     = a[d.YEAR] * 100;
+        a[d.MILLENNIUM]  = a[d.YEAR] * 1000;
+    })();
+
+SimileAjax.DateTime._dateRegexp = new RegExp(
+    "^(-?)([0-9]{4})(" + [
+        "(-?([0-9]{2})(-?([0-9]{2}))?)", // -month-dayOfMonth
+        "(-?([0-9]{3}))",                // -dayOfYear
+        "(-?W([0-9]{2})(-?([1-7]))?)"    // -Wweek-dayOfWeek
+    ].join("|") + ")?$"
+);
+SimileAjax.DateTime._timezoneRegexp = new RegExp(
+    "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$"
+);
+SimileAjax.DateTime._timeRegexp = new RegExp(
+    "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$"
+);
+
+/**
+ * Takes a date object and a string containing an ISO 8601 date and sets the
+ * the date using information parsed from the string.  Note that this method
+ * does not parse any time information.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601Date = function(dateObject, string) {
+    /*
+     *  This function has been adapted from dojo.date, v.0.3.0
+     *  http://dojotoolkit.org/.
+     */
+
+    var d = string.match(SimileAjax.DateTime._dateRegexp);
+    if(!d) {
+        throw new Error("Invalid date string: " + string);
+    }
+
+    var sign = (d[1] == "-") ? -1 : 1; // BC or AD
+    var year = sign * d[2];
+    var month = d[5];
+    var date = d[7];
+    var dayofyear = d[9];
+    var week = d[11];
+    var dayofweek = (d[13]) ? d[13] : 1;
+
+    dateObject.setUTCFullYear(year);
+    if (dayofyear) {
+        dateObject.setUTCMonth(0);
+        dateObject.setUTCDate(Number(dayofyear));
+    } else if (week) {
+        dateObject.setUTCMonth(0);
+        dateObject.setUTCDate(1);
+        var gd = dateObject.getUTCDay();
+        var day =  (gd) ? gd : 7;
+        var offset = Number(dayofweek) + (7 * Number(week));
+
+        if (day <= 4) {
+            dateObject.setUTCDate(offset + 1 - day);
+        } else {
+            dateObject.setUTCDate(offset + 8 - day);
+        }
+    } else {
+        if (month) {
+            dateObject.setUTCDate(1);
+            dateObject.setUTCMonth(month - 1);
+        }
+        if (date) {
+            dateObject.setUTCDate(date);
+        }
+    }
+
+    return dateObject;
+};
+
+/**
+ * Takes a date object and a string containing an ISO 8601 time and sets the
+ * the time using information parsed from the string.  Note that this method
+ * does not parse any date information.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601Time = function (dateObject, string) {
+    /*
+     *  This function has been adapted from dojo.date, v.0.3.0
+     *  http://dojotoolkit.org/.
+     */
+
+    var d = string.match(SimileAjax.DateTime._timeRegexp);
+    if(!d) {
+        SimileAjax.Debug.warn("Invalid time string: " + string);
+        return false;
+    }
+    var hours = d[1];
+    var mins = Number((d[3]) ? d[3] : 0);
+    var secs = (d[5]) ? d[5] : 0;
+    var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
+
+    dateObject.setUTCHours(hours);
+    dateObject.setUTCMinutes(mins);
+    dateObject.setUTCSeconds(secs);
+    dateObject.setUTCMilliseconds(ms);
+
+    return dateObject;
+};
+
+/**
+ * The timezone offset in minutes in the user's browser.
+ * @type Number
+ */
+SimileAjax.DateTime.timezoneOffset = new Date().getTimezoneOffset();
+
+/**
+ * Takes a date object and a string containing an ISO 8601 date and time and
+ * sets the date object using information parsed from the string.
+ *
+ * @param {Date} dateObject the date object to modify
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} the modified date object
+ */
+SimileAjax.DateTime.setIso8601 = function (dateObject, string){
+    /*
+     *  This function has been adapted from dojo.date, v.0.3.0
+     *  http://dojotoolkit.org/.
+     */
+
+    var offset = null;
+    var comps = (string.indexOf("T") == -1) ? string.split(" ") : string.split("T");
+
+    SimileAjax.DateTime.setIso8601Date(dateObject, comps[0]);
+    if (comps.length == 2) {
+        // first strip timezone info from the end
+        var d = comps[1].match(SimileAjax.DateTime._timezoneRegexp);
+        if (d) {
+            if (d[0] == 'Z') {
+                offset = 0;
+            } else {
+                offset = (Number(d[3]) * 60) + Number(d[5]);
+                offset *= ((d[2] == '-') ? 1 : -1);
+            }
+            comps[1] = comps[1].substr(0, comps[1].length - d[0].length);
+        }
+
+        SimileAjax.DateTime.setIso8601Time(dateObject, comps[1]);
+    }
+    if (offset == null) {
+        offset = dateObject.getTimezoneOffset(); // local time zone if no tz info
+    }
+    dateObject.setTime(dateObject.getTime() + offset * 60000);
+
+    return dateObject;
+};
+
+/**
+ * Takes a string containing an ISO 8601 date and returns a newly instantiated
+ * date object with the parsed date and time information from the string.
+ *
+ * @param {String} string an ISO 8601 string to parse
+ * @return {Date} a new date object created from the string
+ */
+SimileAjax.DateTime.parseIso8601DateTime = function (string) {
+    try {
+        return SimileAjax.DateTime.setIso8601(new Date(0), string);
+    } catch (e) {
+        return null;
+    }
+};
+
+/**
+ * Takes a string containing a Gregorian date and time and returns a newly
+ * instantiated date object with the parsed date and time information from the
+ * string.  If the param is actually an instance of Date instead of a string,
+ * simply returns the given date instead.
+ *
+ * @param {Object} o an object, to either return or parse as a string
+ * @return {Date} the date object
+ */
+SimileAjax.DateTime.parseGregorianDateTime = function(o) {
+    if (o == null) {
+        return null;
+    } else if (o instanceof Date) {
+        return o;
+    }
+
+    var s = o.toString();
+    if (s.length > 0 && s.length < 8) {
+        var space = s.indexOf(" ");
+        if (space > 0) {
+            var year = parseInt(s.substr(0, space));
+            var suffix = s.substr(space + 1);
+            if (suffix.toLowerCase() == "bc") {
+                year = 1 - year;
+            }
         } else {
-            to[i] = type.apply(this, data);
-        }
-    }
-    return to;
-};
-
-
-SimileAjax.Platform = new Object();
-SimileAjax.urlPrefix = baseuri();
-
-window.Timeline = new Object();
-Timeline.urlPrefix = baseuri();
-window.Timeline.DateTime = window.SimileAjax.DateTime; // for backward compatibility
-
-/* platform.js */
-SimileAjax.jQuery = jQuery;
-// SimileAjax.jQuery=jQuery.noConflict(true);
-if(typeof window["$"]=="undefined"){window.$=SimileAjax.jQuery;
-}SimileAjax.Platform.os={isMac:false,isWin:false,isWin32:false,isUnix:false};
-SimileAjax.Platform.browser={isIE:false,isNetscape:false,isMozilla:false,isFirefox:false,isOpera:false,isSafari:false,majorVersion:0,minorVersion:0};
-(function(){var C=navigator.appName.toLowerCase();
-var A=navigator.userAgent.toLowerCase();
-SimileAjax.Platform.os.isMac=(A.indexOf("mac")!=-1);
-SimileAjax.Platform.os.isWin=(A.indexOf("win")!=-1);
-SimileAjax.Platform.os.isWin32=SimileAjax.Platform.isWin&&(A.indexOf("95")!=-1||A.indexOf("98")!=-1||A.indexOf("nt")!=-1||A.indexOf("win32")!=-1||A.indexOf("32bit")!=-1);
-SimileAjax.Platform.os.isUnix=(A.indexOf("x11")!=-1);
-SimileAjax.Platform.browser.isIE=(C.indexOf("microsoft")!=-1);
-SimileAjax.Platform.browser.isNetscape=(C.indexOf("netscape")!=-1);
-SimileAjax.Platform.browser.isMozilla=(A.indexOf("mozilla")!=-1);
-SimileAjax.Platform.browser.isFirefox=(A.indexOf("firefox")!=-1);
-SimileAjax.Platform.browser.isOpera=(C.indexOf("opera")!=-1);
-SimileAjax.Platform.browser.isSafari=(C.indexOf("safari")!=-1);
-var E=function(G){var F=G.split(".");
-SimileAjax.Platform.browser.majorVersion=parseInt(F[0]);
-SimileAjax.Platform.browser.minorVersion=parseInt(F[1]);
-};
-var B=function(H,G,I){var F=H.indexOf(G,I);
-return F>=0?F:H.length;
-};
-if(SimileAjax.Platform.browser.isMozilla){var D=A.indexOf("mozilla/");
-if(D>=0){E(A.substring(D+8,B(A," ",D)));
-}}if(SimileAjax.Platform.browser.isIE){var D=A.indexOf("msie ");
-if(D>=0){E(A.substring(D+5,B(A,";",D)));
-}}if(SimileAjax.Platform.browser.isNetscape){var D=A.indexOf("rv:");
-if(D>=0){E(A.substring(D+3,B(A,")",D)));
-}}if(SimileAjax.Platform.browser.isFirefox){var D=A.indexOf("firefox/");
-if(D>=0){E(A.substring(D+8,B(A," ",D)));
-}}if(!("localeCompare" in String.prototype)){String.prototype.localeCompare=function(F){if(this<F){return -1;
-}else{if(this>F){return 1;
-}else{return 0;
-}}};
-}})();
-SimileAjax.Platform.getDefaultLocale=function(){return SimileAjax.Platform.clientLocale;
-};
-
-
-/* ajax.js */
-SimileAjax.ListenerQueue=function(A){this._listeners=[];
-this._wildcardHandlerName=A;
-};
-SimileAjax.ListenerQueue.prototype.add=function(A){this._listeners.push(A);
-};
-SimileAjax.ListenerQueue.prototype.remove=function(C){var B=this._listeners;
-for(var A=0;
-A<B.length;
-A++){if(B[A]==C){B.splice(A,1);
-break;
-}}};
-SimileAjax.ListenerQueue.prototype.fire=function(B,A){var D=[].concat(this._listeners);
-for(var C=0;
-C<D.length;
-C++){var E=D[C];
-if(B in E){try{E[B].apply(E,A);
-}catch(F){SimileAjax.Debug.exception("Error firing event of name "+B,F);
-}}else{if(this._wildcardHandlerName!=null&&this._wildcardHandlerName in E){try{E[this._wildcardHandlerName].apply(E,[B]);
-}catch(F){SimileAjax.Debug.exception("Error firing event of name "+B+" to wildcard handler",F);
-}}}}};
-
-
-/* data-structure.js */
-SimileAjax.Set=function(A){this._hash={};
-this._count=0;
-if(A instanceof Array){for(var B=0;
-B<A.length;
-B++){this.add(A[B]);
-}}else{if(A instanceof SimileAjax.Set){this.addSet(A);
-}}};
-SimileAjax.Set.prototype.add=function(A){if(!(A in this._hash)){this._hash[A]=true;
-this._count++;
-return true;
-}return false;
-};
-SimileAjax.Set.prototype.addSet=function(B){for(var A in B._hash){this.add(A);
-}};
-SimileAjax.Set.prototype.remove=function(A){if(A in this._hash){delete this._hash[A];
-this._count--;
-return true;
-}return false;
-};
-SimileAjax.Set.prototype.removeSet=function(B){for(var A in B._hash){this.remove(A);
-}};
-SimileAjax.Set.prototype.retainSet=function(B){for(var A in this._hash){if(!B.contains(A)){delete this._hash[A];
-this._count--;
-}}};
-SimileAjax.Set.prototype.contains=function(A){return(A in this._hash);
-};
-SimileAjax.Set.prototype.size=function(){return this._count;
-};
-SimileAjax.Set.prototype.toArray=function(){var A=[];
-for(var B in this._hash){A.push(B);
-}return A;
-};
-SimileAjax.Set.prototype.visit=function(A){for(var B in this._hash){if(A(B)==true){break;
-}}};
-SimileAjax.SortedArray=function(B,A){this._a=(A instanceof Array)?A:[];
-this._compare=B;
-};
-SimileAjax.SortedArray.prototype.add=function(C){var A=this;
-var B=this.find(function(D){return A._compare(D,C);
-});
-if(B<this._a.length){this._a.splice(B,0,C);
-}else{this._a.push(C);
-}};
-SimileAjax.SortedArray.prototype.remove=function(C){var A=this;
-var B=this.find(function(D){return A._compare(D,C);
-});
-while(B<this._a.length&&this._compare(this._a[B],C)==0){if(this._a[B]==C){this._a.splice(B,1);
-return true;
-}else{B++;
-}}return false;
-};
-SimileAjax.SortedArray.prototype.removeAll=function(){this._a=[];
-};
-SimileAjax.SortedArray.prototype.elementAt=function(A){return this._a[A];
-};
-SimileAjax.SortedArray.prototype.length=function(){return this._a.length;
-};
-SimileAjax.SortedArray.prototype.find=function(D){var B=0;
-var A=this._a.length;
-while(B<A){var C=Math.floor((B+A)/2);
-var E=D(this._a[C]);
-if(C==B){return E<0?B+1:B;
-}else{if(E<0){B=C;
-}else{A=C;
-}}}return B;
-};
-SimileAjax.SortedArray.prototype.getFirst=function(){return(this._a.length>0)?this._a[0]:null;
-};
-SimileAjax.SortedArray.prototype.getLast=function(){return(this._a.length>0)?this._a[this._a.length-1]:null;
-};
-SimileAjax.EventIndex=function(B){var A=this;
-this._unit=(B!=null)?B:SimileAjax.NativeDateUnit;
-this._events=new SimileAjax.SortedArray(function(D,C){return A._unit.compare(D.getStart(),C.getStart());
-});
-this._idToEvent={};
-this._indexed=true;
-};
-SimileAjax.EventIndex.prototype.getUnit=function(){return this._unit;
-};
-SimileAjax.EventIndex.prototype.getEvent=function(A){return this._idToEvent[A];
-};
-SimileAjax.EventIndex.prototype.add=function(A){this._events.add(A);
-this._idToEvent[A.getID()]=A;
-this._indexed=false;
-};
-SimileAjax.EventIndex.prototype.removeAll=function(){this._events.removeAll();
-this._idToEvent={};
-this._indexed=false;
-};
-SimileAjax.EventIndex.prototype.getCount=function(){return this._events.length();
-};
-SimileAjax.EventIndex.prototype.getIterator=function(A,B){if(!this._indexed){this._index();
-}return new SimileAjax.EventIndex._Iterator(this._events,A,B,this._unit);
-};
-SimileAjax.EventIndex.prototype.getReverseIterator=function(A,B){if(!this._indexed){this._index();
-}return new SimileAjax.EventIndex._ReverseIterator(this._events,A,B,this._unit);
-};
-SimileAjax.EventIndex.prototype.getAllIterator=function(){return new SimileAjax.EventIndex._AllIterator(this._events);
-};
-SimileAjax.EventIndex.prototype.getEarliestDate=function(){var A=this._events.getFirst();
-return(A==null)?null:A.getStart();
-};
-SimileAjax.EventIndex.prototype.getLatestDate=function(){var A=this._events.getLast();
-if(A==null){return null;
-}if(!this._indexed){this._index();
-}var C=A._earliestOverlapIndex;
-var B=this._events.elementAt(C).getEnd();
-for(var D=C+1;
-D<this._events.length();
-D++){B=this._unit.later(B,this._events.elementAt(D).getEnd());
-}return B;
-};
-SimileAjax.EventIndex.prototype._index=function(){var D=this._events.length();
-for(var E=0;
-E<D;
-E++){var C=this._events.elementAt(E);
-C._earliestOverlapIndex=E;
-}var G=1;
-for(var E=0;
-E<D;
-E++){var C=this._events.elementAt(E);
-var B=C.getEnd();
-G=Math.max(G,E+1);
-while(G<D){var A=this._events.elementAt(G);
-var F=A.getStart();
-if(this._unit.compare(F,B)<0){A._earliestOverlapIndex=E;
-G++;
-}else{break;
-}}}this._indexed=true;
-};
-SimileAjax.EventIndex._Iterator=function(B,A,D,C){this._events=B;
-this._startDate=A;
-this._endDate=D;
-this._unit=C;
-this._currentIndex=B.find(function(E){return C.compare(E.getStart(),A);
-});
-if(this._currentIndex-1>=0){this._currentIndex=this._events.elementAt(this._currentIndex-1)._earliestOverlapIndex;
-}this._currentIndex--;
-this._maxIndex=B.find(function(E){return C.compare(E.getStart(),D);
-});
-this._hasNext=false;
-this._next=null;
-this._findNext();
-};
-SimileAjax.EventIndex._Iterator.prototype={hasNext:function(){return this._hasNext;
-},next:function(){if(this._hasNext){var A=this._next;
-this._findNext();
-return A;
-}else{return null;
-}},_findNext:function(){var B=this._unit;
-while((++this._currentIndex)<this._maxIndex){var A=this._events.elementAt(this._currentIndex);
-if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
-this._hasNext=true;
-return ;
-}}this._next=null;
-this._hasNext=false;
-}};
-SimileAjax.EventIndex._ReverseIterator=function(B,A,D,C){this._events=B;
-this._startDate=A;
-this._endDate=D;
-this._unit=C;
-this._minIndex=B.find(function(E){return C.compare(E.getStart(),A);
-});
-if(this._minIndex-1>=0){this._minIndex=this._events.elementAt(this._minIndex-1)._earliestOverlapIndex;
-}this._maxIndex=B.find(function(E){return C.compare(E.getStart(),D);
-});
-this._currentIndex=this._maxIndex;
-this._hasNext=false;
-this._next=null;
-this._findNext();
-};
-SimileAjax.EventIndex._ReverseIterator.prototype={hasNext:function(){return this._hasNext;
-},next:function(){if(this._hasNext){var A=this._next;
-this._findNext();
-return A;
-}else{return null;
-}},_findNext:function(){var B=this._unit;
-while((--this._currentIndex)>=this._minIndex){var A=this._events.elementAt(this._currentIndex);
-if(B.compare(A.getStart(),this._endDate)<0&&B.compare(A.getEnd(),this._startDate)>0){this._next=A;
-this._hasNext=true;
-return ;
-}}this._next=null;
-this._hasNext=false;
-}};
-SimileAjax.EventIndex._AllIterator=function(A){this._events=A;
-this._index=0;
-};
-SimileAjax.EventIndex._AllIterator.prototype={hasNext:function(){return this._index<this._events.length();
-},next:function(){return this._index<this._events.length()?this._events.elementAt(this._index++):null;
-}};
-
-
-/* date-time.js */
-SimileAjax.DateTime=new Object();
-SimileAjax.DateTime.MILLISECOND=0;
-SimileAjax.DateTime.SECOND=1;
-SimileAjax.DateTime.MINUTE=2;
-SimileAjax.DateTime.HOUR=3;
-SimileAjax.DateTime.DAY=4;
-SimileAjax.DateTime.WEEK=5;
-SimileAjax.DateTime.MONTH=6;
-SimileAjax.DateTime.YEAR=7;
-SimileAjax.DateTime.DECADE=8;
-SimileAjax.DateTime.CENTURY=9;
-SimileAjax.DateTime.MILLENNIUM=10;
-SimileAjax.DateTime.EPOCH=-1;
-SimileAjax.DateTime.ERA=-2;
-SimileAjax.DateTime.gregorianUnitLengths=[];
-(function(){var B=SimileAjax.DateTime;
-var A=B.gregorianUnitLengths;
-A[B.MILLISECOND]=1;
-A[B.SECOND]=1000;
-A[B.MINUTE]=A[B.SECOND]*60;
-A[B.HOUR]=A[B.MINUTE]*60;
-A[B.DAY]=A[B.HOUR]*24;
-A[B.WEEK]=A[B.DAY]*7;
-A[B.MONTH]=A[B.DAY]*31;
-A[B.YEAR]=A[B.DAY]*365;
-A[B.DECADE]=A[B.YEAR]*10;
-A[B.CENTURY]=A[B.YEAR]*100;
-A[B.MILLENNIUM]=A[B.YEAR]*1000;
+            var year = parseInt(s);
+        }
+
+        var d = new Date(0);
+        d.setUTCFullYear(year);
+
+        return d;
+    }
+
+    try {
+        return new Date(Date.parse(s));
+    } catch (e) {
+        return null;
+    }
+};
+
+/**
+ * Rounds date objects down to the nearest interval or multiple of an interval.
+ * This method modifies the given date object, converting it to the given
+ * timezone if specified.
+ *
+ * @param {Date} date the date object to round
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ *   interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone a timezone shift, given in hours
+ * @param {Number} multiple a multiple of the interval to round by
+ * @param {Number} firstDayOfWeek an integer specifying the first day of the
+ *   week, 0 corresponds to Sunday, 1 to Monday, etc.
+ */
+SimileAjax.DateTime.roundDownToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+    var timeShift = timeZone *
+        SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+
+    var date2 = new Date(date.getTime() + timeShift);
+    var clearInDay = function(d) {
+        d.setUTCMilliseconds(0);
+        d.setUTCSeconds(0);
+        d.setUTCMinutes(0);
+        d.setUTCHours(0);
+    };
+    var clearInYear = function(d) {
+        clearInDay(d);
+        d.setUTCDate(1);
+        d.setUTCMonth(0);
+    };
+
+    switch(intervalUnit) {
+    case SimileAjax.DateTime.MILLISECOND:
+        var x = date2.getUTCMilliseconds();
+        date2.setUTCMilliseconds(x - (x % multiple));
+        break;
+    case SimileAjax.DateTime.SECOND:
+        date2.setUTCMilliseconds(0);
+
+        var x = date2.getUTCSeconds();
+        date2.setUTCSeconds(x - (x % multiple));
+        break;
+    case SimileAjax.DateTime.MINUTE:
+        date2.setUTCMilliseconds(0);
+        date2.setUTCSeconds(0);
+
+        var x = date2.getUTCMinutes();
+        date2.setTime(date2.getTime() -
+            (x % multiple) * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+        break;
+    case SimileAjax.DateTime.HOUR:
+        date2.setUTCMilliseconds(0);
+        date2.setUTCSeconds(0);
+        date2.setUTCMinutes(0);
+
+        var x = date2.getUTCHours();
+        date2.setUTCHours(x - (x % multiple));
+        break;
+    case SimileAjax.DateTime.DAY:
+        clearInDay(date2);
+        break;
+    case SimileAjax.DateTime.WEEK:
+        clearInDay(date2);
+        var d = (date2.getUTCDay() + 7 - firstDayOfWeek) % 7;
+        date2.setTime(date2.getTime() -
+            d * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
+        break;
+    case SimileAjax.DateTime.MONTH:
+        clearInDay(date2);
+        date2.setUTCDate(1);
+
+        var x = date2.getUTCMonth();
+        date2.setUTCMonth(x - (x % multiple));
+        break;
+    case SimileAjax.DateTime.YEAR:
+        clearInYear(date2);
+
+        var x = date2.getUTCFullYear();
+        date2.setUTCFullYear(x - (x % multiple));
+        break;
+    case SimileAjax.DateTime.DECADE:
+        clearInYear(date2);
+        date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 10) * 10);
+        break;
+    case SimileAjax.DateTime.CENTURY:
+        clearInYear(date2);
+        date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 100) * 100);
+        break;
+    case SimileAjax.DateTime.MILLENNIUM:
+        clearInYear(date2);
+        date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 1000) * 1000);
+        break;
+    }
+
+    date.setTime(date2.getTime() - timeShift);
+};
+
+/**
+ * Rounds date objects up to the nearest interval or multiple of an interval.
+ * This method modifies the given date object, converting it to the given
+ * timezone if specified.
+ *
+ * @param {Date} date the date object to round
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ *   interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone a timezone shift, given in hours
+ * @param {Number} multiple a multiple of the interval to round by
+ * @param {Number} firstDayOfWeek an integer specifying the first day of the
+ *   week, 0 corresponds to Sunday, 1 to Monday, etc.
+ * @see SimileAjax.DateTime.roundDownToInterval
+ */
+SimileAjax.DateTime.roundUpToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
+    var originalTime = date.getTime();
+    SimileAjax.DateTime.roundDownToInterval(date, intervalUnit, timeZone, multiple, firstDayOfWeek);
+    if (date.getTime() < originalTime) {
+        date.setTime(date.getTime() +
+            SimileAjax.DateTime.gregorianUnitLengths[intervalUnit] * multiple);
+    }
+};
+
+/**
+ * Increments a date object by a specified interval, taking into
+ * consideration the timezone.
+ *
+ * @param {Date} date the date object to increment
+ * @param {Number} intervalUnit a constant, integer index specifying an
+ *   interval, e.g. SimileAjax.DateTime.HOUR
+ * @param {Number} timeZone the timezone offset in hours
+ */
+SimileAjax.DateTime.incrementByInterval = function(date, intervalUnit, timeZone) {
+    timeZone = (typeof timeZone == 'undefined') ? 0 : timeZone;
+
+    var timeShift = timeZone *
+        SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
+
+    var date2 = new Date(date.getTime() + timeShift);
+
+    switch(intervalUnit) {
+    case SimileAjax.DateTime.MILLISECOND:
+        date2.setTime(date2.getTime() + 1)
+        break;
+    case SimileAjax.DateTime.SECOND:
+        date2.setTime(date2.getTime() + 1000);
+        break;
+    case SimileAjax.DateTime.MINUTE:
+        date2.setTime(date2.getTime() +
+            SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
+        break;
+    case SimileAjax.DateTime.HOUR:
+        date2.setTime(date2.getTime() +
+            SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+        break;
+    case SimileAjax.DateTime.DAY:
+        date2.setUTCDate(date2.getUTCDate() + 1);
+        break;
+    case SimileAjax.DateTime.WEEK:
+        date2.setUTCDate(date2.getUTCDate() + 7);
+        break;
+    case SimileAjax.DateTime.MONTH:
+        date2.setUTCMonth(date2.getUTCMonth() + 1);
+        break;
+    case SimileAjax.DateTime.YEAR:
+        date2.setUTCFullYear(date2.getUTCFullYear() + 1);
+        break;
+    case SimileAjax.DateTime.DECADE:
+        date2.setUTCFullYear(date2.getUTCFullYear() + 10);
+        break;
+    case SimileAjax.DateTime.CENTURY:
+        date2.setUTCFullYear(date2.getUTCFullYear() + 100);
+        break;
+    case SimileAjax.DateTime.MILLENNIUM:
+        date2.setUTCFullYear(date2.getUTCFullYear() + 1000);
+        break;
+    }
+
+    date.setTime(date2.getTime() - timeShift);
+};
+
+/**
+ * Returns a new date object with the given time offset removed.
+ *
+ * @param {Date} date the starting date
+ * @param {Number} timeZone a timezone specified in an hour offset to remove
+ * @return {Date} a new date object with the offset removed
+ */
+SimileAjax.DateTime.removeTimeZoneOffset = function(date, timeZone) {
+    return new Date(date.getTime() +
+        timeZone * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
+};
+
+/**
+ * Returns the timezone of the user's browser.
+ *
+ * @return {Number} the timezone in the user's locale in hours
+ */
+SimileAjax.DateTime.getTimezone = function() {
+    var d = new Date().getTimezoneOffset();
+    return d / -60;
+};
+/*==================================================
+ *  String Utility Functions and Constants
+ *==================================================
+ */
+
+String.prototype.trim = function() {
+    return this.replace(/^\s+|\s+$/g, '');
+};
+
+String.prototype.startsWith = function(prefix) {
+    return this.length >= prefix.length && this.substr(0, prefix.length) == prefix;
+};
+
+String.prototype.endsWith = function(suffix) {
+    return this.length >= suffix.length && this.substr(this.length - suffix.length) == suffix;
+};
+
+String.substitute = function(s, objects) {
+    var result = "";
+    var start = 0;
+    while (start < s.length - 1) {
+        var percent = s.indexOf("%", start);
+        if (percent < 0 || percent == s.length - 1) {
+            break;
+        } else if (percent > start && s.charAt(percent - 1) == "\\") {
+            result += s.substring(start, percent - 1) + "%";
+            start = percent + 1;
+        } else {
+            var n = parseInt(s.charAt(percent + 1));
+            if (isNaN(n) || n >= objects.length) {
+                result += s.substring(start, percent + 2);
+            } else {
+                result += s.substring(start, percent) + objects[n].toString();
+            }
+            start = percent + 2;
+        }
+    }
+
+    if (start < s.length) {
+        result += s.substring(start);
+    }
+    return result;
+};
+/*==================================================
+ *  HTML Utility Functions
+ *==================================================
+ */
+
+SimileAjax.HTML = new Object();
+
+SimileAjax.HTML._e2uHash = {};
+(function() {
+    var e2uHash = SimileAjax.HTML._e2uHash;
+    e2uHash['nbsp']= '\u00A0[space]';
+    e2uHash['iexcl']= '\u00A1';
+    e2uHash['cent']= '\u00A2';
+    e2uHash['pound']= '\u00A3';
+    e2uHash['curren']= '\u00A4';
+    e2uHash['yen']= '\u00A5';
+    e2uHash['brvbar']= '\u00A6';
+    e2uHash['sect']= '\u00A7';
+    e2uHash['uml']= '\u00A8';
+    e2uHash['copy']= '\u00A9';
+    e2uHash['ordf']= '\u00AA';
+    e2uHash['laquo']= '\u00AB';
+    e2uHash['not']= '\u00AC';
+    e2uHash['shy']= '\u00AD';
+    e2uHash['reg']= '\u00AE';
+    e2uHash['macr']= '\u00AF';
+    e2uHash['deg']= '\u00B0';
+    e2uHash['plusmn']= '\u00B1';
+    e2uHash['sup2']= '\u00B2';
+    e2uHash['sup3']= '\u00B3';
+    e2uHash['acute']= '\u00B4';
+    e2uHash['micro']= '\u00B5';
+    e2uHash['para']= '\u00B6';
+    e2uHash['middot']= '\u00B7';
+    e2uHash['cedil']= '\u00B8';
+    e2uHash['sup1']= '\u00B9';
+    e2uHash['ordm']= '\u00BA';
+    e2uHash['raquo']= '\u00BB';
+    e2uHash['frac14']= '\u00BC';
+    e2uHash['frac12']= '\u00BD';
+    e2uHash['frac34']= '\u00BE';
+    e2uHash['iquest']= '\u00BF';
+    e2uHash['Agrave']= '\u00C0';
+    e2uHash['Aacute']= '\u00C1';
+    e2uHash['Acirc']= '\u00C2';
+    e2uHash['Atilde']= '\u00C3';
+    e2uHash['Auml']= '\u00C4';
+    e2uHash['Aring']= '\u00C5';
+    e2uHash['AElig']= '\u00C6';
+    e2uHash['Ccedil']= '\u00C7';
+    e2uHash['Egrave']= '\u00C8';
+    e2uHash['Eacute']= '\u00C9';
+    e2uHash['Ecirc']= '\u00CA';
+    e2uHash['Euml']= '\u00CB';
+    e2uHash['Igrave']= '\u00CC';
+    e2uHash['Iacute']= '\u00CD';
+    e2uHash['Icirc']= '\u00CE';
+    e2uHash['Iuml']= '\u00CF';
+    e2uHash['ETH']= '\u00D0';
+    e2uHash['Ntilde']= '\u00D1';
+    e2uHash['Ograve']= '\u00D2';
+    e2uHash['Oacute']= '\u00D3';
+    e2uHash['Ocirc']= '\u00D4';
+    e2uHash['Otilde']= '\u00D5';
+    e2uHash['Ouml']= '\u00D6';
+    e2uHash['times']= '\u00D7';
+    e2uHash['Oslash']= '\u00D8';
+    e2uHash['Ugrave']= '\u00D9';
+    e2uHash['Uacute']= '\u00DA';
+    e2uHash['Ucirc']= '\u00DB';
+    e2uHash['Uuml']= '\u00DC';
+    e2uHash['Yacute']= '\u00DD';
+    e2uHash['THORN']= '\u00DE';
+    e2uHash['szlig']= '\u00DF';
+    e2uHash['agrave']= '\u00E0';
+    e2uHash['aacute']= '\u00E1';
+    e2uHash['acirc']= '\u00E2';
+    e2uHash['atilde']= '\u00E3';
+    e2uHash['auml']= '\u00E4';
+    e2uHash['aring']= '\u00E5';
+    e2uHash['aelig']= '\u00E6';
+    e2uHash['ccedil']= '\u00E7';
+    e2uHash['egrave']= '\u00E8';
+    e2uHash['eacute']= '\u00E9';
+    e2uHash['ecirc']= '\u00EA';
+    e2uHash['euml']= '\u00EB';
+    e2uHash['igrave']= '\u00EC';
+    e2uHash['iacute']= '\u00ED';
+    e2uHash['icirc']= '\u00EE';
+    e2uHash['iuml']= '\u00EF';
+    e2uHash['eth']= '\u00F0';
+    e2uHash['ntilde']= '\u00F1';
+    e2uHash['ograve']= '\u00F2';
+    e2uHash['oacute']= '\u00F3';
+    e2uHash['ocirc']= '\u00F4';
+    e2uHash['otilde']= '\u00F5';
+    e2uHash['ouml']= '\u00F6';
+    e2uHash['divide']= '\u00F7';
+    e2uHash['oslash']= '\u00F8';
+    e2uHash['ugrave']= '\u00F9';
+    e2uHash['uacute']= '\u00FA';
+    e2uHash['ucirc']= '\u00FB';
+    e2uHash['uuml']= '\u00FC';
+    e2uHash['yacute']= '\u00FD';
+    e2uHash['thorn']= '\u00FE';
+    e2uHash['yuml']= '\u00FF';
+    e2uHash['quot']= '\u0022';
+    e2uHash['amp']= '\u0026';
+    e2uHash['lt']= '\u003C';
+    e2uHash['gt']= '\u003E';
+    e2uHash['OElig']= '';
+    e2uHash['oelig']= '\u0153';
+    e2uHash['Scaron']= '\u0160';
+    e2uHash['scaron']= '\u0161';
+    e2uHash['Yuml']= '\u0178';
+    e2uHash['circ']= '\u02C6';
+    e2uHash['tilde']= '\u02DC';
+    e2uHash['ensp']= '\u2002';
+    e2uHash['emsp']= '\u2003';
+    e2uHash['thinsp']= '\u2009';
+    e2uHash['zwnj']= '\u200C';
+    e2uHash['zwj']= '\u200D';
+    e2uHash['lrm']= '\u200E';
+    e2uHash['rlm']= '\u200F';
+    e2uHash['ndash']= '\u2013';
+    e2uHash['mdash']= '\u2014';
+    e2uHash['lsquo']= '\u2018';
+    e2uHash['rsquo']= '\u2019';
+    e2uHash['sbquo']= '\u201A';
+    e2uHash['ldquo']= '\u201C';
+    e2uHash['rdquo']= '\u201D';
+    e2uHash['bdquo']= '\u201E';
+    e2uHash['dagger']= '\u2020';
+    e2uHash['Dagger']= '\u2021';
+    e2uHash['permil']= '\u2030';
+    e2uHash['lsaquo']= '\u2039';
+    e2uHash['rsaquo']= '\u203A';
+    e2uHash['euro']= '\u20AC';
+    e2uHash['fnof']= '\u0192';
+    e2uHash['Alpha']= '\u0391';
+    e2uHash['Beta']= '\u0392';
+    e2uHash['Gamma']= '\u0393';
+    e2uHash['Delta']= '\u0394';
+    e2uHash['Epsilon']= '\u0395';
+    e2uHash['Zeta']= '\u0396';
+    e2uHash['Eta']= '\u0397';
+    e2uHash['Theta']= '\u0398';
+    e2uHash['Iota']= '\u0399';
+    e2uHash['Kappa']= '\u039A';
+    e2uHash['Lambda']= '\u039B';
+    e2uHash['Mu']= '\u039C';
+    e2uHash['Nu']= '\u039D';
+    e2uHash['Xi']= '\u039E';
+    e2uHash['Omicron']= '\u039F';
+    e2uHash['Pi']= '\u03A0';
+    e2uHash['Rho']= '\u03A1';
+    e2uHash['Sigma']= '\u03A3';
+    e2uHash['Tau']= '\u03A4';
+    e2uHash['Upsilon']= '\u03A5';
+    e2uHash['Phi']= '\u03A6';
+    e2uHash['Chi']= '\u03A7';
+    e2uHash['Psi']= '\u03A8';
+    e2uHash['Omega']= '\u03A9';
+    e2uHash['alpha']= '\u03B1';
+    e2uHash['beta']= '\u03B2';
+    e2uHash['gamma']= '\u03B3';
+    e2uHash['delta']= '\u03B4';
+    e2uHash['epsilon']= '\u03B5';
+    e2uHash['zeta']= '\u03B6';
+    e2uHash['eta']= '\u03B7';
+    e2uHash['theta']= '\u03B8';
+    e2uHash['iota']= '\u03B9';
+    e2uHash['kappa']= '\u03BA';
+    e2uHash['lambda']= '\u03BB';
+    e2uHash['mu']= '\u03BC';
+    e2uHash['nu']= '\u03BD';
+    e2uHash['xi']= '\u03BE';
+    e2uHash['omicron']= '\u03BF';
+    e2uHash['pi']= '\u03C0';
+    e2uHash['rho']= '\u03C1';
+    e2uHash['sigmaf']= '\u03C2';
+    e2uHash['sigma']= '\u03C3';
+    e2uHash['tau']= '\u03C4';
+    e2uHash['upsilon']= '\u03C5';
+    e2uHash['phi']= '\u03C6';
+    e2uHash['chi']= '\u03C7';
+    e2uHash['psi']= '\u03C8';
+    e2uHash['omega']= '\u03C9';
+    e2uHash['thetasym']= '\u03D1';
+    e2uHash['upsih']= '\u03D2';
+    e2uHash['piv']= '\u03D6';
+    e2uHash['bull']= '\u2022';
+    e2uHash['hellip']= '\u2026';
+    e2uHash['prime']= '\u2032';
+    e2uHash['Prime']= '\u2033';
+    e2uHash['oline']= '\u203E';
+    e2uHash['frasl']= '\u2044';
+    e2uHash['weierp']= '\u2118';
+    e2uHash['image']= '\u2111';
+    e2uHash['real']= '\u211C';
+    e2uHash['trade']= '\u2122';
+    e2uHash['alefsym']= '\u2135';
+    e2uHash['larr']= '\u2190';
+    e2uHash['uarr']= '\u2191';
+    e2uHash['rarr']= '\u2192';
+    e2uHash['darr']= '\u2193';
+    e2uHash['harr']= '\u2194';
+    e2uHash['crarr']= '\u21B5';
+    e2uHash['lArr']= '\u21D0';
+    e2uHash['uArr']= '\u21D1';
+    e2uHash['rArr']= '\u21D2';
+    e2uHash['dArr']= '\u21D3';
+    e2uHash['hArr']= '\u21D4';
+    e2uHash['forall']= '\u2200';
+    e2uHash['part']= '\u2202';
+    e2uHash['exist']= '\u2203';
+    e2uHash['empty']= '\u2205';
+    e2uHash['nabla']= '\u2207';
+    e2uHash['isin']= '\u2208';
+    e2uHash['notin']= '\u2209';
+    e2uHash['ni']= '\u220B';
+    e2uHash['prod']= '\u220F';
+    e2uHash['sum']= '\u2211';
+    e2uHash['minus']= '\u2212';
+    e2uHash['lowast']= '\u2217';
+    e2uHash['radic']= '\u221A';
+    e2uHash['prop']= '\u221D';
+    e2uHash['infin']= '\u221E';
+    e2uHash['ang']= '\u2220';
+    e2uHash['and']= '\u2227';
+    e2uHash['or']= '\u2228';
+    e2uHash['cap']= '\u2229';
+    e2uHash['cup']= '\u222A';
+    e2uHash['int']= '\u222B';
+    e2uHash['there4']= '\u2234';
+    e2uHash['sim']= '\u223C';
+    e2uHash['cong']= '\u2245';
+    e2uHash['asymp']= '\u2248';
+    e2uHash['ne']= '\u2260';
+    e2uHash['equiv']= '\u2261';
+    e2uHash['le']= '\u2264';
+    e2uHash['ge']= '\u2265';
+    e2uHash['sub']= '\u2282';
+    e2uHash['sup']= '\u2283';
+    e2uHash['nsub']= '\u2284';
+    e2uHash['sube']= '\u2286';
+    e2uHash['supe']= '\u2287';
+    e2uHash['oplus']= '\u2295';
+    e2uHash['otimes']= '\u2297';
+    e2uHash['perp']= '\u22A5';
+    e2uHash['sdot']= '\u22C5';
+    e2uHash['lceil']= '\u2308';
+    e2uHash['rceil']= '\u2309';
+    e2uHash['lfloor']= '\u230A';
+    e2uHash['rfloor']= '\u230B';
+    e2uHash['lang']= '\u2329';
+    e2uHash['rang']= '\u232A';
+    e2uHash['loz']= '\u25CA';
+    e2uHash['spades']= '\u2660';
+    e2uHash['clubs']= '\u2663';
+    e2uHash['hearts']= '\u2665';
+    e2uHash['diams']= '\u2666';
 })();
-SimileAjax.DateTime._dateRegexp=new RegExp("^(-?)([0-9]{4})("+["(-?([0-9]{2})(-?([0-9]{2}))?)","(-?([0-9]{3}))","(-?W([0-9]{2})(-?([1-7]))?)"].join("|")+")?$");
-SimileAjax.DateTime._timezoneRegexp=new RegExp("Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$");
-SimileAjax.DateTime._timeRegexp=new RegExp("^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(.([0-9]+))?)?)?$");
-SimileAjax.DateTime.setIso8601Date=function(H,F){var I=F.match(SimileAjax.DateTime._dateRegexp);
-if(!I){throw new Error("Invalid date string: "+F);
-}var B=(I[1]=="-")?-1:1;
-var J=B*I[2];
-var G=I[5];
-var C=I[7];
-var E=I[9];
-var A=I[11];
-var M=(I[13])?I[13]:1;
-H.setUTCFullYear(J);
-if(E){H.setUTCMonth(0);
-H.setUTCDate(Number(E));
-}else{if(A){H.setUTCMonth(0);
-H.setUTCDate(1);
-var L=H.getUTCDay();
-var K=(L)?L:7;
-var D=Number(M)+(7*Number(A));
-if(K<=4){H.setUTCDate(D+1-K);
-}else{H.setUTCDate(D+8-K);
-}}else{if(G){H.setUTCDate(1);
-H.setUTCMonth(G-1);
-}if(C){H.setUTCDate(C);
-}}}return H;
-};
-SimileAjax.DateTime.setIso8601Time=function(F,C){var G=C.match(SimileAjax.DateTime._timeRegexp);
-if(!G){SimileAjax.Debug.warn("Invalid time string: "+C);
-return false;
-}var A=G[1];
-var E=Number((G[3])?G[3]:0);
-var D=(G[5])?G[5]:0;
-var B=G[7]?(Number("0."+G[7])*1000):0;
-F.setUTCHours(A);
-F.setUTCMinutes(E);
-F.setUTCSeconds(D);
-F.setUTCMilliseconds(B);
-return F;
-};
-SimileAjax.DateTime.timezoneOffset=new Date().getTimezoneOffset();
-SimileAjax.DateTime.setIso8601=function(B,A){var D=null;
-var E=(A.indexOf("T")==-1)?A.split(" "):A.split("T");
-SimileAjax.DateTime.setIso8601Date(B,E[0]);
-if(E.length==2){var C=E[1].match(SimileAjax.DateTime._timezoneRegexp);
-if(C){if(C[0]=="Z"){D=0;
-}else{D=(Number(C[3])*60)+Number(C[5]);
-D*=((C[2]=="-")?1:-1);
-}E[1]=E[1].substr(0,E[1].length-C[0].length);
-}SimileAjax.DateTime.setIso8601Time(B,E[1]);
-}if(D==null){D=B.getTimezoneOffset();
-}B.setTime(B.getTime()+D*60000);
-return B;
-};
-SimileAjax.DateTime.parseIso8601DateTime=function(A){try{return SimileAjax.DateTime.setIso8601(new Date(0),A);
-}catch(B){return null;
-}};
-SimileAjax.DateTime.parseGregorianDateTime=function(G){if(G==null){return null;
-}else{if(G instanceof Date){return G;
-}}var B=G.toString();
-if(B.length>0&&B.length<8){var C=B.indexOf(" ");
-if(C>0){var A=parseInt(B.substr(0,C));
-var E=B.substr(C+1);
-if(E.toLowerCase()=="bc"){A=1-A;
-}}else{var A=parseInt(B);
-}var F=new Date(0);
-F.setUTCFullYear(A);
-return F;
-}try{return new Date(Date.parse(B));
-}catch(D){return null;
-}};
-SimileAjax.DateTime.roundDownToInterval=function(B,G,J,K,A){var D=J*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
-var I=new Date(B.getTime()+D);
-var E=function(L){L.setUTCMilliseconds(0);
-L.setUTCSeconds(0);
-L.setUTCMinutes(0);
-L.setUTCHours(0);
-};
-var C=function(L){E(L);
-L.setUTCDate(1);
-L.setUTCMonth(0);
-};
-switch(G){case SimileAjax.DateTime.MILLISECOND:var H=I.getUTCMilliseconds();
-I.setUTCMilliseconds(H-(H%K));
-break;
-case SimileAjax.DateTime.SECOND:I.setUTCMilliseconds(0);
-var H=I.getUTCSeconds();
-I.setUTCSeconds(H-(H%K));
-break;
-case SimileAjax.DateTime.MINUTE:I.setUTCMilliseconds(0);
-I.setUTCSeconds(0);
-var H=I.getUTCMinutes();
-I.setTime(I.getTime()-(H%K)*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
-break;
-case SimileAjax.DateTime.HOUR:I.setUTCMilliseconds(0);
-I.setUTCSeconds(0);
-I.setUTCMinutes(0);
-var H=I.getUTCHours();
-I.setUTCHours(H-(H%K));
-break;
-case SimileAjax.DateTime.DAY:E(I);
-break;
-case SimileAjax.DateTime.WEEK:E(I);
-var F=(I.getUTCDay()+7-A)%7;
-I.setTime(I.getTime()-F*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
-break;
-case SimileAjax.DateTime.MONTH:E(I);
-I.setUTCDate(1);
-var H=I.getUTCMonth();
-I.setUTCMonth(H-(H%K));
-break;
-case SimileAjax.DateTime.YEAR:C(I);
-var H=I.getUTCFullYear();
-I.setUTCFullYear(H-(H%K));
-break;
-case SimileAjax.DateTime.DECADE:C(I);
-I.setUTCFullYear(Math.floor(I.getUTCFullYear()/10)*10);
-break;
-case SimileAjax.DateTime.CENTURY:C(I);
-I.setUTCFullYear(Math.floor(I.getUTCFullYear()/100)*100);
-break;
-case SimileAjax.DateTime.MILLENNIUM:C(I);
-I.setUTCFullYear(Math.floor(I.getUTCFullYear()/1000)*1000);
-break;
-}B.setTime(I.getTime()-D);
-};
-SimileAjax.DateTime.roundUpToInterval=function(D,F,C,A,B){var E=D.getTime();
-SimileAjax.DateTime.roundDownToInterval(D,F,C,A,B);
-if(D.getTime()<E){D.setTime(D.getTime()+SimileAjax.DateTime.gregorianUnitLengths[F]*A);
-}};
-SimileAjax.DateTime.incrementByInterval=function(B,E,A){A=(typeof A=="undefined")?0:A;
-var D=A*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
-var C=new Date(B.getTime()+D);
-switch(E){case SimileAjax.DateTime.MILLISECOND:C.setTime(C.getTime()+1);
-break;
-case SimileAjax.DateTime.SECOND:C.setTime(C.getTime()+1000);
-break;
-case SimileAjax.DateTime.MINUTE:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
-break;
-case SimileAjax.DateTime.HOUR:C.setTime(C.getTime()+SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
-break;
-case SimileAjax.DateTime.DAY:C.setUTCDate(C.getUTCDate()+1);
-break;
-case SimileAjax.DateTime.WEEK:C.setUTCDate(C.getUTCDate()+7);
-break;
-case SimileAjax.DateTime.MONTH:C.setUTCMonth(C.getUTCMonth()+1);
-break;
-case SimileAjax.DateTime.YEAR:C.setUTCFullYear(C.getUTCFullYear()+1);
-break;
-case SimileAjax.DateTime.DECADE:C.setUTCFullYear(C.getUTCFullYear()+10);
-break;
-case SimileAjax.DateTime.CENTURY:C.setUTCFullYear(C.getUTCFullYear()+100);
-break;
-case SimileAjax.DateTime.MILLENNIUM:C.setUTCFullYear(C.getUTCFullYear()+1000);
-break;
-}B.setTime(C.getTime()-D);
-};
-SimileAjax.DateTime.removeTimeZoneOffset=function(B,A){return new Date(B.getTime()+A*SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
-};
-SimileAjax.DateTime.getTimezone=function(){var A=new Date().getTimezoneOffset();
-return A/-60;
-};
-
-
-/* debug.js */
-SimileAjax.Debug={silent:false};
-SimileAjax.Debug.log=function(B){var A;
-if("console" in window&&"log" in window.console){A=function(C){console.log(C);
-};
-}else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
-}};
-}SimileAjax.Debug.log=A;
-A(B);
-};
-SimileAjax.Debug.warn=function(B){var A;
-if("console" in window&&"warn" in window.console){A=function(C){console.warn(C);
-};
-}else{A=function(C){if(!SimileAjax.Debug.silent){alert(C);
-}};
-}SimileAjax.Debug.warn=A;
-A(B);
-};
-SimileAjax.Debug.exception=function(B,D){var A,C=SimileAjax.parseURLParameters();
-if(C.errors=="throw"||SimileAjax.params.errors=="throw"){A=function(F,E){throw (F);
-};
-}else{if("console" in window&&"error" in window.console){A=function(F,E){if(E!=null){console.error(E+" %o",F);
-}else{console.error(F);
-}throw (F);
-};
-}else{A=function(F,E){if(!SimileAjax.Debug.silent){alert("Caught exception: "+E+"\n\nDetails: "+("description" in F?F.description:F));
-}throw (F);
-};
-}}SimileAjax.Debug.exception=A;
-A(B,D);
-};
-SimileAjax.Debug.objectToString=function(A){return SimileAjax.Debug._objectToString(A,"");
-};
-SimileAjax.Debug._objectToString=function(D,A){var C=A+" ";
-if(typeof D=="object"){var B="{";
-for(E in D){B+=C+E+": "+SimileAjax.Debug._objectToString(D[E],C)+"\n";
-}B+=A+"}";
-return B;
-}else{if(typeof D=="array"){var B="[";
-for(var E=0;
-E<D.length;
-E++){B+=SimileAjax.Debug._objectToString(D[E],C)+"\n";
-}B+=A+"]";
-return B;
-}else{return D;
-}}};
-
-
-/* dom.js */
-SimileAjax.DOM=new Object();
-SimileAjax.DOM.registerEventWithObject=function(C,A,D,B){SimileAjax.DOM.registerEvent(C,A,function(F,E,G){return D[B].call(D,F,E,G);
-});
-};
-SimileAjax.DOM.registerEvent=function(C,B,D){var A=function(E){E=(E)?E:((event)?event:null);
-if(E){var F=(E.target)?E.target:((E.srcElement)?E.srcElement:null);
-if(F){F=(F.nodeType==1||F.nodeType==9)?F:F.parentNode;
-}return D(C,E,F);
-}return true;
-};
-if(SimileAjax.Platform.browser.isIE){C.attachEvent("on"+B,A);
-}else{C.addEventListener(B,A,false);
-}};
-SimileAjax.DOM.getPageCoordinates=function(B){var E=0;
-var D=0;
-if(B.nodeType!=1){B=B.parentNode;
-}var C=B;
-while(C!=null){E+=C.offsetLeft;
-D+=C.offsetTop;
-C=C.offsetParent;
-}var A=document.body;
-while(B!=null&&B!=A){if("scrollLeft" in B){E-=B.scrollLeft;
-D-=B.scrollTop;
-}B=B.parentNode;
-}return{left:E,top:D};
-};
-SimileAjax.DOM.getSize=function(B){var A=this.getStyle(B,"width");
-var C=this.getStyle(B,"height");
-if(A.indexOf("px")>-1){A=A.replace("px","");
-}if(C.indexOf("px")>-1){C=C.replace("px","");
-}return{w:A,h:C};
-};
-SimileAjax.DOM.getStyle=function(B,A){if(B.currentStyle){var C=B.currentStyle[A];
-}else{if(window.getComputedStyle){var C=document.defaultView.getComputedStyle(B,null).getPropertyValue(A);
-}else{var C="";
-}}return C;
-};
-SimileAjax.DOM.getEventRelativeCoordinates=function(A,B){if(SimileAjax.Platform.browser.isIE){if(A.type=="mousewheel"){var C=SimileAjax.DOM.getPageCoordinates(B);
-return{x:A.clientX-C.left,y:A.clientY-C.top};
-}else{return{x:A.offsetX,y:A.offsetY};
-}}else{var C=SimileAjax.DOM.getPageCoordinates(B);
-if((A.type=="DOMMouseScroll")&&SimileAjax.Platform.browser.isFirefox&&(SimileAjax.Platform.browser.majorVersion==2)){return{x:A.screenX-C.left,y:A.screenY-C.top};
-}else{return{x:A.pageX-C.left,y:A.pageY-C.top};
-}}};
-SimileAjax.DOM.getEventPageCoordinates=function(A){if(SimileAjax.Platform.browser.isIE){return{x:A.clientX+document.body.scrollLeft,y:A.clientY+document.body.scrollTop};
-}else{return{x:A.pageX,y:A.pageY};
-}};
-SimileAjax.DOM.hittest=function(A,C,B){return SimileAjax.DOM._hittest(document.body,A,C,B);
-};
-SimileAjax.DOM._hittest=function(C,L,K,H){var M=C.childNodes;
-outer:for(var G=0;
-G<M.length;
-G++){var A=M[G];
-for(var F=0;
-F<H.length;
-F++){if(A==H[F]){continue outer;
-}}if(A.offsetWidth==0&&A.offsetHeight==0){var B=SimileAjax.DOM._hittest(A,L,K,H);
-if(B!=A){return B;
-}}else{var J=0;
-var E=0;
-var D=A;
-while(D){J+=D.offsetTop;
-E+=D.offsetLeft;
-D=D.offsetParent;
-}if(E<=L&&J<=K&&(L-E)<A.offsetWidth&&(K-J)<A.offsetHeight){return SimileAjax.DOM._hittest(A,L,K,H);
-}else{if(A.nodeType==1&&A.tagName=="TR"){var I=SimileAjax.DOM._hittest(A,L,K,H);
-if(I!=A){return I;
-}}}}}return C;
-};
-SimileAjax.DOM.cancelEvent=function(A){A.returnValue=false;
-A.cancelBubble=true;
-if("preventDefault" in A){A.preventDefault();
-}};
-SimileAjax.DOM.appendClassName=function(C,D){var B=C.className.split(" ");
-for(var A=0;
-A<B.length;
-A++){if(B[A]==D){return ;
-}}B.push(D);
-C.className=B.join(" ");
-};
-SimileAjax.DOM.createInputElement=function(A){var B=document.createElement("div");
-B.innerHTML="<input type='"+A+"' />";
-return B.firstChild;
-};
-SimileAjax.DOM.createDOMFromTemplate=function(B){var A={};
-A.elmt=SimileAjax.DOM._createDOMFromTemplate(B,A,null);
-return A;
-};
-SimileAjax.DOM._createDOMFromTemplate=function(A,I,E){if(A==null){return null;
-}else{if(typeof A!="object"){var D=document.createTextNode(A);
-if(E!=null){E.appendChild(D);
-}return D;
-}else{var C=null;
-if("tag" in A){var J=A.tag;
-if(E!=null){if(J=="tr"){C=E.insertRow(E.rows.length);
-}else{if(J=="td"){C=E.insertCell(E.cells.length);
-}}}if(C==null){C=J=="input"?SimileAjax.DOM.createInputElement(A.type):document.createElement(J);
-if(E!=null){E.appendChild(C);
-}}}else{C=A.elmt;
-if(E!=null){E.appendChild(C);
-}}for(var B in A){var G=A[B];
-if(B=="field"){I[G]=C;
-}else{if(B=="className"){C.className=G;
-}else{if(B=="id"){C.id=G;
-}else{if(B=="title"){C.title=G;
-}else{if(B=="type"&&C.tagName=="input"){}else{if(B=="style"){for(n in G){var H=G[n];
-if(n=="float"){n=SimileAjax.Platform.browser.isIE?"styleFloat":"cssFloat";
-}C.style[n]=H;
-}}else{if(B=="children"){for(var F=0;
-F<G.length;
-F++){SimileAjax.DOM._createDOMFromTemplate(G[F],I,C);
-}}else{if(B!="tag"&&B!="elmt"){C.setAttribute(B,G);
-}}}}}}}}}return C;
-}}};
-SimileAjax.DOM._cachedParent=null;
-SimileAjax.DOM.createElementFromString=function(A){if(SimileAjax.DOM._cachedParent==null){SimileAjax.DOM._cachedParent=document.createElement("div");
-}SimileAjax.DOM._cachedParent.innerHTML=A;
-return SimileAjax.DOM._cachedParent.firstChild;
-};
-SimileAjax.DOM.createDOMFromString=function(A,C,D){var B=typeof A=="string"?document.createElement(A):A;
-B.innerHTML=C;
-var E={elmt:B};
-SimileAjax.DOM._processDOMChildrenConstructedFromString(E,B,D!=null?D:{});
-return E;
-};
-SimileAjax.DOM._processDOMConstructedFromString=function(D,A,B){var E=A.id;
-if(E!=null&&E.length>0){A.removeAttribute("id");
-if(E in B){var C=A.parentNode;
-C.insertBefore(B[E],A);
-C.removeChild(A);
-D[E]=B[E];
-return ;
-}else{D[E]=A;
-}}if(A.hasChildNodes()){SimileAjax.DOM._processDOMChildrenConstructedFromString(D,A,B);
-}};
-SimileAjax.DOM._processDOMChildrenConstructedFromString=function(E,B,D){var C=B.firstChild;
-while(C!=null){var A=C.nextSibling;
-if(C.nodeType==1){SimileAjax.DOM._processDOMConstructedFromString(E,C,D);
-}C=A;
-}};
-
-
-/* graphics.js */
-SimileAjax.Graphics=new Object();
-SimileAjax.Graphics.pngIsTranslucent=(!SimileAjax.Platform.browser.isIE)||(SimileAjax.Platform.browser.majorVersion>6);
-SimileAjax.Graphics._createTranslucentImage1=function(A,C){var B=document.createElement("img");
-B.setAttribute("src",A);
-if(C!=null){B.style.verticalAlign=C;
-}return B;
-};
-SimileAjax.Graphics._createTranslucentImage2=function(A,C){var B=document.createElement("img");
-B.style.width="1px";
-B.style.height="1px";
-B.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image')";
-B.style.verticalAlign=(C!=null)?C:"middle";
-return B;
-};
-SimileAjax.Graphics.createTranslucentImage=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImage1:SimileAjax.Graphics._createTranslucentImage2;
-SimileAjax.Graphics._createTranslucentImageHTML1=function(A,B){return'<img src="'+A+'"'+(B!=null?' style="vertical-align: '+B+';"':"")+" />";
-};
-SimileAjax.Graphics._createTranslucentImageHTML2=function(A,C){var B="width: 1px; height: 1px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+A+"', sizingMethod='image');"+(C!=null?" vertical-align: "+C+";":"");
-return"<img src='"+A+"' style=\""+B+'" />';
-};
-SimileAjax.Graphics.createTranslucentImageHTML=SimileAjax.Graphics.pngIsTranslucent?SimileAjax.Graphics._createTranslucentImageHTML1:SimileAjax.Graphics._createTranslucentImageHTML2;
-SimileAjax.Graphics.setOpacity=function(B,A){if(SimileAjax.Platform.browser.isIE){B.style.filter="progid:DXImageTransform.Microsoft.Alpha(Style=0,Opacity="+A+")";
-}else{var C=(A/100).toString();
-B.style.opacity=C;
-B.style.MozOpacity=C;
-}};
-SimileAjax.Graphics._bubbleMargins={top:33,bottom:42,left:33,right:40};
-SimileAjax.Graphics._arrowOffsets={top:0,bottom:9,left:1,right:8};
-SimileAjax.Graphics._bubblePadding=15;
-SimileAjax.Graphics._bubblePointOffset=6;
-SimileAjax.Graphics._halfArrowWidth=18;
-SimileAjax.Graphics.createBubbleForContentAndPoint=function(F,D,C,A,B,E){if(typeof A!="number"){A=300;
-}if(typeof E!="number"){E=0;
-}F.style.position="absolute";
-F.style.left="-5000px";
-F.style.top="0px";
-F.style.width=A+"px";
-document.body.appendChild(F);
-window.setTimeout(function(){var J=F.scrollWidth+10;
-var G=F.scrollHeight+10;
-var I=0;
-if(E>0&&G>E){G=E;
-I=J-25;
-}var H=SimileAjax.Graphics.createBubbleForPoint(D,C,J,G,B);
-document.body.removeChild(F);
-F.style.position="static";
-F.style.left="";
-F.style.top="";
-if(I>0){var K=document.createElement("div");
-F.style.width="";
-K.style.width=I+"px";
-K.appendChild(F);
-H.content.appendChild(K);
-}else{F.style.width=J+"px";
-H.content.appendChild(F);
-}},200);
-};
-SimileAjax.Graphics.createBubbleForPoint=function(C,B,N,R,F){function T(){if(typeof window.innerHeight=="number"){return{w:window.innerWidth,h:window.innerHeight};
-}else{if(document.documentElement&&document.documentElement.clientHeight){return{w:document.documentElement.clientWidth,h:document.documentElement.clientHeight};
-}else{if(document.body&&document.body.clientHeight){return{w:document.body.clientWidth,h:document.body.clientHeight};
-}}}}var L=function(){if(!M._closed){document.body.removeChild(M._div);
-M._doc=null;
-M._div=null;
-M._content=null;
-M._closed=true;
-}};
-var M={_closed:false};
-var O=T();
-var H=O.w;
-var G=O.h;
-var D=SimileAjax.Graphics._bubbleMargins;
-N=parseInt(N,10);
-R=parseInt(R,10);
-var P=D.left+N+D.right;
-var U=D.top+R+D.bottom;
-var Q=SimileAjax.Graphics.pngIsTranslucent;
-var J=SimileAjax.urlPrefix;
-var A=function(Z,Y,a,X){Z.style.position="absolute";
-Z.style.width=a+"px";
-Z.style.height=X+"px";
-if(Q){Z.style.background="url("+Y+")";
-}else{Z.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+Y+"', sizingMethod='crop')";
-}};
-var K=document.createElement("div");
-K.style.width=P+"px";
-K.style.height=U+"px";
-K.style.position="absolute";
-K.style.zIndex=1000;
-var W=SimileAjax.WindowManager.pushLayer(L,true,K);
-M._div=K;
-M.close=function(){SimileAjax.WindowManager.popLayer(W);
-};
-var I=document.createElement("div");
-I.style.width="100%";
-I.style.height="100%";
-I.style.position="relative";
-K.appendChild(I);
-var S=function(Z,c,b,a,Y){var X=document.createElement("div");
-X.style.left=c+"px";
-X.style.top=b+"px";
-A(X,Z,a,Y);
-I.appendChild(X);
-};
-S(J+"data/timeline/bubble-top-left.png",0,0,D.left,D.top);
-S(J+"data/timeline/bubble-top.png",D.left,0,N,D.top);
-S(J+"data/timeline/bubble-top-right.png",D.left+N,0,D.right,D.top);
-S(J+"data/timeline/bubble-left.png",0,D.top,D.left,R);
-S(J+"data/timeline/bubble-right.png",D.left+N,D.top,D.right,R);
-S(J+"data/timeline/bubble-bottom-left.png",0,D.top+R,D.left,D.bottom);
-S(J+"data/timeline/bubble-bottom.png",D.left,D.top+R,N,D.bottom);
-S(J+"data/timeline/bubble-bottom-right.png",D.left+N,D.top+R,D.right,D.bottom);
-var V=document.createElement("div");
-V.style.left=(P-D.right+SimileAjax.Graphics._bubblePadding-16-2)+"px";
-V.style.top=(D.top-SimileAjax.Graphics._bubblePadding+1)+"px";
-V.style.cursor="pointer";
-A(V,J+"data/timeline/close-button.png",16,16);
-SimileAjax.WindowManager.registerEventWithObject(V,"click",M,"close");
-I.appendChild(V);
-var E=document.createElement("div");
-E.style.position="absolute";
-E.style.left=D.left+"px";
-E.style.top=D.top+"px";
-E.style.width=N+"px";
-E.style.height=R+"px";
-E.style.overflow="auto";
-E.style.background="white";
-I.appendChild(E);
-M.content=E;
-(function(){if(C-SimileAjax.Graphics._halfArrowWidth-SimileAjax.Graphics._bubblePadding>0&&C+SimileAjax.Graphics._halfArrowWidth+SimileAjax.Graphics._bubblePadding<H){var Z=C-Math.round(N/2)-D.left;
-Z=C<(H/2)?Math.max(Z,-(D.left-SimileAjax.Graphics._bubblePadding)):Math.min(Z,H+(D.right-SimileAjax.Graphics._bubblePadding)-P);
-if((F&&F=="top")||(!F&&(B-SimileAjax.Graphics._bubblePointOffset-U>0))){var X=document.createElement("div");
-X.style.left=(C-SimileAjax.Graphics._halfArrowWidth-Z)+"px";
-X.style.top=(D.top+R)+"px";
-A(X,J+"data/timeline/bubble-bottom-arrow.png",37,D.bottom);
-I.appendChild(X);
-K.style.left=Z+"px";
-K.style.top=(B-SimileAjax.Graphics._bubblePointOffset-U+SimileAjax.Graphics._arrowOffsets.bottom)+"px";
-return ;
-}else{if((F&&F=="bottom")||(!F&&(B+SimileAjax.Graphics._bubblePointOffset+U<G))){var X=document.createElement("div");
-X.style.left=(C-SimileAjax.Graphics._halfArrowWidth-Z)+"px";
-X.style.top="0px";
-A(X,J+"data/timeline/bubble-top-arrow.png",37,D.top);
-I.appendChild(X);
-K.style.left=Z+"px";
-K.style.top=(B+SimileAjax.Graphics._bubblePointOffset-SimileAjax.Graphics._arrowOffsets.top)+"px";
-return ;
-}}}var Y=B-Math.round(R/2)-D.top;
-Y=B<(G/2)?Math.max(Y,-(D.top-SimileAjax.Graphics._bubblePadding)):Math.min(Y,G+(D.bottom-SimileAjax.Graphics._bubblePadding)-U);
-if((F&&F=="left")||(!F&&(C-SimileAjax.Graphics._bubblePointOffset-P>0))){var X=document.createElement("div");
-X.style.left=(D.left+N)+"px";
-X.style.top=(B-SimileAjax.Graphics._halfArrowWidth-Y)+"px";
-A(X,J+"data/timeline/bubble-right-arrow.png",D.right,37);
-I.appendChild(X);
-K.style.left=(C-SimileAjax.Graphics._bubblePointOffset-P+SimileAjax.Graphics._arrowOffsets.right)+"px";
-K.style.top=Y+"px";
-}else{if((F&&F=="right")||(!F&&(C-SimileAjax.Graphics._bubblePointOffset-P<H))){var X=document.createElement("div");
-X.style.left="0px";
-X.style.top=(B-SimileAjax.Graphics._halfArrowWidth-Y)+"px";
-A(X,J+"data/timeline/bubble-left-arrow.png",D.left,37);
-I.appendChild(X);
-K.style.left=(C+SimileAjax.Graphics._bubblePointOffset-SimileAjax.Graphics._arrowOffsets.left)+"px";
-K.style.top=Y+"px";
-}}})();
-document.body.appendChild(K);
-return M;
-};
-SimileAjax.Graphics.createMessageBubble=function(H){var G=H.createElement("div");
-if(SimileAjax.Graphics.pngIsTranslucent){var I=H.createElement("div");
-I.style.height="33px";
-I.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-top-left.png) top left no-repeat";
-I.style.paddingLeft="44px";
-G.appendChild(I);
-var C=H.createElement("div");
-C.style.height="33px";
-C.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-top-right.png) top right no-repeat";
-I.appendChild(C);
-var F=H.createElement("div");
-F.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-left.png) top left repeat-y";
-F.style.paddingLeft="44px";
-G.appendChild(F);
-var A=H.createElement("div");
-A.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-right.png) top right repeat-y";
-A.style.paddingRight="44px";
-F.appendChild(A);
-var D=H.createElement("div");
-A.appendChild(D);
-var B=H.createElement("div");
-B.style.height="55px";
-B.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-bottom-left.png) bottom left no-repeat";
-B.style.paddingLeft="44px";
-G.appendChild(B);
-var E=H.createElement("div");
-E.style.height="55px";
-E.style.background="url("+SimileAjax.urlPrefix+"data/timeline/message-bottom-right.png) bottom right no-repeat";
-B.appendChild(E);
-}else{G.style.border="2px solid #7777AA";
-G.style.padding="20px";
-G.style.background="white";
-SimileAjax.Graphics.setOpacity(G,90);
-var D=H.createElement("div");
-G.appendChild(D);
-}return{containerDiv:G,contentDiv:D};
-};
-SimileAjax.Graphics.createAnimation=function(B,E,D,C,A){return new SimileAjax.Graphics._Animation(B,E,D,C,A);
-};
-SimileAjax.Graphics._Animation=function(B,E,D,C,A){this.f=B;
-this.cont=(typeof A=="function")?A:function(){};
-this.from=E;
-this.to=D;
-this.current=E;
-this.duration=C;
-this.start=new Date().getTime();
-this.timePassed=0;
-};
-SimileAjax.Graphics._Animation.prototype.run=function(){var A=this;
-window.setTimeout(function(){A.step();
-},50);
-};
-SimileAjax.Graphics._Animation.prototype.step=function(){this.timePassed+=50;
-var B=this.timePassed/this.duration;
-var A=-Math.cos(B*Math.PI)/2+0.5;
-var D=A*(this.to-this.from)+this.from;
-try{this.f(D,D-this.current);
-}catch(C){}this.current=D;
-if(this.timePassed<this.duration){this.run();
-}else{this.f(this.to,0);
-this["cont"]();
-}};
-SimileAjax.Graphics.createStructuredDataCopyButton=function(F,D,A,E){var G=document.createElement("div");
-G.style.position="relative";
-G.style.display="inline";
-G.style.width=D+"px";
-G.style.height=A+"px";
-G.style.overflow="hidden";
-G.style.margin="2px";
-if(SimileAjax.Graphics.pngIsTranslucent){G.style.background="url("+F+") no-repeat";
-}else{G.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+F+"', sizingMethod='image')";
-}var C;
-if(SimileAjax.Platform.browser.isIE){C="filter:alpha(opacity=0)";
-}else{C="opacity: 0";
-}G.innerHTML="<textarea rows='1' autocomplete='off' value='none' style='"+C+"' />";
-var B=G.firstChild;
-B.style.width=D+"px";
-B.style.height=A+"px";
-B.onmousedown=function(H){H=(H)?H:((event)?event:null);
-if(H.button==2){B.value=E();
-B.select();
-}};
-return G;
-};
-SimileAjax.Graphics.getWidthHeight=function(C){var A,B;
-if(C.getBoundingClientRect==null){A=C.offsetWidth;
-B=C.offsetHeight;
-}else{var D=C.getBoundingClientRect();
-A=Math.ceil(D.right-D.left);
-B=Math.ceil(D.bottom-D.top);
-}return{width:A,height:B};
-};
-SimileAjax.Graphics.getFontRenderingContext=function(A,B){return new SimileAjax.Graphics._FontRenderingContext(A,B);
-};
-SimileAjax.Graphics._FontRenderingContext=function(A,B){this._elmt=A;
-this._elmt.style.visibility="hidden";
-if(typeof B=="string"){this._elmt.style.width=B;
-}else{if(typeof B=="number"){this._elmt.style.width=B+"px";
-}}};
-SimileAjax.Graphics._FontRenderingContext.prototype.dispose=function(){this._elmt=null;
-};
-SimileAjax.Graphics._FontRenderingContext.prototype.update=function(){this._elmt.innerHTML="A";
-this._lineHeight=this._elmt.offsetHeight;
-};
-SimileAjax.Graphics._FontRenderingContext.prototype.computeSize=function(D,C){var B=this._elmt;
-B.innerHTML=D;
-B.className=C===undefined?"":C;
-var A=SimileAjax.Graphics.getWidthHeight(B);
-B.className="";
-return A;
-};
-SimileAjax.Graphics._FontRenderingContext.prototype.getLineHeight=function(){return this._lineHeight;
-};
-
-
-/* history.js */
-SimileAjax.History={maxHistoryLength:10,historyFile:"__history__.html",enabled:true,_initialized:false,_listeners:new SimileAjax.ListenerQueue(),_actions:[],_baseIndex:0,_currentIndex:0,_plainDocumentTitle:document.title};
-SimileAjax.History.formatHistoryEntryTitle=function(A){return SimileAjax.History._plainDocumentTitle+" {"+A+"}";
-};
-SimileAjax.History.initialize=function(){if(SimileAjax.History._initialized){return ;
-}if(SimileAjax.History.enabled){var A=document.createElement("iframe");
-A.id="simile-ajax-history";
-A.style.position="absolute";
-A.style.width="10px";
-A.style.height="10px";
-A.style.top="0px";
-A.style.left="0px";
-A.style.visibility="hidden";
-A.src=SimileAjax.History.historyFile+"?0";
-document.body.appendChild(A);
-SimileAjax.DOM.registerEvent(A,"load",SimileAjax.History._handleIFrameOnLoad);
-SimileAjax.History._iframe=A;
-}SimileAjax.History._initialized=true;
-};
-SimileAjax.History.addListener=function(A){SimileAjax.History.initialize();
-SimileAjax.History._listeners.add(A);
-};
-SimileAjax.History.removeListener=function(A){SimileAjax.History.initialize();
-SimileAjax.History._listeners.remove(A);
-};
-SimileAjax.History.addAction=function(A){SimileAjax.History.initialize();
-SimileAjax.History._listeners.fire("onBeforePerform",[A]);
-window.setTimeout(function(){try{A.perform();
-SimileAjax.History._listeners.fire("onAfterPerform",[A]);
-if(SimileAjax.History.enabled){SimileAjax.History._actions=SimileAjax.History._actions.slice(0,SimileAjax.History._currentIndex-SimileAjax.History._baseIndex);
-SimileAjax.History._actions.push(A);
-SimileAjax.History._currentIndex++;
-var C=SimileAjax.History._actions.length-SimileAjax.History.maxHistoryLength;
-if(C>0){SimileAjax.History._actions=SimileAjax.History._actions.slice(C);
-SimileAjax.History._baseIndex+=C;
-}try{SimileAjax.History._iframe.contentWindow.location.search="?"+SimileAjax.History._currentIndex;
-}catch(B){var D=SimileAjax.History.formatHistoryEntryTitle(A.label);
-document.title=D;
-}}}catch(B){SimileAjax.Debug.exception(B,"Error adding action {"+A.label+"} to history");
-}},0);
-};
-SimileAjax.History.addLengthyAction=function(C,A,B){SimileAjax.History.addAction({perform:C,undo:A,label:B,uiLayer:SimileAjax.WindowManager.getBaseLayer(),lengthy:true});
-};
-SimileAjax.History._handleIFrameOnLoad=function(){try{var B=SimileAjax.History._iframe.contentWindow.location.search;
-var F=(B.length==0)?0:Math.max(0,parseInt(B.substr(1)));
-var E=function(){var G=F-SimileAjax.History._currentIndex;
-SimileAjax.History._currentIndex+=G;
-SimileAjax.History._baseIndex+=G;
-SimileAjax.History._iframe.contentWindow.location.search="?"+F;
-};
-if(F<SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeUndoSeveral",[]);
-window.setTimeout(function(){while(SimileAjax.History._currentIndex>F&&SimileAjax.History._currentIndex>SimileAjax.History._baseIndex){SimileAjax.History._currentIndex--;
-var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
-try{G.undo();
-}catch(H){SimileAjax.Debug.exception(H,"History: Failed to undo action {"+G.label+"}");
-}}SimileAjax.History._listeners.fire("onAfterUndoSeveral",[]);
-E();
-},0);
-}else{if(F>SimileAjax.History._currentIndex){SimileAjax.History._listeners.fire("onBeforeRedoSeveral",[]);
-window.setTimeout(function(){while(SimileAjax.History._currentIndex<F&&SimileAjax.History._currentIndex-SimileAjax.History._baseIndex<SimileAjax.History._actions.length){var G=SimileAjax.History._actions[SimileAjax.History._currentIndex-SimileAjax.History._baseIndex];
-try{G.perform();
-}catch(H){SimileAjax.Debug.exception(H,"History: Failed to redo action {"+G.label+"}");
-}SimileAjax.History._currentIndex++;
-}SimileAjax.History._listeners.fire("onAfterRedoSeveral",[]);
-E();
-},0);
-}else{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
-var D=(A>=0&&A<SimileAjax.History._actions.length)?SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[A].label):SimileAjax.History._plainDocumentTitle;
-SimileAjax.History._iframe.contentWindow.document.title=D;
-document.title=D;
-}}}catch(C){}};
-SimileAjax.History.getNextUndoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex-1;
-return SimileAjax.History._actions[A];
-}catch(B){return null;
-}};
-SimileAjax.History.getNextRedoAction=function(){try{var A=SimileAjax.History._currentIndex-SimileAjax.History._baseIndex;
-return SimileAjax.History._actions[A];
-}catch(B){return null;
-}};
-
-
-/* html.js */
-SimileAjax.HTML=new Object();
-SimileAjax.HTML._e2uHash={};
-(function(){var A=SimileAjax.HTML._e2uHash;
-A["nbsp"]="\u00A0[space]";
-A["iexcl"]="\u00A1";
-A["cent"]="\u00A2";
-A["pound"]="\u00A3";
-A["curren"]="\u00A4";
-A["yen"]="\u00A5";
-A["brvbar"]="\u00A6";
-A["sect"]="\u00A7";
-A["uml"]="\u00A8";
-A["copy"]="\u00A9";
-A["ordf"]="\u00AA";
-A["laquo"]="\u00AB";
-A["not"]="\u00AC";
-A["shy"]="\u00AD";
-A["reg"]="\u00AE";
-A["macr"]="\u00AF";
-A["deg"]="\u00B0";
-A["plusmn"]="\u00B1";
-A["sup2"]="\u00B2";
-A["sup3"]="\u00B3";
-A["acute"]="\u00B4";
-A["micro"]="\u00B5";
-A["para"]="\u00B6";
-A["middot"]="\u00B7";
-A["cedil"]="\u00B8";
-A["sup1"]="\u00B9";
-A["ordm"]="\u00BA";
-A["raquo"]="\u00BB";
-A["frac14"]="\u00BC";
-A["frac12"]="\u00BD";
-A["frac34"]="\u00BE";
-A["iquest"]="\u00BF";
-A["Agrave"]="\u00C0";
-A["Aacute"]="\u00C1";
-A["Acirc"]="\u00C2";
-A["Atilde"]="\u00C3";
-A["Auml"]="\u00C4";
-A["Aring"]="\u00C5";
-A["AElig"]="\u00C6";
-A["Ccedil"]="\u00C7";
-A["Egrave"]="\u00C8";
-A["Eacute"]="\u00C9";
-A["Ecirc"]="\u00CA";
-A["Euml"]="\u00CB";
-A["Igrave"]="\u00CC";
-A["Iacute"]="\u00CD";
-A["Icirc"]="\u00CE";
-A["Iuml"]="\u00CF";
-A["ETH"]="\u00D0";
-A["Ntilde"]="\u00D1";
-A["Ograve"]="\u00D2";
-A["Oacute"]="\u00D3";
-A["Ocirc"]="\u00D4";
-A["Otilde"]="\u00D5";
-A["Ouml"]="\u00D6";
-A["times"]="\u00D7";
-A["Oslash"]="\u00D8";
-A["Ugrave"]="\u00D9";
-A["Uacute"]="\u00DA";
-A["Ucirc"]="\u00DB";
-A["Uuml"]="\u00DC";
-A["Yacute"]="\u00DD";
-A["THORN"]="\u00DE";
-A["szlig"]="\u00DF";
-A["agrave"]="\u00E0";
-A["aacute"]="\u00E1";
-A["acirc"]="\u00E2";
-A["atilde"]="\u00E3";
-A["auml"]="\u00E4";
-A["aring"]="\u00E5";
-A["aelig"]="\u00E6";
-A["ccedil"]="\u00E7";
-A["egrave"]="\u00E8";
-A["eacute"]="\u00E9";
-A["ecirc"]="\u00EA";
-A["euml"]="\u00EB";
-A["igrave"]="\u00EC";
-A["iacute"]="\u00ED";
-A["icirc"]="\u00EE";
-A["iuml"]="\u00EF";
-A["eth"]="\u00F0";
-A["ntilde"]="\u00F1";
-A["ograve"]="\u00F2";
-A["oacute"]="\u00F3";
-A["ocirc"]="\u00F4";
-A["otilde"]="\u00F5";
-A["ouml"]="\u00F6";
-A["divide"]="\u00F7";
-A["oslash"]="\u00F8";
-A["ugrave"]="\u00F9";
-A["uacute"]="\u00FA";
-A["ucirc"]="\u00FB";
-A["uuml"]="\u00FC";
-A["yacute"]="\u00FD";
-A["thorn"]="\u00FE";
-A["yuml"]="\u00FF";
-A["quot"]="\u0022";
-A["amp"]="\u0026";
-A["lt"]="\u003C";
-A["gt"]="\u003E";
-A["OElig"]="";
-A["oelig"]="\u0153";
-A["Scaron"]="\u0160";
-A["scaron"]="\u0161";
-A["Yuml"]="\u0178";
-A["circ"]="\u02C6";
-A["tilde"]="\u02DC";
-A["ensp"]="\u2002";
-A["emsp"]="\u2003";
-A["thinsp"]="\u2009";
-A["zwnj"]="\u200C";
-A["zwj"]="\u200D";
-A["lrm"]="\u200E";
-A["rlm"]="\u200F";
-A["ndash"]="\u2013";
-A["mdash"]="\u2014";
-A["lsquo"]="\u2018";
-A["rsquo"]="\u2019";
-A["sbquo"]="\u201A";
-A["ldquo"]="\u201C";
-A["rdquo"]="\u201D";
-A["bdquo"]="\u201E";
-A["dagger"]="\u2020";
-A["Dagger"]="\u2021";
-A["permil"]="\u2030";
-A["lsaquo"]="\u2039";
-A["rsaquo"]="\u203A";
-A["euro"]="\u20AC";
-A["fnof"]="\u0192";
-A["Alpha"]="\u0391";
-A["Beta"]="\u0392";
-A["Gamma"]="\u0393";
-A["Delta"]="\u0394";
-A["Epsilon"]="\u0395";
-A["Zeta"]="\u0396";
-A["Eta"]="\u0397";
-A["Theta"]="\u0398";
-A["Iota"]="\u0399";
-A["Kappa"]="\u039A";
-A["Lambda"]="\u039B";
-A["Mu"]="\u039C";
-A["Nu"]="\u039D";
-A["Xi"]="\u039E";
-A["Omicron"]="\u039F";
-A["Pi"]="\u03A0";
-A["Rho"]="\u03A1";
-A["Sigma"]="\u03A3";
-A["Tau"]="\u03A4";
-A["Upsilon"]="\u03A5";
-A["Phi"]="\u03A6";
-A["Chi"]="\u03A7";
-A["Psi"]="\u03A8";
-A["Omega"]="\u03A9";
-A["alpha"]="\u03B1";
-A["beta"]="\u03B2";
-A["gamma"]="\u03B3";
-A["delta"]="\u03B4";
-A["epsilon"]="\u03B5";
-A["zeta"]="\u03B6";
-A["eta"]="\u03B7";
-A["theta"]="\u03B8";
-A["iota"]="\u03B9";
-A["kappa"]="\u03BA";
-A["lambda"]="\u03BB";
-A["mu"]="\u03BC";
-A["nu"]="\u03BD";
-A["xi"]="\u03BE";
-A["omicron"]="\u03BF";
-A["pi"]="\u03C0";
-A["rho"]="\u03C1";
-A["sigmaf"]="\u03C2";
-A["sigma"]="\u03C3";
-A["tau"]="\u03C4";
-A["upsilon"]="\u03C5";
-A["phi"]="\u03C6";
-A["chi"]="\u03C7";
-A["psi"]="\u03C8";
-A["omega"]="\u03C9";
-A["thetasym"]="\u03D1";
-A["upsih"]="\u03D2";
-A["piv"]="\u03D6";
-A["bull"]="\u2022";
-A["hellip"]="\u2026";
-A["prime"]="\u2032";
-A["Prime"]="\u2033";
-A["oline"]="\u203E";
-A["frasl"]="\u2044";
-A["weierp"]="\u2118";
-A["image"]="\u2111";
-A["real"]="\u211C";
-A["trade"]="\u2122";
-A["alefsym"]="\u2135";
-A["larr"]="\u2190";
-A["uarr"]="\u2191";
-A["rarr"]="\u2192";
-A["darr"]="\u2193";
-A["harr"]="\u2194";
-A["crarr"]="\u21B5";
-A["lArr"]="\u21D0";
-A["uArr"]="\u21D1";
-A["rArr"]="\u21D2";
-A["dArr"]="\u21D3";
-A["hArr"]="\u21D4";
-A["forall"]="\u2200";
-A["part"]="\u2202";
-A["exist"]="\u2203";
-A["empty"]="\u2205";
-A["nabla"]="\u2207";
-A["isin"]="\u2208";
-A["notin"]="\u2209";
-A["ni"]="\u220B";
-A["prod"]="\u220F";
-A["sum"]="\u2211";
-A["minus"]="\u2212";
-A["lowast"]="\u2217";
-A["radic"]="\u221A";
-A["prop"]="\u221D";
-A["infin"]="\u221E";
-A["ang"]="\u2220";
-A["and"]="\u2227";
-A["or"]="\u2228";
-A["cap"]="\u2229";
-A["cup"]="\u222A";
-A["int"]="\u222B";
-A["there4"]="\u2234";
-A["sim"]="\u223C";
-A["cong"]="\u2245";
-A["asymp"]="\u2248";
-A["ne"]="\u2260";
-A["equiv"]="\u2261";
-A["le"]="\u2264";
-A["ge"]="\u2265";
-A["sub"]="\u2282";
-A["sup"]="\u2283";
-A["nsub"]="\u2284";
-A["sube"]="\u2286";
-A["supe"]="\u2287";
-A["oplus"]="\u2295";
-A["otimes"]="\u2297";
-A["perp"]="\u22A5";
-A["sdot"]="\u22C5";
-A["lceil"]="\u2308";
-A["rceil"]="\u2309";
-A["lfloor"]="\u230A";
-A["rfloor"]="\u230B";
-A["lang"]="\u2329";
-A["rang"]="\u232A";
-A["loz"]="\u25CA";
-A["spades"]="\u2660";
-A["clubs"]="\u2663";
-A["hearts"]="\u2665";
-A["diams"]="\u2666";
-})();
-SimileAjax.HTML.deEntify=function(C){var D=SimileAjax.HTML._e2uHash;
-var B=/&(\w+?);/;
-while(B.test(C)){var A=C.match(B);
-C=C.replace(B,D[A[1]]);
-}return C;
-};
-
-
-/* json.js */
-SimileAjax.JSON=new Object();
-(function(){var m={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};
-var s={array:function(x){var a=["["],b,f,i,l=x.length,v;
-for(i=0;
-i<l;
-i+=1){v=x[i];
-f=s[typeof v];
-if(f){v=f(v);
-if(typeof v=="string"){if(b){a[a.length]=",";
-}a[a.length]=v;
-b=true;
-}}}a[a.length]="]";
-return a.join("");
-},"boolean":function(x){return String(x);
-},"null":function(x){return"null";
-},number:function(x){return isFinite(x)?String(x):"null";
-},object:function(x){if(x){if(x instanceof Array){return s.array(x);
-}var a=["{"],b,f,i,v;
-for(i in x){v=x[i];
-f=s[typeof v];
-if(f){v=f(v);
-if(typeof v=="string"){if(b){a[a.length]=",";
-}a.push(s.string(i),":",v);
-b=true;
-}}}a[a.length]="}";
-return a.join("");
-}return"null";
-},string:function(x){if(/["\\\x00-\x1f]/.test(x)){x=x.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];
-if(c){return c;
-}c=b.charCodeAt();
-return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16);
-});
-}return'"'+x+'"';
-}};
-SimileAjax.JSON.toJSONString=function(o){if(o instanceof Object){return s.object(o);
-}else{if(o instanceof Array){return s.array(o);
-}else{return o.toString();
-}}};
-SimileAjax.JSON.parseJSON=function(){try{return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(this.replace(/"(\\.|[^"\\])*"/g,"")))&&eval("("+this+")");
-}catch(e){return false;
-}};
+
+SimileAjax.HTML.deEntify = function(s) {
+    var e2uHash = SimileAjax.HTML._e2uHash;
+
+    var re = /&(\w+?);/;
+    while (re.test(s)) {
+        var m = s.match(re);
+        s = s.replace(re, e2uHash[m[1]]);
+    }
+    return s;
+};/**
+ * A basic set (in the mathematical sense) data structure
+ *
+ * @constructor
+ * @param {Array or SimileAjax.Set} [a] an initial collection
+ */
+SimileAjax.Set = function(a) {
+    this._hash = {};
+    this._count = 0;
+
+    if (a instanceof Array) {
+        for (var i = 0; i < a.length; i++) {
+            this.add(a[i]);
+        }
+    } else if (a instanceof SimileAjax.Set) {
+        this.addSet(a);
+    }
+}
+
+/**
+ * Adds the given object to this set, assuming there it does not already exist
+ *
+ * @param {Object} o the object to add
+ * @return {Boolean} true if the object was added, false if not
+ */
+SimileAjax.Set.prototype.add = function(o) {
+    if (!(o in this._hash)) {
+        this._hash[o] = true;
+        this._count++;
+        return true;
+    }
+    return false;
+}
+
+/**
+ * Adds each element in the given set to this set
+ *
+ * @param {SimileAjax.Set} set the set of elements to add
+ */
+SimileAjax.Set.prototype.addSet = function(set) {
+    for (var o in set._hash) {
+        this.add(o);
+    }
+}
+
+/**
+ * Removes the given element from this set
+ *
+ * @param {Object} o the object to remove
+ * @return {Boolean} true if the object was successfully removed,
+ *   false otherwise
+ */
+SimileAjax.Set.prototype.remove = function(o) {
+    if (o in this._hash) {
+        delete this._hash[o];
+        this._count--;
+        return true;
+    }
+    return false;
+}
+
+/**
+ * Removes the elements in this set that correspond to the elements in the
+ * given set
+ *
+ * @param {SimileAjax.Set} set the set of elements to remove
+ */
+SimileAjax.Set.prototype.removeSet = function(set) {
+    for (var o in set._hash) {
+        this.remove(o);
+    }
+}
+
+/**
+ * Removes all elements in this set that are not present in the given set, i.e.
+ * modifies this set to the intersection of the two sets
+ *
+ * @param {SimileAjax.Set} set the set to intersect
+ */
+SimileAjax.Set.prototype.retainSet = function(set) {
+    for (var o in this._hash) {
+        if (!set.contains(o)) {
+            delete this._hash[o];
+            this._count--;
+        }
+    }
+}
+
+/**
+ * Returns whether or not the given element exists in this set
+ *
+ * @param {SimileAjax.Set} o the object to test for
+ * @return {Boolean} true if the object is present, false otherwise
+ */
+SimileAjax.Set.prototype.contains = function(o) {
+    return (o in this._hash);
+}
+
+/**
+ * Returns the number of elements in this set
+ *
+ * @return {Number} the number of elements in this set
+ */
+SimileAjax.Set.prototype.size = function() {
+    return this._count;
+}
+
+/**
+ * Returns the elements of this set as an array
+ *
+ * @return {Array} a new array containing the elements of this set
+ */
+SimileAjax.Set.prototype.toArray = function() {
+    var a = [];
+    for (var o in this._hash) {
+        a.push(o);
+    }
+    return a;
+}
+
+/**
+ * Iterates through the elements of this set, order unspecified, executing the
+ * given function on each element until the function returns true
+ *
+ * @param {Function} f a function of form f(element)
+ */
+SimileAjax.Set.prototype.visit = function(f) {
+    for (var o in this._hash) {
+        if (f(o) == true) {
+            break;
+        }
+    }
+}
+
+/**
+ * A sorted array data structure
+ *
+ * @constructor
+ */
+SimileAjax.SortedArray = function(compare, initialArray) {
+    this._a = (initialArray instanceof Array) ? initialArray : [];
+    this._compare = compare;
+};
+
+SimileAjax.SortedArray.prototype.add = function(elmt) {
+    var sa = this;
+    var index = this.find(function(elmt2) {
+        return sa._compare(elmt2, elmt);
+    });
+
+    if (index < this._a.length) {
+        this._a.splice(index, 0, elmt);
+    } else {
+        this._a.push(elmt);
+    }
+};
+
+SimileAjax.SortedArray.prototype.remove = function(elmt) {
+    var sa = this;
+    var index = this.find(function(elmt2) {
+        return sa._compare(elmt2, elmt);
+    });
+
+    while (index < this._a.length && this._compare(this._a[index], elmt) == 0) {
+        if (this._a[index] == elmt) {
+            this._a.splice(index, 1);
+            return true;
+        } else {
+            index++;
+        }
+    }
+    return false;
+};
+
+SimileAjax.SortedArray.prototype.removeAll = function() {
+    this._a = [];
+};
+
+SimileAjax.SortedArray.prototype.elementAt = function(index) {
+    return this._a[index];
+};
+
+SimileAjax.SortedArray.prototype.length = function() {
+    return this._a.length;
+};
+
+SimileAjax.SortedArray.prototype.find = function(compare) {
+    var a = 0;
+    var b = this._a.length;
+
+    while (a < b) {
+        var mid = Math.floor((a + b) / 2);
+        var c = compare(this._a[mid]);
+        if (mid == a) {
+            return c < 0 ? a+1 : a;
+        } else if (c < 0) {
+            a = mid;
+        } else {
+            b = mid;
+        }
+    }
+    return a;
+};
+
+SimileAjax.SortedArray.prototype.getFirst = function() {
+    return (this._a.length > 0) ? this._a[0] : null;
+};
+
+SimileAjax.SortedArray.prototype.getLast = function() {
+    return (this._a.length > 0) ? this._a[this._a.length - 1] : null;
+};
+
+/*==================================================
+ *  Event Index
+ *==================================================
+ */
+
+SimileAjax.EventIndex = function(unit) {
+    var eventIndex = this;
+
+    this._unit = (unit != null) ? unit : SimileAjax.NativeDateUnit;
+    this._events = new SimileAjax.SortedArray(
+        function(event1, event2) {
+            return eventIndex._unit.compare(event1.getStart(), event2.getStart());
+        }
+    );
+    this._idToEvent = {};
+    this._indexed = true;
+};
+
+SimileAjax.EventIndex.prototype.getUnit = function() {
+    return this._unit;
+};
+
+SimileAjax.EventIndex.prototype.getEvent = function(id) {
+    return this._idToEvent[id];
+};
+
+SimileAjax.EventIndex.prototype.add = function(evt) {
+    this._events.add(evt);
+    this._idToEvent[evt.getID()] = evt;
+    this._indexed = false;
+};
+
+SimileAjax.EventIndex.prototype.removeAll = function() {
+    this._events.removeAll();
+    this._idToEvent = {};
+    this._indexed = false;
+};
+
+SimileAjax.EventIndex.prototype.getCount = function() {
+    return this._events.length();
+};
+
+SimileAjax.EventIndex.prototype.getIterator = function(startDate, endDate) {
+    if (!this._indexed) {
+        this._index();
+    }
+    return new SimileAjax.EventIndex._Iterator(this._events, startDate, endDate, this._unit);
+};
+
+SimileAjax.EventIndex.prototype.getReverseIterator = function(startDate, endDate) {
+    if (!this._indexed) {
+        this._index();
+    }
+    return new SimileAjax.EventIndex._ReverseIterator(this._events, startDate, endDate, this._unit);
+};
+
+SimileAjax.EventIndex.prototype.getAllIterator = function() {
+    return new SimileAjax.EventIndex._AllIterator(this._events);
+};
+
+SimileAjax.EventIndex.prototype.getEarliestDate = function() {
+    var evt = this._events.getFirst();
+    return (evt == null) ? null : evt.getStart();
+};
+
+SimileAjax.EventIndex.prototype.getLatestDate = function() {
+    var evt = this._events.getLast();
+    if (evt == null) {
+        return null;
+    }
+
+    if (!this._indexed) {
+        this._index();
+    }
+
+    var index = evt._earliestOverlapIndex;
+    var date = this._events.elementAt(index).getEnd();
+    for (var i = index + 1; i < this._events.length(); i++) {
+        date = this._unit.later(date, this._events.elementAt(i).getEnd());
+    }
+
+    return date;
+};
+
+SimileAjax.EventIndex.prototype._index = function() {
+    /*
+     *  For each event, we want to find the earliest preceding
+     *  event that overlaps with it, if any.
+     */
+
+    var l = this._events.length();
+    for (var i = 0; i < l; i++) {
+        var evt = this._events.elementAt(i);
+        evt._earliestOverlapIndex = i;
+    }
+
+    var toIndex = 1;
+    for (var i = 0; i < l; i++) {
+        var evt = this._events.elementAt(i);
+        var end = evt.getEnd();
+
+        toIndex = Math.max(toIndex, i + 1);
+        while (toIndex < l) {
+            var evt2 = this._events.elementAt(toIndex);
+            var start2 = evt2.getStart();
+
+            if (this._unit.compare(start2, end) < 0) {
+                evt2._earliestOverlapIndex = i;
+                toIndex++;
+            } else {
+                break;
+            }
+        }
+    }
+    this._indexed = true;
+};
+
+SimileAjax.EventIndex._Iterator = function(events, startDate, endDate, unit) {
+    this._events = events;
+    this._startDate = startDate;
+    this._endDate = endDate;
+    this._unit = unit;
+
+    this._currentIndex = events.find(function(evt) {
+        return unit.compare(evt.getStart(), startDate);
+    });
+    if (this._currentIndex - 1 >= 0) {
+        this._currentIndex = this._events.elementAt(this._currentIndex - 1)._earliestOverlapIndex;
+    }
+    this._currentIndex--;
+
+    this._maxIndex = events.find(function(evt) {
+        return unit.compare(evt.getStart(), endDate);
+    });
+
+    this._hasNext = false;
+    this._next = null;
+    this._findNext();
+};
+
+SimileAjax.EventIndex._Iterator.prototype = {
+    hasNext: function() { return this._hasNext; },
+    next: function() {
+        if (this._hasNext) {
+            var next = this._next;
+            this._findNext();
+
+            return next;
+        } else {
+            return null;
+        }
+    },
+    _findNext: function() {
+        var unit = this._unit;
+        while ((++this._currentIndex) < this._maxIndex) {
+            var evt = this._events.elementAt(this._currentIndex);
+            if (unit.compare(evt.getStart(), this._endDate) < 0 &&
+                unit.compare(evt.getEnd(), this._startDate) > 0) {
+
+                this._next = evt;
+                this._hasNext = true;
+                return;
+            }
+        }
+        this._next = null;
+        this._hasNext = false;
+    }
+};
+
+SimileAjax.EventIndex._ReverseIterator = function(events, startDate, endDate, unit) {
+    this._events = events;
+    this._startDate = startDate;
+    this._endDate = endDate;
+    this._unit = unit;
+
+    this._minIndex = events.find(function(evt) {
+        return unit.compare(evt.getStart(), startDate);
+    });
+    if (this._minIndex - 1 >= 0) {
+        this._minIndex = this._events.elementAt(this._minIndex - 1)._earliestOverlapIndex;
+    }
+
+    this._maxIndex = events.find(function(evt) {
+        return unit.compare(evt.getStart(), endDate);
+    });
+
+    this._currentIndex = this._maxIndex;
+    this._hasNext = false;
+    this._next = null;
+    this._findNext();
+};
+
+SimileAjax.EventIndex._ReverseIterator.prototype = {
+    hasNext: function() { return this._hasNext; },
+    next: function() {
+        if (this._hasNext) {
+            var next = this._next;
+            this._findNext();
+
+            return next;
+        } else {
+            return null;
+        }
+    },
+    _findNext: function() {
+        var unit = this._unit;
+        while ((--this._currentIndex) >= this._minIndex) {
+            var evt = this._events.elementAt(this._currentIndex);
+            if (unit.compare(evt.getStart(), this._endDate) < 0 &&
+                unit.compare(evt.getEnd(), this._startDate) > 0) {
+
+                this._next = evt;
+                this._hasNext = true;
+                return;
+            }
+        }
+        this._next = null;
+        this._hasNext = false;
+    }
+};
+
+SimileAjax.EventIndex._AllIterator = function(events) {
+    this._events = events;
+    this._index = 0;
+};
+
+SimileAjax.EventIndex._AllIterator.prototype = {
+    hasNext: function() {
+        return this._index < this._events.length();
+    },
+    next: function() {
+        return this._index < this._events.length() ?
+            this._events.elementAt(this._index++) : null;
+    }
+};/*==================================================
+ *  Default Unit
+ *==================================================
+ */
+
+SimileAjax.NativeDateUnit = new Object();
+
+SimileAjax.NativeDateUnit.makeDefaultValue = function() {
+    return new Date();
+};
+
+SimileAjax.NativeDateUnit.cloneValue = function(v) {
+    return new Date(v.getTime());
+};
+
+SimileAjax.NativeDateUnit.getParser = function(format) {
+    if (typeof format == "string") {
+        format = format.toLowerCase();
+    }
+    return (format == "iso8601" || format == "iso 8601") ?
+        SimileAjax.DateTime.parseIso8601DateTime : 
+        SimileAjax.DateTime.parseGregorianDateTime;
+};
+
+SimileAjax.NativeDateUnit.parseFromObject = function(o) {
+    return SimileAjax.DateTime.parseGregorianDateTime(o);
+};
+
+SimileAjax.NativeDateUnit.toNumber = function(v) {
+    return v.getTime();
+};
+
+SimileAjax.NativeDateUnit.fromNumber = function(n) {
+    return new Date(n);
+};
+
+SimileAjax.NativeDateUnit.compare = function(v1, v2) {
+    var n1, n2;
+    if (typeof v1 == "object") {
+        n1 = v1.getTime();
+    } else {
+        n1 = Number(v1);
+    }
+    if (typeof v2 == "object") {
+        n2 = v2.getTime();
+    } else {
+        n2 = Number(v2);
+    }
+    
+    return n1 - n2;
+};
+
+SimileAjax.NativeDateUnit.earlier = function(v1, v2) {
+    return SimileAjax.NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+SimileAjax.NativeDateUnit.later = function(v1, v2) {
+    return SimileAjax.NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+SimileAjax.NativeDateUnit.change = function(v, n) {
+    return new Date(v.getTime() + n);
+};
+
+/*==================================================
+ *  General, miscellaneous SimileAjax stuff
+ *==================================================
+ */
+
+SimileAjax.ListenerQueue = function(wildcardHandlerName) {
+    this._listeners = [];
+    this._wildcardHandlerName = wildcardHandlerName;
+};
+
+SimileAjax.ListenerQueue.prototype.add = function(listener) {
+    this._listeners.push(listener);
+};
+
+SimileAjax.ListenerQueue.prototype.remove = function(listener) {
+    var listeners = this._listeners;
+    for (var i = 0; i < listeners.length; i++) {
+        if (listeners[i] == listener) {
+            listeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+SimileAjax.ListenerQueue.prototype.fire = function(handlerName, args) {
+    var listeners = [].concat(this._listeners);
+    for (var i = 0; i < listeners.length; i++) {
+        var listener = listeners[i];
+        if (handlerName in listener) {
+            try {
+                listener[handlerName].apply(listener, args);
+            } catch (e) {
+                SimileAjax.Debug.exception("Error firing event of name " + handlerName, e);
+            }
+        } else if (this._wildcardHandlerName != null &&
+            this._wildcardHandlerName in listener) {
+            try {
+                listener[this._wildcardHandlerName].apply(listener, [ handlerName ]);
+            } catch (e) {
+                SimileAjax.Debug.exception("Error firing event of name " + handlerName + " to wildcard handler", e);
+            }
+        }
+    }
+};
+
+/*======================================================================
+ *  History
+ *
+ *  This is a singleton that keeps track of undoable user actions and
+ *  performs undos and redos in response to the browser's Back and
+ *  Forward buttons.
+ *
+ *  Call addAction(action) to register an undoable user action. action
+ *  must have 4 fields:
+ *
+ *      perform: an argument-less function that carries out the action
+ *      undo:    an argument-less function that undos the action
+ *      label:   a short, user-friendly string describing the action
+ *      uiLayer: the UI layer on which the action takes place
+ *
+ *  By default, the history keeps track of upto 10 actions. You can
+ *  configure this behavior by setting
+ *      SimileAjax.History.maxHistoryLength
+ *  to a different number.
+ *
+ *  An iframe is inserted into the document's body element to track
+ *  onload events.
+ *======================================================================
+ */
+
+SimileAjax.History = {
+    maxHistoryLength:       10,
+    historyFile:            "__history__.html",
+    enabled:               true,
+
+    _initialized:           false,
+    _listeners:             new SimileAjax.ListenerQueue(),
+
+    _actions:               [],
+    _baseIndex:             0,
+    _currentIndex:          0,
+
+    _plainDocumentTitle:    document.title
+};
+
+SimileAjax.History.formatHistoryEntryTitle = function(actionLabel) {
+    return SimileAjax.History._plainDocumentTitle + " {" + actionLabel + "}";
+};
+
+SimileAjax.History.initialize = function() {
+    if (SimileAjax.History._initialized) {
+        return;
+    }
+
+    if (SimileAjax.History.enabled) {
+        var iframe = document.createElement("iframe");
+        iframe.id = "simile-ajax-history";
+        iframe.style.position = "absolute";
+        iframe.style.width = "10px";
+        iframe.style.height = "10px";
+        iframe.style.top = "0px";
+        iframe.style.left = "0px";
+        iframe.style.visibility = "hidden";
+        iframe.src = SimileAjax.History.historyFile + "?0";
+
+        document.body.appendChild(iframe);
+        SimileAjax.DOM.registerEvent(iframe, "load", SimileAjax.History._handleIFrameOnLoad);
+
+        SimileAjax.History._iframe = iframe;
+    }
+    SimileAjax.History._initialized = true;
+};
+
+SimileAjax.History.addListener = function(listener) {
+    SimileAjax.History.initialize();
+
+    SimileAjax.History._listeners.add(listener);
+};
+
+SimileAjax.History.removeListener = function(listener) {
+    SimileAjax.History.initialize();
+
+    SimileAjax.History._listeners.remove(listener);
+};
+
+SimileAjax.History.addAction = function(action) {
+    SimileAjax.History.initialize();
+
+    SimileAjax.History._listeners.fire("onBeforePerform", [ action ]);
+    window.setTimeout(function() {
+        try {
+            action.perform();
+            SimileAjax.History._listeners.fire("onAfterPerform", [ action ]);
+
+            if (SimileAjax.History.enabled) {
+                SimileAjax.History._actions = SimileAjax.History._actions.slice(
+                    0, SimileAjax.History._currentIndex - SimileAjax.History._baseIndex);
+
+                SimileAjax.History._actions.push(action);
+                SimileAjax.History._currentIndex++;
+
+                var diff = SimileAjax.History._actions.length - SimileAjax.History.maxHistoryLength;
+                if (diff > 0) {
+                    SimileAjax.History._actions = SimileAjax.History._actions.slice(diff);
+                    SimileAjax.History._baseIndex += diff;
+                }
+
+                try {
+                    SimileAjax.History._iframe.contentWindow.location.search =
+                        "?" + SimileAjax.History._currentIndex;
+                } catch (e) {
+                    /*
+                     *  We can't modify location.search most probably because it's a file:// url.
+                     *  We'll just going to modify the document's title.
+                     */
+                    var title = SimileAjax.History.formatHistoryEntryTitle(action.label);
+                    document.title = title;
+                }
+            }
+        } catch (e) {
+            SimileAjax.Debug.exception(e, "Error adding action {" + action.label + "} to history");
+        }
+    }, 0);
+};
+
+SimileAjax.History.addLengthyAction = function(perform, undo, label) {
+    SimileAjax.History.addAction({
+        perform:    perform,
+        undo:       undo,
+        label:      label,
+        uiLayer:    SimileAjax.WindowManager.getBaseLayer(),
+        lengthy:    true
+    });
+};
+
+SimileAjax.History._handleIFrameOnLoad = function() {
+    /*
+     *  This function is invoked when the user herself
+     *  navigates backward or forward. We need to adjust
+     *  the application's state accordingly.
+     */
+
+    try {
+        var q = SimileAjax.History._iframe.contentWindow.location.search;
+        var c = (q.length == 0) ? 0 : Math.max(0, parseInt(q.substr(1)));
+
+        var finishUp = function() {
+            var diff = c - SimileAjax.History._currentIndex;
+            SimileAjax.History._currentIndex += diff;
+            SimileAjax.History._baseIndex += diff;
+
+            SimileAjax.History._iframe.contentWindow.location.search = "?" + c;
+        };
+
+        if (c < SimileAjax.History._currentIndex) { // need to undo
+            SimileAjax.History._listeners.fire("onBeforeUndoSeveral", []);
+            window.setTimeout(function() {
+                while (SimileAjax.History._currentIndex > c &&
+                       SimileAjax.History._currentIndex > SimileAjax.History._baseIndex) {
+
+                    SimileAjax.History._currentIndex--;
+
+                    var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
+
+                    try {
+                        action.undo();
+                    } catch (e) {
+                        SimileAjax.Debug.exception(e, "History: Failed to undo action {" + action.label + "}");
+                    }
+                }
+
+                SimileAjax.History._listeners.fire("onAfterUndoSeveral", []);
+                finishUp();
+            }, 0);
+        } else if (c > SimileAjax.History._currentIndex) { // need to redo
+            SimileAjax.History._listeners.fire("onBeforeRedoSeveral", []);
+            window.setTimeout(function() {
+                while (SimileAjax.History._currentIndex < c &&
+                       SimileAjax.History._currentIndex - SimileAjax.History._baseIndex < SimileAjax.History._actions.length) {
+
+                    var action = SimileAjax.History._actions[SimileAjax.History._currentIndex - SimileAjax.History._baseIndex];
+
+                    try {
+                        action.perform();
+                    } catch (e) {
+                        SimileAjax.Debug.exception(e, "History: Failed to redo action {" + action.label + "}");
+                    }
+
+                    SimileAjax.History._currentIndex++;
+                }
+
+                SimileAjax.History._listeners.fire("onAfterRedoSeveral", []);
+                finishUp();
+            }, 0);
+        } else {
+            var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
+            var title = (index >= 0 && index < SimileAjax.History._actions.length) ?
+                SimileAjax.History.formatHistoryEntryTitle(SimileAjax.History._actions[index].label) :
+                SimileAjax.History._plainDocumentTitle;
+
+            SimileAjax.History._iframe.contentWindow.document.title = title;
+            document.title = title;
+        }
+    } catch (e) {
+        // silent
+    }
+};
+
+SimileAjax.History.getNextUndoAction = function() {
+    try {
+        var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex - 1;
+        return SimileAjax.History._actions[index];
+    } catch (e) {
+        return null;
+    }
+};
+
+SimileAjax.History.getNextRedoAction = function() {
+    try {
+        var index = SimileAjax.History._currentIndex - SimileAjax.History._baseIndex;
+        return SimileAjax.History._actions[index];
+    } catch (e) {
+        return null;
+    }
+};
+/**
+ * @fileOverview UI layers and window-wide dragging
+ * @name SimileAjax.WindowManager
+ */
+
+/**
+ *  This is a singleton that keeps track of UI layers (modal and
+ *  modeless) and enables/disables UI elements based on which layers
+ *  they belong to. It also provides window-wide dragging
+ *  implementation.
+ */
+SimileAjax.WindowManager = {
+    _initialized:       false,
+    _listeners:         [],
+
+    _draggedElement:                null,
+    _draggedElementCallback:        null,
+    _dropTargetHighlightElement:    null,
+    _lastCoords:                    null,
+    _ghostCoords:                   null,
+    _draggingMode:                  "",
+    _dragging:                      false,
+
+    _layers:            []
+};
+
+SimileAjax.WindowManager.initialize = function() {
+    if (SimileAjax.WindowManager._initialized) {
+        return;
+    }
+
+    SimileAjax.DOM.registerEvent(document.body, "mousedown", SimileAjax.WindowManager._onBodyMouseDown);
+    SimileAjax.DOM.registerEvent(document.body, "mousemove", SimileAjax.WindowManager._onBodyMouseMove);
+    SimileAjax.DOM.registerEvent(document.body, "mouseup",   SimileAjax.WindowManager._onBodyMouseUp);
+    SimileAjax.DOM.registerEvent(document, "keydown",       SimileAjax.WindowManager._onBodyKeyDown);
+    SimileAjax.DOM.registerEvent(document, "keyup",         SimileAjax.WindowManager._onBodyKeyUp);
+
+    SimileAjax.WindowManager._layers.push({index: 0});
+
+    SimileAjax.WindowManager._historyListener = {
+        onBeforeUndoSeveral:    function() {},
+        onAfterUndoSeveral:     function() {},
+        onBeforeUndo:           function() {},
+        onAfterUndo:            function() {},
+
+        onBeforeRedoSeveral:    function() {},
+        onAfterRedoSeveral:     function() {},
+        onBeforeRedo:           function() {},
+        onAfterRedo:            function() {}
+    };
+    SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
+
+    SimileAjax.WindowManager._initialized = true;
+};
+
+SimileAjax.WindowManager.getBaseLayer = function() {
+    SimileAjax.WindowManager.initialize();
+    return SimileAjax.WindowManager._layers[0];
+};
+
+SimileAjax.WindowManager.getHighestLayer = function() {
+    SimileAjax.WindowManager.initialize();
+    return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length - 1];
+};
+
+SimileAjax.WindowManager.registerEventWithObject = function(elmt, eventName, obj, handlerName, layer) {
+    SimileAjax.WindowManager.registerEvent(
+        elmt,
+        eventName,
+        function(elmt2, evt, target) {
+            return obj[handlerName].call(obj, elmt2, evt, target);
+        },
+        layer
+    );
+};
+
+SimileAjax.WindowManager.registerEvent = function(elmt, eventName, handler, layer) {
+    if (layer == null) {
+        layer = SimileAjax.WindowManager.getHighestLayer();
+    }
+
+    var handler2 = function(elmt, evt, target) {
+        if (SimileAjax.WindowManager._canProcessEventAtLayer(layer)) {
+            SimileAjax.WindowManager._popToLayer(layer.index);
+            try {
+                handler(elmt, evt, target);
+            } catch (e) {
+                SimileAjax.Debug.exception(e);
+            }
+        }
+        SimileAjax.DOM.cancelEvent(evt);
+        return false;
+    }
+
+    SimileAjax.DOM.registerEvent(elmt, eventName, handler2);
+};
+
+SimileAjax.WindowManager.pushLayer = function(f, ephemeral, elmt) {
+    var layer = { onPop: f, index: SimileAjax.WindowManager._layers.length, ephemeral: (ephemeral), elmt: elmt };
+    SimileAjax.WindowManager._layers.push(layer);
+
+    return layer;
+};
+
+SimileAjax.WindowManager.popLayer = function(layer) {
+    for (var i = 1; i < SimileAjax.WindowManager._layers.length; i++) {
+        if (SimileAjax.WindowManager._layers[i] == layer) {
+            SimileAjax.WindowManager._popToLayer(i - 1);
+            break;
+        }
+    }
+};
+
+SimileAjax.WindowManager.popAllLayers = function() {
+    SimileAjax.WindowManager._popToLayer(0);
+};
+
+SimileAjax.WindowManager.registerForDragging = function(elmt, callback, layer) {
+    SimileAjax.WindowManager.registerEvent(
+        elmt,
+        "mousedown",
+        function(elmt, evt, target) {
+            SimileAjax.WindowManager._handleMouseDown(elmt, evt, callback);
+        },
+        layer
+    );
+};
+
+SimileAjax.WindowManager._popToLayer = function(level) {
+    while (level+1 < SimileAjax.WindowManager._layers.length) {
+        try {
+            var layer = SimileAjax.WindowManager._layers.pop();
+            if (layer.onPop != null) {
+                layer.onPop();
+            }
+        } catch (e) {
+        }
+    }
+};
+
+SimileAjax.WindowManager._canProcessEventAtLayer = function(layer) {
+    if (layer.index == (SimileAjax.WindowManager._layers.length - 1)) {
+        return true;
+    }
+    for (var i = layer.index + 1; i < SimileAjax.WindowManager._layers.length; i++) {
+        if (!SimileAjax.WindowManager._layers[i].ephemeral) {
+            return false;
+        }
+    }
+    return true;
+};
+
+SimileAjax.WindowManager.cancelPopups = function(evt) {
+    var evtCoords = (evt) ? SimileAjax.DOM.getEventPageCoordinates(evt) : { x: -1, y: -1 };
+
+    var i = SimileAjax.WindowManager._layers.length - 1;
+    while (i > 0 && SimileAjax.WindowManager._layers[i].ephemeral) {
+        var layer = SimileAjax.WindowManager._layers[i];
+        if (layer.elmt != null) { // if event falls within main element of layer then don't cancel
+            var elmt = layer.elmt;
+            var elmtCoords = SimileAjax.DOM.getPageCoordinates(elmt);
+            if (evtCoords.x >= elmtCoords.left && evtCoords.x < (elmtCoords.left + elmt.offsetWidth) &&
+                evtCoords.y >= elmtCoords.top && evtCoords.y < (elmtCoords.top + elmt.offsetHeight)) {
+                break;
+            }
+        }
+        i--;
+    }
+    SimileAjax.WindowManager._popToLayer(i);
+};
+
+SimileAjax.WindowManager._onBodyMouseDown = function(elmt, evt, target) {
+    if (!("eventPhase" in evt) || evt.eventPhase == evt.BUBBLING_PHASE) {
+        SimileAjax.WindowManager.cancelPopups(evt);
+    }
+};
+
+SimileAjax.WindowManager._handleMouseDown = function(elmt, evt, callback) {
+    SimileAjax.WindowManager._draggedElement = elmt;
+    SimileAjax.WindowManager._draggedElementCallback = callback;
+    SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+    SimileAjax.DOM.cancelEvent(evt);
+    return false;
+};
+
+SimileAjax.WindowManager._onBodyKeyDown = function(elmt, evt, target) {
+    if (SimileAjax.WindowManager._dragging) {
+        if (evt.keyCode == 27) { // esc
+            SimileAjax.WindowManager._cancelDragging();
+        } else if ((evt.keyCode == 17 || evt.keyCode == 16) && SimileAjax.WindowManager._draggingMode != "copy") {
+            SimileAjax.WindowManager._draggingMode = "copy";
+
+            var img = SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix + "images/copy.png");
+            img.style.position = "absolute";
+            img.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
+            img.style.top = (SimileAjax.WindowManager._ghostCoords.top) + "px";
+            document.body.appendChild(img);
+
+            SimileAjax.WindowManager._draggingModeIndicatorElmt = img;
+        }
+    }
+};
+
+SimileAjax.WindowManager._onBodyKeyUp = function(elmt, evt, target) {
+    if (SimileAjax.WindowManager._dragging) {
+        if (evt.keyCode == 17 || evt.keyCode == 16) {
+            SimileAjax.WindowManager._draggingMode = "";
+            if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+                document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+                SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
+            }
+        }
+    }
+};
+
+SimileAjax.WindowManager._onBodyMouseMove = function(elmt, evt, target) {
+    if (SimileAjax.WindowManager._draggedElement != null) {
+        var callback = SimileAjax.WindowManager._draggedElementCallback;
+
+        var lastCoords = SimileAjax.WindowManager._lastCoords;
+        var diffX = evt.clientX - lastCoords.x;
+        var diffY = evt.clientY - lastCoords.y;
+
+        if (!SimileAjax.WindowManager._dragging) {
+            if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) {
+                try {
+                    if ("onDragStart" in callback) {
+                        callback.onDragStart();
+                    }
+
+                    if ("ghost" in callback && callback.ghost) {
+                        var draggedElmt = SimileAjax.WindowManager._draggedElement;
+
+                        SimileAjax.WindowManager._ghostCoords = SimileAjax.DOM.getPageCoordinates(draggedElmt);
+                        SimileAjax.WindowManager._ghostCoords.left += diffX;
+                        SimileAjax.WindowManager._ghostCoords.top += diffY;
+
+                        var ghostElmt = draggedElmt.cloneNode(true);
+                        ghostElmt.style.position = "absolute";
+                        ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
+                        ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+                        ghostElmt.style.zIndex = 1000;
+                        SimileAjax.Graphics.setOpacity(ghostElmt, 50);
+
+                        document.body.appendChild(ghostElmt);
+                        callback._ghostElmt = ghostElmt;
+                    }
+
+                    SimileAjax.WindowManager._dragging = true;
+                    SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+                    document.body.focus();
+                } catch (e) {
+                    SimileAjax.Debug.exception("WindowManager: Error handling mouse down", e);
+                    SimileAjax.WindowManager._cancelDragging();
+                }
+            }
+        } else {
+            try {
+                SimileAjax.WindowManager._lastCoords = { x: evt.clientX, y: evt.clientY };
+
+                if ("onDragBy" in callback) {
+                    callback.onDragBy(diffX, diffY);
+                }
+
+                if ("_ghostElmt" in callback) {
+                    var ghostElmt = callback._ghostElmt;
+
+                    SimileAjax.WindowManager._ghostCoords.left += diffX;
+                    SimileAjax.WindowManager._ghostCoords.top += diffY;
+
+                    ghostElmt.style.left = SimileAjax.WindowManager._ghostCoords.left + "px";
+                    ghostElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+                    if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+                        var indicatorElmt = SimileAjax.WindowManager._draggingModeIndicatorElmt;
+
+                        indicatorElmt.style.left = (SimileAjax.WindowManager._ghostCoords.left - 16) + "px";
+                        indicatorElmt.style.top = SimileAjax.WindowManager._ghostCoords.top + "px";
+                    }
+
+                    if ("droppable" in callback && callback.droppable) {
+                        var coords = SimileAjax.DOM.getEventPageCoordinates(evt);
+                        var target = SimileAjax.DOM.hittest(
+                            coords.x, coords.y,
+                            [   SimileAjax.WindowManager._ghostElmt,
+                                SimileAjax.WindowManager._dropTargetHighlightElement
+                            ]
+                        );
+                        target = SimileAjax.WindowManager._findDropTarget(target);
+
+                        if (target != SimileAjax.WindowManager._potentialDropTarget) {
+                            if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
+                                document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+
+                                SimileAjax.WindowManager._dropTargetHighlightElement = null;
+                                SimileAjax.WindowManager._potentialDropTarget = null;
+                            }
+
+                            var droppable = false;
+                            if (target != null) {
+                                if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
+                                    (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
+
+                                    droppable = true;
+                                }
+                            }
+
+                            if (droppable) {
+                                var border = 4;
+                                var targetCoords = SimileAjax.DOM.getPageCoordinates(target);
+                                var highlight = document.createElement("div");
+                                highlight.style.border = border + "px solid yellow";
+                                highlight.style.backgroundColor = "yellow";
+                                highlight.style.position = "absolute";
+                                highlight.style.left = targetCoords.left + "px";
+                                highlight.style.top = targetCoords.top + "px";
+                                highlight.style.width = (target.offsetWidth - border * 2) + "px";
+                                highlight.style.height = (target.offsetHeight - border * 2) + "px";
+                                SimileAjax.Graphics.setOpacity(highlight, 30);
+                                document.body.appendChild(highlight);
+
+                                SimileAjax.WindowManager._potentialDropTarget = target;
+                                SimileAjax.WindowManager._dropTargetHighlightElement = highlight;
+                            }
+                        }
+                    }
+                }
+            } catch (e) {
+                SimileAjax.Debug.exception("WindowManager: Error handling mouse move", e);
+                SimileAjax.WindowManager._cancelDragging();
+            }
+        }
+
+        SimileAjax.DOM.cancelEvent(evt);
+        return false;
+    }
+};
+
+SimileAjax.WindowManager._onBodyMouseUp = function(elmt, evt, target) {
+    if (SimileAjax.WindowManager._draggedElement != null) {
+        try {
+            if (SimileAjax.WindowManager._dragging) {
+                var callback = SimileAjax.WindowManager._draggedElementCallback;
+                if ("onDragEnd" in callback) {
+                    callback.onDragEnd();
+                }
+                if ("droppable" in callback && callback.droppable) {
+                    var dropped = false;
+
+                    var target = SimileAjax.WindowManager._potentialDropTarget;
+                    if (target != null) {
+                        if ((!("canDropOn" in callback) || callback.canDropOn(target)) &&
+                            (!("canDrop" in target) || target.canDrop(SimileAjax.WindowManager._draggedElement))) {
+
+                            if ("onDropOn" in callback) {
+                                callback.onDropOn(target);
+                            }
+                            target.ondrop(SimileAjax.WindowManager._draggedElement, SimileAjax.WindowManager._draggingMode);
+
+                            dropped = true;
+                        }
+                    }
+
+                    if (!dropped) {
+                        // TODO: do holywood explosion here
+                    }
+                }
+            }
+        } finally {
+            SimileAjax.WindowManager._cancelDragging();
+        }
+
+        SimileAjax.DOM.cancelEvent(evt);
+        return false;
+    }
+};
+
+SimileAjax.WindowManager._cancelDragging = function() {
+    var callback = SimileAjax.WindowManager._draggedElementCallback;
+    if ("_ghostElmt" in callback) {
+        var ghostElmt = callback._ghostElmt;
+        document.body.removeChild(ghostElmt);
+
+        delete callback._ghostElmt;
+    }
+    if (SimileAjax.WindowManager._dropTargetHighlightElement != null) {
+        document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
+        SimileAjax.WindowManager._dropTargetHighlightElement = null;
+    }
+    if (SimileAjax.WindowManager._draggingModeIndicatorElmt != null) {
+        document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
+        SimileAjax.WindowManager._draggingModeIndicatorElmt = null;
+    }
+
+    SimileAjax.WindowManager._draggedElement = null;
+    SimileAjax.WindowManager._draggedElementCallback = null;
+    SimileAjax.WindowManager._potentialDropTarget = null;
+    SimileAjax.WindowManager._dropTargetHighlightElement = null;
+    SimileAjax.WindowManager._lastCoords = null;
+    SimileAjax.WindowManager._ghostCoords = null;
+    SimileAjax.WindowManager._draggingMode = "";
+    SimileAjax.WindowManager._dragging = false;
+};
+
+SimileAjax.WindowManager._findDropTarget = function(elmt) {
+    while (elmt != null) {
+        if ("ondrop" in elmt && (typeof elmt.ondrop) == "function") {
+            break;
+        }
+        elmt = elmt.parentNode;
+    }
+    return elmt;
+};
+/*==================================================
+ *  Timeline API
+ *
+ *  This file will load all the Javascript files
+ *  necessary to make the standard timeline work.
+ *  It also detects the default locale.
+ *
+ *  To run from the MIT copy of Timeline:
+ *  Include this file in your HTML file as follows:
+ *
+ *    <script src="http://api.simile-widgets.org/timeline/2.3.1/timeline-api.js"
+ *     type="text/javascript"></script>
+ *
+ *
+ * To host the Timeline files on your own server:
+ *   1) Install the Timeline and Simile-Ajax files onto your webserver using
+ *      timeline_libraries.zip or timeline_source.zip
+ *
+ *   2) Set global js variables used to send parameters to this script:
+ *        var Timeline_ajax_url -- url for simile-ajax-api.js
+ *        var Timeline_urlPrefix -- url for the *directory* that contains timeline-api.js
+ *            Include trailing slash
+ *        var Timeline_parameters='bundle=true'; // you must set bundle to true if you are using
+ *                                               // timeline_libraries.zip since only the
+ *                                               // bundled libraries are included
+ *
+ * eg your html page would include
+ *
+ *   <script>
+ *     var Timeline_ajax_url="http://YOUR_SERVER/javascripts/timeline/timeline_ajax/simile-ajax-api.js";
+ *     var Timeline_urlPrefix='http://YOUR_SERVER/javascripts/timeline/timeline_js/';
+ *     var Timeline_parameters='bundle=true';
+ *   </script>
+ *   <script src="http://YOUR_SERVER/javascripts/timeline/timeline_js/timeline-api.js"
+ *     type="text/javascript">
+ *   </script>
+ *
+ * SCRIPT PARAMETERS
+ * This script auto-magically figures out locale and has defaults for other parameters
+ * To set parameters explicity, set js global variable Timeline_parameters or include as
+ * parameters on the url using GET style. Eg the two next lines pass the same parameters:
+ *     Timeline_parameters='bundle=true';                    // pass parameter via js variable
+ *     <script src="http://....timeline-api.js?bundle=true"  // pass parameter via url
+ *
+ * Parameters
+ *   timeline-use-local-resources --
+ *   bundle -- true: use the single js bundle file; false: load individual files (for debugging)
+ *   locales --
+ *   defaultLocale --
+ *   forceLocale -- force locale to be a particular value--used for debugging. Normally locale is determined
+ *                  by browser's and server's locale settings.
+ *
+ * DEBUGGING
+ * If you have a problem with Timeline, the first step is to use the unbundled Javascript files. To do so:
+ * To use the unbundled Timeline and Ajax libraries
+ * Change
+ *   <script src="http://api.simile-widgets.org/timeline/2.3.1/api/timeline-api.js?bundle=true" type="text/javascript"></script>
+ * To
+ *   <script>var Timeline_ajax_url = "http://api.simile-widgets.org/ajax/2.2.1/simile-ajax-api.js?bundle=false"</script>
+ *   <script src="http://api.simile-widgets.org/timeline/2.3.1/api/timeline-api.js?bundle=false" type="text/javascript"></script>
+ *
+ * Note that the Ajax version is usually NOT the same as the Timeline version.
+ * See variable simile_ajax_ver below for the current version
+ *
+ *==================================================
+ */
+
+(function() {
+
+    var simile_ajax_ver = "2.2.1"; // ===========>>>  current Simile-Ajax version
+
+    var useLocalResources = false;
+    if (document.location.search.length > 0) {
+        var params = document.location.search.substr(1).split("&");
+        for (var i = 0; i < params.length; i++) {
+            if (params[i] == "timeline-use-local-resources") {
+                useLocalResources = true;
+            }
+        }
+    };
+
+    var loadMe = function() {
+        if ("Timeline" in window) {
+            return;
+        }
+
+        window.Timeline = new Object();
+        window.Timeline.DateTime = window.SimileAjax.DateTime; // for backward compatibility
+
+        var bundle = false;
+        var javascriptFiles = [
+            "timeline.js",
+            "band.js",
+            "themes.js",
+            "ethers.js",
+            "ether-painters.js",
+            "event-utils.js",
+            "labellers.js",
+            "sources.js",
+            "original-painter.js",
+            "detailed-painter.js",
+            "overview-painter.js",
+            "compact-painter.js",
+            "decorators.js",
+            "units.js"
+        ];
+        var cssFiles = [
+            "timeline.css",
+            "ethers.css",
+            "events.css"
+        ];
+
+        var localizedJavascriptFiles = [
+            "timeline.js",
+            "labellers.js"
+        ];
+        var localizedCssFiles = [
+        ];
+
+        // ISO-639 language codes, ISO-3166 country codes (2 characters)
+        var supportedLocales = [
+            "cs",       // Czech
+            "de",       // German
+            "en",       // English
+            "es",       // Spanish
+            "fr",       // French
+            "it",       // Italian
+            "nl",       // Dutch (The Netherlands)
+            "ru",       // Russian
+            "se",       // Swedish
+            "tr",       // Turkish
+            "vi",       // Vietnamese
+            "zh"        // Chinese
+        ];
+
+        try {
+            var desiredLocales = [ "en" ],
+                defaultServerLocale = "en",
+                forceLocale = null;
+
+            var parseURLParameters = function(parameters) {
+                var params = parameters.split("&");
+                for (var p = 0; p < params.length; p++) {
+                    var pair = params[p].split("=");
+                    if (pair[0] == "locales") {
+                        desiredLocales = desiredLocales.concat(pair[1].split(","));
+                    } else if (pair[0] == "defaultLocale") {
+                        defaultServerLocale = pair[1];
+                    } else if (pair[0] == "forceLocale") {
+                        forceLocale = pair[1];
+                        desiredLocales = desiredLocales.concat(pair[1].split(","));
+                    } else if (pair[0] == "bundle") {
+                        bundle = pair[1] != "false";
+                    }
+                }
+            };
+
+            (function() {
+                if (typeof Timeline_urlPrefix == "string") {
+                    Timeline.urlPrefix = Timeline_urlPrefix;
+                    if (typeof Timeline_parameters == "string") {
+                        parseURLParameters(Timeline_parameters);
+                    }
+                } else {
+                    var heads = document.documentElement.getElementsByTagName("head");
+                    for (var h = 0; h < heads.length; h++) {
+                        var scripts = heads[h].getElementsByTagName("script");
+                        for (var s = 0; s < scripts.length; s++) {
+                            var url = scripts[s].src;
+                            var i = url.indexOf("timeline-api.js");
+                            if (i >= 0) {
+                                Timeline.urlPrefix = url.substr(0, i);
+                                var q = url.indexOf("?");
+                                if (q > 0) {
+                                    parseURLParameters(url.substr(q + 1));
+                                }
+                                return;
+                            }
+                        }
+                    }
+                    throw new Error("Failed to derive URL prefix for Timeline API code files");
+                }
+            })();
+
+            var includeJavascriptFiles = function(urlPrefix, filenames) {
+                SimileAjax.includeJavascriptFiles(document, urlPrefix, filenames);
+            }
+            var includeCssFiles = function(urlPrefix, filenames) {
+                SimileAjax.includeCssFiles(document, urlPrefix, filenames);
+            }
+
+            /*
+             *  Include non-localized files
+             */
+            if (bundle) {
+                includeJavascriptFiles(Timeline.urlPrefix, [ "timeline-bundle.js" ]);
+                includeCssFiles(Timeline.urlPrefix, [ "timeline-bundle.css" ]);
+            } else {
+                includeJavascriptFiles(Timeline.urlPrefix + "scripts/", javascriptFiles);
+                includeCssFiles(Timeline.urlPrefix + "styles/", cssFiles);
+            }
+
+            /*
+             *  Include localized files
+             */
+            var loadLocale = [];
+            loadLocale[defaultServerLocale] = true;
+
+            var tryExactLocale = function(locale) {
+                for (var l = 0; l < supportedLocales.length; l++) {
+                    if (locale == supportedLocales[l]) {
+                        loadLocale[locale] = true;
+                        return true;
+                    }
+                }
+                return false;
+            }
+            var tryLocale = function(locale) {
+                if (tryExactLocale(locale)) {
+                    return locale;
+                }
+
+                var dash = locale.indexOf("-");
+                if (dash > 0 && tryExactLocale(locale.substr(0, dash))) {
+                    return locale.substr(0, dash);
+                }
+
+                return null;
+            }
+
+            for (var l = 0; l < desiredLocales.length; l++) {
+                tryLocale(desiredLocales[l]);
+            }
+
+            var defaultClientLocale = defaultServerLocale;
+            var defaultClientLocales = ("language" in navigator ? navigator.language : navigator.browserLanguage).split(";");
+            for (var l = 0; l < defaultClientLocales.length; l++) {
+                var locale = tryLocale(defaultClientLocales[l]);
+                if (locale != null) {
+                    defaultClientLocale = locale;
+                    break;
+                }
+            }
+
+            for (var l = 0; l < supportedLocales.length; l++) {
+                var locale = supportedLocales[l];
+                if (loadLocale[locale]) {
+                    includeJavascriptFiles(Timeline.urlPrefix + "scripts/l10n/" + locale + "/", localizedJavascriptFiles);
+                    includeCssFiles(Timeline.urlPrefix + "styles/l10n/" + locale + "/", localizedCssFiles);
+                }
+            }
+
+            if (forceLocale == null) {
+              Timeline.serverLocale = defaultServerLocale;
+              Timeline.clientLocale = defaultClientLocale;
+            } else {
+              Timeline.serverLocale = forceLocale;
+              Timeline.clientLocale = forceLocale;
+            }
+        } catch (e) {
+            alert(e);
+        }
+    };
+
+    /*
+     *  Load SimileAjax if it's not already loaded
+     */
+    if (typeof SimileAjax == "undefined") {
+        window.SimileAjax_onLoad = loadMe;
+
+        var url = useLocalResources ?
+            "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
+            "http://api.simile-widgets.org/ajax/" + simile_ajax_ver + "/simile-ajax-api.js";
+        if (typeof Timeline_ajax_url == "string") {
+           url = Timeline_ajax_url;
+        }
+        var createScriptElement = function() {
+            var script = document.createElement("script");
+            script.type = "text/javascript";
+            script.language = "JavaScript";
+            script.src = url;
+            document.getElementsByTagName("head")[0].appendChild(script);
+        }
+        if (document.body == null) {
+            try {
+                document.write("<script src='" + url + "' type='text/javascript'></script>");
+            } catch (e) {
+                createScriptElement();
+            }
+        } else {
+            createScriptElement();
+        }
+    } else {
+        loadMe();
+    }
 })();
-
-
-/* string.js */
-String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"");
-};
-String.prototype.startsWith=function(A){return this.length>=A.length&&this.substr(0,A.length)==A;
-};
-String.prototype.endsWith=function(A){return this.length>=A.length&&this.substr(this.length-A.length)==A;
-};
-String.substitute=function(B,D){var A="";
-var F=0;
-while(F<B.length-1){var C=B.indexOf("%",F);
-if(C<0||C==B.length-1){break;
-}else{if(C>F&&B.charAt(C-1)=="\\"){A+=B.substring(F,C-1)+"%";
-F=C+1;
-}else{var E=parseInt(B.charAt(C+1));
-if(isNaN(E)||E>=D.length){A+=B.substring(F,C+2);
-}else{A+=B.substring(F,C)+D[E].toString();
-}F=C+2;
-}}}if(F<B.length){A+=B.substring(F);
-}return A;
-};
-
-
-/* units.js */
-SimileAjax.NativeDateUnit=new Object();
-SimileAjax.NativeDateUnit.makeDefaultValue=function(){return new Date();
-};
-SimileAjax.NativeDateUnit.cloneValue=function(A){return new Date(A.getTime());
-};
-SimileAjax.NativeDateUnit.getParser=function(A){if(typeof A=="string"){A=A.toLowerCase();
-}return(A=="iso8601"||A=="iso 8601")?SimileAjax.DateTime.parseIso8601DateTime:SimileAjax.DateTime.parseGregorianDateTime;
-};
-SimileAjax.NativeDateUnit.parseFromObject=function(A){return SimileAjax.DateTime.parseGregorianDateTime(A);
-};
-SimileAjax.NativeDateUnit.toNumber=function(A){return A.getTime();
-};
-SimileAjax.NativeDateUnit.fromNumber=function(A){return new Date(A);
-};
-SimileAjax.NativeDateUnit.compare=function(D,C){var B,A;
-if(typeof D=="object"){B=D.getTime();
-}else{B=Number(D);
-}if(typeof C=="object"){A=C.getTime();
-}else{A=Number(C);
-}return B-A;
-};
-SimileAjax.NativeDateUnit.earlier=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)<0?B:A;
-};
-SimileAjax.NativeDateUnit.later=function(B,A){return SimileAjax.NativeDateUnit.compare(B,A)>0?B:A;
-};
-SimileAjax.NativeDateUnit.change=function(A,B){return new Date(A.getTime()+B);
-};
-
-
-/* window-manager.js */
-SimileAjax.WindowManager={_initialized:false,_listeners:[],_draggedElement:null,_draggedElementCallback:null,_dropTargetHighlightElement:null,_lastCoords:null,_ghostCoords:null,_draggingMode:"",_dragging:false,_layers:[]};
-SimileAjax.WindowManager.initialize=function(){if(SimileAjax.WindowManager._initialized){return ;
-}SimileAjax.DOM.registerEvent(document.body,"mousedown",SimileAjax.WindowManager._onBodyMouseDown);
-SimileAjax.DOM.registerEvent(document.body,"mousemove",SimileAjax.WindowManager._onBodyMouseMove);
-SimileAjax.DOM.registerEvent(document.body,"mouseup",SimileAjax.WindowManager._onBodyMouseUp);
-SimileAjax.DOM.registerEvent(document,"keydown",SimileAjax.WindowManager._onBodyKeyDown);
-SimileAjax.DOM.registerEvent(document,"keyup",SimileAjax.WindowManager._onBodyKeyUp);
-SimileAjax.WindowManager._layers.push({index:0});
-SimileAjax.WindowManager._historyListener={onBeforeUndoSeveral:function(){},onAfterUndoSeveral:function(){},onBeforeUndo:function(){},onAfterUndo:function(){},onBeforeRedoSeveral:function(){},onAfterRedoSeveral:function(){},onBeforeRedo:function(){},onAfterRedo:function(){}};
-SimileAjax.History.addListener(SimileAjax.WindowManager._historyListener);
-SimileAjax.WindowManager._initialized=true;
-};
-SimileAjax.WindowManager.getBaseLayer=function(){SimileAjax.WindowManager.initialize();
-return SimileAjax.WindowManager._layers[0];
-};
-SimileAjax.WindowManager.getHighestLayer=function(){SimileAjax.WindowManager.initialize();
-return SimileAjax.WindowManager._layers[SimileAjax.WindowManager._layers.length-1];
-};
-SimileAjax.WindowManager.registerEventWithObject=function(D,A,E,B,C){SimileAjax.WindowManager.registerEvent(D,A,function(G,F,H){return E[B].call(E,G,F,H);
-},C);
-};
-SimileAjax.WindowManager.registerEvent=function(D,B,E,C){if(C==null){C=SimileAjax.WindowManager.getHighestLayer();
-}var A=function(G,F,I){if(SimileAjax.WindowManager._canProcessEventAtLayer(C)){SimileAjax.WindowManager._popToLayer(C.index);
-try{E(G,F,I);
-}catch(H){SimileAjax.Debug.exception(H);
-}}SimileAjax.DOM.cancelEvent(F);
-return false;
-};
-SimileAjax.DOM.registerEvent(D,B,A);
-};
-SimileAjax.WindowManager.pushLayer=function(C,D,B){var A={onPop:C,index:SimileAjax.WindowManager._layers.length,ephemeral:(D),elmt:B};
-SimileAjax.WindowManager._layers.push(A);
-return A;
-};
-SimileAjax.WindowManager.popLayer=function(B){for(var A=1;
-A<SimileAjax.WindowManager._layers.length;
-A++){if(SimileAjax.WindowManager._layers[A]==B){SimileAjax.WindowManager._popToLayer(A-1);
-break;
-}}};
-SimileAjax.WindowManager.popAllLayers=function(){SimileAjax.WindowManager._popToLayer(0);
-};
-SimileAjax.WindowManager.registerForDragging=function(B,C,A){SimileAjax.WindowManager.registerEvent(B,"mousedown",function(E,D,F){SimileAjax.WindowManager._handleMouseDown(E,D,C);
-},A);
-};
-SimileAjax.WindowManager._popToLayer=function(C){while(C+1<SimileAjax.WindowManager._layers.length){try{var A=SimileAjax.WindowManager._layers.pop();
-if(A.onPop!=null){A.onPop();
-}}catch(B){}}};
-SimileAjax.WindowManager._canProcessEventAtLayer=function(B){if(B.index==(SimileAjax.WindowManager._layers.length-1)){return true;
-}for(var A=B.index+1;
-A<SimileAjax.WindowManager._layers.length;
-A++){if(!SimileAjax.WindowManager._layers[A].ephemeral){return false;
-}}return true;
-};
-SimileAjax.WindowManager.cancelPopups=function(A){var F=(A)?SimileAjax.DOM.getEventPageCoordinates(A):{x:-1,y:-1};
-var E=SimileAjax.WindowManager._layers.length-1;
-while(E>0&&SimileAjax.WindowManager._layers[E].ephemeral){var D=SimileAjax.WindowManager._layers[E];
-if(D.elmt!=null){var C=D.elmt;
-var B=SimileAjax.DOM.getPageCoordinates(C);
-if(F.x>=B.left&&F.x<(B.left+C.offsetWidth)&&F.y>=B.top&&F.y<(B.top+C.offsetHeight)){break;
-}}E--;
-}SimileAjax.WindowManager._popToLayer(E);
-};
-SimileAjax.WindowManager._onBodyMouseDown=function(B,A,C){if(!("eventPhase" in A)||A.eventPhase==A.BUBBLING_PHASE){SimileAjax.WindowManager.cancelPopups(A);
-}};
-SimileAjax.WindowManager._handleMouseDown=function(B,A,C){SimileAjax.WindowManager._draggedElement=B;
-SimileAjax.WindowManager._draggedElementCallback=C;
-SimileAjax.WindowManager._lastCoords={x:A.clientX,y:A.clientY};
-SimileAjax.DOM.cancelEvent(A);
-return false;
-};
-SimileAjax.WindowManager._onBodyKeyDown=function(C,A,D){if(SimileAjax.WindowManager._dragging){if(A.keyCode==27){SimileAjax.WindowManager._cancelDragging();
-}else{if((A.keyCode==17||A.keyCode==16)&&SimileAjax.WindowManager._draggingMode!="copy"){SimileAjax.WindowManager._draggingMode="copy";
-var B=SimileAjax.Graphics.createTranslucentImage(SimileAjax.urlPrefix+"data/timeline/copy.png");
-B.style.position="absolute";
-B.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
-B.style.top=(SimileAjax.WindowManager._ghostCoords.top)+"px";
-document.body.appendChild(B);
-SimileAjax.WindowManager._draggingModeIndicatorElmt=B;
-}}}};
-SimileAjax.WindowManager._onBodyKeyUp=function(B,A,C){if(SimileAjax.WindowManager._dragging){if(A.keyCode==17||A.keyCode==16){SimileAjax.WindowManager._draggingMode="";
-if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
-SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
-}}}};
-SimileAjax.WindowManager._onBodyMouseMove=function(A,N,H){if(SimileAjax.WindowManager._draggedElement!=null){var P=SimileAjax.WindowManager._draggedElementCallback;
-var E=SimileAjax.WindowManager._lastCoords;
-var M=N.clientX-E.x;
-var J=N.clientY-E.y;
-if(!SimileAjax.WindowManager._dragging){if(Math.abs(M)>5||Math.abs(J)>5){try{if("onDragStart" in P){P.onDragStart();
-}if("ghost" in P&&P.ghost){var K=SimileAjax.WindowManager._draggedElement;
-SimileAjax.WindowManager._ghostCoords=SimileAjax.DOM.getPageCoordinates(K);
-SimileAjax.WindowManager._ghostCoords.left+=M;
-SimileAjax.WindowManager._ghostCoords.top+=J;
-var O=K.cloneNode(true);
-O.style.position="absolute";
-O.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
-O.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
-O.style.zIndex=1000;
-SimileAjax.Graphics.setOpacity(O,50);
-document.body.appendChild(O);
-P._ghostElmt=O;
-}SimileAjax.WindowManager._dragging=true;
-SimileAjax.WindowManager._lastCoords={x:N.clientX,y:N.clientY};
-document.body.focus();
-}catch(G){SimileAjax.Debug.exception("WindowManager: Error handling mouse down",G);
-SimileAjax.WindowManager._cancelDragging();
-}}}else{try{SimileAjax.WindowManager._lastCoords={x:N.clientX,y:N.clientY};
-if("onDragBy" in P){P.onDragBy(M,J);
-}if("_ghostElmt" in P){var O=P._ghostElmt;
-SimileAjax.WindowManager._ghostCoords.left+=M;
-SimileAjax.WindowManager._ghostCoords.top+=J;
-O.style.left=SimileAjax.WindowManager._ghostCoords.left+"px";
-O.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
-if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){var I=SimileAjax.WindowManager._draggingModeIndicatorElmt;
-I.style.left=(SimileAjax.WindowManager._ghostCoords.left-16)+"px";
-I.style.top=SimileAjax.WindowManager._ghostCoords.top+"px";
-}if("droppable" in P&&P.droppable){var L=SimileAjax.DOM.getEventPageCoordinates(N);
-var H=SimileAjax.DOM.hittest(L.x,L.y,[SimileAjax.WindowManager._ghostElmt,SimileAjax.WindowManager._dropTargetHighlightElement]);
-H=SimileAjax.WindowManager._findDropTarget(H);
-if(H!=SimileAjax.WindowManager._potentialDropTarget){if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
-SimileAjax.WindowManager._dropTargetHighlightElement=null;
-SimileAjax.WindowManager._potentialDropTarget=null;
-}var F=false;
-if(H!=null){if((!("canDropOn" in P)||P.canDropOn(H))&&(!("canDrop" in H)||H.canDrop(SimileAjax.WindowManager._draggedElement))){F=true;
-}}if(F){var C=4;
-var D=SimileAjax.DOM.getPageCoordinates(H);
-var B=document.createElement("div");
-B.style.border=C+"px solid yellow";
-B.style.backgroundColor="yellow";
-B.style.position="absolute";
-B.style.left=D.left+"px";
-B.style.top=D.top+"px";
-B.style.width=(H.offsetWidth-C*2)+"px";
-B.style.height=(H.offsetHeight-C*2)+"px";
-SimileAjax.Graphics.setOpacity(B,30);
-document.body.appendChild(B);
-SimileAjax.WindowManager._potentialDropTarget=H;
-SimileAjax.WindowManager._dropTargetHighlightElement=B;
-}}}}}catch(G){SimileAjax.Debug.exception("WindowManager: Error handling mouse move",G);
-SimileAjax.WindowManager._cancelDragging();
-}}SimileAjax.DOM.cancelEvent(N);
-return false;
-}};
-SimileAjax.WindowManager._onBodyMouseUp=function(B,A,C){if(SimileAjax.WindowManager._draggedElement!=null){try{if(SimileAjax.WindowManager._dragging){var E=SimileAjax.WindowManager._draggedElementCallback;
-if("onDragEnd" in E){E.onDragEnd();
-}if("droppable" in E&&E.droppable){var D=false;
-var C=SimileAjax.WindowManager._potentialDropTarget;
-if(C!=null){if((!("canDropOn" in E)||E.canDropOn(C))&&(!("canDrop" in C)||C.canDrop(SimileAjax.WindowManager._draggedElement))){if("onDropOn" in E){E.onDropOn(C);
-}C.ondrop(SimileAjax.WindowManager._draggedElement,SimileAjax.WindowManager._draggingMode);
-D=true;
-}}if(!D){}}}}finally{SimileAjax.WindowManager._cancelDragging();
-}SimileAjax.DOM.cancelEvent(A);
-return false;
-}};
-SimileAjax.WindowManager._cancelDragging=function(){var B=SimileAjax.WindowManager._draggedElementCallback;
-if("_ghostElmt" in B){var A=B._ghostElmt;
-document.body.removeChild(A);
-delete B._ghostElmt;
-}if(SimileAjax.WindowManager._dropTargetHighlightElement!=null){document.body.removeChild(SimileAjax.WindowManager._dropTargetHighlightElement);
-SimileAjax.WindowManager._dropTargetHighlightElement=null;
-}if(SimileAjax.WindowManager._draggingModeIndicatorElmt!=null){document.body.removeChild(SimileAjax.WindowManager._draggingModeIndicatorElmt);
-SimileAjax.WindowManager._draggingModeIndicatorElmt=null;
-}SimileAjax.WindowManager._draggedElement=null;
-SimileAjax.WindowManager._draggedElementCallback=null;
-SimileAjax.WindowManager._potentialDropTarget=null;
-SimileAjax.WindowManager._dropTargetHighlightElement=null;
-SimileAjax.WindowManager._lastCoords=null;
-SimileAjax.WindowManager._ghostCoords=null;
-SimileAjax.WindowManager._draggingMode="";
-SimileAjax.WindowManager._dragging=false;
-};
-SimileAjax.WindowManager._findDropTarget=function(A){while(A!=null){if("ondrop" in A&&(typeof A.ondrop)=="function"){break;
-}A=A.parentNode;
-}return A;
-};
-
-
-/* xmlhttp.js */
-SimileAjax.XmlHttp=new Object();
-SimileAjax.XmlHttp._onReadyStateChange=function(A,D,B){switch(A.readyState){case 4:try{if(A.status==0||A.status==200){if(B){B(A);
-}}else{if(D){D(A.statusText,A.status,A);
-}}}catch(C){SimileAjax.Debug.exception("XmlHttp: Error handling onReadyStateChange",C);
-}break;
-}};
-SimileAjax.XmlHttp._createRequest=function(){if(SimileAjax.Platform.browser.isIE){var A=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"];
-for(var B=0;
-B<A.length;
-B++){try{var C=A[B];
-var D=function(){return new ActiveXObject(C);
-};
-var F=D();
-SimileAjax.XmlHttp._createRequest=D;
-return F;
-}catch(E){}}}try{var D=function(){return new XMLHttpRequest();
-};
-var F=D();
-SimileAjax.XmlHttp._createRequest=D;
-return F;
-}catch(E){throw new Error("Failed to create an XMLHttpRequest object");
-}};
-SimileAjax.XmlHttp.get=function(A,D,C){var B=SimileAjax.XmlHttp._createRequest();
-B.open("GET",A,true);
-B.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(B,D,C);
-};
-B.send(null);
-};
-SimileAjax.XmlHttp.post=function(B,A,E,D){var C=SimileAjax.XmlHttp._createRequest();
-C.open("POST",B,true);
-C.onreadystatechange=function(){SimileAjax.XmlHttp._onReadyStateChange(C,E,D);
-};
-C.send(A);
-};
-SimileAjax.XmlHttp._forceXML=function(A){try{A.overrideMimeType("text/xml");
-}catch(B){A.setrequestheader("Content-Type","text/xml");
-}};
-
-/******** end of simile-ajax-bundle.js ********/
-
-/******** start of simile-timeline-bundle.js ********/
-
-/* band.js */
-Timeline._Band=function(B,C,A){if(B!==undefined){this.initialize(B,C,A);
-}};
-Timeline._Band.prototype.initialize=function(F,G,B){if(F.autoWidth&&typeof G.width=="string"){G.width=G.width.indexOf("%")>-1?0:parseInt(G.width);
-}this._timeline=F;
-this._bandInfo=G;
-this._index=B;
-this._locale=("locale" in G)?G.locale:Timeline.getDefaultLocale();
-this._timeZone=("timeZone" in G)?G.timeZone:0;
-this._labeller=("labeller" in G)?G.labeller:(("createLabeller" in F.getUnit())?F.getUnit().createLabeller(this._locale,this._timeZone):new Timeline.GregorianDateLabeller(this._locale,this._timeZone));
-this._theme=G.theme;
-this._zoomIndex=("zoomIndex" in G)?G.zoomIndex:0;
-this._zoomSteps=("zoomSteps" in G)?G.zoomSteps:null;
-this._dragging=false;
-this._changing=false;
-this._originalScrollSpeed=5;
-this._scrollSpeed=this._originalScrollSpeed;
-this._onScrollListeners=[];
-var A=this;
-this._syncWithBand=null;
-this._syncWithBandHandler=function(H){A._onHighlightBandScroll();
-};
-this._selectorListener=function(H){A._onHighlightBandScroll();
-};
-var D=this._timeline.getDocument().createElement("div");
-D.className="timeline-band-input";
-this._timeline.addDiv(D);
-this._keyboardInput=document.createElement("input");
-this._keyboardInput.type="text";
-D.appendChild(this._keyboardInput);
-SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keydown",this,"_onKeyDown");
-SimileAjax.DOM.registerEventWithObject(this._keyboardInput,"keyup",this,"_onKeyUp");
-this._div=this._timeline.getDocument().createElement("div");
-this._div.id="timeline-band-"+B;
-this._div.className="timeline-band timeline-band-"+B;
-this._timeline.addDiv(this._div);
-SimileAjax.DOM.registerEventWithObject(this._div,"mousedown",this,"_onMouseDown");
-SimileAjax.DOM.registerEventWithObject(this._div,"mousemove",this,"_onMouseMove");
-SimileAjax.DOM.registerEventWithObject(this._div,"mouseup",this,"_onMouseUp");
-SimileAjax.DOM.registerEventWithObject(this._div,"mouseout",this,"_onMouseOut");
-SimileAjax.DOM.registerEventWithObject(this._div,"dblclick",this,"_onDblClick");
-var E=this._theme!=null?this._theme.mouseWheel:"scroll";
-if(E==="zoom"||E==="scroll"||this._zoomSteps){if(SimileAjax.Platform.browser.isFirefox){SimileAjax.DOM.registerEventWithObject(this._div,"DOMMouseScroll",this,"_onMouseScroll");
-}else{SimileAjax.DOM.registerEventWithObject(this._div,"mousewheel",this,"_onMouseScroll");
-}}this._innerDiv=this._timeline.getDocument().createElement("div");
-this._innerDiv.className="timeline-band-inner";
-this._div.appendChild(this._innerDiv);
-this._ether=G.ether;
-G.ether.initialize(this,F);
-this._etherPainter=G.etherPainter;
-G.etherPainter.initialize(this,F);
-this._eventSource=G.eventSource;
-if(this._eventSource){this._eventListener={onAddMany:function(){A._onAddMany();
-},onClear:function(){A._onClear();
-}};
-this._eventSource.addListener(this._eventListener);
-}this._eventPainter=G.eventPainter;
-this._eventTracksNeeded=0;
-this._eventTrackIncrement=0;
-G.eventPainter.initialize(this,F);
-this._decorators=("decorators" in G)?G.decorators:[];
-for(var C=0;
-C<this._decorators.length;
-C++){this._decorators[C].initialize(this,F);
-}};
-Timeline._Band.SCROLL_MULTIPLES=5;
-Timeline._Band.prototype.dispose=function(){this.closeBubble();
-if(this._eventSource){this._eventSource.removeListener(this._eventListener);
-this._eventListener=null;
-this._eventSource=null;
-}this._timeline=null;
-this._bandInfo=null;
-this._labeller=null;
-this._ether=null;
-this._etherPainter=null;
-this._eventPainter=null;
-this._decorators=null;
-this._onScrollListeners=null;
-this._syncWithBandHandler=null;
-this._selectorListener=null;
-this._div=null;
-this._innerDiv=null;
-this._keyboardInput=null;
-};
-Timeline._Band.prototype.addOnScrollListener=function(A){this._onScrollListeners.push(A);
-};
-Timeline._Band.prototype.removeOnScrollListener=function(B){for(var A=0;
-A<this._onScrollListeners.length;
-A++){if(this._onScrollListeners[A]==B){this._onScrollListeners.splice(A,1);
-break;
-}}};
-Timeline._Band.prototype.setSyncWithBand=function(B,A){if(this._syncWithBand){this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
-}this._syncWithBand=B;
-this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
-this._highlight=A;
-this._positionHighlight();
-};
-Timeline._Band.prototype.getLocale=function(){return this._locale;
-};
-Timeline._Band.prototype.getTimeZone=function(){return this._timeZone;
-};
-Timeline._Band.prototype.getLabeller=function(){return this._labeller;
-};
-Timeline._Band.prototype.getIndex=function(){return this._index;
-};
-Timeline._Band.prototype.getEther=function(){return this._ether;
-};
-Timeline._Band.prototype.getEtherPainter=function(){return this._etherPainter;
-};
-Timeline._Band.prototype.getEventSource=function(){return this._eventSource;
-};
-Timeline._Band.prototype.getEventPainter=function(){return this._eventPainter;
-};
-Timeline._Band.prototype.getTimeline=function(){return this._timeline;
-};
-Timeline._Band.prototype.updateEventTrackInfo=function(B,A){this._eventTrackIncrement=A;
-if(B>this._eventTracksNeeded){this._eventTracksNeeded=B;
-}};
-Timeline._Band.prototype.checkAutoWidth=function(){if(!this._timeline.autoWidth){return ;
-}var A=this._eventPainter.getType()=="overview";
-var C=A?this._theme.event.overviewTrack.autoWidthMargin:this._theme.event.track.autoWidthMargin;
-var B=Math.ceil((this._eventTracksNeeded+C)*this._eventTrackIncrement);
-B+=A?this._theme.event.overviewTrack.offset:this._theme.event.track.offset;
-var D=this._bandInfo;
-if(B!=D.width){D.width=B;
-}};
-Timeline._Band.prototype.layout=function(){this.paint();
-};
-Timeline._Band.prototype.paint=function(){this._etherPainter.paint();
-this._paintDecorators();
-this._paintEvents();
-};
-Timeline._Band.prototype.softLayout=function(){this.softPaint();
-};
-Timeline._Band.prototype.softPaint=function(){this._etherPainter.softPaint();
-this._softPaintDecorators();
-this._softPaintEvents();
-};
-Timeline._Band.prototype.setBandShiftAndWidth=function(A,D){var C=this._keyboardInput.parentNode;
-var B=A+Math.floor(D/2);
-if(this._timeline.isHorizontal()){this._div.style.top=A+"px";
-this._div.style.height=D+"px";
-C.style.top=B+"px";
-C.style.left="-1em";
-}else{this._div.style.left=A+"px";
-this._div.style.width=D+"px";
-C.style.left=B+"px";
-C.style.top="-1em";
-}};
-Timeline._Band.prototype.getViewWidth=function(){if(this._timeline.isHorizontal()){return this._div.offsetHeight;
-}else{return this._div.offsetWidth;
-}};
-Timeline._Band.prototype.setViewLength=function(A){this._viewLength=A;
-this._recenterDiv();
-this._onChanging();
-};
-Timeline._Band.prototype.getViewLength=function(){return this._viewLength;
-};
-Timeline._Band.prototype.getTotalViewLength=function(){return Timeline._Band.SCROLL_MULTIPLES*this._viewLength;
-};
-Timeline._Band.prototype.getViewOffset=function(){return this._viewOffset;
-};
-Timeline._Band.prototype.getMinDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset);
-};
-Timeline._Band.prototype.getMaxDate=function(){return this._ether.pixelOffsetToDate(this._viewOffset+Timeline._Band.SCROLL_MULTIPLES*this._viewLength);
-};
-Timeline._Band.prototype.getMinVisibleDate=function(){return this._ether.pixelOffsetToDate(0);
-};
-Timeline._Band.prototype.getMaxVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength);
-};
-Timeline._Band.prototype.getCenterVisibleDate=function(){return this._ether.pixelOffsetToDate(this._viewLength/2);
-};
-Timeline._Band.prototype.setMinVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(-this._ether.dateToPixelOffset(A)));
-}};
-Timeline._Band.prototype.setMaxVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(this._viewLength-this._ether.dateToPixelOffset(A)));
-}};
-Timeline._Band.prototype.setCenterVisibleDate=function(A){if(!this._changing){this._moveEther(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(A)));
-}};
-Timeline._Band.prototype.dateToPixelOffset=function(A){return this._ether.dateToPixelOffset(A)-this._viewOffset;
-};
-Timeline._Band.prototype.pixelOffsetToDate=function(A){return this._ether.pixelOffsetToDate(A+this._viewOffset);
-};
-Timeline._Band.prototype.createLayerDiv=function(D,B){var C=this._timeline.getDocument().createElement("div");
-C.className="timeline-band-layer"+(typeof B=="string"?(" "+B):"");
-C.style.zIndex=D;
-this._innerDiv.appendChild(C);
-var A=this._timeline.getDocument().createElement("div");
-A.className="timeline-band-layer-inner";
-if(SimileAjax.Platform.browser.isIE){A.style.cursor="move";
-}else{A.style.cursor="-moz-grab";
-}C.appendChild(A);
-return A;
-};
-Timeline._Band.prototype.removeLayerDiv=function(A){this._innerDiv.removeChild(A.parentNode);
-};
-Timeline._Band.prototype.scrollToCenter=function(B,C){var A=this._ether.dateToPixelOffset(B);
-if(A<-this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(A+this._viewLength));
-}else{if(A>3*this._viewLength/2){this.setCenterVisibleDate(this.pixelOffsetToDate(A-this._viewLength));
-}}this._autoScroll(Math.round(this._viewLength/2-this._ether.dateToPixelOffset(B)),C);
-};
-Timeline._Band.prototype.showBubbleForEvent=function(C){var A=this.getEventSource().getEvent(C);
-if(A){var B=this;
-this.scrollToCenter(A.getStart(),function(){B._eventPainter.showBubble(A);
-});
-}};
-Timeline._Band.prototype.zoom=function(F,A,E,C){if(!this._zoomSteps){return ;
-}A+=this._viewOffset;
-var D=this._ether.pixelOffsetToDate(A);
-var B=this._ether.zoom(F);
-this._etherPainter.zoom(B);
-this._moveEther(Math.round(-this._ether.dateToPixelOffset(D)));
-this._moveEther(A);
-};
-Timeline._Band.prototype._onMouseDown=function(B,A,C){this.closeBubble();
-this._dragging=true;
-this._dragX=A.clientX;
-this._dragY=A.clientY;
-};
-Timeline._Band.prototype._onMouseMove=function(D,A,E){if(this._dragging){var C=A.clientX-this._dragX;
-var B=A.clientY-this._dragY;
-this._dragX=A.clientX;
-this._dragY=A.clientY;
-this._moveEther(this._timeline.isHorizontal()?C:B);
-this._positionHighlight();
-}};
-Timeline._Band.prototype._onMouseUp=function(B,A,C){this._dragging=false;
-this._keyboardInput.focus();
-};
-Timeline._Band.prototype._onMouseOut=function(B,A,D){var C=SimileAjax.DOM.getEventRelativeCoordinates(A,B);
-C.x+=this._viewOffset;
-if(C.x<0||C.x>B.offsetWidth||C.y<0||C.y>B.offsetHeight){this._dragging=false;
-}};
-Timeline._Band.prototype._onMouseScroll=function(G,I,E){var A=new Date();
-A=A.getTime();
-if(!this._lastScrollTime||((A-this._lastScrollTime)>50)){this._lastScrollTime=A;
-var H=0;
-if(I.wheelDelta){H=I.wheelDelta/120;
-}else{if(I.detail){H=-I.detail/3;
-}}var F=this._theme.mouseWheel;
-if(this._zoomSteps||F==="zoom"){var D=SimileAjax.DOM.getEventRelativeCoordinates(I,G);
-if(H!=0){var C;
-if(H>0){C=true;
-}if(H<0){C=false;
-}this._timeline.zoom(C,D.x,D.y,G);
-}}else{if(F==="scroll"){var B=50*(H<0?-1:1);
-this._moveEther(B);
-}}}if(I.stopPropagation){I.stopPropagation();
-}I.cancelBubble=true;
-if(I.preventDefault){I.preventDefault();
-}I.returnValue=false;
-};
-Timeline._Band.prototype._onDblClick=function(B,A,D){var C=SimileAjax.DOM.getEventRelativeCoordinates(A,B);
-var E=C.x-(this._viewLength/2-this._viewOffset);
-this._autoScroll(-E);
-};
-Timeline._Band.prototype._onKeyDown=function(B,A,C){if(!this._dragging){switch(A.keyCode){case 27:break;
-case 37:case 38:this._scrollSpeed=Math.min(50,Math.abs(this._scrollSpeed*1.05));
-this._moveEther(this._scrollSpeed);
-break;
-case 39:case 40:this._scrollSpeed=-Math.min(50,Math.abs(this._scrollSpeed*1.05));
-this._moveEther(this._scrollSpeed);
-break;
-default:return true;
-}this.closeBubble();
-SimileAjax.DOM.cancelEvent(A);
-return false;
-}return true;
-};
-Timeline._Band.prototype._onKeyUp=function(B,A,C){if(!this._dragging){this._scrollSpeed=this._originalScrollSpeed;
-switch(A.keyCode){case 35:this.setCenterVisibleDate(this._eventSource.getLatestDate());
-break;
-case 36:this.setCenterVisibleDate(this._eventSource.getEarliestDate());
-break;
-case 33:this._autoScroll(this._timeline.getPixelLength());
-break;
-case 34:this._autoScroll(-this._timeline.getPixelLength());
-break;
-default:return true;
-}this.closeBubble();
-SimileAjax.DOM.cancelEvent(A);
-return false;
-}return true;
-};
-Timeline._Band.prototype._autoScroll=function(D,C){var A=this;
-var B=SimileAjax.Graphics.createAnimation(function(E,F){A._moveEther(F);
-},0,D,1000,C);
-B.run();
-};
-Timeline._Band.prototype._moveEther=function(A){this.closeBubble();
-this._viewOffset+=A;
-this._ether.shiftPixels(-A);
-if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
-}else{this._div.style.top=this._viewOffset+"px";
-}if(this._viewOffset>-this._viewLength*0.5||this._viewOffset<-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1.5)){this._recenterDiv();
-}else{this.softLayout();
-}this._onChanging();
-};
-Timeline._Band.prototype._onChanging=function(){this._changing=true;
-this._fireOnScroll();
-this._setSyncWithBandDate();
-this._changing=false;
-};
-Timeline._Band.prototype._fireOnScroll=function(){for(var A=0;
-A<this._onScrollListeners.length;
-A++){this._onScrollListeners[A](this);
-}};
-Timeline._Band.prototype._setSyncWithBandDate=function(){if(this._syncWithBand){var A=this._ether.pixelOffsetToDate(this.getViewLength()/2);
-this._syncWithBand.setCenterVisibleDate(A);
-}};
-Timeline._Band.prototype._onHighlightBandScroll=function(){if(this._syncWithBand){var A=this._syncWithBand.getCenterVisibleDate();
-var B=this._ether.dateToPixelOffset(A);
-this._moveEther(Math.round(this._viewLength/2-B));
-if(this._highlight){this._etherPainter.setHighlight(this._syncWithBand.getMinVisibleDate(),this._syncWithBand.getMaxVisibleDate());
-}}};
-Timeline._Band.prototype._onAddMany=function(){this._paintEvents();
-};
-Timeline._Band.prototype._onClear=function(){this._paintEvents();
-};
-Timeline._Band.prototype._positionHighlight=function(){if(this._syncWithBand){var A=this._syncWithBand.getMinVisibleDate();
-var B=this._syncWithBand.getMaxVisibleDate();
-if(this._highlight){this._etherPainter.setHighlight(A,B);
-}}};
-Timeline._Band.prototype._recenterDiv=function(){this._viewOffset=-this._viewLength*(Timeline._Band.SCROLL_MULTIPLES-1)/2;
-if(this._timeline.isHorizontal()){this._div.style.left=this._viewOffset+"px";
-this._div.style.width=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
-}else{this._div.style.top=this._viewOffset+"px";
-this._div.style.height=(Timeline._Band.SCROLL_MULTIPLES*this._viewLength)+"px";
-}this.layout();
-};
-Timeline._Band.prototype._paintEvents=function(){this._eventPainter.paint();
-};
-Timeline._Band.prototype._softPaintEvents=function(){this._eventPainter.softPaint();
-};
-Timeline._Band.prototype._paintDecorators=function(){for(var A=0;
-A<this._decorators.length;
-A++){this._decorators[A].paint();
-}};
-Timeline._Band.prototype._softPaintDecorators=function(){for(var A=0;
-A<this._decorators.length;
-A++){this._decorators[A].softPaint();
-}};
-Timeline._Band.prototype.closeBubble=function(){SimileAjax.WindowManager.cancelPopups();
-};
-
-
-/* decorators.js */
-Timeline.SpanHighlightDecorator=function(A){this._unit=("unit" in A)?A.unit:SimileAjax.NativeDateUnit;
-this._startDate=(typeof A.startDate=="string")?this._unit.parseFromObject(A.startDate):A.startDate;
-this._endDate=(typeof A.endDate=="string")?this._unit.parseFromObject(A.endDate):A.endDate;
-this._startLabel=A.startLabel;
-this._endLabel=A.endLabel;
-this._color=A.color;
-this._cssClass=("cssClass" in A)?A.cssClass:null;
-this._opacity=("opacity" in A)?A.opacity:100;
-};
-Timeline.SpanHighlightDecorator.prototype.initialize=function(B,A){this._band=B;
-this._timeline=A;
-this._layerDiv=null;
-};
-Timeline.SpanHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
-}this._layerDiv=this._band.createLayerDiv(10);
-this._layerDiv.setAttribute("name","span-highlight-decorator");
-this._layerDiv.style.display="none";
-var F=this._band.getMinDate();
-var C=this._band.getMaxDate();
-if(this._unit.compare(this._startDate,C)<0&&this._unit.compare(this._endDate,F)>0){F=this._unit.later(F,this._startDate);
-C=this._unit.earlier(C,this._endDate);
-var D=this._band.dateToPixelOffset(F);
-var K=this._band.dateToPixelOffset(C);
-var I=this._timeline.getDocument();
-var H=function(){var L=I.createElement("table");
-L.insertRow(0).insertCell(0);
-return L;
-};
-var B=I.createElement("div");
-B.className="timeline-highlight-decorator";
-if(this._cssClass){B.className+=" "+this._cssClass;
-}if(this._opacity<100){SimileAjax.Graphics.setOpacity(B,this._opacity);
-}this._layerDiv.appendChild(B);
-var J=H();
-J.className="timeline-highlight-label timeline-highlight-label-start";
-var G=J.rows[0].cells[0];
-G.innerHTML=this._startLabel;
-if(this._cssClass){G.className="label_"+this._cssClass;
-}this._layerDiv.appendChild(J);
-var A=H();
-A.className="timeline-highlight-label timeline-highlight-label-end";
-var E=A.rows[0].cells[0];
-E.innerHTML=this._endLabel;
-if(this._cssClass){E.className="label_"+this._cssClass;
-}this._layerDiv.appendChild(A);
-if(this._timeline.isHorizontal()){B.style.left=D+"px";
-B.style.width=(K-D)+"px";
-J.style.right=(this._band.getTotalViewLength()-D)+"px";
-J.style.width=(this._startLabel.length)+"em";
-A.style.left=K+"px";
-A.style.width=(this._endLabel.length)+"em";
-}else{B.style.top=D+"px";
-B.style.height=(K-D)+"px";
-J.style.bottom=D+"px";
-J.style.height="1.5px";
-A.style.top=K+"px";
-A.style.height="1.5px";
-}}this._layerDiv.style.display="block";
-};
-Timeline.SpanHighlightDecorator.prototype.softPaint=function(){};
-Timeline.PointHighlightDecorator=function(A){this._unit=("unit" in A)?A.unit:SimileAjax.NativeDateUnit;
-this._date=(typeof A.date=="string")?this._unit.parseFromObject(A.date):A.date;
-this._width=("width" in A)?A.width:10;
-this._color=A.color;
-this._cssClass=("cssClass" in A)?A.cssClass:"";
-this._opacity=("opacity" in A)?A.opacity:100;
-};
-Timeline.PointHighlightDecorator.prototype.initialize=function(B,A){this._band=B;
-this._timeline=A;
-this._layerDiv=null;
-};
-Timeline.PointHighlightDecorator.prototype.paint=function(){if(this._layerDiv!=null){this._band.removeLayerDiv(this._layerDiv);
-}this._layerDiv=this._band.createLayerDiv(10);
-this._layerDiv.setAttribute("name","span-highlight-decorator");
-this._layerDiv.style.display="none";
-var C=this._band.getMinDate();
-var E=this._band.getMaxDate();
-if(this._unit.compare(this._date,E)<0&&this._unit.compare(this._date,C)>0){var B=this._band.dateToPixelOffset(this._date);
-var A=B-Math.round(this._width/2);
-var D=this._timeline.getDocument();
-var F=D.createElement("div");
-F.className="timeline-highlight-point-decorator";
-F.className+=" "+this._cssClass;
-if(this._opacity<100){SimileAjax.Graphics.setOpacity(F,this._opacity);
-}this._layerDiv.appendChild(F);
-if(this._timeline.isHorizontal()){F.style.left=A+"px";
-}else{F.style.top=A+"px";
-}}this._layerDiv.style.display="block";
-};
-Timeline.PointHighlightDecorator.prototype.softPaint=function(){};
-
-
-/* detailed-painter.js */
-Timeline.DetailedEventPainter=function(A){this._params=A;
-this._onSelectListeners=[];
-this._filterMatcher=null;
-this._highlightMatcher=null;
-this._frc=null;
-this._eventIdToElmt={};
-};
-Timeline.DetailedEventPainter.prototype.initialize=function(B,A){this._band=B;
-this._timeline=A;
-this._backLayer=null;
-this._eventLayer=null;
-this._lineLayer=null;
-this._highlightLayer=null;
-this._eventIdToElmt=null;
-};
-Timeline.DetailedEventPainter.prototype.getType=function(){return"detailed";
-};
-Timeline.DetailedEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
-};
-Timeline.DetailedEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
-A<this._onSelectListeners.length;
-A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
-break;
-}}};
-Timeline.DetailedEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
-};
-Timeline.DetailedEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
-};
-Timeline.DetailedEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
-};
-Timeline.DetailedEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
-};
-Timeline.DetailedEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
-if(B==null){return ;
-}this._eventIdToElmt={};
-this._prepareForPainting();
-var I=this._params.theme.event;
-var G=Math.max(I.track.height,this._frc.getLineHeight());
-var F={trackOffset:Math.round(this._band.getViewWidth()/2-G/2),trackHeight:G,trackGap:I.track.gap,trackIncrement:G+I.track.gap,icon:I.instant.icon,iconWidth:I.instant.iconWidth,iconHeight:I.instant.iconHeight,labelWidth:I.label.width};
-var C=this._band.getMinDate();
-var A=this._band.getMaxDate();
-var J=(this._filterMatcher!=null)?this._filterMatcher:function(K){return true;
-};
-var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(K){return -1;
-};
-var D=B.getEventReverseIterator(C,A);
-while(D.hasNext()){var H=D.next();
-if(J(H)){this.paintEvent(H,F,this._params.theme,E(H));
-}}this._highlightLayer.style.display="block";
-this._lineLayer.style.display="block";
-this._eventLayer.style.display="block";
-this._band.updateEventTrackInfo(this._lowerTracks.length+this._upperTracks.length,F.trackIncrement);
-};
-Timeline.DetailedEventPainter.prototype.softPaint=function(){};
-Timeline.DetailedEventPainter.prototype._prepareForPainting=function(){var B=this._band;
-if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
-this._backLayer.style.visibility="hidden";
-var A=document.createElement("span");
-A.className="timeline-event-label";
-this._backLayer.appendChild(A);
-this._frc=SimileAjax.Graphics.getFontRenderingContext(A);
-}this._frc.update();
-this._lowerTracks=[];
-this._upperTracks=[];
-if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
-}this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
-this._highlightLayer.style.display="none";
-if(this._lineLayer!=null){B.removeLayerDiv(this._lineLayer);
-}this._lineLayer=B.createLayerDiv(110,"timeline-band-lines");
-this._lineLayer.style.display="none";
-if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
-}this._eventLayer=B.createLayerDiv(110,"timeline-band-events");
-this._eventLayer.style.display="none";
-};
-Timeline.DetailedEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
-}else{this.paintDurationEvent(B,C,D,A);
-}};
-Timeline.DetailedEventPainter.prototype.paintInstantEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseInstantEvent(B,C,D,A);
-}else{this.paintPreciseInstantEvent(B,C,D,A);
-}};
-Timeline.DetailedEventPainter.prototype.paintDurationEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseDurationEvent(B,C,D,A);
-}else{this.paintPreciseDurationEvent(B,C,D,A);
-}};
-Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent=function(K,N,Q,O){var S=this._timeline.getDocument();
-var J=K.getText();
-var E=K.getStart();
-var C=Math.round(this._band.dateToPixelOffset(E));
-var A=Math.round(C+N.iconWidth/2);
-var I=Math.round(C-N.iconWidth/2);
-var G=this._frc.computeSize(J);
-var D=this._findFreeTrackForSolid(A,C);
-var B=this._paintEventIcon(K,D,I,N,Q);
-var T=A+Q.event.label.offsetFromLine;
-var P=D;
-var F=this._getTrackData(D);
-if(Math.min(F.solid,F.text)>=T+G.width){F.solid=I;
-F.text=T;
-}else{F.solid=I;
-T=C+Q.event.label.offsetFromLine;
-P=this._findFreeTrackForText(D,T+G.width,function(U){U.line=C-2;
-});
-this._getTrackData(P).text=I;
-this._paintEventLine(K,C,D,P,N,Q);
-}var R=Math.round(N.trackOffset+P*N.trackIncrement+N.trackHeight/2-G.height/2);
-var M=this._paintEventLabel(K,J,T,R,G.width,G.height,Q);
-var L=this;
-var H=function(U,V,W){return L._onClickInstantEvent(B.elmt,V,K);
-};
-SimileAjax.DOM.registerEvent(B.elmt,"mousedown",H);
-SimileAjax.DOM.registerEvent(M.elmt,"mousedown",H);
-this._createHighlightDiv(O,B,Q);
-this._eventIdToElmt[K.getID()]=B.elmt;
-};
-Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent=function(N,Q,V,R){var X=this._timeline.getDocument();
-var M=N.getText();
-var H=N.getStart();
-var S=N.getEnd();
-var E=Math.round(this._band.dateToPixelOffset(H));
-var B=Math.round(this._band.dateToPixelOffset(S));
-var A=Math.round(E+Q.iconWidth/2);
-var L=Math.round(E-Q.iconWidth/2);
-var J=this._frc.computeSize(M);
-var F=this._findFreeTrackForSolid(B,E);
-var G=this._paintEventTape(N,F,E,B,V.event.instant.impreciseColor,V.event.instant.impreciseOpacity,Q,V);
-var C=this._paintEventIcon(N,F,L,Q,V);
-var I=this._getTrackData(F);
-I.solid=L;
-var W=A+V.event.label.offsetFromLine;
-var D=W+J.width;
-var T;
-if(D<B){T=F;
-}else{W=E+V.event.label.offsetFromLine;
-D=W+J.width;
-T=this._findFreeTrackForText(F,D,function(Y){Y.line=E-2;
-});
-this._getTrackData(T).text=L;
-this._paintEventLine(N,E,F,T,Q,V);
-}var U=Math.round(Q.trackOffset+T*Q.trackIncrement+Q.trackHeight/2-J.height/2);
-var P=this._paintEventLabel(N,M,W,U,J.width,J.height,V);
-var O=this;
-var K=function(Y,Z,a){return O._onClickInstantEvent(C.elmt,Z,N);
-};
-SimileAjax.DOM.registerEvent(C.elmt,"mousedown",K);
-SimileAjax.DOM.registerEvent(G.elmt,"mousedown",K);
-SimileAjax.DOM.registerEvent(P.elmt,"mousedown",K);
-this._createHighlightDiv(R,C,V);
-this._eventIdToElmt[N.getID()]=C.elmt;
-};
-Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent=function(J,M,S,O){var T=this._timeline.getDocument();
-var I=J.getText();
-var D=J.getStart();
-var P=J.getEnd();
-var B=Math.round(this._band.dateToPixelOffset(D));
-var A=Math.round(this._band.dateToPixelOffset(P));
-var F=this._frc.computeSize(I);
-var E=this._findFreeTrackForSolid(A);
-var N=J.getColor();
-N=N!=null?N:S.event.duration.color;
-var C=this._paintEventTape(J,E,B,A,N,100,M,S);
-var H=this._getTrackData(E);
-H.solid=B;
-var U=B+S.event.label.offsetFromLine;
-var Q=this._findFreeTrackForText(E,U+F.width,function(V){V.line=B-2;
-});
-this._getTrackData(Q).text=B-2;
-this._paintEventLine(J,B,E,Q,M,S);
-var R=Math.round(M.trackOffset+Q*M.trackIncrement+M.trackHeight/2-F.height/2);
-var L=this._paintEventLabel(J,I,U,R,F.width,F.height,S);
-var K=this;
-var G=function(V,W,X){return K._onClickDurationEvent(C.elmt,W,J);
-};
-SimileAjax.DOM.registerEvent(C.elmt,"mousedown",G);
-SimileAjax.DOM.registerEvent(L.elmt,"mousedown",G);
-this._createHighlightDiv(O,C,S);
-this._eventIdToElmt[J.getID()]=C.elmt;
-};
-Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent=function(L,P,W,S){var Z=this._timeline.getDocument();
-var K=L.getText();
-var D=L.getStart();
-var Q=L.getLatestStart();
-var T=L.getEnd();
-var X=L.getEarliestEnd();
-var B=Math.round(this._band.dateToPixelOffset(D));
-var F=Math.round(this._band.dateToPixelOffset(Q));
-var A=Math.round(this._band.dateToPixelOffset(T));
-var G=Math.round(this._band.dateToPixelOffset(X));
-var H=this._frc.computeSize(K);
-var E=this._findFreeTrackForSolid(A);
-var R=L.getColor();
-R=R!=null?R:W.event.duration.color;
-var O=this._paintEventTape(L,E,B,A,W.event.duration.impreciseColor,W.event.duration.impreciseOpacity,P,W);
-var C=this._paintEventTape(L,E,F,G,R,100,P,W);
-var J=this._getTrackData(E);
-J.solid=B;
-var Y=F+W.event.label.offsetFromLine;
-var U=this._findFreeTrackForText(E,Y+H.width,function(a){a.line=F-2;
-});
-this._getTrackData(U).text=F-2;
-this._paintEventLine(L,F,E,U,P,W);
-var V=Math.round(P.trackOffset+U*P.trackIncrement+P.trackHeight/2-H.height/2);
-var N=this._paintEventLabel(L,K,Y,V,H.width,H.height,W);
-var M=this;
-var I=function(a,b,c){return M._onClickDurationEvent(C.elmt,b,L);
-};
-SimileAjax.DOM.registerEvent(C.elmt,"mousedown",I);
-SimileAjax.DOM.registerEvent(N.elmt,"mousedown",I);
-this._createHighlightDiv(S,C,W);
-this._eventIdToElmt[L.getID()]=C.elmt;
-};
-Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid=function(B,A){for(var D=0;
-true;
-D++){if(D<this._lowerTracks.length){var C=this._lowerTracks[D];
-if(Math.min(C.solid,C.text)>B&&(!(A)||C.line>A)){return D;
-}}else{this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
-return D;
-}if(D<this._upperTracks.length){var C=this._upperTracks[D];
-if(Math.min(C.solid,C.text)>B&&(!(A)||C.line>A)){return -1-D;
-}}else{this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
-return -1-D;
-}}};
-Timeline.DetailedEventPainter.prototype._findFreeTrackForText=function(D,C,H){var F;
-var G;
-var B;
-var J;
-if(D<0){F=true;
-B=-D;
-G=this._findFreeUpperTrackForText(B,C);
-J=-1-G;
-}else{if(D>0){F=false;
-B=D+1;
-G=this._findFreeLowerTrackForText(B,C);
-J=G;
-}else{var A=this._findFreeUpperTrackForText(0,C);
-var I=this._findFreeLowerTrackForText(1,C);
-if(I-1<=A){F=false;
-B=1;
-G=I;
-J=G;
-}else{F=true;
-B=0;
-G=A;
-J=-1-G;
-}}}if(F){if(G==this._upperTracks.length){this._upperTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
-}for(var E=B;
-E<G;
-E++){H(this._upperTracks[E]);
-}}else{if(G==this._lowerTracks.length){this._lowerTracks.push({solid:Number.POSITIVE_INFINITY,text:Number.POSITIVE_INFINITY,line:Number.POSITIVE_INFINITY});
-}for(var E=B;
-E<G;
-E++){H(this._lowerTracks[E]);
-}}return J;
-};
-Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText=function(A,C){for(;
-A<this._lowerTracks.length;
-A++){var B=this._lowerTracks[A];
-if(Math.min(B.solid,B.text)>=C){break;
-}}return A;
-};
-Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText=function(A,C){for(;
-A<this._upperTracks.length;
-A++){var B=this._upperTracks[A];
-if(Math.min(B.solid,B.text)>=C){break;
-}}return A;
-};
-Timeline.DetailedEventPainter.prototype._getTrackData=function(A){return(A<0)?this._upperTracks[-A-1]:this._lowerTracks[A];
-};
-Timeline.DetailedEventPainter.prototype._paintEventLine=function(I,C,F,A,G,D){var H=Math.round(G.trackOffset+F*G.trackIncrement+G.trackHeight/2);
-var J=Math.round(Math.abs(A-F)*G.trackIncrement);
-var E="1px solid "+D.event.label.lineColor;
-var B=this._timeline.getDocument().createElement("div");
-B.style.position="absolute";
-B.style.left=C+"px";
-B.style.width=D.event.label.offsetFromLine+"px";
-B.style.height=J+"px";
-if(F>A){B.style.top=(H-J)+"px";
-B.style.borderTop=E;
-}else{B.style.top=H+"px";
-B.style.borderBottom=E;
-}B.style.borderLeft=E;
-this._lineLayer.appendChild(B);
-};
-Timeline.DetailedEventPainter.prototype._paintEventIcon=function(I,E,B,F,D){var H=I.getIcon();
-H=H!=null?H:F.icon;
-var J=F.trackOffset+E*F.trackIncrement+F.trackHeight/2;
-var G=Math.round(J-F.iconHeight/2);
-var C=SimileAjax.Graphics.createTranslucentImage(H);
-var A=this._timeline.getDocument().createElement("div");
-A.style.position="absolute";
-A.style.left=B+"px";
-A.style.top=G+"px";
-A.appendChild(C);
-A.style.cursor="pointer";
-if(I._title!=null){A.title=I._title;
-}this._eventLayer.appendChild(A);
-return{left:B,top:G,width:F.iconWidth,height:F.iconHeight,elmt:A};
-};
-Timeline.DetailedEventPainter.prototype._paintEventLabel=function(H,I,B,F,A,J,D){var G=this._timeline.getDocument();
-var K=G.createElement("div");
-K.style.position="absolute";
-K.style.left=B+"px";
-K.style.width=A+"px";
-K.style.top=F+"px";
-K.style.height=J+"px";
-K.style.backgroundColor=D.event.label.backgroundColor;
-SimileAjax.Graphics.setOpacity(K,D.event.label.backgroundOpacity);
-this._eventLayer.appendChild(K);
-var E=G.createElement("div");
-E.style.position="absolute";
-E.style.left=B+"px";
-E.style.width=A+"px";
-E.style.top=F+"px";
-E.innerHTML=I;
-E.style.cursor="pointer";
-if(H._title!=null){E.title=H._title;
-}var C=H.getTextColor();
-if(C==null){C=H.getColor();
-}if(C!=null){E.style.color=C;
-}this._eventLayer.appendChild(E);
-return{left:B,top:F,width:A,height:J,elmt:E};
-};
-Timeline.DetailedEventPainter.prototype._paintEventTape=function(L,H,E,A,C,G,I,F){var B=A-E;
-var D=F.event.tape.height;
-var M=I.trackOffset+H*I.trackIncrement+I.trackHeight/2;
-var J=Math.round(M-D/2);
-var K=this._timeline.getDocument().createElement("div");
-K.style.position="absolute";
-K.style.left=E+"px";
-K.style.width=B+"px";
-K.style.top=J+"px";
-K.style.height=D+"px";
-K.style.backgroundColor=C;
-K.style.overflow="hidden";
-K.style.cursor="pointer";
-if(L._title!=null){K.title=L._title;
-}SimileAjax.Graphics.setOpacity(K,G);
-this._eventLayer.appendChild(K);
-return{left:E,top:J,width:B,height:D,elmt:K};
-};
-Timeline.DetailedEventPainter.prototype._createHighlightDiv=function(A,C,E){if(A>=0){var D=this._timeline.getDocument();
-var G=E.event;
-var B=G.highlightColors[Math.min(A,G.highlightColors.length-1)];
-var F=D.createElement("div");
-F.style.position="absolute";
-F.style.overflow="hidden";
-F.style.left=(C.left-2)+"px";
-F.style.width=(C.width+4)+"px";
-F.style.top=(C.top-2)+"px";
-F.style.height=(C.height+4)+"px";
-F.style.background=B;
-this._highlightLayer.appendChild(F);
-}};
-Timeline.DetailedEventPainter.prototype._onClickInstantEvent=function(B,C,A){var D=SimileAjax.DOM.getPageCoordinates(B);
-this._showBubble(D.left+Math.ceil(B.offsetWidth/2),D.top+Math.ceil(B.offsetHeight/2),A);
-this._fireOnSelect(A.getID());
-C.cancelBubble=true;
-SimileAjax.DOM.cancelEvent(C);
-return false;
-};
-Timeline.DetailedEventPainter.prototype._onClickDurationEvent=function(D,C,B){if("pageX" in C){var A=C.pageX;
-var F=C.pageY;
-}else{var E=SimileAjax.DOM.getPageCoordinates(D);
-var A=C.offsetX+E.left;
-var F=C.offsetY+E.top;
-}this._showBubble(A,F,B);
-this._fireOnSelect(B.getID());
-C.cancelBubble=true;
-SimileAjax.DOM.cancelEvent(C);
-return false;
-};
-Timeline.DetailedEventPainter.prototype.showBubble=function(A){var B=this._eventIdToElmt[A.getID()];
-if(B){var C=SimileAjax.DOM.getPageCoordinates(B);
-this._showBubble(C.left+B.offsetWidth/2,C.top+B.offsetHeight/2,A);
-}};
-Timeline.DetailedEventPainter.prototype._showBubble=function(A,E,B){var D=document.createElement("div");
-var C=this._params.theme.event.bubble;
-B.fillInfoBubble(D,this._params.theme,this._band.getLabeller());
-SimileAjax.WindowManager.cancelPopups();
-SimileAjax.Graphics.createBubbleForContentAndPoint(D,A,E,C.width,null,C.maxHeight);
-};
-Timeline.DetailedEventPainter.prototype._fireOnSelect=function(B){for(var A=0;
-A<this._onSelectListeners.length;
-A++){this._onSelectListeners[A](B);
-}};
-
-
-/* ether-painters.js */
-Timeline.GregorianEtherPainter=function(A){this._params=A;
-this._theme=A.theme;
-this._unit=A.unit;
-this._multiple=("multiple" in A)?A.multiple:1;
-};
-Timeline.GregorianEtherPainter.prototype.initialize=function(C,B){this._band=C;
-this._timeline=B;
-this._backgroundLayer=C.createLayerDiv(0);
-this._backgroundLayer.setAttribute("name","ether-background");
-this._backgroundLayer.className="timeline-ether-bg";
-this._markerLayer=null;
-this._lineLayer=null;
-var D=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
-var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
-this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
-this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
-};
-Timeline.GregorianEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
-};
-Timeline.GregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
-}this._markerLayer=this._band.createLayerDiv(100);
-this._markerLayer.setAttribute("name","ether-markers");
-this._markerLayer.style.display="none";
-if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
-}this._lineLayer=this._band.createLayerDiv(1);
-this._lineLayer.setAttribute("name","ether-lines");
-this._lineLayer.style.display="none";
-var C=this._band.getMinDate();
-var F=this._band.getMaxDate();
-var B=this._band.getTimeZone();
-var E=this._band.getLabeller();
-SimileAjax.DateTime.roundDownToInterval(C,this._unit,B,this._multiple,this._theme.firstDayOfWeek);
-var D=this;
-var A=function(G){for(var H=0;
-H<D._multiple;
-H++){SimileAjax.DateTime.incrementByInterval(G,D._unit);
-}};
-while(C.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(C,E,this._unit,this._markerLayer,this._lineLayer);
-A(C);
-}this._markerLayer.style.display="block";
-this._lineLayer.style.display="block";
-};
-Timeline.GregorianEtherPainter.prototype.softPaint=function(){};
-Timeline.GregorianEtherPainter.prototype.zoom=function(A){if(A!=0){this._unit+=A;
-}};
-Timeline.HotZoneGregorianEtherPainter=function(G){this._params=G;
-this._theme=G.theme;
-this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,unit:G.unit,multiple:1}];
-for(var E=0;
-E<G.zones.length;
-E++){var B=G.zones[E];
-var D=SimileAjax.DateTime.parseGregorianDateTime(B.start).getTime();
-var F=SimileAjax.DateTime.parseGregorianDateTime(B.end).getTime();
-for(var C=0;
-C<this._zones.length&&F>D;
-C++){var A=this._zones[C];
-if(D<A.endTime){if(D>A.startTime){this._zones.splice(C,0,{startTime:A.startTime,endTime:D,unit:A.unit,multiple:A.multiple});
-C++;
-A.startTime=D;
-}if(F<A.endTime){this._zones.splice(C,0,{startTime:D,endTime:F,unit:B.unit,multiple:(B.multiple)?B.multiple:1});
-C++;
-A.startTime=F;
-D=F;
-}else{A.multiple=B.multiple;
-A.unit=B.unit;
-D=A.endTime;
-}}}}};
-Timeline.HotZoneGregorianEtherPainter.prototype.initialize=function(C,B){this._band=C;
-this._timeline=B;
-this._backgroundLayer=C.createLayerDiv(0);
-this._backgroundLayer.setAttribute("name","ether-background");
-this._backgroundLayer.className="timeline-ether-bg";
-this._markerLayer=null;
-this._lineLayer=null;
-var D=("align" in this._params&&this._params.align!=undefined)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
-var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
-this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
-this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
-};
-Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
-};
-Timeline.HotZoneGregorianEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
-}this._markerLayer=this._band.createLayerDiv(100);
-this._markerLayer.setAttribute("name","ether-markers");
-this._markerLayer.style.display="none";
-if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
-}this._lineLayer=this._band.createLayerDiv(1);
-this._lineLayer.setAttribute("name","ether-lines");
-this._lineLayer.style.display="none";
-var D=this._band.getMinDate();
-var A=this._band.getMaxDate();
-var K=this._band.getTimeZone();
-var I=this._band.getLabeller();
-var B=this;
-var L=function(N,M){for(var O=0;
-O<M.multiple;
-O++){SimileAjax.DateTime.incrementByInterval(N,M.unit);
-}};
-var C=0;
-while(C<this._zones.length){if(D.getTime()<this._zones[C].endTime){break;
-}C++;
-}var E=this._zones.length-1;
-while(E>=0){if(A.getTime()>this._zones[E].startTime){break;
-}E--;
-}for(var H=C;
-H<=E;
-H++){var G=this._zones[H];
-var J=new Date(Math.max(D.getTime(),G.startTime));
-var F=new Date(Math.min(A.getTime(),G.endTime));
-SimileAjax.DateTime.roundDownToInterval(J,G.unit,K,G.multiple,this._theme.firstDayOfWeek);
-SimileAjax.DateTime.roundUpToInterval(F,G.unit,K,G.multiple,this._theme.firstDayOfWeek);
-while(J.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(J,I,G.unit,this._markerLayer,this._lineLayer);
-L(J,G);
-}}this._markerLayer.style.display="block";
-this._lineLayer.style.display="block";
-};
-Timeline.HotZoneGregorianEtherPainter.prototype.softPaint=function(){};
-Timeline.HotZoneGregorianEtherPainter.prototype.zoom=function(B){if(B!=0){for(var A=0;
-A<this._zones.length;
-++A){if(this._zones[A]){this._zones[A].unit+=B;
-}}}};
-Timeline.YearCountEtherPainter=function(A){this._params=A;
-this._theme=A.theme;
-this._startDate=SimileAjax.DateTime.parseGregorianDateTime(A.startDate);
-this._multiple=("multiple" in A)?A.multiple:1;
-};
-Timeline.YearCountEtherPainter.prototype.initialize=function(C,B){this._band=C;
-this._timeline=B;
-this._backgroundLayer=C.createLayerDiv(0);
-this._backgroundLayer.setAttribute("name","ether-background");
-this._backgroundLayer.className="timeline-ether-bg";
-this._markerLayer=null;
-this._lineLayer=null;
-var D=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
-var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
-this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
-this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
-};
-Timeline.YearCountEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
-};
-Timeline.YearCountEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
-}this._markerLayer=this._band.createLayerDiv(100);
-this._markerLayer.setAttribute("name","ether-markers");
-this._markerLayer.style.display="none";
-if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
-}this._lineLayer=this._band.createLayerDiv(1);
-this._lineLayer.setAttribute("name","ether-lines");
-this._lineLayer.style.display="none";
-var B=new Date(this._startDate.getTime());
-var F=this._band.getMaxDate();
-var E=this._band.getMinDate().getUTCFullYear()-this._startDate.getUTCFullYear();
-B.setUTCFullYear(this._band.getMinDate().getUTCFullYear()-E%this._multiple);
-var C=this;
-var A=function(G){for(var H=0;
-H<C._multiple;
-H++){SimileAjax.DateTime.incrementByInterval(G,SimileAjax.DateTime.YEAR);
-}};
-var D={labelInterval:function(G,I){var H=G.getUTCFullYear()-C._startDate.getUTCFullYear();
-return{text:H,emphasized:H==0};
-}};
-while(B.getTime()<F.getTime()){this._intervalMarkerLayout.createIntervalMarker(B,D,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
-A(B);
-}this._markerLayer.style.display="block";
-this._lineLayer.style.display="block";
-};
-Timeline.YearCountEtherPainter.prototype.softPaint=function(){};
-Timeline.QuarterlyEtherPainter=function(A){this._params=A;
-this._theme=A.theme;
-this._startDate=SimileAjax.DateTime.parseGregorianDateTime(A.startDate);
-};
-Timeline.QuarterlyEtherPainter.prototype.initialize=function(C,B){this._band=C;
-this._timeline=B;
-this._backgroundLayer=C.createLayerDiv(0);
-this._backgroundLayer.setAttribute("name","ether-background");
-this._backgroundLayer.className="timeline-ether-bg";
-this._markerLayer=null;
-this._lineLayer=null;
-var D=("align" in this._params)?this._params.align:this._theme.ether.interval.marker[B.isHorizontal()?"hAlign":"vAlign"];
-var A=("showLine" in this._params)?this._params.showLine:this._theme.ether.interval.line.show;
-this._intervalMarkerLayout=new Timeline.EtherIntervalMarkerLayout(this._timeline,this._band,this._theme,D,A);
-this._highlight=new Timeline.EtherHighlight(this._timeline,this._band,this._theme,this._backgroundLayer);
-};
-Timeline.QuarterlyEtherPainter.prototype.setHighlight=function(A,B){this._highlight.position(A,B);
-};
-Timeline.QuarterlyEtherPainter.prototype.paint=function(){if(this._markerLayer){this._band.removeLayerDiv(this._markerLayer);
-}this._markerLayer=this._band.createLayerDiv(100);
-this._markerLayer.setAttribute("name","ether-markers");
-this._markerLayer.style.display="none";
-if(this._lineLayer){this._band.removeLayerDiv(this._lineLayer);
-}this._lineLayer=this._band.createLayerDiv(1);
-this._lineLayer.setAttribute("name","ether-lines");
-this._lineLayer.style.display="none";
-var B=new Date(0);
-var E=this._band.getMaxDate();
-B.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(),this._band.getMinDate().getUTCFullYear()));
-B.setUTCMonth(this._startDate.getUTCMonth());
-var C=this;
-var A=function(F){F.setUTCMonth(F.getUTCMonth()+3);
-};
-var D={labelInterval:function(F,H){var G=(4+(F.getUTCMonth()-C._startDate.getUTCMonth())/3)%4;
-if(G!=0){return{text:"Q"+(G+1),emphasized:false};
-}else{return{text:"Y"+(F.getUTCFullYear()-C._startDate.getUTCFullYear()+1),emphasized:true};
-}}};
-while(B.getTime()<E.getTime()){this._intervalMarkerLayout.createIntervalMarker(B,D,SimileAjax.DateTime.YEAR,this._markerLayer,this._lineLayer);
-A(B);
-}this._markerLayer.style.display="block";
-this._lineLayer.style.display="block";
-};
-Timeline.QuarterlyEtherPainter.prototype.softPaint=function(){};
-Timeline.EtherIntervalMarkerLayout=function(M,L,C,E,H){var A=M.isHorizontal();
-if(A){if(E=="Top"){this.positionDiv=function(O,N){O.style.left=N+"px";
-O.style.top="0px";
-};
-}else{this.positionDiv=function(O,N){O.style.left=N+"px";
-O.style.bottom="0px";
-};
-}}else{if(E=="Left"){this.positionDiv=function(O,N){O.style.top=N+"px";
-O.style.left="0px";
-};
-}else{this.positionDiv=function(O,N){O.style.top=N+"px";
-O.style.right="0px";
-};
-}}var D=C.ether.interval.marker;
-var I=C.ether.interval.line;
-var B=C.ether.interval.weekend;
-var K=(A?"h":"v")+E;
-var G=D[K+"Styler"];
-var J=D[K+"EmphasizedStyler"];
-var F=SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
-this.createIntervalMarker=function(T,a,b,c,Q){var U=Math.round(L.dateToPixelOffset(T));
-if(H&&b!=SimileAjax.DateTime.WEEK){var V=M.getDocument().createElement("div");
-V.className="timeline-ether-lines";
-if(I.opacity<100){SimileAjax.Graphics.setOpacity(V,I.opacity);
-}if(A){V.style.left=U+"px";
-}else{V.style.top=U+"px";
-}Q.appendChild(V);
-}if(b==SimileAjax.DateTime.WEEK){var N=C.firstDayOfWeek;
-var W=new Date(T.getTime()+(6-N-7)*F);
-var Z=new Date(W.getTime()+2*F);
-var X=Math.round(L.dateToPixelOffset(W));
-var S=Math.round(L.dateToPixelOffset(Z));
-var R=Math.max(1,S-X);
-var P=M.getDocument().createElement("div");
-P.className="timeline-ether-weekends";
-if(B.opacity<100){SimileAjax.Graphics.setOpacity(P,B.opacity);
-}if(A){P.style.left=X+"px";
-P.style.width=R+"px";
-}else{P.style.top=X+"px";
-P.style.height=R+"px";
-}Q.appendChild(P);
-}var Y=a.labelInterval(T,b);
-var O=M.getDocument().createElement("div");
-O.innerHTML=Y.text;
-O.className="timeline-date-label";
-if(Y.emphasized){O.className+=" timeline-date-label-em";
-}this.positionDiv(O,U);
-c.appendChild(O);
-return O;
-};
-};
-Timeline.EtherHighlight=function(C,E,D,B){var A=C.isHorizontal();
-this._highlightDiv=null;
-this._createHighlightDiv=function(){if(this._highlightDiv==null){this._highlightDiv=C.getDocument().createElement("div");
-this._highlightDiv.setAttribute("name","ether-highlight");
-this._highlightDiv.className="timeline-ether-highlight";
-var F=D.ether.highlightOpacity;
-if(F<100){SimileAjax.Graphics.setOpacity(this._highlightDiv,F);
-}B.appendChild(this._highlightDiv);
-}};
-this.position=function(F,I){this._createHighlightDiv();
-var J=Math.round(E.dateToPixelOffset(F));
-var H=Math.round(E.dateToPixelOffset(I));
-var G=Math.max(H-J,3);
-if(A){this._highlightDiv.style.left=J+"px";
-this._highlightDiv.style.width=G+"px";
-this._highlightDiv.style.height=(E.getViewWidth()-4)+"px";
-}else{this._highlightDiv.style.top=J+"px";
-this._highlightDiv.style.height=G+"px";
-this._highlightDiv.style.width=(E.getViewWidth()-4)+"px";
-}};
-};
-
-
-/* ethers.js */
-Timeline.LinearEther=function(A){this._params=A;
-this._interval=A.interval;
-this._pixelsPerInterval=A.pixelsPerInterval;
-};
-Timeline.LinearEther.prototype.initialize=function(B,A){this._band=B;
-this._timeline=A;
-this._unit=A.getUnit();
-if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
-}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
-this.shiftPixels(-this._timeline.getPixelLength());
-}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
-this.shiftPixels(-this._timeline.getPixelLength()/2);
-}else{this._start=this._unit.makeDefaultValue();
-this.shiftPixels(-this._timeline.getPixelLength()/2);
-}}}};
-Timeline.LinearEther.prototype.setDate=function(A){this._start=this._unit.cloneValue(A);
-};
-Timeline.LinearEther.prototype.shiftPixels=function(B){var A=this._interval*B/this._pixelsPerInterval;
-this._start=this._unit.change(this._start,A);
-};
-Timeline.LinearEther.prototype.dateToPixelOffset=function(A){var B=this._unit.compare(A,this._start);
-return this._pixelsPerInterval*B/this._interval;
-};
-Timeline.LinearEther.prototype.pixelOffsetToDate=function(B){var A=B*this._interval/this._pixelsPerInterval;
-return this._unit.change(this._start,A);
-};
-Timeline.LinearEther.prototype.zoom=function(D){var B=0;
-var A=this._band._zoomIndex;
-var C=A;
-if(D&&(A>0)){C=A-1;
-}if(!D&&(A<(this._band._zoomSteps.length-1))){C=A+1;
-}this._band._zoomIndex=C;
-this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[C].unit];
-this._pixelsPerInterval=this._band._zoomSteps[C].pixelsPerInterval;
-B=this._band._zoomSteps[C].unit-this._band._zoomSteps[A].unit;
-return B;
-};
-Timeline.HotZoneEther=function(A){this._params=A;
-this._interval=A.interval;
-this._pixelsPerInterval=A.pixelsPerInterval;
-this._theme=A.theme;
-};
-Timeline.HotZoneEther.prototype.initialize=function(H,I){this._band=H;
-this._timeline=I;
-this._unit=I.getUnit();
-this._zones=[{startTime:Number.NEGATIVE_INFINITY,endTime:Number.POSITIVE_INFINITY,magnify:1}];
-var B=this._params;
-for(var D=0;
-D<B.zones.length;
-D++){var G=B.zones[D];
-var E=this._unit.parseFromObject(G.start);
-var F=this._unit.parseFromObject(G.end);
-for(var C=0;
-C<this._zones.length&&this._unit.compare(F,E)>0;
-C++){var A=this._zones[C];
-if(this._unit.compare(E,A.endTime)<0){if(this._unit.compare(E,A.startTime)>0){this._zones.splice(C,0,{startTime:A.startTime,endTime:E,magnify:A.magnify});
-C++;
-A.startTime=E;
-}if(this._unit.compare(F,A.endTime)<0){this._zones.splice(C,0,{startTime:E,endTime:F,magnify:G.magnify*A.magnify});
-C++;
-A.startTime=F;
-E=F;
-}else{A.magnify*=G.magnify;
-E=A.endTime;
-}}}}if("startsOn" in this._params){this._start=this._unit.parseFromObject(this._params.startsOn);
-}else{if("endsOn" in this._params){this._start=this._unit.parseFromObject(this._params.endsOn);
-this.shiftPixels(-this._timeline.getPixelLength());
-}else{if("centersOn" in this._params){this._start=this._unit.parseFromObject(this._params.centersOn);
-this.shiftPixels(-this._timeline.getPixelLength()/2);
-}else{this._start=this._unit.makeDefaultValue();
-this.shiftPixels(-this._timeline.getPixelLength()/2);
-}}}};
-Timeline.HotZoneEther.prototype.setDate=function(A){this._start=this._unit.cloneValue(A);
-};
-Timeline.HotZoneEther.prototype.shiftPixels=function(A){this._start=this.pixelOffsetToDate(A);
-};
-Timeline.HotZoneEther.prototype.dateToPixelOffset=function(A){return this._dateDiffToPixelOffset(this._start,A);
-};
-Timeline.HotZoneEther.prototype.pixelOffsetToDate=function(A){return this._pixelOffsetToDate(A,this._start);
-};
-Timeline.HotZoneEther.prototype.zoom=function(D){var B=0;
-var A=this._band._zoomIndex;
-var C=A;
-if(D&&(A>0)){C=A-1;
-}if(!D&&(A<(this._band._zoomSteps.length-1))){C=A+1;
-}this._band._zoomIndex=C;
-this._interval=SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[C].unit];
-this._pixelsPerInterval=this._band._zoomSteps[C].pixelsPerInterval;
-B=this._band._zoomSteps[C].unit-this._band._zoomSteps[A].unit;
-return B;
-};
-Timeline.HotZoneEther.prototype._dateDiffToPixelOffset=function(I,D){var B=this._getScale();
-var H=I;
-var C=D;
-var A=0;
-if(this._unit.compare(H,C)<0){var G=0;
-while(G<this._zones.length){if(this._unit.compare(H,this._zones[G].endTime)<0){break;
-}G++;
-}while(this._unit.compare(H,C)<0){var E=this._zones[G];
-var F=this._unit.earlier(C,E.endTime);
-A+=(this._unit.compare(F,H)/(B/E.magnify));
-H=F;
-G++;
-}}else{var G=this._zones.length-1;
-while(G>=0){if(this._unit.compare(H,this._zones[G].startTime)>0){break;
-}G--;
-}while(this._unit.compare(H,C)>0){var E=this._zones[G];
-var F=this._unit.later(C,E.startTime);
-A+=(this._unit.compare(F,H)/(B/E.magnify));
-H=F;
-G--;
-}}return A;
-};
-Timeline.HotZoneEther.prototype._pixelOffsetToDate=function(H,C){var G=this._getScale();
-var E=C;
-if(H>0){var F=0;
-while(F<this._zones.length){if(this._unit.compare(E,this._zones[F].endTime)<0){break;
-}F++;
-}while(H>0){var A=this._zones[F];
-var D=G/A.magnify;
-if(A.endTime==Number.POSITIVE_INFINITY){E=this._unit.change(E,H*D);
-H=0;
-}else{var B=this._unit.compare(A.endTime,E)/D;
-if(B>H){E=this._unit.change(E,H*D);
-H=0;
-}else{E=A.endTime;
-H-=B;
-}}F++;
-}}else{var F=this._zones.length-1;
-while(F>=0){if(this._unit.compare(E,this._zones[F].startTime)>0){break;
-}F--;
-}H=-H;
-while(H>0){var A=this._zones[F];
-var D=G/A.magnify;
-if(A.startTime==Number.NEGATIVE_INFINITY){E=this._unit.change(E,-H*D);
-H=0;
-}else{var B=this._unit.compare(E,A.startTime)/D;
-if(B>H){E=this._unit.change(E,-H*D);
-H=0;
-}else{E=A.startTime;
-H-=B;
-}}F--;
-}}return E;
-};
-Timeline.HotZoneEther.prototype._getScale=function(){return this._interval/this._pixelsPerInterval;
-};
-
-
-/* event-utils.js */
-Timeline.EventUtils={};
-Timeline.EventUtils.getNewEventID=function(){if(this._lastEventID==null){this._lastEventID=0;
-}this._lastEventID+=1;
-return"e"+this._lastEventID;
-};
-Timeline.EventUtils.decodeEventElID=function(B){var D=B.split("-");
-if(D[1]!="tl"){alert("Internal Timeline problem 101, please consult support");
-return{band:null,evt:null};
-}var C=Timeline.getTimelineFromID(D[2]);
-var E=C.getBand(D[3]);
-var A=E.getEventSource.getEvent(D[4]);
-return{band:E,evt:A};
-};
-Timeline.EventUtils.encodeEventElID=function(C,D,B,A){return B+"-tl-"+C.timelineID+"-"+D.getIndex()+"-"+A.getID();
-};
-
-
-/* labellers.js */
-Timeline.GregorianDateLabeller=function(A,B){this._locale=A;
-this._timeZone=B;
-};
-Timeline.GregorianDateLabeller.monthNames=[];
-Timeline.GregorianDateLabeller.dayNames=[];
-Timeline.GregorianDateLabeller.labelIntervalFunctions=[];
-Timeline.GregorianDateLabeller.getMonthName=function(B,A){return Timeline.GregorianDateLabeller.monthNames[A][B];
-};
-Timeline.GregorianDateLabeller.prototype.labelInterval=function(A,C){var B=Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
-if(B==null){B=Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
-}return B.call(this,A,C);
-};
-Timeline.GregorianDateLabeller.prototype.labelPrecise=function(A){return SimileAjax.DateTime.removeTimeZoneOffset(A,this._timeZone).toUTCString();
-};
-Timeline.GregorianDateLabeller.prototype.defaultLabelInterval=function(B,F){var C;
-var E=false;
-B=SimileAjax.DateTime.removeTimeZoneOffset(B,this._timeZone);
-switch(F){case SimileAjax.DateTime.MILLISECOND:C=B.getUTCMilliseconds();
-break;
-case SimileAjax.DateTime.SECOND:C=B.getUTCSeconds();
-break;
-case SimileAjax.DateTime.MINUTE:var A=B.getUTCMinutes();
-if(A==0){C=B.getUTCHours()+":00";
-E=true;
-}else{C=A;
-}break;
-case SimileAjax.DateTime.HOUR:C=B.getUTCHours()+"hr";
-break;
-case SimileAjax.DateTime.DAY:C=Timeline.GregorianDateLabeller.getMonthName(B.getUTCMonth(),this._locale)+" "+B.getUTCDate();
-break;
-case SimileAjax.DateTime.WEEK:C=Timeline.GregorianDateLabeller.getMonthName(B.getUTCMonth(),this._locale)+" "+B.getUTCDate();
-break;
-case SimileAjax.DateTime.MONTH:var A=B.getUTCMonth();
-if(A!=0){C=Timeline.GregorianDateLabeller.getMonthName(A,this._locale);
-break;
-}case SimileAjax.DateTime.YEAR:case SimileAjax.DateTime.DECADE:case SimileAjax.DateTime.CENTURY:case SimileAjax.DateTime.MILLENNIUM:var D=B.getUTCFullYear();
-if(D>0){C=B.getUTCFullYear();
-}else{C=(1-D)+"BC";
-}E=(F==SimileAjax.DateTime.MONTH)||(F==SimileAjax.DateTime.DECADE&&D%100==0)||(F==SimileAjax.DateTime.CENTURY&&D%1000==0);
-break;
-default:C=B.toUTCString();
-}return{text:C,emphasized:E};
-};
-
-
-/* original-painter.js */
-Timeline.OriginalEventPainter=function(A){this._params=A;
-this._onSelectListeners=[];
-this._eventPaintListeners=[];
-this._filterMatcher=null;
-this._highlightMatcher=null;
-this._frc=null;
-this._eventIdToElmt={};
-};
-Timeline.OriginalEventPainter.prototype.initialize=function(B,A){this._band=B;
-this._timeline=A;
-this._backLayer=null;
-this._eventLayer=null;
-this._lineLayer=null;
-this._highlightLayer=null;
-this._eventIdToElmt=null;
-};
-Timeline.OriginalEventPainter.prototype.getType=function(){return"original";
-};
-Timeline.OriginalEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
-};
-Timeline.OriginalEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
-A<this._onSelectListeners.length;
-A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
-break;
-}}};
-Timeline.OriginalEventPainter.prototype.addEventPaintListener=function(A){this._eventPaintListeners.push(A);
-};
-Timeline.OriginalEventPainter.prototype.removeEventPaintListener=function(B){for(var A=0;
-A<this._eventPaintListeners.length;
-A++){if(this._eventPaintListeners[A]==B){this._eventPaintListeners.splice(A,1);
-break;
-}}};
-Timeline.OriginalEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
-};
-Timeline.OriginalEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
-};
-Timeline.OriginalEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
-};
-Timeline.OriginalEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
-};
-Timeline.OriginalEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
-if(B==null){return ;
-}this._eventIdToElmt={};
-this._fireEventPaintListeners("paintStarting",null,null);
-this._prepareForPainting();
-var I=this._params.theme.event;
-var G=Math.max(I.track.height,I.tape.height+this._frc.getLineHeight());
-var F={trackOffset:I.track.offset,trackHeight:G,trackGap:I.track.gap,trackIncrement:G+I.track.gap,icon:I.instant.icon,iconWidth:I.instant.iconWidth,iconHeight:I.instant.iconHeight,labelWidth:I.label.width,maxLabelChar:I.label.maxLabelChar,impreciseIconMargin:I.instant.impreciseIconMargin};
-var C=this._band.getMinDate();
-var A=this._band.getMaxDate();
-var J=(this._filterMatcher!=null)?this._filterMatcher:function(K){return true;
-};
-var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(K){return -1;
-};
-var D=B.getEventReverseIterator(C,A);
-while(D.hasNext()){var H=D.next();
-if(J(H)){this.paintEvent(H,F,this._params.theme,E(H));
-}}this._highlightLayer.style.display="block";
-this._lineLayer.style.display="block";
-this._eventLayer.style.display="block";
-this._band.updateEventTrackInfo(this._tracks.length,F.trackIncrement);
-this._fireEventPaintListeners("paintEnded",null,null);
-};
-Timeline.OriginalEventPainter.prototype.softPaint=function(){};
-Timeline.OriginalEventPainter.prototype._prepareForPainting=function(){var B=this._band;
-if(this._backLayer==null){this._backLayer=this._band.createLayerDiv(0,"timeline-band-events");
-this._backLayer.style.visibility="hidden";
-var A=document.createElement("span");
-A.className="timeline-event-label";
-this._backLayer.appendChild(A);
-this._frc=SimileAjax.Graphics.getFontRenderingContext(A);
-}this._frc.update();
-this._tracks=[];
-if(this._highlightLayer!=null){B.removeLayerDiv(this._highlightLayer);
-}this._highlightLayer=B.createLayerDiv(105,"timeline-band-highlights");
-this._highlightLayer.style.display="none";
-if(this._lineLayer!=null){B.removeLayerDiv(this._lineLayer);
-}this._lineLayer=B.createLayerDiv(110,"timeline-band-lines");
-this._lineLayer.style.display="none";
-if(this._eventLayer!=null){B.removeLayerDiv(this._eventLayer);
-}this._eventLayer=B.createLayerDiv(115,"timeline-band-events");
-this._eventLayer.style.display="none";
-};
-Timeline.OriginalEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
-}else{this.paintDurationEvent(B,C,D,A);
-}};
-Timeline.OriginalEventPainter.prototype.paintInstantEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseInstantEvent(B,C,D,A);
-}else{this.paintPreciseInstantEvent(B,C,D,A);
-}};
-Timeline.OriginalEventPainter.prototype.paintDurationEvent=function(B,C,D,A){if(B.isImprecise()){this.paintImpreciseDurationEvent(B,C,D,A);
-}else{this.paintPreciseDurationEvent(B,C,D,A);
-}};
-Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent=function(M,Q,S,R){var V=this._timeline.getDocument();
-var L=M.getText();
-var E=M.getStart();
-var C=Math.round(this._band.dateToPixelOffset(E));
-var A=Math.round(C+Q.iconWidth/2);
-var K=Math.round(C-Q.iconWidth/2);
-var H=this._getLabelDivClassName(M);
-var I=this._frc.computeSize(L,H);
-var W=A+S.event.label.offsetFromLine;
-var D=W+I.width;
-var U=D;
-var O=this._findFreeTrack(M,U);
-var T=Math.round(Q.trackOffset+O*Q.trackIncrement+Q.trackHeight/2-I.height/2);
-var B=this._paintEventIcon(M,O,K,Q,S,0);
-var P=this._paintEventLabel(M,L,W,T,I.width,I.height,S,H,R);
-var F=[B.elmt,P.elmt];
-var N=this;
-var J=function(X,Y,Z){return N._onClickInstantEvent(B.elmt,Y,M);
-};
-SimileAjax.DOM.registerEvent(B.elmt,"mousedown",J);
-SimileAjax.DOM.registerEvent(P.elmt,"mousedown",J);
-var G=this._createHighlightDiv(R,B,S,M);
-if(G!=null){F.push(G);
-}this._fireEventPaintListeners("paintedEvent",M,F);
-this._eventIdToElmt[M.getID()]=B.elmt;
-this._tracks[O]=K;
-};
-Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent=function(P,T,Y,V){var a=this._timeline.getDocument();
-var N=P.getText();
-var G=P.getStart();
-var W=P.getEnd();
-var D=Math.round(this._band.dateToPixelOffset(G));
-var B=Math.round(this._band.dateToPixelOffset(W));
-var A=Math.round(D+T.iconWidth/2);
-var M=Math.round(D-T.iconWidth/2);
-var J=this._getLabelDivClassName(P);
-var K=this._frc.computeSize(N,J);
-var b=A+Y.event.label.offsetFromLine;
-var E=b+K.width;
-var Z=Math.max(E,B);
-var R=this._findFreeTrack(P,Z);
-var O=Y.event.tape.height;
-var X=Math.round(T.trackOffset+R*T.trackIncrement+O);
-var C=this._paintEventIcon(P,R,M,T,Y,O);
-var S=this._paintEventLabel(P,N,b,X,K.width,K.height,Y,J,V);
-var U=P.getColor();
-U=U!=null?U:Y.event.instant.impreciseColor;
-var F=this._paintEventTape(P,R,D,B,U,Y.event.instant.impreciseOpacity,T,Y,0);
-var H=[C.elmt,S.elmt,F.elmt];
-var Q=this;
-var L=function(c,d,e){return Q._onClickInstantEvent(C.elmt,d,P);
-};
-SimileAjax.DOM.registerEvent(C.elmt,"mousedown",L);
-SimileAjax.DOM.registerEvent(F.elmt,"mousedown",L);
-SimileAjax.DOM.registerEvent(S.elmt,"mousedown",L);
-var I=this._createHighlightDiv(V,C,Y,P);
-if(I!=null){H.push(I);
-}this._fireEventPaintListeners("paintedEvent",P,H);
-this._eventIdToElmt[P.getID()]=C.elmt;
-this._tracks[R]=M;
-};
-Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent=function(L,P,T,R){var W=this._timeline.getDocument();
-var K=L.getText();
-var E=L.getStart();
-var S=L.getEnd();
-var B=Math.round(this._band.dateToPixelOffset(E));
-var A=Math.round(this._band.dateToPixelOffset(S));
-var H=this._getLabelDivClassName(L);
-var I=this._frc.computeSize(K,H);
-var X=B;
-var C=X+I.width;
-var V=Math.max(C,A);
-var N=this._findFreeTrack(L,V);
-var U=Math.round(P.trackOffset+N*P.trackIncrement+T.event.tape.height);
-var Q=L.getColor();
-Q=Q!=null?Q:T.event.duration.color;
-var D=this._paintEventTape(L,N,B,A,Q,100,P,T,0);
-var O=this._paintEventLabel(L,K,X,U,I.width,I.height,T,H,R);
-var F=[D.elmt,O.elmt];
-var M=this;
-var J=function(Y,Z,a){return M._onClickDurationEvent(D.elmt,Z,L);
-};
-SimileAjax.DOM.registerEvent(D.elmt,"mousedown",J);
-SimileAjax.DOM.registerEvent(O.elmt,"mousedown",J);
-var G=this._createHighlightDiv(R,D,T,L);
-if(G!=null){F.push(G);
-}this._fireEventPaintListeners("paintedEvent",L,F);
-this._eventIdToElmt[L.getID()]=D.elmt;
-this._tracks[N]=B;
-};
-Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent=function(N,S,Y,V){var b=this._timeline.getDocument();
-var M=N.getText();
-var E=N.getStart();
-var T=N.getLatestStart();
-var W=N.getEnd();
-var a=N.getEarliestEnd();
-var C=Math.round(this._band.dateToPixelOffset(E));
-var G=Math.round(this._band.dateToPixelOffset(T));
-var A=Math.round(this._band.dateToPixelOffset(W));
-var H=Math.round(this._band.dateToPixelOffset(a));
-var J=this._getLabelDivClassName(N);
-var K=this._frc.computeSize(M,J);
-var c=G;
-var B=c+K.width;
-var Z=Math.max(B,A);
-var P=this._findFreeTrack(N,Z);
-var X=Math.round(S.trackOffset+P*S.trackIncrement+Y.event.tape.height);
-var U=N.getColor();
-U=U!=null?U:Y.event.duration.color;
-var R=this._paintEventTape(N,P,C,A,Y.event.duration.impreciseColor,Y.event.duration.impreciseOpacity,S,Y,0);
-var D=this._paintEventTape(N,P,G,H,U,100,S,Y,1);
-var Q=this._paintEventLabel(N,M,c,X,K.width,K.height,Y,J,V);
-var F=[R.elmt,D.elmt,Q.elmt];
-var O=this;
-var L=function(d,e,f){return O._onClickDurationEvent(D.elmt,e,N);
-};
-SimileAjax.DOM.registerEvent(D.elmt,"mousedown",L);
-SimileAjax.DOM.registerEvent(Q.elmt,"mousedown",L);
-var I=this._createHighlightDiv(V,D,Y,N);
-if(I!=null){F.push(I);
-}this._fireEventPaintListeners("paintedEvent",N,F);
-this._eventIdToElmt[N.getID()]=D.elmt;
-this._tracks[P]=C;
-};
-Timeline.OriginalEventPainter.prototype._encodeEventElID=function(B,A){return Timeline.EventUtils.encodeEventElID(this._timeline,this._band,B,A);
-};
-Timeline.OriginalEventPainter.prototype._findFreeTrack=function(E,A){var D=E.getTrackNum();
-if(D!=null){return D;
-}for(var C=0;
-C<this._tracks.length;
-C++){var B=this._tracks[C];
-if(B>A){break;
-}}return C;
-};
-Timeline.OriginalEventPainter.prototype._paintEventIcon=function(J,F,B,G,E,C){var I=J.getIcon();
-I=I!=null?I:G.icon;
-var H;
-if(C>0){H=G.trackOffset+F*G.trackIncrement+C+G.impreciseIconMargin;
-}else{var K=G.trackOffset+F*G.trackIncrement+G.trackHeight/2;
-H=Math.round(K-G.iconHeight/2);
-}var D=SimileAjax.Graphics.createTranslucentImage(I);
-var A=this._timeline.getDocument().createElement("div");
-A.className=this._getElClassName("timeline-event-icon",J);
-A.id=this._encodeEventElID("icon",J);
-A.style.left=B+"px";
-A.style.top=H+"px";
-A.appendChild(D);
-if(J._title!=null){A.title=J._title;
-}this._eventLayer.appendChild(A);
-return{left:B,top:H,width:G.iconWidth,height:G.iconHeight,elmt:A};
-};
-Timeline.OriginalEventPainter.prototype._paintEventLabel=function(J,K,C,H,A,L,E,F,B){var I=this._timeline.getDocument();
-var G=I.createElement("div");
-G.className=F;
-G.id=this._encodeEventElID("label",J);
-G.style.left=C+"px";
-G.style.width=A+"px";
-G.style.top=H+"px";
-G.innerHTML=K;
-if(J._title!=null){G.title=J._title;
-}var D=J.getTextColor();
-if(D==null){D=J.getColor();
-}if(D!=null){G.style.color=D;
-}if(E.event.highlightLabelBackground&&B>=0){G.style.background=this._getHighlightColor(B,E);
-}this._eventLayer.appendChild(G);
-return{left:C,top:H,width:A,height:L,elmt:G};
-};
-Timeline.OriginalEventPainter.prototype._paintEventTape=function(N,I,F,A,C,H,J,G,O){var B=A-F;
-var E=G.event.tape.height;
-var K=J.trackOffset+I*J.trackIncrement;
-var M=this._timeline.getDocument().createElement("div");
-M.className=this._getElClassName("timeline-event-tape",N);
-M.id=this._encodeEventElID("tape"+O,N);
-M.style.left=F+"px";
-M.style.width=B+"px";
-M.style.height=E+"px";
-M.style.top=K+"px";
-if(N._title!=null){M.title=N._title;
-}if(C!=null){M.style.backgroundColor=C;
-}var L=N.getTapeImage();
-var D=N.getTapeRepeat();
-D=D!=null?D:"repeat";
-if(L!=null){M.style.backgroundImage="url("+L+")";
-M.style.backgroundRepeat=D;
-}SimileAjax.Graphics.setOpacity(M,H);
-this._eventLayer.appendChild(M);
-return{left:F,top:K,width:B,height:E,elmt:M};
-};
-Timeline.OriginalEventPainter.prototype._getLabelDivClassName=function(A){return this._getElClassName("timeline-event-label",A);
-};
-Timeline.OriginalEventPainter.prototype._getElClassName=function(B,A){var C=A.getClassName();
-return B+(C!=null?(" "+C):"");
-};
-Timeline.OriginalEventPainter.prototype._getHighlightColor=function(A,C){var B=C.event.highlightColors;
-return B[Math.min(A,B.length-1)];
-};
-Timeline.OriginalEventPainter.prototype._createHighlightDiv=function(A,D,F,B){var G=null;
-if(A>=0){var E=this._timeline.getDocument();
-var C=this._getHighlightColor(A,F);
-G=E.createElement("div");
-G.className=this._getElClassName("timeline-event-highlight",B);
-G.id=this._encodeEventElID("highlight0",B);
-G.style.position="absolute";
-G.style.overflow="hidden";
-G.style.left=(D.left-2)+"px";
-G.style.width=(D.width+4)+"px";
-G.style.top=(D.top-2)+"px";
-G.style.height=(D.height+4)+"px";
-G.style.background=C;
-this._highlightLayer.appendChild(G);
-}return G;
-};
-Timeline.OriginalEventPainter.prototype._onClickInstantEvent=function(B,C,A){var D=SimileAjax.DOM.getPageCoordinates(B);
-this._showBubble(D.left+Math.ceil(B.offsetWidth/2),D.top+Math.ceil(B.offsetHeight/2),A);
-this._fireOnSelect(A.getID());
-C.cancelBubble=true;
-SimileAjax.DOM.cancelEvent(C);
-return false;
-};
-Timeline.OriginalEventPainter.prototype._onClickDurationEvent=function(D,C,B){if("pageX" in C){var A=C.pageX;
-var F=C.pageY;
-}else{var E=SimileAjax.DOM.getPageCoordinates(D);
-var A=C.offsetX+E.left;
-var F=C.offsetY+E.top;
-}this._showBubble(A,F,B);
-this._fireOnSelect(B.getID());
-C.cancelBubble=true;
-SimileAjax.DOM.cancelEvent(C);
-return false;
-};
-Timeline.OriginalEventPainter.prototype.showBubble=function(A){var B=this._eventIdToElmt[A.getID()];
-if(B){var C=SimileAjax.DOM.getPageCoordinates(B);
-this._showBubble(C.left+B.offsetWidth/2,C.top+B.offsetHeight/2,A);
-}};
-Timeline.OriginalEventPainter.prototype._showBubble=function(A,E,B){var D=document.createElement("div");
-var C=this._params.theme.event.bubble;
-B.fillInfoBubble(D,this._params.theme,this._band.getLabeller());
-SimileAjax.WindowManager.cancelPopups();
-SimileAjax.Graphics.createBubbleForContentAndPoint(D,A,E,C.width,null,C.maxHeight);
-};
-Timeline.OriginalEventPainter.prototype._fireOnSelect=function(B){for(var A=0;
-A<this._onSelectListeners.length;
-A++){this._onSelectListeners[A](B);
-}};
-Timeline.OriginalEventPainter.prototype._fireEventPaintListeners=function(D,A,C){for(var B=0;
-B<this._eventPaintListeners.length;
-B++){this._eventPaintListeners[B](this._band,D,A,C);
-}};
-
-
-/* overview-painter.js */
-Timeline.OverviewEventPainter=function(A){this._params=A;
-this._onSelectListeners=[];
-this._filterMatcher=null;
-this._highlightMatcher=null;
-};
-Timeline.OverviewEventPainter.prototype.initialize=function(B,A){this._band=B;
-this._timeline=A;
-this._eventLayer=null;
-this._highlightLayer=null;
-};
-Timeline.OverviewEventPainter.prototype.getType=function(){return"overview";
-};
-Timeline.OverviewEventPainter.prototype.addOnSelectListener=function(A){this._onSelectListeners.push(A);
-};
-Timeline.OverviewEventPainter.prototype.removeOnSelectListener=function(B){for(var A=0;
-A<this._onSelectListeners.length;
-A++){if(this._onSelectListeners[A]==B){this._onSelectListeners.splice(A,1);
-break;
-}}};
-Timeline.OverviewEventPainter.prototype.getFilterMatcher=function(){return this._filterMatcher;
-};
-Timeline.OverviewEventPainter.prototype.setFilterMatcher=function(A){this._filterMatcher=A;
-};
-Timeline.OverviewEventPainter.prototype.getHighlightMatcher=function(){return this._highlightMatcher;
-};
-Timeline.OverviewEventPainter.prototype.setHighlightMatcher=function(A){this._highlightMatcher=A;
-};
-Timeline.OverviewEventPainter.prototype.paint=function(){var B=this._band.getEventSource();
-if(B==null){return ;
-}this._prepareForPainting();
-var H=this._params.theme.event;
-var F={trackOffset:H.overviewTrack.offset,trackHeight:H.overviewTrack.height,trackGap:H.overviewTrack.gap,trackIncrement:H.overviewTrack.height+H.overviewTrack.gap};
-var C=this._band.getMinDate();
-var A=this._band.getMaxDate();
-var I=(this._filterMatcher!=null)?this._filterMatcher:function(J){return true;
-};
-var E=(this._highlightMatcher!=null)?this._highlightMatcher:function(J){return -1;
-};
-var D=B.getEventReverseIterator(C,A);
-while(D.hasNext()){var G=D.next();
-if(I(G)){this.paintEvent(G,F,this._params.theme,E(G));
-}}this._highlightLayer.style.display="block";
-this._eventLayer.style.display="block";
-this._band.updateEventTrackInfo(this._tracks.length,F.trackIncrement);
-};
-Timeline.OverviewEventPainter.prototype.softPaint=function(){};
-Timeline.OverviewEventPainter.prototype._prepareForPainting=function(){var A=this._band;
-this._tracks=[];
-if(this._highlightLayer!=null){A.removeLayerDiv(this._highlightLayer);
-}this._highlightLayer=A.createLayerDiv(105,"timeline-band-highlights");
-this._highlightLayer.style.display="none";
-if(this._eventLayer!=null){A.removeLayerDiv(this._eventLayer);
-}this._eventLayer=A.createLayerDiv(110,"timeline-band-events");
-this._eventLayer.style.display="none";
-};
-Timeline.OverviewEventPainter.prototype.paintEvent=function(B,C,D,A){if(B.isInstant()){this.paintInstantEvent(B,C,D,A);
-}else{this.paintDurationEvent(B,C,D,A);
-}};
-Timeline.OverviewEventPainter.prototype.paintInstantEvent=function(C,F,G,B){var A=C.getStart();
-var H=Math.round(this._band.dateToPixelOffset(A));
-var D=C.getColor();
-D=D!=null?D:G.event.duration.color;
-var E=this._paintEventTick(C,H,D,100,F,G);
-this._createHighlightDiv(B,E,G);
-};
-Timeline.OverviewEventPainter.prototype.paintDurationEvent=function(K,J,I,D){var A=K.getLatestStart();
-var C=K.getEarliestEnd();
-var B=Math.round(this._band.dateToPixelOffset(A));
-var E=Math.round(this._band.dateToPixelOffset(C));
-var H=0;
-for(;
-H<this._tracks.length;
-H++){if(E<this._tracks[H]){break;
-}}this._tracks[H]=E;
-var G=K.getColor();
-G=G!=null?G:I.event.duration.color;
-var F=this._paintEventTape(K,H,B,E,G,100,J,I);
-this._createHighlightDiv(D,F,I);
-};
-Timeline.OverviewEventPainter.prototype._paintEventTape=function(K,B,C,J,D,F,G,E){var H=G.trackOffset+B*G.trackIncrement;
-var A=J-C;
-var L=G.trackHeight;
-var I=this._timeline.getDocument().createElement("div");
-I.className="timeline-small-event-tape";
-I.style.left=C+"px";
-I.style.width=A+"px";
-I.style.top=H+"px";
-I.style.height=L+"px";
-if(D!=null){I.style.backgroundColor=D;
-}if(F<100){SimileAjax.Graphics.setOpacity(I,F);
-}this._eventLayer.appendChild(I);
-return{left:C,top:H,width:A,height:L,elmt:I};
-};
-Timeline.OverviewEventPainter.prototype._paintEventTick=function(J,B,D,F,G,E){var K=E.event.overviewTrack.tickHeight;
-var H=G.trackOffset-K;
-var A=1;
-var I=this._timeline.getDocument().createElement("div");
-I.className="timeline-small-event-icon";
-I.style.left=B+"px";
-I.style.top=H+"px";
-var C=J.getClassName();
-if(C){I.className+=" small-"+C;
-}if(F<100){SimileAjax.Graphics.setOpacity(I,F);
-}this._eventLayer.appendChild(I);
-return{left:B,top:H,width:A,height:K,elmt:I};
-};
-Timeline.OverviewEventPainter.prototype._createHighlightDiv=function(A,C,E){if(A>=0){var D=this._timeline.getDocument();
-var G=E.event;
-var B=G.highlightColors[Math.min(A,G.highlightColors.length-1)];
-var F=D.createElement("div");
-F.style.position="absolute";
-F.style.overflow="hidden";
-F.style.left=(C.left-1)+"px";
-F.style.width=(C.width+2)+"px";
-F.style.top=(C.top-1)+"px";
-F.style.height=(C.height+2)+"px";
-F.style.background=B;
-this._highlightLayer.appendChild(F);
-}};
-Timeline.OverviewEventPainter.prototype.showBubble=function(A){};
-
-
-/* sources.js */
-Timeline.DefaultEventSource=function(A){this._events=(A instanceof Object)?A:new SimileAjax.EventIndex();
-this._listeners=[];
-};
-Timeline.DefaultEventSource.prototype.addListener=function(A){this._listeners.push(A);
-};
-Timeline.DefaultEventSource.prototype.removeListener=function(B){for(var A=0;
-A<this._listeners.length;
-A++){if(this._listeners[A]==B){this._listeners.splice(A,1);
-break;
-}}};
-Timeline.DefaultEventSource.prototype.loadXML=function(G,A){var C=this._getBaseURL(A);
-var H=G.documentElement.getAttribute("wiki-url");
-var L=G.documentElement.getAttribute("wiki-section");
-var E=G.documentElement.getAttribute("date-time-format");
-var F=this._events.getUnit().getParser(E);
-var D=G.documentElement.firstChild;
-var I=false;
-while(D!=null){if(D.nodeType==1){var K="";
-if(D.firstChild!=null&&D.firstChild.nodeType==3){K=D.firstChild.nodeValue;
-}var B=(D.getAttribute("isDuration")===null&&D.getAttribute("durationEvent")===null)||D.getAttribute("isDuration")=="false"||D.getAttribute("durationEvent")=="false";
-var J=new Timeline.DefaultEventSource.Event({id:D.getAttribute("id"),start:F(D.getAttribute("start")),end:F(D.getAttribute("end")),latestStart:F(D.getAttribute("latestStart")),earliestEnd:F(D.getAttribute("earliestEnd")),instant:B,text:D.getAttribute("title"),description:K,image:this._resolveRelativeURL(D.getAttribute("image"),C),link:this._resolveRelativeURL(D.getAttribute("link"),C),icon:this._resolveRelativeURL(D.getAttribute("icon"),C),color:D.getAttribute("color"),textColor:D.getAttribute("textColor"),hoverText:D.getAttribute("hoverText"),classname:D.getAttribute("classname"),tapeImage:D.getAttribute("tapeImage"),tapeRepeat:D.getAttribute("tapeRepeat"),caption:D.getAttribute("caption"),eventID:D.getAttribute("eventID"),trackNum:D.getAttribute("trackNum")});
-J._node=D;
-J.getProperty=function(M){return this._node.getAttribute(M);
-};
-J.setWikiInfo(H,L);
-this._events.add(J);
-I=true;
-}D=D.nextSibling;
-}if(I){this._fire("onAddMany",[]);
-}};
-Timeline.DefaultEventSource.prototype.loadJSON=function(G,B){var D=this._getBaseURL(B);
-var J=false;
-if(G&&G.events){var I=("wikiURL" in G)?G.wikiURL:null;
-var L=("wikiSection" in G)?G.wikiSection:null;
-var E=("dateTimeFormat" in G)?G.dateTimeFormat:null;
-var H=this._events.getUnit().getParser(E);
-for(var F=0;
-F<G.events.length;
-F++){var A=G.events[F];
-var C=A.isDuration||(A.durationEvent!=null&&!A.durationEvent);
-var K=new Timeline.DefaultEventSource.Event({id:("id" in A)?A.id:undefined,start:H(A.start),end:H(A.end),latestStart:H(A.latestStart),earliestEnd:H(A.earliestEnd),instant:C,text:A.title,description:A.description,image:this._resolveRelativeURL(A.image,D),link:this._resolveRelativeURL(A.link,D),icon:this._resolveRelativeURL(A.icon,D),color:A.color,textColor:A.textColor,hoverText:A.hoverText,classname:A.classname,tapeImage:A.tapeImage,tapeRepeat:A.tapeRepeat,caption:A.caption,eventID:A.eventID,trackNum:A.trackNum});
-K._obj=A;
-K.getProperty=function(M){return this._obj[M];
-};
-K.setWikiInfo(I,L);
-this._events.add(K);
-J=true;
-}}if(J){this._fire("onAddMany",[]);
-}};
-Timeline.DefaultEventSource.prototype.loadSPARQL=function(H,A){var D=this._getBaseURL(A);
-var F="iso8601";
-var G=this._events.getUnit().getParser(F);
-if(H==null){return ;
-}var E=H.documentElement.firstChild;
-while(E!=null&&(E.nodeType!=1||E.nodeName!="results")){E=E.nextSibling;
-}var J=null;
-var M=null;
-if(E!=null){J=E.getAttribute("wiki-url");
-M=E.getAttribute("wiki-section");
-E=E.firstChild;
-}var K=false;
-while(E!=null){if(E.nodeType==1){var C={};
-var I=E.firstChild;
-while(I!=null){if(I.nodeType==1&&I.firstChild!=null&&I.firstChild.nodeType==1&&I.firstChild.firstChild!=null&&I.firstChild.firstChild.nodeType==3){C[I.getAttribute("name")]=I.firstChild.firstChild.nodeValue;
-}I=I.nextSibling;
-}if(C["start"]==null&&C["date"]!=null){C["start"]=C["date"];
-}var B=(C["isDuration"]===null&&C["durationEvent"]===null)||C["isDuration"]=="false"||C["durationEvent"]=="false";
-var L=new Timeline.DefaultEventSource.Event({id:C["id"],start:G(C["start"]),end:G(C["end"]),latestStart:G(C["latestStart"]),earliestEnd:G(C["earliestEnd"]),instant:B,text:C["title"],description:C["description"],image:this._resolveRelativeURL(C["image"],D),link:this._resolveRelativeURL(C["link"],D),icon:this._resolveRelativeURL(C["icon"],D),color:C["color"],textColor:C["textColor"],hoverText:C["hoverText"],caption:C["caption"],classname:C["classname"],tapeImage:C["tapeImage"],tapeRepeat:C["tapeRepeat"],eventID:C["eventID"],trackNum:C["trackNum"]});
-L._bindings=C;
-L.getProperty=function(N){return this._bindings[N];
-};
-L.setWikiInfo(J,M);
-this._events.add(L);
-K=true;
-}E=E.nextSibling;
-}if(K){this._fire("onAddMany",[]);
-}};
-Timeline.DefaultEventSource.prototype.add=function(A){this._events.add(A);
-this._fire("onAddOne",[A]);
-};
-Timeline.DefaultEventSource.prototype.addMany=function(B){for(var A=0;
-A<B.length;
-A++){this._events.add(B[A]);
-}this._fire("onAddMany",[]);
-};
-Timeline.DefaultEventSource.prototype.clear=function(){this._events.removeAll();
-this._fire("onClear",[]);
-};
-Timeline.DefaultEventSource.prototype.getEvent=function(A){return this._events.getEvent(A);
-};
-Timeline.DefaultEventSource.prototype.getEventIterator=function(A,B){return this._events.getIterator(A,B);
-};
-Timeline.DefaultEventSource.prototype.getEventReverseIterator=function(A,B){return this._events.getReverseIterator(A,B);
-};
-Timeline.DefaultEventSource.prototype.getAllEventIterator=function(){return this._events.getAllIterator();
-};
-Timeline.DefaultEventSource.prototype.getCount=function(){return this._events.getCount();
-};
-Timeline.DefaultEventSource.prototype.getEarliestDate=function(){return this._events.getEarliestDate();
-};
-Timeline.DefaultEventSource.prototype.getLatestDate=function(){return this._events.getLatestDate();
-};
-Timeline.DefaultEventSource.prototype._fire=function(B,A){for(var C=0;
-C<this._listeners.length;
-C++){var D=this._listeners[C];
-if(B in D){try{D[B].apply(D,A);
-}catch(E){SimileAjax.Debug.exception(E);
-}}}};
-Timeline.DefaultEventSource.prototype._getBaseURL=function(A){if(A.indexOf("://")<0){var C=this._getBaseURL(document.location.href);
-if(A.substr(0,1)=="/"){A=C.substr(0,C.indexOf("/",C.indexOf("://")+3))+A;
-}else{A=C+A;
-}}var B=A.lastIndexOf("/");
-if(B<0){return"";
-}else{return A.substr(0,B+1);
-}};
-Timeline.DefaultEventSource.prototype._resolveRelativeURL=function(A,B){if(A==null||A==""){return A;
-}else{if(A.indexOf("://")>0){return A;
-}else{if(A.substr(0,1)=="/"){return B.substr(0,B.indexOf("/",B.indexOf("://")+3))+A;
-}else{return B+A;
-}}}};
-Timeline.DefaultEventSource.Event=function(A){function D(E){return(A[E]!=null&&A[E]!="")?A[E]:null;
-}var C=A.id?A.id.trim():"";
-this._id=C.length>0?C:Timeline.EventUtils.getNewEventID();
-this._instant=A.instant||(A.end==null);
-this._start=A.start;
-this._end=(A.end!=null)?A.end:A.start;
-this._latestStart=(A.latestStart!=null)?A.latestStart:(A.instant?this._end:this._start);
-this._earliestEnd=(A.earliestEnd!=null)?A.earliestEnd:this._end;
-var B=[];
-if(this._start>this._latestStart){this._latestStart=this._start;
-B.push("start is > latestStart");
-}if(this._start>this._earliestEnd){this._earliestEnd=this._latestStart;
-B.push("start is > earliestEnd");
-}if(this._start>this._end){this._end=this._earliestEnd;
-B.push("start is > end");
-}if(this._latestStart>this._earliestEnd){this._earliestEnd=this._latestStart;
-B.push("latestStart is > earliestEnd");
-}if(this._latestStart>this._end){this._end=this._earliestEnd;
-B.push("latestStart is > end");
-}if(this._earliestEnd>this._end){this._end=this._earliestEnd;
-B.push("earliestEnd is > end");
-}this._eventID=D("eventID");
-this._text=(A.text!=null)?SimileAjax.HTML.deEntify(A.text):"";
-if(B.length>0){this._text+=" PROBLEM: "+B.join(", ");
-}this._description=SimileAjax.HTML.deEntify(A.description);
-this._image=D("image");
-this._link=D("link");
-this._title=D("hoverText");
-this._title=D("caption");
-this._icon=D("icon");
-this._color=D("color");
-this._textColor=D("textColor");
-this._classname=D("classname");
-this._tapeImage=D("tapeImage");
-this._tapeRepeat=D("tapeRepeat");
-this._trackNum=D("trackNum");
-if(this._trackNum!=null){this._trackNum=parseInt(this._trackNum);
-}this._wikiURL=null;
-this._wikiSection=null;
-};
-Timeline.DefaultEventSource.Event.prototype={getID:function(){return this._id;
-},isInstant:function(){return this._instant;
-},isImprecise:function(){return this._start!=this._latestStart||this._end!=this._earliestEnd;
-},getStart:function(){return this._start;
-},getEnd:function(){return this._end;
-},getLatestStart:function(){return this._latestStart;
-},getEarliestEnd:function(){return this._earliestEnd;
-},getEventID:function(){return this._eventID;
-},getText:function(){return this._text;
-},getDescription:function(){return this._description;
-},getImage:function(){return this._image;
-},getLink:function(){return this._link;
-},getIcon:function(){return this._icon;
-},getColor:function(){return this._color;
-},getTextColor:function(){return this._textColor;
-},getClassName:function(){return this._classname;
-},getTapeImage:function(){return this._tapeImage;
-},getTapeRepeat:function(){return this._tapeRepeat;
-},getTrackNum:function(){return this._trackNum;
-},getProperty:function(A){return null;
-},getWikiURL:function(){return this._wikiURL;
-},getWikiSection:function(){return this._wikiSection;
-},setWikiInfo:function(B,A){this._wikiURL=B;
-this._wikiSection=A;
-},fillDescription:function(A){A.innerHTML=this._description;
-},fillWikiInfo:function(D){D.style.display="none";
-if(this._wikiURL==null||this._wikiSection==null){return ;
-}var C=this.getProperty("wikiID");
-if(C==null||C.length==0){C=this.getText();
-}if(C==null||C.length==0){return ;
-}D.style.display="inline";
-C=C.replace(/\s/g,"_");
-var B=this._wikiURL+this._wikiSection.replace(/\s/g,"_")+"/"+C;
-var A=document.createElement("a");
-A.href=B;
-A.target="new";
-A.innerHTML=Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
-D.appendChild(document.createTextNode("["));
-D.appendChild(A);
-D.appendChild(document.createTextNode("]"));
-},fillTime:function(A,B){if(this._instant){if(this.isImprecise()){A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
-A.appendChild(A.ownerDocument.createElement("br"));
-A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._end)));
-}else{A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
-}}else{if(this.isImprecise()){A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)+" ~ "+B.labelPrecise(this._latestStart)));
-A.appendChild(A.ownerDocument.createElement("br"));
-A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._earliestEnd)+" ~ "+B.labelPrecise(this._end)));
-}else{A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._start)));
-A.appendChild(A.ownerDocument.createElement("br"));
-A.appendChild(A.ownerDocument.createTextNode(B.labelPrecise(this._end)));
-}}},fillInfoBubble:function(A,D,K){var L=A.ownerDocument;
-var J=this.getText();
-var H=this.getLink();
-var C=this.getImage();
-if(C!=null){var E=L.createElement("img");
-E.src=C;
-D.event.bubble.imageStyler(E);
-A.appendChild(E);
-}var M=L.createElement("div");
-var B=L.createTextNode(J);
-if(H!=null){var I=L.createElement("a");
-I.href=H;
-I.appendChild(B);
-M.appendChild(I);
-}else{M.appendChild(B);
-}D.event.bubble.titleStyler(M);
-A.appendChild(M);
-var N=L.createElement("div");
-this.fillDescription(N);
-D.event.bubble.bodyStyler(N);
-A.appendChild(N);
-var G=L.createElement("div");
-this.fillTime(G,K);
-D.event.bubble.timeStyler(G);
-A.appendChild(G);
-var F=L.createElement("div");
-this.fillWikiInfo(F);
-D.event.bubble.wikiStyler(F);
-A.appendChild(F);
-}};
-
-
-/* themes.js */
-Timeline.ClassicTheme=new Object();
-Timeline.ClassicTheme.implementations=[];
-Timeline.ClassicTheme.create=function(A){if(A==null){A=Timeline.getDefaultLocale();
-}var B=Timeline.ClassicTheme.implementations[A];
-if(B==null){B=Timeline.ClassicTheme._Impl;
-}return new B();
-};
-Timeline.ClassicTheme._Impl=function(){this.firstDayOfWeek=0;
-this.autoWidth=false;
-this.autoWidthAnimationTime=1000;
-this.ether={backgroundColors:[],highlightOpacity:50,interval:{line:{show:true,opacity:25},weekend:{opacity:30},marker:{hAlign:"Bottom",vAlign:"Right"}}};
-this.event={track:{height:10,gap:2,offset:2,autoWidthMargin:1.5},overviewTrack:{offset:20,tickHeight:6,height:2,gap:1,autoWidthMargin:5},tape:{height:4},instant:{icon:Timeline.urlPrefix+"data/timeline/dull-blue-circle.png",iconWidth:10,iconHeight:10,impreciseOpacity:20,impreciseIconMargin:3},duration:{impreciseOpacity:20},label:{backgroundOpacity:50,offsetFromLine:3},highlightColors:["#FFFF00","#FFC000","#FF0000","#0000FF"],highlightLabelBackground:false,bubble:{width:250,maxHeight:0,titleStyler:function(A){A.className="timeline-event-bubble-title";
-},bodyStyler:function(A){A.className="timeline-event-bubble-body";
-},imageStyler:function(A){A.className="timeline-event-bubble-image";
-},wikiStyler:function(A){A.className="timeline-event-bubble-wiki";
-},timeStyler:function(A){A.className="timeline-event-bubble-time";
-}}};
-this.mouseWheel="scroll";
-};
-
-
-/* timeline.js */
-Timeline.strings={};
-Timeline.HORIZONTAL=0;
-Timeline.VERTICAL=1;
-Timeline._defaultTheme=null;
-Timeline.getDefaultLocale=function(){return Timeline.clientLocale;
-};
-Timeline.create=function(D,C,B,F){if(Timeline.timelines==null){Timeline.timelines=[];
-}var A=Timeline.timelines.length;
-Timeline.timelines[A]=null;
-var E=new Timeline._Impl(D,C,B,F,A);
-Timeline.timelines[A]=E;
-return E;
-};
-Timeline.createBandInfo=function(D){var E=("theme" in D)?D.theme:Timeline.getDefaultTheme();
-var B=("eventSource" in D)?D.eventSource:null;
-var F={interval:SimileAjax.DateTime.gregorianUnitLengths[D.intervalUnit],pixelsPerInterval:D.intervalPixels,theme:E};
-if("startsOn" in D||"endsOn" in D){if("startsOn" in D){F.startsOn=D.startsOn;
-}if("endsOn" in D){F.endsOn=D.endsOn;
-}}else{F.centersOn=("date" in D)?D.date:new Date();
-}var G=new Timeline.LinearEther(F);
-var H=new Timeline.GregorianEtherPainter({unit:D.intervalUnit,multiple:("multiple" in D)?D.multiple:1,theme:E,align:("align" in D)?D.align:undefined});
-var J={showText:("showEventText" in D)?D.showEventText:true,theme:E};
-if("eventPainterParams" in D){for(var A in D.eventPainterParams){J[A]=D.eventPainterParams[A];
-}}if("trackHeight" in D){J.trackHeight=D.trackHeight;
-}if("trackGap" in D){J.trackGap=D.trackGap;
-}var I=("overview" in D&&D.overview)?"overview":("layout" in D?D.layout:"original");
-var C;
-if("eventPainter" in D){C=new D.eventPainter(J);
-}else{switch(I){case"overview":C=new Timeline.OverviewEventPainter(J);
-break;
-case"detailed":C=new Timeline.DetailedEventPainter(J);
-break;
-default:C=new Timeline.OriginalEventPainter(J);
-}}return{width:D.width,eventSource:B,timeZone:("timeZone" in D)?D.timeZone:0,ether:G,etherPainter:H,eventPainter:C,theme:E,zoomIndex:("zoomIndex" in D)?D.zoomIndex:0,zoomSteps:("zoomSteps" in D)?D.zoomSteps:null};
-};
-Timeline.createHotZoneBandInfo=function(D){var E=("theme" in D)?D.theme:Timeline.getDefaultTheme();
-var B=("eventSource" in D)?D.eventSource:null;
-var F=new Timeline.HotZoneEther({centersOn:("date" in D)?D.date:new Date(),interval:SimileAjax.DateTime.gregorianUnitLengths[D.intervalUnit],pixelsPerInterval:D.intervalPixels,zones:D.zones,theme:E});
-var G=new Timeline.HotZoneGregorianEtherPainter({unit:D.intervalUnit,zones:D.zones,theme:E,align:("align" in D)?D.align:undefined});
-var I={showText:("showEventText" in D)?D.showEventText:true,theme:E};
-if("eventPainterParams" in D){for(var A in D.eventPainterParams){I[A]=D.eventPainterParams[A];
-}}if("trackHeight" in D){I.trackHeight=D.trackHeight;
-}if("trackGap" in D){I.trackGap=D.trackGap;
-}var H=("overview" in D&&D.overview)?"overview":("layout" in D?D.layout:"original");
-var C;
-if("eventPainter" in D){C=new D.eventPainter(I);
-}else{switch(H){case"overview":C=new Timeline.OverviewEventPainter(I);
-break;
-case"detailed":C=new Timeline.DetailedEventPainter(I);
-break;
-default:C=new Timeline.OriginalEventPainter(I);
-}}return{width:D.width,eventSource:B,timeZone:("timeZone" in D)?D.timeZone:0,ether:F,etherPainter:G,eventPainter:C,theme:E,zoomIndex:("zoomIndex" in D)?D.zoomIndex:0,zoomSteps:("zoomSteps" in D)?D.zoomSteps:null};
-};
-Timeline.getDefaultTheme=function(){if(Timeline._defaultTheme==null){Timeline._defaultTheme=Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
-}return Timeline._defaultTheme;
-};
-Timeline.setDefaultTheme=function(A){Timeline._defaultTheme=A;
-};
-Timeline.loadXML=function(A,C){var D=function(G,E,F){alert("Failed to load data xml from "+A+"\n"+G);
-};
-var B=function(F){var E=F.responseXML;
-if(!E.documentElement&&F.responseStream){E.load(F.responseStream);
-}C(E,A);
-};
-SimileAjax.XmlHttp.get(A,D,B);
-};
-Timeline.loadJSON=function(url,f){var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
-};
-var fDone=function(xmlhttp){f(eval("("+xmlhttp.responseText+")"),url);
-};
-SimileAjax.XmlHttp.get(url,fError,fDone);
-};
-Timeline.getTimelineFromID=function(A){return Timeline.timelines[A];
-};
-Timeline._Impl=function(D,C,B,E,A){SimileAjax.WindowManager.initialize();
-this._containerDiv=D;
-this._bandInfos=C;
-this._orientation=B==null?Timeline.HORIZONTAL:B;
-this._unit=(E!=null)?E:SimileAjax.NativeDateUnit;
-this._starting=true;
-this._autoResizing=false;
-this.autoWidth=C&&C[0]&&C[0].theme&&C[0].theme.autoWidth;
-this.autoWidthAnimationTime=C&&C[0]&&C[0].theme&&C[0].theme.autoWidthAnimationTime;
-this.timelineID=A;
-this._initialize();
-};
-Timeline._Impl.prototype.dispose=function(){for(var A=0;
-A<this._bands.length;
-A++){this._bands[A].dispose();
-}this._bands=null;
-this._bandInfos=null;
-this._containerDiv.innerHTML="";
-Timeline.timelines[this.timelineID]=null;
-};
-Timeline._Impl.prototype.getBandCount=function(){return this._bands.length;
-};
-Timeline._Impl.prototype.getBand=function(A){return this._bands[A];
-};
-Timeline._Impl.prototype.finishedEventLoading=function(){this._autoWidthCheck(true);
-this._starting=false;
-};
-Timeline._Impl.prototype.layout=function(){this._autoWidthCheck(true);
-this._distributeWidths();
-};
-Timeline._Impl.prototype.paint=function(){for(var A=0;
-A<this._bands.length;
-A++){this._bands[A].paint();
-}};
-Timeline._Impl.prototype.getDocument=function(){return this._containerDiv.ownerDocument;
-};
-Timeline._Impl.prototype.addDiv=function(A){this._containerDiv.appendChild(A);
-};
-Timeline._Impl.prototype.removeDiv=function(A){this._containerDiv.removeChild(A);
-};
-Timeline._Impl.prototype.isHorizontal=function(){return this._orientation==Timeline.HORIZONTAL;
-};
-Timeline._Impl.prototype.isVertical=function(){return this._orientation==Timeline.VERTICAL;
-};
-Timeline._Impl.prototype.getPixelLength=function(){return this._orientation==Timeline.HORIZONTAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
-};
-Timeline._Impl.prototype.getPixelWidth=function(){return this._orientation==Timeline.VERTICAL?this._containerDiv.offsetWidth:this._containerDiv.offsetHeight;
-};
-Timeline._Impl.prototype.getUnit=function(){return this._unit;
-};
-Timeline._Impl.prototype.getWidthStyle=function(){return this._orientation==Timeline.HORIZONTAL?"height":"width";
-};
-Timeline._Impl.prototype.loadXML=function(B,D){var A=this;
-var E=function(H,F,G){alert("Failed to load data xml from "+B+"\n"+H);
-A.hideLoadingMessage();
-};
-var C=function(G){try{var F=G.responseXML;
-if(!F.documentElement&&G.responseStream){F.load(G.responseStream);
-}D(F,B);
-}finally{A.hideLoadingMessage();
-}};
-this.showLoadingMessage();
-window.setTimeout(function(){SimileAjax.XmlHttp.get(B,E,C);
-},0);
-};
-Timeline._Impl.prototype.loadJSON=function(url,f){var tl=this;
-var fError=function(statusText,status,xmlhttp){alert("Failed to load json data from "+url+"\n"+statusText);
-tl.hideLoadingMessage();
-};
-var fDone=function(xmlhttp){try{f(eval("("+xmlhttp.responseText+")"),url);
-}finally{tl.hideLoadingMessage();
-}};
-this.showLoadingMessage();
-window.setTimeout(function(){SimileAjax.XmlHttp.get(url,fError,fDone);
-},0);
-};
-Timeline._Impl.prototype._autoWidthScrollListener=function(A){A.getTimeline()._autoWidthCheck(false);
-};
-Timeline._Impl.prototype._autoWidthCheck=function(C){var E=this;
-var B=E._starting;
-var D=0;
-function A(){var H=E.getWidthStyle();
-if(B){E._containerDiv.style[H]=D+"px";
-}else{E._autoResizing=true;
-var G={};
-G[H]=D+"px";
-SimileAjax.jQuery(E._containerDiv).animate(G,E.autoWidthAnimationTime,"linear",function(){E._autoResizing=false;
-});
-}}function F(){var I=0;
-var G=E.getPixelWidth();
-if(E._autoResizing){return ;
-}for(var H=0;
-H<E._bands.length;
-H++){E._bands[H].checkAutoWidth();
-I+=E._bandInfos[H].width;
-}if(I>G||C){D=I;
-A();
-E._distributeWidths();
-}}if(!E.autoWidth){return ;
-}F();
-};
-Timeline._Impl.prototype._initialize=function(){var E=this._containerDiv;
-var G=E.ownerDocument;
-E.className=E.className.split(" ").concat("timeline-container").join(" ");
-var A=(this.isHorizontal())?"horizontal":"vertical";
-E.className+=" timeline-"+A;
-while(E.firstChild){E.removeChild(E.firstChild);
-}var B=SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix+(this.isHorizontal()?"data/timeline/copyright-vertical.png":"data/timeline/copyright.png"));
-B.className="timeline-copyright";
-B.title="Timeline &copy; SIMILE - http://simile.mit.edu/timeline/";
-SimileAjax.DOM.registerEvent(B,"click",function(){window.location="http://simile.mit.edu/timeline/";
-});
-E.appendChild(B);
-this._bands=[];
-for(var C=0;
-C<this._bandInfos.length;
-C++){var F=this._bandInfos[C];
-var D=F.bandClass||Timeline._Band;
-var H=new D(this,this._bandInfos[C],C);
-this._bands.push(H);
-}this._distributeWidths();
-for(var C=0;
-C<this._bandInfos.length;
-C++){var F=this._bandInfos[C];
-if("syncWith" in F){this._bands[C].setSyncWithBand(this._bands[F.syncWith],("highlight" in F)?F.highlight:false);
-}}if(this.autoWidth){for(var C=0;
-C<this._bands.length;
-C++){this._bands[C].addOnScrollListener(this._autoWidthScrollListener);
-}}var I=SimileAjax.Graphics.createMessageBubble(G);
-I.containerDiv.className="timeline-message-container";
-E.appendChild(I.containerDiv);
-I.contentDiv.className="timeline-message";
-I.contentDiv.innerHTML="<img src='"+Timeline.urlPrefix+"data/timeline/progress-running.gif' /> Loading...";
-this.showLoadingMessage=function(){I.containerDiv.style.display="block";
-};
-this.hideLoadingMessage=function(){I.containerDiv.style.display="none";
-};
-};
-Timeline._Impl.prototype._distributeWidths=function(){var B=this.getPixelLength();
-var A=this.getPixelWidth();
-var C=0;
-for(var E=0;
-E<this._bands.length;
-E++){var I=this._bands[E];
-var J=this._bandInfos[E];
-var F=J.width;
-var D;
-if(typeof F=="string"){var H=F.indexOf("%");
-if(H>0){var G=parseInt(F.substr(0,H));
-D=Math.round(G*A/100);
-}else{D=parseInt(F);
-}}else{D=F;
-}I.setBandShiftAndWidth(C,D);
-I.setViewLength(B);
-C+=D;
-}};
-Timeline._Impl.prototype.zoom=function(G,B,F,D){var C=new RegExp("^timeline-band-([0-9]+)$");
-var E=null;
-var A=C.exec(D.id);
-if(A){E=parseInt(A[1]);
-}if(E!=null){this._bands[E].zoom(G,B,F,D);
-}this.paint();
-};
-
-
-/* units.js */
-Timeline.NativeDateUnit=new Object();
-Timeline.NativeDateUnit.createLabeller=function(A,B){return new Timeline.GregorianDateLabeller(A,B);
-};
-Timeline.NativeDateUnit.makeDefaultValue=function(){return new Date();
-};
-Timeline.NativeDateUnit.cloneValue=function(A){return new Date(A.getTime());
-};
-Timeline.NativeDateUnit.getParser=function(A){if(typeof A=="string"){A=A.toLowerCase();
-}return(A=="iso8601"||A=="iso 8601")?Timeline.DateTime.parseIso8601DateTime:Timeline.DateTime.parseGregorianDateTime;
-};
-Timeline.NativeDateUnit.parseFromObject=function(A){return Timeline.DateTime.parseGregorianDateTime(A);
-};
-Timeline.NativeDateUnit.toNumber=function(A){return A.getTime();
-};
-Timeline.NativeDateUnit.fromNumber=function(A){return new Date(A);
-};
-Timeline.NativeDateUnit.compare=function(D,C){var B,A;
-if(typeof D=="object"){B=D.getTime();
-}else{B=Number(D);
-}if(typeof C=="object"){A=C.getTime();
-}else{A=Number(C);
-}return B-A;
-};
-Timeline.NativeDateUnit.earlier=function(B,A){return Timeline.NativeDateUnit.compare(B,A)<0?B:A;
-};
-Timeline.NativeDateUnit.later=function(B,A){return Timeline.NativeDateUnit.compare(B,A)>0?B:A;
-};
-Timeline.NativeDateUnit.change=function(A,B){return new Date(A.getTime()+B);
-};
-
-/******** end of simile-timeline-bundle.js ********/
+/*=================================================
+ *
+ * Coding standards:
+ *
+ * We aim towards Douglas Crockford's Javascript conventions.
+ * See:  http://javascript.crockford.com/code.html
+ * See also: http://www.crockford.com/javascript/javascript.html
+ *
+ * That said, this JS code was written before some recent JS
+ * support libraries became widely used or available.
+ * In particular, the _ character is used to indicate a class function or
+ * variable that should be considered private to the class.
+ *
+ * The code mostly uses accessor methods for getting/setting the private
+ * class variables.
+ *
+ * Over time, we'd like to formalize the convention by using support libraries
+ * which enforce privacy in objects.
+ *
+ * We also want to use jslint:  http://www.jslint.com/
+ *
+ *
+ *==================================================
+ */
+
+
+
+/*==================================================
+ *  Timeline VERSION
+ *==================================================
+ */
+// Note: version is also stored in the build.xml file
+Timeline.version = 'pre 2.4.0';  // use format 'pre 1.2.3' for trunk versions
+Timeline.ajax_lib_version = SimileAjax.version;
+Timeline.display_version = Timeline.version + ' (with Ajax lib ' + Timeline.ajax_lib_version + ')';
+ // cf method Timeline.writeVersion
+
+/*==================================================
+ *  Timeline
+ *==================================================
+ */
+Timeline.strings = {}; // localization string tables
+Timeline.HORIZONTAL = 0;
+Timeline.VERTICAL = 1;
+Timeline._defaultTheme = null;
+
+Timeline.getDefaultLocale = function() {
+    return Timeline.clientLocale;
+};
+
+Timeline.create = function(elmt, bandInfos, orientation, unit) {
+    if (Timeline.timelines == null) {
+        Timeline.timelines = [];
+        // Timeline.timelines array can have null members--Timelines that
+        // once existed on the page, but were later disposed of.
+    }
+
+    var timelineID = Timeline.timelines.length;
+    Timeline.timelines[timelineID] = null; // placeholder until we have the object
+    var new_tl = new Timeline._Impl(elmt, bandInfos, orientation, unit,
+      timelineID);
+    Timeline.timelines[timelineID] = new_tl;
+    return new_tl;
+};
+
+Timeline.createBandInfo = function(params) {
+    var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+    var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+    var etherParams = {
+        interval:           SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],
+        pixelsPerInterval: params.intervalPixels,
+	theme: theme
+    };
+    if ('startsOn' in params || 'endsOn' in params) {
+	if ('startsOn' in params) {
+	    etherParams.startsOn = params.startsOn;
+	}
+	if ('endsOn' in params) {
+	    etherParams.endsOn = params.endsOn;
+	}
+    } else {
+	etherParams.centersOn = ("date" in params) ? params.date : new Date();
+    }
+    var ether = new Timeline.LinearEther(etherParams);
+
+    var etherPainter = new Timeline.GregorianEtherPainter({
+        unit:       params.intervalUnit,
+        multiple:   ("multiple" in params) ? params.multiple : 1,
+        theme:      theme,
+        align:      ("align" in params) ? params.align : undefined
+    });
+
+    var eventPainterParams = {
+        showText:   ("showEventText" in params) ? params.showEventText : true,
+        theme:      theme
+    };
+    // pass in custom parameters for the event painter
+    if ("eventPainterParams" in params) {
+        for (var prop in params.eventPainterParams) {
+            eventPainterParams[prop] = params.eventPainterParams[prop];
+        }
+    }
+
+    if ("trackHeight" in params) {
+        eventPainterParams.trackHeight = params.trackHeight;
+    }
+    if ("trackGap" in params) {
+        eventPainterParams.trackGap = params.trackGap;
+    }
+
+    var layout = ("overview" in params && params.overview) ? "overview" : ("layout" in params ? params.layout : "original");
+    var eventPainter;
+    if ("eventPainter" in params) {
+        eventPainter = new params.eventPainter(eventPainterParams);
+    } else {
+        switch (layout) {
+            case "overview" :
+                eventPainter = new Timeline.OverviewEventPainter(eventPainterParams);
+                break;
+            case "detailed" :
+                eventPainter = new Timeline.DetailedEventPainter(eventPainterParams);
+                break;
+            default:
+                eventPainter = new Timeline.OriginalEventPainter(eventPainterParams);
+        }
+    }
+
+    return {
+        width:          params.width,
+        eventSource:    eventSource,
+        timeZone:       ("timeZone" in params) ? params.timeZone : 0,
+        ether:          ether,
+        etherPainter:   etherPainter,
+        eventPainter:   eventPainter,
+        theme:          theme,
+        zoomIndex:      ("zoomIndex" in params) ? params.zoomIndex : 0,
+        zoomSteps:      ("zoomSteps" in params) ? params.zoomSteps : null
+    };
+};
+
+Timeline.createHotZoneBandInfo = function(params) {
+    var theme = ("theme" in params) ? params.theme : Timeline.getDefaultTheme();
+
+    var eventSource = ("eventSource" in params) ? params.eventSource : null;
+
+    var ether = new Timeline.HotZoneEther({
+        centersOn:          ("date" in params) ? params.date : new Date(),
+        interval:           SimileAjax.DateTime.gregorianUnitLengths[params.intervalUnit],
+        pixelsPerInterval:  params.intervalPixels,
+        zones:              params.zones,
+        theme:              theme
+    });
+
+    var etherPainter = new Timeline.HotZoneGregorianEtherPainter({
+        unit:       params.intervalUnit,
+        zones:      params.zones,
+        theme:      theme,
+        align:      ("align" in params) ? params.align : undefined
+    });
+
+    var eventPainterParams = {
+        showText:   ("showEventText" in params) ? params.showEventText : true,
+        theme:      theme
+    };
+    // pass in custom parameters for the event painter
+    if ("eventPainterParams" in params) {
+        for (var prop in params.eventPainterParams) {
+            eventPainterParams[prop] = params.eventPainterParams[prop];
+        }
+    }
+    if ("trackHeight" in params) {
+        eventPainterParams.trackHeight = params.trackHeight;
+    }
+    if ("trackGap" in params) {
+        eventPainterParams.trackGap = params.trackGap;
+    }
+
+    var layout = ("overview" in params && params.overview) ? "overview" : ("layout" in params ? params.layout : "original");
+    var eventPainter;
+    if ("eventPainter" in params) {
+        eventPainter = new params.eventPainter(eventPainterParams);
+    } else {
+        switch (layout) {
+            case "overview" :
+                eventPainter = new Timeline.OverviewEventPainter(eventPainterParams);
+                break;
+            case "detailed" :
+                eventPainter = new Timeline.DetailedEventPainter(eventPainterParams);
+                break;
+            default:
+                eventPainter = new Timeline.OriginalEventPainter(eventPainterParams);
+        }
+    }
+    return {
+        width:          params.width,
+        eventSource:    eventSource,
+        timeZone:       ("timeZone" in params) ? params.timeZone : 0,
+        ether:          ether,
+        etherPainter:   etherPainter,
+        eventPainter:   eventPainter,
+        theme:          theme,
+        zoomIndex:      ("zoomIndex" in params) ? params.zoomIndex : 0,
+        zoomSteps:      ("zoomSteps" in params) ? params.zoomSteps : null
+    };
+};
+
+Timeline.getDefaultTheme = function() {
+    if (Timeline._defaultTheme == null) {
+        Timeline._defaultTheme = Timeline.ClassicTheme.create(Timeline.getDefaultLocale());
+    }
+    return Timeline._defaultTheme;
+};
+
+Timeline.setDefaultTheme = function(theme) {
+    Timeline._defaultTheme = theme;
+};
+
+Timeline.loadXML = function(url, f) {
+    var fError = function(statusText, status, xmlhttp) {
+        alert("Failed to load data xml from " + url + "\n" + statusText);
+    };
+    var fDone = function(xmlhttp) {
+        var xml = xmlhttp.responseXML;
+        if (!xml.documentElement && xmlhttp.responseStream) {
+            xml.load(xmlhttp.responseStream);
+        }
+        f(xml, url);
+    };
+    SimileAjax.XmlHttp.get(url, fError, fDone);
+};
+
+
+Timeline.loadJSON = function(url, f) {
+    var fError = function(statusText, status, xmlhttp) {
+        alert("Failed to load json data from " + url + "\n" + statusText);
+    };
+    var fDone = function(xmlhttp) {
+        f(eval('(' + xmlhttp.responseText + ')'), url);
+    };
+    SimileAjax.XmlHttp.get(url, fError, fDone);
+};
+
+Timeline.getTimelineFromID = function(timelineID) {
+    return Timeline.timelines[timelineID];
+};
+
+// Write the current Timeline version as the contents of element with id el_id
+Timeline.writeVersion = function(el_id) {
+  document.getElementById(el_id).innerHTML = this.display_version;
+};
+
+
+
+/*==================================================
+ *  Timeline Implementation object
+ *==================================================
+ */
+Timeline._Impl = function(elmt, bandInfos, orientation, unit, timelineID) {
+    SimileAjax.WindowManager.initialize();
+
+    this._containerDiv = elmt;
+
+    this._bandInfos = bandInfos;
+    this._orientation = orientation == null ? Timeline.HORIZONTAL : orientation;
+    this._unit = (unit != null) ? unit : SimileAjax.NativeDateUnit;
+    this._starting = true; // is the Timeline being created? Used by autoWidth
+                           // functions
+    this._autoResizing = false;
+
+    // autoWidth is a "public" property of the Timeline object
+    this.autoWidth = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+                     bandInfos[0].theme.autoWidth;
+    this.autoWidthAnimationTime = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+                     bandInfos[0].theme.autoWidthAnimationTime;
+    this.timelineID = timelineID; // also public attribute
+    this.timeline_start = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+                     bandInfos[0].theme.timeline_start;
+    this.timeline_stop  = bandInfos && bandInfos[0] && bandInfos[0].theme &&
+                     bandInfos[0].theme.timeline_stop;
+    this.timeline_at_start = false; // already at start or stop? Then won't
+    this.timeline_at_stop = false;  // try to move further in the wrong direction
+
+    this._initialize();
+};
+
+//
+// Public functions used by client sw
+//
+Timeline._Impl.prototype.dispose = function() {
+    for (var i = 0; i < this._bands.length; i++) {
+        this._bands[i].dispose();
+    }
+    this._bands = null;
+    this._bandInfos = null;
+    this._containerDiv.innerHTML = "";
+    // remove from array of Timelines
+    Timeline.timelines[this.timelineID] = null;
+};
+
+Timeline._Impl.prototype.getBandCount = function() {
+    return this._bands.length;
+};
+
+Timeline._Impl.prototype.getBand = function(index) {
+    return this._bands[index];
+};
+
+Timeline._Impl.prototype.finishedEventLoading = function() {
+    // Called by client after events have been loaded into Timeline
+    // Only used if the client has set autoWidth
+    // Sets width to Timeline's requested amount and will shrink down the div if
+    // need be.
+    this._autoWidthCheck(true);
+    this._starting = false;
+};
+
+Timeline._Impl.prototype.layout = function() {
+    // called by client when browser is resized
+    this._autoWidthCheck(true);
+    this._distributeWidths();
+};
+
+Timeline._Impl.prototype.paint = function() {
+    for (var i = 0; i < this._bands.length; i++) {
+        this._bands[i].paint();
+    }
+};
+
+Timeline._Impl.prototype.getDocument = function() {
+    return this._containerDiv.ownerDocument;
+};
+
+Timeline._Impl.prototype.addDiv = function(div) {
+    this._containerDiv.appendChild(div);
+};
+
+Timeline._Impl.prototype.removeDiv = function(div) {
+    this._containerDiv.removeChild(div);
+};
+
+Timeline._Impl.prototype.isHorizontal = function() {
+    return this._orientation == Timeline.HORIZONTAL;
+};
+
+Timeline._Impl.prototype.isVertical = function() {
+    return this._orientation == Timeline.VERTICAL;
+};
+
+Timeline._Impl.prototype.getPixelLength = function() {
+    return this._orientation == Timeline.HORIZONTAL ?
+        this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
+};
+
+Timeline._Impl.prototype.getPixelWidth = function() {
+    return this._orientation == Timeline.VERTICAL ?
+        this._containerDiv.offsetWidth : this._containerDiv.offsetHeight;
+};
+
+Timeline._Impl.prototype.getUnit = function() {
+    return this._unit;
+};
+
+Timeline._Impl.prototype.getWidthStyle = function() {
+    // which element.style attribute should be changed to affect Timeline's "width"
+    return this._orientation == Timeline.HORIZONTAL ? 'height' : 'width';
+};
+
+Timeline._Impl.prototype.loadXML = function(url, f) {
+    var tl = this;
+
+
+    var fError = function(statusText, status, xmlhttp) {
+        alert("Failed to load data xml from " + url + "\n" + statusText);
+        tl.hideLoadingMessage();
+    };
+    var fDone = function(xmlhttp) {
+        try {
+            var xml = xmlhttp.responseXML;
+            if (!xml.documentElement && xmlhttp.responseStream) {
+                xml.load(xmlhttp.responseStream);
+            }
+            f(xml, url);
+        } finally {
+            tl.hideLoadingMessage();
+        }
+    };
+
+    this.showLoadingMessage();
+    window.setTimeout(function() { SimileAjax.XmlHttp.get(url, fError, fDone); }, 0);
+};
+
+Timeline._Impl.prototype.loadJSON = function(url, f) {
+    var tl = this;
+
+    var fError = function(statusText, status, xmlhttp) {
+        alert("Failed to load json data from " + url + "\n" + statusText);
+        tl.hideLoadingMessage();
+    };
+    var fDone = function(xmlhttp) {
+        try {
+            f(eval('(' + xmlhttp.responseText + ')'), url);
+        } finally {
+            tl.hideLoadingMessage();
+        }
+    };
+
+    this.showLoadingMessage();
+    window.setTimeout(function() { SimileAjax.XmlHttp.get(url, fError, fDone); }, 0);
+};
+
+
+//
+// Private functions used by Timeline object functions
+//
+
+Timeline._Impl.prototype._autoWidthScrollListener = function(band) {
+    band.getTimeline()._autoWidthCheck(false);
+};
+
+// called to re-calculate auto width and adjust the overall Timeline div if needed
+Timeline._Impl.prototype._autoWidthCheck = function(okToShrink) {
+    var timeline = this; // this Timeline
+    var immediateChange = timeline._starting;
+    var newWidth = 0;
+
+    function changeTimelineWidth() {
+        var widthStyle = timeline.getWidthStyle();
+        if (immediateChange) {
+            timeline._containerDiv.style[widthStyle] = newWidth + 'px';
+        } else {
+        	  // animate change
+        	  timeline._autoResizing = true;
+        	  var animateParam ={};
+        	  animateParam[widthStyle] = newWidth + 'px';
+
+        	  SimileAjax.jQuery(timeline._containerDiv).animate(
+        	      animateParam, timeline.autoWidthAnimationTime,
+        	      'linear', function(){timeline._autoResizing = false;});
+        }
+    }
+
+    function checkTimelineWidth() {
+        var targetWidth = 0; // the new desired width
+        var currentWidth = timeline.getPixelWidth();
+
+        if (timeline._autoResizing) {
+        	return; // early return
+        }
+
+        // compute targetWidth
+        for (var i = 0; i < timeline._bands.length; i++) {
+            timeline._bands[i].checkAutoWidth();
+            targetWidth += timeline._bandInfos[i].width;
+        }
+
+        if (targetWidth > currentWidth || okToShrink) {
+            // yes, let's change the size
+            newWidth = targetWidth;
+            changeTimelineWidth();
+            timeline._distributeWidths();
+        }
+    }
+
+    // function's mainline
+    if (!timeline.autoWidth) {
+        return; // early return
+    }
+
+    checkTimelineWidth();
+};
+
+Timeline._Impl.prototype._initialize = function() {
+    var containerDiv = this._containerDiv;
+    var doc = containerDiv.ownerDocument;
+
+    containerDiv.className =
+        containerDiv.className.split(" ").concat("timeline-container").join(" ");
+
+	/*
+	 * Set css-class on container div that will define orientation
+	 */
+	var orientation = (this.isHorizontal()) ? 'horizontal' : 'vertical'
+	containerDiv.className +=' timeline-'+orientation;
+
+
+    while (containerDiv.firstChild) {
+        containerDiv.removeChild(containerDiv.firstChild);
+    }
+
+    /*
+     *  inserting copyright and link to simile
+     */
+    var elmtCopyright = SimileAjax.Graphics.createTranslucentImage(Timeline.urlPrefix + (this.isHorizontal() ? "images/copyright-vertical.png" : "images/copyright.png"));
+    elmtCopyright.className = "timeline-copyright";
+    elmtCopyright.title = "Timeline copyright SIMILE - www.code.google.com/p/simile-widgets/";
+    SimileAjax.DOM.registerEvent(elmtCopyright, "click", function() { window.location = "http://www.simile-widgets.org/"; });
+    containerDiv.appendChild(elmtCopyright);
+
+    /*
+     *  creating bands
+     */
+    this._bands = [];
+    for (var i = 0; i < this._bandInfos.length; i++) {
+        var bandInfo = this._bandInfos[i];
+        var bandClass = bandInfo.bandClass || Timeline._Band;
+        var band = new bandClass(this, this._bandInfos[i], i);
+        this._bands.push(band);
+    }
+    this._distributeWidths();
+
+    /*
+     *  sync'ing bands
+     */
+    for (var i = 0; i < this._bandInfos.length; i++) {
+        var bandInfo = this._bandInfos[i];
+        if ("syncWith" in bandInfo) {
+            this._bands[i].setSyncWithBand(
+                this._bands[bandInfo.syncWith],
+                ("highlight" in bandInfo) ? bandInfo.highlight : false
+            );
+        }
+    }
+
+
+    if (this.autoWidth) {
+        for (var i = 0; i < this._bands.length; i++) {
+            this._bands[i].addOnScrollListener(this._autoWidthScrollListener);
+        }
+    }
+
+
+    /*
+     *  creating loading UI
+     */
+    var message = SimileAjax.Graphics.createMessageBubble(doc);
+    message.containerDiv.className = "timeline-message-container";
+    containerDiv.appendChild(message.containerDiv);
+
+    message.contentDiv.className = "timeline-message";
+    message.contentDiv.innerHTML = "<img src='" + Timeline.urlPrefix + "images/progress-running.gif' /> Loading...";
+
+    this.showLoadingMessage = function() { message.containerDiv.style.display = "block"; };
+    this.hideLoadingMessage = function() { message.containerDiv.style.display = "none"; };
+};
+
+Timeline._Impl.prototype._distributeWidths = function() {
+    var length = this.getPixelLength();
+    var width = this.getPixelWidth();
+    var cumulativeWidth = 0;
+
+    for (var i = 0; i < this._bands.length; i++) {
+        var band = this._bands[i];
+        var bandInfos = this._bandInfos[i];
+        var widthString = bandInfos.width;
+        var bandWidth;
+
+        if (typeof widthString == 'string') {
+          var x =  widthString.indexOf("%");
+          if (x > 0) {
+              var percent = parseInt(widthString.substr(0, x));
+              bandWidth = Math.round(percent * width / 100);
+          } else {
+              bandWidth = parseInt(widthString);
+          }
+        } else {
+        	// was given an integer
+        	bandWidth = widthString;
+        }
+
+        band.setBandShiftAndWidth(cumulativeWidth, bandWidth);
+        band.setViewLength(length);
+
+        cumulativeWidth += bandWidth;
+    }
+};
+
+Timeline._Impl.prototype.shiftOK = function(index, shift) {
+    // Returns true if the proposed shift is ok
+    //
+    // Positive shift means going back in time
+    var going_back = shift > 0,
+        going_forward = shift < 0;
+
+    // Is there an edge?
+    if ((going_back    && this.timeline_start == null) ||
+        (going_forward && this.timeline_stop  == null) ||
+        (shift == 0)) {
+        return (true);  // early return
+    }
+
+    // If any of the bands has noted that it is changing the others,
+    // then this shift is a secondary shift in reaction to the real shift,
+    // which already happened. In such cases, ignore it. (The issue is
+    // that a positive original shift can cause a negative secondary shift,
+    // as the bands adjust.)
+    var secondary_shift = false;
+    for (var i = 0; i < this._bands.length && !secondary_shift; i++) {
+       secondary_shift = this._bands[i].busy();
+    }
+    if (secondary_shift) {
+        return(true); // early return
+    }
+
+    // If we are already at an edge, then don't even think about going any further
+    if ((going_back    && this.timeline_at_start) ||
+        (going_forward && this.timeline_at_stop)) {
+        return (false);  // early return
+    }
+
+    // Need to check all the bands
+    var ok = false; // return value
+    // If any of the bands will be or are showing an ok date, then let the shift proceed.
+    for (var i = 0; i < this._bands.length && !ok; i++) {
+       var band = this._bands[i];
+       if (going_back) {
+           ok = (i == index ? band.getMinVisibleDateAfterDelta(shift) : band.getMinVisibleDate())
+                >= this.timeline_start;
+       } else {
+           ok = (i == index ? band.getMaxVisibleDateAfterDelta(shift) : band.getMaxVisibleDate())
+                <= this.timeline_stop;
+       }
+    }
+
+    // process results
+    if (going_back) {
+       this.timeline_at_start = !ok;
+       this.timeline_at_stop = false;
+    } else {
+       this.timeline_at_stop = !ok;
+       this.timeline_at_start = false;
+    }
+    // This is where you could have an effect once per hitting an
+    // edge of the Timeline. Eg jitter the Timeline
+    //if (!ok) {
+        //alert(going_back ? "At beginning" : "At end");
+    //}
+    return (ok);
+};
+
+Timeline._Impl.prototype.zoom = function (zoomIn, x, y, target) {
+  var matcher = new RegExp("^timeline-band-([0-9]+)$");
+  var bandIndex = null;
+
+  var result = matcher.exec(target.id);
+  if (result) {
+    bandIndex = parseInt(result[1]);
+  }
+
+  if (bandIndex != null) {
+    this._bands[bandIndex].zoom(zoomIn, x, y, target);
+  }
+
+  this.paint();
+};
+
+/*=================================================
+ *
+ * Coding standards:
+ *
+ * We aim towards Douglas Crockford's Javascript conventions.
+ * See:  http://javascript.crockford.com/code.html
+ * See also: http://www.crockford.com/javascript/javascript.html
+ *
+ * That said, this JS code was written before some recent JS
+ * support libraries became widely used or available.
+ * In particular, the _ character is used to indicate a class function or
+ * variable that should be considered private to the class.
+ *
+ * The code mostly uses accessor methods for getting/setting the private
+ * class variables.
+ *
+ * Over time, we'd like to formalize the convention by using support libraries
+ * which enforce privacy in objects.
+ *
+ * We also want to use jslint:  http://www.jslint.com/
+ *
+ *
+ *==================================================
+ */
+
+
+
+/*==================================================
+ *  Band
+ *==================================================
+ */
+Timeline._Band = function(timeline, bandInfo, index) {
+    // hack for easier subclassing
+    if (timeline !== undefined) {
+        this.initialize(timeline, bandInfo, index);
+    }
+};
+
+Timeline._Band.prototype.initialize = function(timeline, bandInfo, index) {
+    // Set up the band's object
+
+    // Munge params: If autoWidth is on for the Timeline, then ensure that
+    // bandInfo.width is an integer
+    if (timeline.autoWidth && typeof bandInfo.width == 'string') {
+        bandInfo.width = bandInfo.width.indexOf("%") > -1 ? 0 : parseInt(bandInfo.width);
+    }
+
+    this._timeline = timeline;
+    this._bandInfo = bandInfo;
+
+    this._index = index;
+
+    this._locale = ("locale" in bandInfo) ? bandInfo.locale : Timeline.getDefaultLocale();
+    this._timeZone = ("timeZone" in bandInfo) ? bandInfo.timeZone : 0;
+    this._labeller = ("labeller" in bandInfo) ? bandInfo.labeller :
+        (("createLabeller" in timeline.getUnit()) ?
+            timeline.getUnit().createLabeller(this._locale, this._timeZone) :
+            new Timeline.GregorianDateLabeller(this._locale, this._timeZone));
+    this._theme = bandInfo.theme;
+    this._zoomIndex = ("zoomIndex" in bandInfo) ? bandInfo.zoomIndex : 0;
+    this._zoomSteps = ("zoomSteps" in bandInfo) ? bandInfo.zoomSteps : null;
+
+    this._dragging = false;
+    this._changing = false;
+    this._originalScrollSpeed = 5; // pixels
+    this._scrollSpeed = this._originalScrollSpeed;
+    this._viewOrthogonalOffset= 0; // vertical offset if the timeline is horizontal, and vice versa
+    this._onScrollListeners = [];
+
+    var b = this;
+    this._syncWithBand = null;
+    this._syncWithBandHandler = function(band) {
+        b._onHighlightBandScroll();
+    };
+    this._selectorListener = function(band) {
+        b._onHighlightBandScroll();
+    };
+
+    /*
+     *  Install a textbox to capture keyboard events
+     */
+    var inputDiv = this._timeline.getDocument().createElement("div");
+    inputDiv.className = "timeline-band-input";
+    this._timeline.addDiv(inputDiv);
+
+    this._keyboardInput = document.createElement("input");
+    this._keyboardInput.type = "text";
+    inputDiv.appendChild(this._keyboardInput);
+    SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keydown", this, "_onKeyDown");
+    SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keyup", this, "_onKeyUp");
+
+    /*
+     *  The band's outer most div that slides with respect to the timeline's div
+     */
+    this._div = this._timeline.getDocument().createElement("div");
+    this._div.id = "timeline-band-" + index;
+    this._div.className = "timeline-band timeline-band-" + index;
+    this._timeline.addDiv(this._div);
+
+    SimileAjax.DOM.registerEventWithObject(this._div, "mousedown", this, "_onMouseDown");
+    SimileAjax.DOM.registerEventWithObject(this._div, "mousemove", this, "_onMouseMove");
+    SimileAjax.DOM.registerEventWithObject(this._div, "mouseup", this, "_onMouseUp");
+    SimileAjax.DOM.registerEventWithObject(this._div, "mouseout", this, "_onMouseOut");
+    SimileAjax.DOM.registerEventWithObject(this._div, "dblclick", this, "_onDblClick");
+
+    var mouseWheel = this._theme!= null ? this._theme.mouseWheel : 'scroll'; // theme is not always defined
+    if (mouseWheel === 'zoom' || mouseWheel === 'scroll' || this._zoomSteps) {
+        // capture mouse scroll
+        if (SimileAjax.Platform.browser.isFirefox) {
+            SimileAjax.DOM.registerEventWithObject(this._div, "DOMMouseScroll", this, "_onMouseScroll");
+        } else {
+            SimileAjax.DOM.registerEventWithObject(this._div, "mousewheel", this, "_onMouseScroll");
+        }
+    }
+
+    /*
+     *  The inner div that contains layers
+     */
+    this._innerDiv = this._timeline.getDocument().createElement("div");
+    this._innerDiv.className = "timeline-band-inner";
+    this._div.appendChild(this._innerDiv);
+
+    /*
+     *  Initialize parts of the band
+     */
+    this._ether = bandInfo.ether;
+    bandInfo.ether.initialize(this, timeline);
+
+    this._etherPainter = bandInfo.etherPainter;
+    bandInfo.etherPainter.initialize(this, timeline);
+
+    this._eventSource = bandInfo.eventSource;
+    if (this._eventSource) {
+        this._eventListener = {
+            onAddMany: function() { b._onAddMany(); },
+            onClear:   function() { b._onClear(); }
+        }
+        this._eventSource.addListener(this._eventListener);
+    }
+
+    this._eventPainter = bandInfo.eventPainter;
+    this._eventTracksNeeded = 0;   // set by painter via updateEventTrackInfo
+    this._eventTrackIncrement = 0;
+    bandInfo.eventPainter.initialize(this, timeline);
+
+    this._decorators = ("decorators" in bandInfo) ? bandInfo.decorators : [];
+    for (var i = 0; i < this._decorators.length; i++) {
+        this._decorators[i].initialize(this, timeline);
+    }
+};
+
+Timeline._Band.SCROLL_MULTIPLES = 5;
+
+Timeline._Band.prototype.dispose = function() {
+    this.closeBubble();
+
+    if (this._eventSource) {
+        this._eventSource.removeListener(this._eventListener);
+        this._eventListener = null;
+        this._eventSource = null;
+    }
+
+    this._timeline = null;
+    this._bandInfo = null;
+
+    this._labeller = null;
+    this._ether = null;
+    this._etherPainter = null;
+    this._eventPainter = null;
+    this._decorators = null;
+
+    this._onScrollListeners = null;
+    this._syncWithBandHandler = null;
+    this._selectorListener = null;
+
+    this._div = null;
+    this._innerDiv = null;
+    this._keyboardInput = null;
+};
+
+Timeline._Band.prototype.addOnScrollListener = function(listener) {
+    this._onScrollListeners.push(listener);
+};
+
+Timeline._Band.prototype.removeOnScrollListener = function(listener) {
+    for (var i = 0; i < this._onScrollListeners.length; i++) {
+        if (this._onScrollListeners[i] == listener) {
+            this._onScrollListeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+Timeline._Band.prototype.setSyncWithBand = function(band, highlight) {
+    if (this._syncWithBand) {
+        this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler);
+    }
+
+    this._syncWithBand = band;
+    this._syncWithBand.addOnScrollListener(this._syncWithBandHandler);
+    this._highlight = highlight;
+    this._positionHighlight();
+};
+
+Timeline._Band.prototype.getLocale = function() {
+    return this._locale;
+};
+
+Timeline._Band.prototype.getTimeZone = function() {
+    return this._timeZone;
+};
+
+Timeline._Band.prototype.getLabeller = function() {
+    return this._labeller;
+};
+
+Timeline._Band.prototype.getIndex = function() {
+    return this._index;
+};
+
+Timeline._Band.prototype.getEther = function() {
+    return this._ether;
+};
+
+Timeline._Band.prototype.getEtherPainter = function() {
+    return this._etherPainter;
+};
+
+Timeline._Band.prototype.getEventSource = function() {
+    return this._eventSource;
+};
+
+Timeline._Band.prototype.getEventPainter = function() {
+    return this._eventPainter;
+};
+
+Timeline._Band.prototype.getTimeline = function() {
+    return this._timeline;
+};
+
+// Autowidth support
+Timeline._Band.prototype.updateEventTrackInfo = function(tracks, increment) {
+    this._eventTrackIncrement = increment; // doesn't vary for a specific band
+
+    if (tracks > this._eventTracksNeeded) {
+        this._eventTracksNeeded = tracks;
+    }
+};
+
+// Autowidth support
+Timeline._Band.prototype.checkAutoWidth = function() {
+    // if a new (larger) width is needed by the band
+    // then: a) updates the band's bandInfo.width
+    //
+    // desiredWidth for the band is
+    //   (number of tracks + margin) * track increment
+    if (! this._timeline.autoWidth) {
+      return; // early return
+    }
+
+    var overviewBand = this._eventPainter.getType() == 'overview';
+    var margin = overviewBand ?
+       this._theme.event.overviewTrack.autoWidthMargin :
+       this._theme.event.track.autoWidthMargin;
+    var desiredWidth = Math.ceil((this._eventTracksNeeded + margin) *
+                       this._eventTrackIncrement);
+    // add offset amount (additional margin)
+    desiredWidth += overviewBand ? this._theme.event.overviewTrack.offset :
+                                   this._theme.event.track.offset;
+    var bandInfo = this._bandInfo;
+
+    if (desiredWidth != bandInfo.width) {
+        bandInfo.width = desiredWidth;
+    }
+};
+
+Timeline._Band.prototype.layout = function() {
+    this.paint();
+};
+
+Timeline._Band.prototype.paint = function() {
+    this._etherPainter.paint();
+    this._paintDecorators();
+    this._paintEvents();
+};
+
+Timeline._Band.prototype.softLayout = function() {
+    this.softPaint();
+};
+
+Timeline._Band.prototype.softPaint = function() {
+    this._etherPainter.softPaint();
+    this._softPaintDecorators();
+    this._softPaintEvents();
+};
+
+Timeline._Band.prototype.setBandShiftAndWidth = function(shift, width) {
+    var inputDiv = this._keyboardInput.parentNode;
+    var middle = shift + Math.floor(width / 2);
+    if (this._timeline.isHorizontal()) {
+        this._div.style.top = shift + "px";
+        this._div.style.height = width + "px";
+
+        inputDiv.style.top = middle + "px";
+        inputDiv.style.left = "-1em";
+    } else {
+        this._div.style.left = shift + "px";
+        this._div.style.width = width + "px";
+
+        inputDiv.style.left = middle + "px";
+        inputDiv.style.top = "-1em";
+    }
+};
+
+Timeline._Band.prototype.getViewWidth = function() {
+    if (this._timeline.isHorizontal()) {
+        return this._div.offsetHeight;
+    } else {
+        return this._div.offsetWidth;
+    }
+};
+
+Timeline._Band.prototype.setViewLength = function(length) {
+    this._viewLength = length;
+    this._recenterDiv();
+    this._onChanging();
+};
+
+Timeline._Band.prototype.getViewLength = function() {
+    return this._viewLength;
+};
+
+Timeline._Band.prototype.getTotalViewLength = function() {
+    return Timeline._Band.SCROLL_MULTIPLES * this._viewLength;
+};
+
+Timeline._Band.prototype.getViewOffset = function() {
+    return this._viewOffset;
+};
+
+Timeline._Band.prototype.getMinDate = function() {
+    return this._ether.pixelOffsetToDate(this._viewOffset);
+};
+
+Timeline._Band.prototype.getMaxDate = function() {
+    return this._ether.pixelOffsetToDate(this._viewOffset + Timeline._Band.SCROLL_MULTIPLES * this._viewLength);
+};
+
+Timeline._Band.prototype.getMinVisibleDate = function() {
+    return this._ether.pixelOffsetToDate(0);
+};
+
+Timeline._Band.prototype.getMinVisibleDateAfterDelta = function(delta) {
+    return this._ether.pixelOffsetToDate(delta);
+};
+
+Timeline._Band.prototype.getMaxVisibleDate = function() {
+    // Max date currently visible on band
+    return this._ether.pixelOffsetToDate(this._viewLength);
+};
+
+Timeline._Band.prototype.getMaxVisibleDateAfterDelta = function(delta) {
+    // Max date visible on band after delta px view change is applied
+    return this._ether.pixelOffsetToDate(this._viewLength + delta);
+};
+
+Timeline._Band.prototype.getCenterVisibleDate = function() {
+    return this._ether.pixelOffsetToDate(this._viewLength / 2);
+};
+
+Timeline._Band.prototype.setMinVisibleDate = function(date) {
+    if (!this._changing) {
+        this._moveEther(Math.round(-this._ether.dateToPixelOffset(date)));
+    }
+};
+
+Timeline._Band.prototype.setMaxVisibleDate = function(date) {
+    if (!this._changing) {
+        this._moveEther(Math.round(this._viewLength - this._ether.dateToPixelOffset(date)));
+    }
+};
+
+Timeline._Band.prototype.setCenterVisibleDate = function(date) {
+    if (!this._changing) {
+        this._moveEther(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)));
+    }
+};
+
+Timeline._Band.prototype.dateToPixelOffset = function(date) {
+    return this._ether.dateToPixelOffset(date) - this._viewOffset;
+};
+
+Timeline._Band.prototype.pixelOffsetToDate = function(pixels) {
+    return this._ether.pixelOffsetToDate(pixels + this._viewOffset);
+};
+
+Timeline._Band.prototype.getViewOrthogonalOffset = function() {
+    return this._viewOrthogonalOffset;
+};
+
+Timeline._Band.prototype.setViewOrthogonalOffset = function(offset) {
+    this._viewOrthogonalOffset = Math.max(0, offset);
+};
+
+Timeline._Band.prototype.createLayerDiv = function(zIndex, className) {
+    var div = this._timeline.getDocument().createElement("div");
+    div.className = "timeline-band-layer" + (typeof className == "string" ? (" " + className) : "");
+    div.style.zIndex = zIndex;
+    this._innerDiv.appendChild(div);
+
+    var innerDiv = this._timeline.getDocument().createElement("div");
+    innerDiv.className = "timeline-band-layer-inner";
+    if (SimileAjax.Platform.browser.isIE) {
+        innerDiv.style.cursor = "move";
+    } else {
+        innerDiv.style.cursor = "-moz-grab";
+    }
+    div.appendChild(innerDiv);
+
+    return innerDiv;
+};
+
+Timeline._Band.prototype.removeLayerDiv = function(div) {
+    this._innerDiv.removeChild(div.parentNode);
+};
+
+Timeline._Band.prototype.scrollToCenter = function(date, f) {
+    var pixelOffset = this._ether.dateToPixelOffset(date);
+    if (pixelOffset < -this._viewLength / 2) {
+        this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset + this._viewLength));
+    } else if (pixelOffset > 3 * this._viewLength / 2) {
+        this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset - this._viewLength));
+    }
+    this._autoScroll(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)), f);
+};
+
+Timeline._Band.prototype.showBubbleForEvent = function(eventID) {
+    var evt = this.getEventSource().getEvent(eventID);
+    if (evt) {
+        var self = this;
+        this.scrollToCenter(evt.getStart(), function() {
+            self._eventPainter.showBubble(evt);
+        });
+    }
+};
+
+Timeline._Band.prototype.zoom = function(zoomIn, x, y, target) {
+  if (!this._zoomSteps) {
+    // zoom disabled
+    return;
+  }
+
+  // shift the x value by our offset
+  x += this._viewOffset;
+
+  var zoomDate = this._ether.pixelOffsetToDate(x);
+  var netIntervalChange = this._ether.zoom(zoomIn);
+  this._etherPainter.zoom(netIntervalChange);
+
+  // shift our zoom date to the far left
+  this._moveEther(Math.round(-this._ether.dateToPixelOffset(zoomDate)));
+  // then shift it back to where the mouse was
+  this._moveEther(x);
+};
+
+Timeline._Band.prototype._onMouseDown = function(innerFrame, evt, target) {
+    this.closeBubble();
+
+    this._dragging = true;
+    this._dragX = evt.clientX;
+    this._dragY = evt.clientY;
+};
+
+Timeline._Band.prototype._onMouseMove = function(innerFrame, evt, target) {
+    if (this._dragging) {
+        var diffX = evt.clientX - this._dragX;
+        var diffY = evt.clientY - this._dragY;
+
+        this._dragX = evt.clientX;
+        this._dragY = evt.clientY;
+
+        if (this._timeline.isHorizontal()) {
+            this._moveEther(diffX, diffY);
+        } else {
+            this._moveEther(diffY, diffX);
+        }
+        this._positionHighlight();
+    }
+};
+
+Timeline._Band.prototype._onMouseUp = function(innerFrame, evt, target) {
+    this._dragging = false;
+    this._keyboardInput.focus();
+};
+
+Timeline._Band.prototype._onMouseOut = function(innerFrame, evt, target) {
+    var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+    coords.x += this._viewOffset;
+    if (coords.x < 0 || coords.x > innerFrame.offsetWidth ||
+        coords.y < 0 || coords.y > innerFrame.offsetHeight) {
+        this._dragging = false;
+    }
+};
+
+Timeline._Band.prototype._onMouseScroll = function(innerFrame, evt, target) {
+  var now = new Date();
+  now = now.getTime();
+
+  if (!this._lastScrollTime || ((now - this._lastScrollTime) > 50)) {
+    // limit 1 scroll per 200ms due to FF3 sending multiple events back to back
+    this._lastScrollTime = now;
+
+    var delta = 0;
+    if (evt.wheelDelta) {
+      delta = evt.wheelDelta/120;
+    } else if (evt.detail) {
+      delta = -evt.detail/3;
+    }
+
+    // either scroll or zoom
+    var mouseWheel = this._theme.mouseWheel;
+
+    if (this._zoomSteps || mouseWheel === 'zoom') {
+      var loc = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+      if (delta != 0) {
+        var zoomIn;
+        if (delta > 0)
+          zoomIn = true;
+        if (delta < 0)
+          zoomIn = false;
+        // call zoom on the timeline so we could zoom multiple bands if desired
+        this._timeline.zoom(zoomIn, loc.x, loc.y, innerFrame);
+      }
+    }
+    else if (mouseWheel === 'scroll') {
+    	var move_amt = 50 * (delta < 0 ? -1 : 1);
+      this._moveEther(move_amt);
+    }
+  }
+
+  // prevent bubble
+  if (evt.stopPropagation) {
+    evt.stopPropagation();
+  }
+  evt.cancelBubble = true;
+
+  // prevent the default action
+  if (evt.preventDefault) {
+    evt.preventDefault();
+  }
+  evt.returnValue = false;
+};
+
+Timeline._Band.prototype._onDblClick = function(innerFrame, evt, target) {
+    var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame);
+    var distance = coords.x - (this._viewLength / 2 - this._viewOffset);
+
+    this._autoScroll(-distance);
+};
+
+Timeline._Band.prototype._onKeyDown = function(keyboardInput, evt, target) {
+    if (!this._dragging) {
+        switch (evt.keyCode) {
+        case 27: // ESC
+            break;
+        case 37: // left arrow
+        case 38: // up arrow
+            this._scrollSpeed = Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+            this._moveEther(this._scrollSpeed);
+            break;
+        case 39: // right arrow
+        case 40: // down arrow
+            this._scrollSpeed = -Math.min(50, Math.abs(this._scrollSpeed * 1.05));
+            this._moveEther(this._scrollSpeed);
+            break;
+        default:
+            return true;
+        }
+        this.closeBubble();
+
+        SimileAjax.DOM.cancelEvent(evt);
+        return false;
+    }
+    return true;
+};
+
+Timeline._Band.prototype._onKeyUp = function(keyboardInput, evt, target) {
+    if (!this._dragging) {
+        this._scrollSpeed = this._originalScrollSpeed;
+
+        switch (evt.keyCode) {
+        case 35: // end
+            this.setCenterVisibleDate(this._eventSource.getLatestDate());
+            break;
+        case 36: // home
+            this.setCenterVisibleDate(this._eventSource.getEarliestDate());
+            break;
+        case 33: // page up
+            this._autoScroll(this._timeline.getPixelLength());
+            break;
+        case 34: // page down
+            this._autoScroll(-this._timeline.getPixelLength());
+            break;
+        default:
+            return true;
+        }
+
+        this.closeBubble();
+
+        SimileAjax.DOM.cancelEvent(evt);
+        return false;
+    }
+    return true;
+};
+
+Timeline._Band.prototype._autoScroll = function(distance, f) {
+    var b = this;
+    var a = SimileAjax.Graphics.createAnimation(
+        function(abs, diff) {
+            b._moveEther(diff);
+        },
+        0,
+        distance,
+        1000,
+        f
+    );
+    a.run();
+};
+
+Timeline._Band.prototype._moveEther = function(shift, orthogonalShift) {
+    if (orthogonalShift === undefined) {
+        orthogonalShift = 0;
+    }
+
+    this.closeBubble();
+
+    // A positive shift means back in time
+    // Check that we're not moving beyond Timeline's limits
+    if (!this._timeline.shiftOK(this._index, shift)) {
+        return; // early return
+    }
+
+    this._viewOffset += shift;
+    this._viewOrthogonalOffset = Math.min(0, this._viewOrthogonalOffset + orthogonalShift);
+
+    this._ether.shiftPixels(-shift);
+    if (this._timeline.isHorizontal()) {
+        this._div.style.left = this._viewOffset + "px";
+    } else {
+        this._div.style.top = this._viewOffset + "px";
+    }
+
+    if (this._viewOffset > -this._viewLength * 0.5 ||
+        this._viewOffset < -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1.5)) {
+
+        this._recenterDiv();
+    } else {
+        this.softLayout();
+    }
+
+    this._onChanging();
+}
+
+Timeline._Band.prototype._onChanging = function() {
+    this._changing = true;
+
+    this._fireOnScroll();
+    this._setSyncWithBandDate();
+
+    this._changing = false;
+};
+
+Timeline._Band.prototype.busy = function() {
+    // Is this band busy changing other bands?
+    return(this._changing);
+};
+
+Timeline._Band.prototype._fireOnScroll = function() {
+    for (var i = 0; i < this._onScrollListeners.length; i++) {
+        this._onScrollListeners[i](this);
+    }
+};
+
+Timeline._Band.prototype._setSyncWithBandDate = function() {
+    if (this._syncWithBand) {
+        var centerDate = this._ether.pixelOffsetToDate(this.getViewLength() / 2);
+        this._syncWithBand.setCenterVisibleDate(centerDate);
+    }
+};
+
+Timeline._Band.prototype._onHighlightBandScroll = function() {
+    if (this._syncWithBand) {
+        var centerDate = this._syncWithBand.getCenterVisibleDate();
+        var centerPixelOffset = this._ether.dateToPixelOffset(centerDate);
+
+        this._moveEther(Math.round(this._viewLength / 2 - centerPixelOffset));
+
+        if (this._highlight) {
+            this._etherPainter.setHighlight(
+                this._syncWithBand.getMinVisibleDate(),
+                this._syncWithBand.getMaxVisibleDate());
+        }
+    }
+};
+
+Timeline._Band.prototype._onAddMany = function() {
+    this._paintEvents();
+};
+
+Timeline._Band.prototype._onClear = function() {
+    this._paintEvents();
+};
+
+Timeline._Band.prototype._positionHighlight = function() {
+    if (this._syncWithBand) {
+        var startDate = this._syncWithBand.getMinVisibleDate();
+        var endDate = this._syncWithBand.getMaxVisibleDate();
+
+        if (this._highlight) {
+            this._etherPainter.setHighlight(startDate, endDate);
+        }
+    }
+};
+
+Timeline._Band.prototype._recenterDiv = function() {
+    this._viewOffset = -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1) / 2;
+    if (this._timeline.isHorizontal()) {
+        this._div.style.left = this._viewOffset + "px";
+        this._div.style.width = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+    } else {
+        this._div.style.top = this._viewOffset + "px";
+        this._div.style.height = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px";
+    }
+    this.layout();
+};
+
+Timeline._Band.prototype._paintEvents = function() {
+    this._eventPainter.paint();
+};
+
+Timeline._Band.prototype._softPaintEvents = function() {
+    this._eventPainter.softPaint();
+};
+
+Timeline._Band.prototype._paintDecorators = function() {
+    for (var i = 0; i < this._decorators.length; i++) {
+        this._decorators[i].paint();
+    }
+};
+
+Timeline._Band.prototype._softPaintDecorators = function() {
+    for (var i = 0; i < this._decorators.length; i++) {
+        this._decorators[i].softPaint();
+    }
+};
+
+Timeline._Band.prototype.closeBubble = function() {
+    SimileAjax.WindowManager.cancelPopups();
+};
+/*==================================================
+ *  Classic Theme
+ *==================================================
+ */
+
+
+
+Timeline.ClassicTheme = new Object();
+
+Timeline.ClassicTheme.implementations = [];
+
+Timeline.ClassicTheme.create = function(locale) {
+    if (locale == null) {
+        locale = Timeline.getDefaultLocale();
+    }
+
+    var f = Timeline.ClassicTheme.implementations[locale];
+    if (f == null) {
+        f = Timeline.ClassicTheme._Impl;
+    }
+    return new f();
+};
+
+Timeline.ClassicTheme._Impl = function() {
+    this.firstDayOfWeek = 0; // Sunday
+
+    // Note: Many styles previously set here are now set using CSS
+    //       The comments indicate settings controlled by CSS, not
+    //       lines to be un-commented.
+    //
+    //
+    // Attributes autoWidth, autoWidthAnimationTime, timeline_start
+    // and timeline_stop must be set on the first band's theme.
+    // The other attributes can be set differently for each
+    // band by using different themes for the bands.
+    this.autoWidth = false; // Should the Timeline automatically grow itself, as
+                            // needed when too many events for the available width
+                            // are painted on the visible part of the Timeline?
+    this.autoWidthAnimationTime = 500; // mSec
+    this.timeline_start = null; // Setting a date, eg new Date(Date.UTC(2008,0,17,20,00,00,0)) will prevent the
+                                // Timeline from being moved to anytime before the date.
+    this.timeline_stop = null;  // Use for setting a maximum date. The Timeline will not be able
+                                // to be moved to anytime after this date.
+    this.ether = {
+        backgroundColors: [
+        //    "#EEE",
+        //    "#DDD",
+        //    "#CCC",
+        //    "#AAA"
+        ],
+     //   highlightColor:     "white",
+        highlightOpacity:   50,
+        interval: {
+            line: {
+                show:       true,
+                opacity:    25
+               // color:      "#aaa",
+            },
+            weekend: {
+                opacity:    30
+              //  color:      "#FFFFE0",
+            },
+            marker: {
+                hAlign:     "Bottom",
+                vAlign:     "Right"
+                                        /*
+                hBottomStyler: function(elmt) {
+                    elmt.className = "timeline-ether-marker-bottom";
+                },
+                hBottomEmphasizedStyler: function(elmt) {
+                    elmt.className = "timeline-ether-marker-bottom-emphasized";
+                },
+                hTopStyler: function(elmt) {
+                    elmt.className = "timeline-ether-marker-top";
+                },
+                hTopEmphasizedStyler: function(elmt) {
+                    elmt.className = "timeline-ether-marker-top-emphasized";
+                },
+                */
+
+
+               /*
+                                  vRightStyler: function(elmt) {
+                    elmt.className = "timeline-ether-marker-right";
+                },
+                vRightEmphasizedStyler: function(elmt) {
+                    elmt.className = "timeline-ether-marker-right-emphasized";
+                },
+                vLeftStyler: function(elmt) {
+                    elmt.className = "timeline-ether-marker-left";
+                },
+                vLeftEmphasizedStyler:function(elmt) {
+                    elmt.className = "timeline-ether-marker-left-emphasized";
+                }
+                */
+            }
+        }
+    };
+
+    this.event = {
+        track: {
+                   height: 10, // px. You will need to change the track
+                               //     height if you change the tape height.
+                      gap:  2, // px. Gap between tracks
+                   offset:  2, // px. top margin above tapes
+          autoWidthMargin:  1.5
+          /* autoWidthMargin is only used if autoWidth (see above) is true.
+             The autoWidthMargin setting is used to set how close the bottom of the
+             lowest track is to the edge of the band's div. The units are total track
+             width (tape + label + gap). A min of 0.5 is suggested. Use this setting to
+             move the bottom track's tapes above the axis markers, if needed for your
+             Timeline.
+          */
+        },
+        overviewTrack: {
+                  offset: 20, // px -- top margin above tapes
+              tickHeight:  6, // px
+                  height:  2, // px
+                     gap:  1, // px
+         autoWidthMargin:  5 // This attribute is only used if autoWidth (see above) is true.
+        },
+        tape: {
+            height:         4 // px. For thicker tapes, remember to change track height too.
+        },
+        instant: {
+                           icon: Timeline.urlPrefix + "images/dull-blue-circle.png",
+                                 // default icon. Icon can also be specified per event
+                      iconWidth: 10,
+                     iconHeight: 10,
+               impreciseOpacity: 20, // opacity of the tape when durationEvent is false
+            impreciseIconMargin: 3   // A tape and an icon are painted for imprecise instant
+                                     // events. This attribute is the margin between the
+                                     // bottom of the tape and the top of the icon in that
+                                     // case.
+    //        color:             "#58A0DC",
+    //        impreciseColor:    "#58A0DC",
+        },
+        duration: {
+            impreciseOpacity: 20 // tape opacity for imprecise part of duration events
+      //      color:            "#58A0DC",
+      //      impreciseColor:   "#58A0DC",
+        },
+        label: {
+            backgroundOpacity: 50,// only used in detailed painter
+               offsetFromLine:  3 // px left margin amount from icon's right edge
+      //      backgroundColor:   "white",
+      //      lineColor:         "#58A0DC",
+        },
+        highlightColors: [  // Use with getEventPainter().setHighlightMatcher
+                            // See webapp/examples/examples.js
+            "#FFFF00",
+            "#FFC000",
+            "#FF0000",
+            "#0000FF"
+        ],
+        highlightLabelBackground: false, // When highlighting an event, also change the event's label background?
+        bubble: {
+            width:          250, // px
+            maxHeight:        0, // px Maximum height of bubbles. 0 means no max height.
+                                 // scrollbar will be added for taller bubbles
+            titleStyler: function(elmt) {
+                elmt.className = "timeline-event-bubble-title";
+            },
+            bodyStyler: function(elmt) {
+                elmt.className = "timeline-event-bubble-body";
+            },
+            imageStyler: function(elmt) {
+                elmt.className = "timeline-event-bubble-image";
+            },
+            wikiStyler: function(elmt) {
+                elmt.className = "timeline-event-bubble-wiki";
+            },
+            timeStyler: function(elmt) {
+                elmt.className = "timeline-event-bubble-time";
+            }
+        }
+    };
+
+    this.mouseWheel = 'scroll'; // 'default', 'zoom', 'scroll'
+};/*==================================================
+ *  An "ether" is a object that maps date/time to pixel coordinates.
+ *==================================================
+ */
+
+/*==================================================
+ *  Linear Ether
+ *==================================================
+ */
+
+Timeline.LinearEther = function(params) {
+    this._params = params;
+    this._interval = params.interval;
+    this._pixelsPerInterval = params.pixelsPerInterval;
+};
+
+Timeline.LinearEther.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+    this._unit = timeline.getUnit();
+
+    if ("startsOn" in this._params) {
+        this._start = this._unit.parseFromObject(this._params.startsOn);
+    } else if ("endsOn" in this._params) {
+        this._start = this._unit.parseFromObject(this._params.endsOn);
+        this.shiftPixels(-this._timeline.getPixelLength());
+    } else if ("centersOn" in this._params) {
+        this._start = this._unit.parseFromObject(this._params.centersOn);
+        this.shiftPixels(-this._timeline.getPixelLength() / 2);
+    } else {
+        this._start = this._unit.makeDefaultValue();
+        this.shiftPixels(-this._timeline.getPixelLength() / 2);
+    }
+};
+
+Timeline.LinearEther.prototype.setDate = function(date) {
+    this._start = this._unit.cloneValue(date);
+};
+
+Timeline.LinearEther.prototype.shiftPixels = function(pixels) {
+    var numeric = this._interval * pixels / this._pixelsPerInterval;
+    this._start = this._unit.change(this._start, numeric);
+};
+
+Timeline.LinearEther.prototype.dateToPixelOffset = function(date) {
+    var numeric = this._unit.compare(date, this._start);
+    return this._pixelsPerInterval * numeric / this._interval;
+};
+
+Timeline.LinearEther.prototype.pixelOffsetToDate = function(pixels) {
+    var numeric = pixels * this._interval / this._pixelsPerInterval;
+    return this._unit.change(this._start, numeric);
+};
+
+Timeline.LinearEther.prototype.zoom = function(zoomIn) {
+  var netIntervalChange = 0;
+  var currentZoomIndex = this._band._zoomIndex;
+  var newZoomIndex = currentZoomIndex;
+
+  if (zoomIn && (currentZoomIndex > 0)) {
+    newZoomIndex = currentZoomIndex - 1;
+  }
+
+  if (!zoomIn && (currentZoomIndex < (this._band._zoomSteps.length - 1))) {
+    newZoomIndex = currentZoomIndex + 1;
+  }
+
+  this._band._zoomIndex = newZoomIndex;
+  this._interval =
+    SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+  this._pixelsPerInterval = this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+  netIntervalChange = this._band._zoomSteps[newZoomIndex].unit -
+    this._band._zoomSteps[currentZoomIndex].unit;
+
+  return netIntervalChange;
+};
+
+
+/*==================================================
+ *  Hot Zone Ether
+ *==================================================
+ */
+
+Timeline.HotZoneEther = function(params) {
+    this._params = params;
+    this._interval = params.interval;
+    this._pixelsPerInterval = params.pixelsPerInterval;
+    this._theme = params.theme;
+};
+
+Timeline.HotZoneEther.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+    this._unit = timeline.getUnit();
+
+    this._zones = [{
+        startTime:  Number.NEGATIVE_INFINITY,
+        endTime:    Number.POSITIVE_INFINITY,
+        magnify:    1
+    }];
+    var params = this._params;
+    for (var i = 0; i < params.zones.length; i++) {
+        var zone = params.zones[i];
+        var zoneStart = this._unit.parseFromObject(zone.start);
+        var zoneEnd =   this._unit.parseFromObject(zone.end);
+
+        for (var j = 0; j < this._zones.length && this._unit.compare(zoneEnd, zoneStart) > 0; j++) {
+            var zone2 = this._zones[j];
+
+            if (this._unit.compare(zoneStart, zone2.endTime) < 0) {
+                if (this._unit.compare(zoneStart, zone2.startTime) > 0) {
+                    this._zones.splice(j, 0, {
+                        startTime:   zone2.startTime,
+                        endTime:     zoneStart,
+                        magnify:     zone2.magnify
+                    });
+                    j++;
+
+                    zone2.startTime = zoneStart;
+                }
+
+                if (this._unit.compare(zoneEnd, zone2.endTime) < 0) {
+                    this._zones.splice(j, 0, {
+                        startTime:  zoneStart,
+                        endTime:    zoneEnd,
+                        magnify:    zone.magnify * zone2.magnify
+                    });
+                    j++;
+
+                    zone2.startTime = zoneEnd;
+                    zoneStart = zoneEnd;
+                } else {
+                    zone2.magnify *= zone.magnify;
+                    zoneStart = zone2.endTime;
+                }
+            } // else, try the next existing zone
+        }
+    }
+
+    if ("startsOn" in this._params) {
+        this._start = this._unit.parseFromObject(this._params.startsOn);
+    } else if ("endsOn" in this._params) {
+        this._start = this._unit.parseFromObject(this._params.endsOn);
+        this.shiftPixels(-this._timeline.getPixelLength());
+    } else if ("centersOn" in this._params) {
+        this._start = this._unit.parseFromObject(this._params.centersOn);
+        this.shiftPixels(-this._timeline.getPixelLength() / 2);
+    } else {
+        this._start = this._unit.makeDefaultValue();
+        this.shiftPixels(-this._timeline.getPixelLength() / 2);
+    }
+};
+
+Timeline.HotZoneEther.prototype.setDate = function(date) {
+    this._start = this._unit.cloneValue(date);
+};
+
+Timeline.HotZoneEther.prototype.shiftPixels = function(pixels) {
+    this._start = this.pixelOffsetToDate(pixels);
+};
+
+Timeline.HotZoneEther.prototype.dateToPixelOffset = function(date) {
+    return this._dateDiffToPixelOffset(this._start, date);
+};
+
+Timeline.HotZoneEther.prototype.pixelOffsetToDate = function(pixels) {
+    return this._pixelOffsetToDate(pixels, this._start);
+};
+
+Timeline.HotZoneEther.prototype.zoom = function(zoomIn) {
+  var netIntervalChange = 0;
+  var currentZoomIndex = this._band._zoomIndex;
+  var newZoomIndex = currentZoomIndex;
+
+  if (zoomIn && (currentZoomIndex > 0)) {
+    newZoomIndex = currentZoomIndex - 1;
+  }
+
+  if (!zoomIn && (currentZoomIndex < (this._band._zoomSteps.length - 1))) {
+    newZoomIndex = currentZoomIndex + 1;
+  }
+
+  this._band._zoomIndex = newZoomIndex;
+  this._interval =
+    SimileAjax.DateTime.gregorianUnitLengths[this._band._zoomSteps[newZoomIndex].unit];
+  this._pixelsPerInterval = this._band._zoomSteps[newZoomIndex].pixelsPerInterval;
+  netIntervalChange = this._band._zoomSteps[newZoomIndex].unit -
+    this._band._zoomSteps[currentZoomIndex].unit;
+
+  return netIntervalChange;
+};
+
+Timeline.HotZoneEther.prototype._dateDiffToPixelOffset = function(fromDate, toDate) {
+    var scale = this._getScale();
+    var fromTime = fromDate;
+    var toTime = toDate;
+
+    var pixels = 0;
+    if (this._unit.compare(fromTime, toTime) < 0) {
+        var z = 0;
+        while (z < this._zones.length) {
+            if (this._unit.compare(fromTime, this._zones[z].endTime) < 0) {
+                break;
+            }
+            z++;
+        }
+
+        while (this._unit.compare(fromTime, toTime) < 0) {
+            var zone = this._zones[z];
+            var toTime2 = this._unit.earlier(toTime, zone.endTime);
+
+            pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
+
+            fromTime = toTime2;
+            z++;
+        }
+    } else {
+        var z = this._zones.length - 1;
+        while (z >= 0) {
+            if (this._unit.compare(fromTime, this._zones[z].startTime) > 0) {
+                break;
+            }
+            z--;
+        }
+
+        while (this._unit.compare(fromTime, toTime) > 0) {
+            var zone = this._zones[z];
+            var toTime2 = this._unit.later(toTime, zone.startTime);
+
+            pixels += (this._unit.compare(toTime2, fromTime) / (scale / zone.magnify));
+
+            fromTime = toTime2;
+            z--;
+        }
+    }
+    return pixels;
+};
+
+Timeline.HotZoneEther.prototype._pixelOffsetToDate = function(pixels, fromDate) {
+    var scale = this._getScale();
+    var time = fromDate;
+    if (pixels > 0) {
+        var z = 0;
+        while (z < this._zones.length) {
+            if (this._unit.compare(time, this._zones[z].endTime) < 0) {
+                break;
+            }
+            z++;
+        }
+
+        while (pixels > 0) {
+            var zone = this._zones[z];
+            var scale2 = scale / zone.magnify;
+
+            if (zone.endTime == Number.POSITIVE_INFINITY) {
+                time = this._unit.change(time, pixels * scale2);
+                pixels = 0;
+            } else {
+                var pixels2 = this._unit.compare(zone.endTime, time) / scale2;
+                if (pixels2 > pixels) {
+                    time = this._unit.change(time, pixels * scale2);
+                    pixels = 0;
+                } else {
+                    time = zone.endTime;
+                    pixels -= pixels2;
+                }
+            }
+            z++;
+        }
+    } else {
+        var z = this._zones.length - 1;
+        while (z >= 0) {
+            if (this._unit.compare(time, this._zones[z].startTime) > 0) {
+                break;
+            }
+            z--;
+        }
+
+        pixels = -pixels;
+        while (pixels > 0) {
+            var zone = this._zones[z];
+            var scale2 = scale / zone.magnify;
+
+            if (zone.startTime == Number.NEGATIVE_INFINITY) {
+                time = this._unit.change(time, -pixels * scale2);
+                pixels = 0;
+            } else {
+                var pixels2 = this._unit.compare(time, zone.startTime) / scale2;
+                if (pixels2 > pixels) {
+                    time = this._unit.change(time, -pixels * scale2);
+                    pixels = 0;
+                } else {
+                    time = zone.startTime;
+                    pixels -= pixels2;
+                }
+            }
+            z--;
+        }
+    }
+    return time;
+};
+
+Timeline.HotZoneEther.prototype._getScale = function() {
+    return this._interval / this._pixelsPerInterval;
+};
+/*==================================================
+ *  Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.GregorianEtherPainter = function(params) {
+    this._params = params;
+    this._theme = params.theme;
+    this._unit = params.unit;
+    this._multiple = ("multiple" in params) ? params.multiple : 1;
+};
+
+Timeline.GregorianEtherPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._backgroundLayer = band.createLayerDiv(0);
+    this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+    this._backgroundLayer.className = 'timeline-ether-bg';
+  //  this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+
+    this._markerLayer = null;
+    this._lineLayer = null;
+
+    var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
+        this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+    var showLine = ("showLine" in this._params) ? this._params.showLine :
+        this._theme.ether.interval.line.show;
+
+    this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+        this._timeline, this._band, this._theme, align, showLine);
+
+    this._highlight = new Timeline.EtherHighlight(
+        this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.GregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+    this._highlight.position(startDate, endDate);
+}
+
+Timeline.GregorianEtherPainter.prototype.paint = function() {
+    if (this._markerLayer) {
+        this._band.removeLayerDiv(this._markerLayer);
+    }
+    this._markerLayer = this._band.createLayerDiv(100);
+    this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+    this._markerLayer.style.display = "none";
+
+    if (this._lineLayer) {
+        this._band.removeLayerDiv(this._lineLayer);
+    }
+    this._lineLayer = this._band.createLayerDiv(1);
+    this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+    this._lineLayer.style.display = "none";
+
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    var timeZone = this._band.getTimeZone();
+    var labeller = this._band.getLabeller();
+
+    SimileAjax.DateTime.roundDownToInterval(minDate, this._unit, timeZone, this._multiple, this._theme.firstDayOfWeek);
+
+    var p = this;
+    var incrementDate = function(date) {
+        for (var i = 0; i < p._multiple; i++) {
+            SimileAjax.DateTime.incrementByInterval(date, p._unit);
+        }
+    };
+
+    while (minDate.getTime() < maxDate.getTime()) {
+        this._intervalMarkerLayout.createIntervalMarker(
+            minDate, labeller, this._unit, this._markerLayer, this._lineLayer);
+
+        incrementDate(minDate);
+    }
+    this._markerLayer.style.display = "block";
+    this._lineLayer.style.display = "block";
+};
+
+Timeline.GregorianEtherPainter.prototype.softPaint = function() {
+};
+
+Timeline.GregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
+  if (netIntervalChange != 0) {
+    this._unit += netIntervalChange;
+  }
+};
+
+
+/*==================================================
+ *  Hot Zone Gregorian Ether Painter
+ *==================================================
+ */
+
+Timeline.HotZoneGregorianEtherPainter = function(params) {
+    this._params = params;
+    this._theme = params.theme;
+
+    this._zones = [{
+        startTime:  Number.NEGATIVE_INFINITY,
+        endTime:    Number.POSITIVE_INFINITY,
+        unit:       params.unit,
+        multiple:   1
+    }];
+    for (var i = 0; i < params.zones.length; i++) {
+        var zone = params.zones[i];
+        var zoneStart = SimileAjax.DateTime.parseGregorianDateTime(zone.start).getTime();
+        var zoneEnd = SimileAjax.DateTime.parseGregorianDateTime(zone.end).getTime();
+
+        for (var j = 0; j < this._zones.length && zoneEnd > zoneStart; j++) {
+            var zone2 = this._zones[j];
+
+            if (zoneStart < zone2.endTime) {
+                if (zoneStart > zone2.startTime) {
+                    this._zones.splice(j, 0, {
+                        startTime:   zone2.startTime,
+                        endTime:     zoneStart,
+                        unit:        zone2.unit,
+                        multiple:    zone2.multiple
+                    });
+                    j++;
+
+                    zone2.startTime = zoneStart;
+                }
+
+                if (zoneEnd < zone2.endTime) {
+                    this._zones.splice(j, 0, {
+                        startTime:  zoneStart,
+                        endTime:    zoneEnd,
+                        unit:       zone.unit,
+                        multiple:   (zone.multiple) ? zone.multiple : 1
+                    });
+                    j++;
+
+                    zone2.startTime = zoneEnd;
+                    zoneStart = zoneEnd;
+                } else {
+                    zone2.multiple = zone.multiple;
+                    zone2.unit = zone.unit;
+                    zoneStart = zone2.endTime;
+                }
+            } // else, try the next existing zone
+        }
+    }
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._backgroundLayer = band.createLayerDiv(0);
+    this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+    this._backgroundLayer.className ='timeline-ether-bg';
+    //this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+    this._markerLayer = null;
+    this._lineLayer = null;
+
+    var align = ("align" in this._params && this._params.align != undefined) ? this._params.align :
+        this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+    var showLine = ("showLine" in this._params) ? this._params.showLine :
+        this._theme.ether.interval.line.show;
+
+    this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+        this._timeline, this._band, this._theme, align, showLine);
+
+    this._highlight = new Timeline.EtherHighlight(
+        this._timeline, this._band, this._theme, this._backgroundLayer);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+    this._highlight.position(startDate, endDate);
+}
+
+Timeline.HotZoneGregorianEtherPainter.prototype.paint = function() {
+    if (this._markerLayer) {
+        this._band.removeLayerDiv(this._markerLayer);
+    }
+    this._markerLayer = this._band.createLayerDiv(100);
+    this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+    this._markerLayer.style.display = "none";
+
+    if (this._lineLayer) {
+        this._band.removeLayerDiv(this._lineLayer);
+    }
+    this._lineLayer = this._band.createLayerDiv(1);
+    this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+    this._lineLayer.style.display = "none";
+
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    var timeZone = this._band.getTimeZone();
+    var labeller = this._band.getLabeller();
+
+    var p = this;
+    var incrementDate = function(date, zone) {
+        for (var i = 0; i < zone.multiple; i++) {
+            SimileAjax.DateTime.incrementByInterval(date, zone.unit);
+        }
+    };
+
+    var zStart = 0;
+    while (zStart < this._zones.length) {
+        if (minDate.getTime() < this._zones[zStart].endTime) {
+            break;
+        }
+        zStart++;
+    }
+    var zEnd = this._zones.length - 1;
+    while (zEnd >= 0) {
+        if (maxDate.getTime() > this._zones[zEnd].startTime) {
+            break;
+        }
+        zEnd--;
+    }
+
+    for (var z = zStart; z <= zEnd; z++) {
+        var zone = this._zones[z];
+
+        var minDate2 = new Date(Math.max(minDate.getTime(), zone.startTime));
+        var maxDate2 = new Date(Math.min(maxDate.getTime(), zone.endTime));
+
+        SimileAjax.DateTime.roundDownToInterval(minDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+        SimileAjax.DateTime.roundUpToInterval(maxDate2, zone.unit, timeZone, zone.multiple, this._theme.firstDayOfWeek);
+
+        while (minDate2.getTime() < maxDate2.getTime()) {
+            this._intervalMarkerLayout.createIntervalMarker(
+                minDate2, labeller, zone.unit, this._markerLayer, this._lineLayer);
+
+            incrementDate(minDate2, zone);
+        }
+    }
+    this._markerLayer.style.display = "block";
+    this._lineLayer.style.display = "block";
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.softPaint = function() {
+};
+
+Timeline.HotZoneGregorianEtherPainter.prototype.zoom = function(netIntervalChange) {
+  if (netIntervalChange != 0) {
+    for (var i = 0; i < this._zones.length; ++i) {
+      if (this._zones[i]) {
+        this._zones[i].unit += netIntervalChange;
+      }
+    }
+  }
+};
+
+/*==================================================
+ *  Year Count Ether Painter
+ *==================================================
+ */
+
+Timeline.YearCountEtherPainter = function(params) {
+    this._params = params;
+    this._theme = params.theme;
+    this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+    this._multiple = ("multiple" in params) ? params.multiple : 1;
+};
+
+Timeline.YearCountEtherPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._backgroundLayer = band.createLayerDiv(0);
+    this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+    this._backgroundLayer.className = 'timeline-ether-bg';
+   // this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+    this._markerLayer = null;
+    this._lineLayer = null;
+
+    var align = ("align" in this._params) ? this._params.align :
+        this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+    var showLine = ("showLine" in this._params) ? this._params.showLine :
+        this._theme.ether.interval.line.show;
+
+    this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+        this._timeline, this._band, this._theme, align, showLine);
+
+    this._highlight = new Timeline.EtherHighlight(
+        this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.YearCountEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+    this._highlight.position(startDate, endDate);
+};
+
+Timeline.YearCountEtherPainter.prototype.paint = function() {
+    if (this._markerLayer) {
+        this._band.removeLayerDiv(this._markerLayer);
+    }
+    this._markerLayer = this._band.createLayerDiv(100);
+    this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+    this._markerLayer.style.display = "none";
+
+    if (this._lineLayer) {
+        this._band.removeLayerDiv(this._lineLayer);
+    }
+    this._lineLayer = this._band.createLayerDiv(1);
+    this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+    this._lineLayer.style.display = "none";
+
+    var minDate = new Date(this._startDate.getTime());
+    var maxDate = this._band.getMaxDate();
+    var yearDiff = this._band.getMinDate().getUTCFullYear() - this._startDate.getUTCFullYear();
+    minDate.setUTCFullYear(this._band.getMinDate().getUTCFullYear() - yearDiff % this._multiple);
+
+    var p = this;
+    var incrementDate = function(date) {
+        for (var i = 0; i < p._multiple; i++) {
+            SimileAjax.DateTime.incrementByInterval(date, SimileAjax.DateTime.YEAR);
+        }
+    };
+    var labeller = {
+        labelInterval: function(date, intervalUnit) {
+            var diff = date.getUTCFullYear() - p._startDate.getUTCFullYear();
+            return {
+                text: diff,
+                emphasized: diff == 0
+            };
+        }
+    };
+
+    while (minDate.getTime() < maxDate.getTime()) {
+        this._intervalMarkerLayout.createIntervalMarker(
+            minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+        incrementDate(minDate);
+    }
+    this._markerLayer.style.display = "block";
+    this._lineLayer.style.display = "block";
+};
+
+Timeline.YearCountEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ *  Quarterly Ether Painter
+ *==================================================
+ */
+
+Timeline.QuarterlyEtherPainter = function(params) {
+    this._params = params;
+    this._theme = params.theme;
+    this._startDate = SimileAjax.DateTime.parseGregorianDateTime(params.startDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._backgroundLayer = band.createLayerDiv(0);
+    this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
+    this._backgroundLayer.className = 'timeline-ether-bg';
+ //   this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
+
+    this._markerLayer = null;
+    this._lineLayer = null;
+
+    var align = ("align" in this._params) ? this._params.align :
+        this._theme.ether.interval.marker[timeline.isHorizontal() ? "hAlign" : "vAlign"];
+    var showLine = ("showLine" in this._params) ? this._params.showLine :
+        this._theme.ether.interval.line.show;
+
+    this._intervalMarkerLayout = new Timeline.EtherIntervalMarkerLayout(
+        this._timeline, this._band, this._theme, align, showLine);
+
+    this._highlight = new Timeline.EtherHighlight(
+        this._timeline, this._band, this._theme, this._backgroundLayer);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.setHighlight = function(startDate, endDate) {
+    this._highlight.position(startDate, endDate);
+};
+
+Timeline.QuarterlyEtherPainter.prototype.paint = function() {
+    if (this._markerLayer) {
+        this._band.removeLayerDiv(this._markerLayer);
+    }
+    this._markerLayer = this._band.createLayerDiv(100);
+    this._markerLayer.setAttribute("name", "ether-markers"); // for debugging
+    this._markerLayer.style.display = "none";
+
+    if (this._lineLayer) {
+        this._band.removeLayerDiv(this._lineLayer);
+    }
+    this._lineLayer = this._band.createLayerDiv(1);
+    this._lineLayer.setAttribute("name", "ether-lines"); // for debugging
+    this._lineLayer.style.display = "none";
+
+    var minDate = new Date(0);
+    var maxDate = this._band.getMaxDate();
+
+    minDate.setUTCFullYear(Math.max(this._startDate.getUTCFullYear(), this._band.getMinDate().getUTCFullYear()));
+    minDate.setUTCMonth(this._startDate.getUTCMonth());
+
+    var p = this;
+    var incrementDate = function(date) {
+        date.setUTCMonth(date.getUTCMonth() + 3);
+    };
+    var labeller = {
+        labelInterval: function(date, intervalUnit) {
+            var quarters = (4 + (date.getUTCMonth() - p._startDate.getUTCMonth()) / 3) % 4;
+            if (quarters != 0) {
+                return { text: "Q" + (quarters + 1), emphasized: false };
+            } else {
+                return { text: "Y" + (date.getUTCFullYear() - p._startDate.getUTCFullYear() + 1), emphasized: true };
+            }
+        }
+    };
+
+    while (minDate.getTime() < maxDate.getTime()) {
+        this._intervalMarkerLayout.createIntervalMarker(
+            minDate, labeller, SimileAjax.DateTime.YEAR, this._markerLayer, this._lineLayer);
+
+        incrementDate(minDate);
+    }
+    this._markerLayer.style.display = "block";
+    this._lineLayer.style.display = "block";
+};
+
+Timeline.QuarterlyEtherPainter.prototype.softPaint = function() {
+};
+
+/*==================================================
+ *  Ether Interval Marker Layout
+ *==================================================
+ */
+
+Timeline.EtherIntervalMarkerLayout = function(timeline, band, theme, align, showLine) {
+    var horizontal = timeline.isHorizontal();
+    if (horizontal) {
+        if (align == "Top") {
+            this.positionDiv = function(div, offset) {
+                div.style.left = offset + "px";
+                div.style.top = "0px";
+            };
+        } else {
+            this.positionDiv = function(div, offset) {
+                div.style.left = offset + "px";
+                div.style.bottom = "0px";
+            };
+        }
+    } else {
+        if (align == "Left") {
+            this.positionDiv = function(div, offset) {
+                div.style.top = offset + "px";
+                div.style.left = "0px";
+            };
+        } else {
+            this.positionDiv = function(div, offset) {
+                div.style.top = offset + "px";
+                div.style.right = "0px";
+            };
+        }
+    }
+
+    var markerTheme = theme.ether.interval.marker;
+    var lineTheme = theme.ether.interval.line;
+    var weekendTheme = theme.ether.interval.weekend;
+
+    var stylePrefix = (horizontal ? "h" : "v") + align;
+    var labelStyler = markerTheme[stylePrefix + "Styler"];
+    var emphasizedLabelStyler = markerTheme[stylePrefix + "EmphasizedStyler"];
+    var day = SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY];
+
+    this.createIntervalMarker = function(date, labeller, unit, markerDiv, lineDiv) {
+        var offset = Math.round(band.dateToPixelOffset(date));
+
+        if (showLine && unit != SimileAjax.DateTime.WEEK) {
+            var divLine = timeline.getDocument().createElement("div");
+            divLine.className = "timeline-ether-lines";
+
+            if (lineTheme.opacity < 100) {
+                SimileAjax.Graphics.setOpacity(divLine, lineTheme.opacity);
+            }
+
+            if (horizontal) {
+				//divLine.className += " timeline-ether-lines-vertical";
+				divLine.style.left = offset + "px";
+            } else {
+				//divLine.className += " timeline-ether-lines-horizontal";
+                divLine.style.top = offset + "px";
+            }
+            lineDiv.appendChild(divLine);
+        }
+        if (unit == SimileAjax.DateTime.WEEK) {
+            var firstDayOfWeek = theme.firstDayOfWeek;
+
+            var saturday = new Date(date.getTime() + (6 - firstDayOfWeek - 7) * day);
+            var monday = new Date(saturday.getTime() + 2 * day);
+
+            var saturdayPixel = Math.round(band.dateToPixelOffset(saturday));
+            var mondayPixel = Math.round(band.dateToPixelOffset(monday));
+            var length = Math.max(1, mondayPixel - saturdayPixel);
+
+            var divWeekend = timeline.getDocument().createElement("div");
+			divWeekend.className = 'timeline-ether-weekends'
+
+            if (weekendTheme.opacity < 100) {
+                SimileAjax.Graphics.setOpacity(divWeekend, weekendTheme.opacity);
+            }
+
+            if (horizontal) {
+                divWeekend.style.left = saturdayPixel + "px";
+                divWeekend.style.width = length + "px";
+            } else {
+                divWeekend.style.top = saturdayPixel + "px";
+                divWeekend.style.height = length + "px";
+            }
+            lineDiv.appendChild(divWeekend);
+        }
+
+        var label = labeller.labelInterval(date, unit);
+
+        var div = timeline.getDocument().createElement("div");
+        div.innerHTML = label.text;
+
+
+
+		div.className = 'timeline-date-label'
+		if(label.emphasized) div.className += ' timeline-date-label-em'
+
+        this.positionDiv(div, offset);
+        markerDiv.appendChild(div);
+
+        return div;
+    };
+};
+
+/*==================================================
+ *  Ether Highlight Layout
+ *==================================================
+ */
+
+Timeline.EtherHighlight = function(timeline, band, theme, backgroundLayer) {
+    var horizontal = timeline.isHorizontal();
+
+    this._highlightDiv = null;
+    this._createHighlightDiv = function() {
+        if (this._highlightDiv == null) {
+            this._highlightDiv = timeline.getDocument().createElement("div");
+            this._highlightDiv.setAttribute("name", "ether-highlight"); // for debugging
+            this._highlightDiv.className = 'timeline-ether-highlight'
+
+            var opacity = theme.ether.highlightOpacity;
+            if (opacity < 100) {
+                SimileAjax.Graphics.setOpacity(this._highlightDiv, opacity);
+            }
+
+            backgroundLayer.appendChild(this._highlightDiv);
+        }
+    }
+
+    this.position = function(startDate, endDate) {
+        this._createHighlightDiv();
+
+        var startPixel = Math.round(band.dateToPixelOffset(startDate));
+        var endPixel = Math.round(band.dateToPixelOffset(endDate));
+        var length = Math.max(endPixel - startPixel, 3);
+        if (horizontal) {
+            this._highlightDiv.style.left = startPixel + "px";
+            this._highlightDiv.style.width = length + "px";
+            this._highlightDiv.style.height = (band.getViewWidth() - 4) + "px";
+        } else {
+            this._highlightDiv.style.top = startPixel + "px";
+            this._highlightDiv.style.height = length + "px";
+            this._highlightDiv.style.width = (band.getViewWidth() - 4) + "px";
+        }
+    }
+};
+/*==================================================
+ *  Event Utils
+ *==================================================
+ */
+Timeline.EventUtils = {};
+
+Timeline.EventUtils.getNewEventID = function() {
+    // global across page
+    if (this._lastEventID == null) {
+        this._lastEventID = 0;
+    }
+
+    this._lastEventID += 1;
+    return "e" + this._lastEventID;
+};
+
+Timeline.EventUtils.decodeEventElID = function(elementID) {
+    /*==================================================
+     *
+     * Use this function to decode an event element's id on a band (label div,
+     * tape div or icon img).
+     *
+     * Returns {band: <bandObj>, evt: <eventObj>}
+     *
+     * To enable a single event listener to monitor everything
+     * on a Timeline, a set format is used for the id's of the
+     * elements on the Timeline--
+     *
+     * element id format for labels, icons, tapes:
+     *   labels: label-tl-<timelineID>-<band_index>-<evt.id>
+     *    icons: icon-tl-<timelineID>-<band_index>-<evt.id>
+     *    tapes: tape1-tl-<timelineID>-<band_index>-<evt.id>
+     *           tape2-tl-<timelineID>-<band_index>-<evt.id>
+     *           // some events have more than one tape
+     *    highlight: highlight1-tl-<timelineID>-<band_index>-<evt.id>
+     *               highlight2-tl-<timelineID>-<band_index>-<evt.id>
+     *           // some events have more than one highlight div (future)
+     * Note: use split('-') to get array of the format's parts
+     *
+     * You can then retrieve the timeline object and event object
+     * by using Timeline.getTimeline, Timeline.getBand, or
+     * Timeline.getEvent and passing in the element's id
+     *
+     *==================================================
+     */
+
+    var parts = elementID.split('-');
+    if (parts[1] != 'tl') {
+        alert("Internal Timeline problem 101, please consult support");
+        return {band: null, evt: null}; // early return
+    }
+
+    var timeline = Timeline.getTimelineFromID(parts[2]);
+    var band = timeline.getBand(parts[3]);
+    var evt = band.getEventSource.getEvent(parts[4]);
+
+    return {band: band, evt: evt};
+};
+
+Timeline.EventUtils.encodeEventElID = function(timeline, band, elType, evt) {
+    // elType should be one of {label | icon | tapeN | highlightN}
+    return elType + "-tl-" + timeline.timelineID +
+       "-" + band.getIndex() + "-" + evt.getID();
+};/*==================================================
+ *  Gregorian Date Labeller
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller = function(locale, timeZone) {
+    this._locale = locale;
+    this._timeZone = timeZone;
+};
+
+Timeline.GregorianDateLabeller.monthNames = [];
+Timeline.GregorianDateLabeller.dayNames = [];
+Timeline.GregorianDateLabeller.labelIntervalFunctions = [];
+
+Timeline.GregorianDateLabeller.getMonthName = function(month, locale) {
+    return Timeline.GregorianDateLabeller.monthNames[locale][month];
+};
+
+Timeline.GregorianDateLabeller.prototype.labelInterval = function(date, intervalUnit) {
+    var f = Timeline.GregorianDateLabeller.labelIntervalFunctions[this._locale];
+    if (f == null) {
+        f = Timeline.GregorianDateLabeller.prototype.defaultLabelInterval;
+    }
+    return f.call(this, date, intervalUnit);
+};
+
+Timeline.GregorianDateLabeller.prototype.labelPrecise = function(date) {
+    return SimileAjax.DateTime.removeTimeZoneOffset(
+        date,
+        this._timeZone //+ (new Date().getTimezoneOffset() / 60)
+    ).toUTCString();
+};
+
+Timeline.GregorianDateLabeller.prototype.defaultLabelInterval = function(date, intervalUnit) {
+    var text;
+    var emphasized = false;
+
+    date = SimileAjax.DateTime.removeTimeZoneOffset(date, this._timeZone);
+
+    switch(intervalUnit) {
+    case SimileAjax.DateTime.MILLISECOND:
+        text = date.getUTCMilliseconds();
+        break;
+    case SimileAjax.DateTime.SECOND:
+        text = date.getUTCSeconds();
+        break;
+    case SimileAjax.DateTime.MINUTE:
+        var m = date.getUTCMinutes();
+        if (m == 0) {
+            text = date.getUTCHours() + ":00";
+            emphasized = true;
+        } else {
+            text = m;
+        }
+        break;
+    case SimileAjax.DateTime.HOUR:
+        text = date.getUTCHours() + "hr";
+        break;
+    case SimileAjax.DateTime.DAY:
+        text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
+        break;
+    case SimileAjax.DateTime.WEEK:
+        text = Timeline.GregorianDateLabeller.getMonthName(date.getUTCMonth(), this._locale) + " " + date.getUTCDate();
+        break;
+    case SimileAjax.DateTime.MONTH:
+        var m = date.getUTCMonth();
+        if (m != 0) {
+            text = Timeline.GregorianDateLabeller.getMonthName(m, this._locale);
+            break;
+        } // else, fall through
+    case SimileAjax.DateTime.YEAR:
+    case SimileAjax.DateTime.DECADE:
+    case SimileAjax.DateTime.CENTURY:
+    case SimileAjax.DateTime.MILLENNIUM:
+        var y = date.getUTCFullYear();
+        if (y > 0) {
+            text = date.getUTCFullYear();
+        } else {
+            text = (1 - y) + "BC";
+        }
+        emphasized =
+            (intervalUnit == SimileAjax.DateTime.MONTH) ||
+            (intervalUnit == SimileAjax.DateTime.DECADE && y % 100 == 0) ||
+            (intervalUnit == SimileAjax.DateTime.CENTURY && y % 1000 == 0);
+        break;
+    default:
+        text = date.toUTCString();
+    }
+    return { text: text, emphasized: emphasized };
+}
+
+/*==================================================
+ *  Default Event Source
+ *==================================================
+ */
+
+
+Timeline.DefaultEventSource = function(eventIndex) {
+    this._events = (eventIndex instanceof Object) ? eventIndex : new SimileAjax.EventIndex();
+    this._listeners = [];
+};
+
+Timeline.DefaultEventSource.prototype.addListener = function(listener) {
+    this._listeners.push(listener);
+};
+
+Timeline.DefaultEventSource.prototype.removeListener = function(listener) {
+    for (var i = 0; i < this._listeners.length; i++) {
+        if (this._listeners[i] == listener) {
+            this._listeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+Timeline.DefaultEventSource.prototype.loadXML = function(xml, url) {
+    var base = this._getBaseURL(url);
+
+    var wikiURL = xml.documentElement.getAttribute("wiki-url");
+    var wikiSection = xml.documentElement.getAttribute("wiki-section");
+
+    var dateTimeFormat = xml.documentElement.getAttribute("date-time-format");
+    var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+    var node = xml.documentElement.firstChild;
+    var added = false;
+    while (node != null) {
+        if (node.nodeType == 1) {
+            var description = "";
+            if (node.firstChild != null && node.firstChild.nodeType == 3) {
+                description = node.firstChild.nodeValue;
+            }
+            // instant event: default is true. Or use values from isDuration or durationEvent
+            var instant = (node.getAttribute("isDuration")    === null &&
+                           node.getAttribute("durationEvent") === null) ||
+                          node.getAttribute("isDuration") == "false" ||
+                          node.getAttribute("durationEvent") == "false";
+
+            var evt = new Timeline.DefaultEventSource.Event( {
+                          id: node.getAttribute("id"),
+                       start: parseDateTimeFunction(node.getAttribute("start")),
+                         end: parseDateTimeFunction(node.getAttribute("end")),
+                 latestStart: parseDateTimeFunction(node.getAttribute("latestStart")),
+                 earliestEnd: parseDateTimeFunction(node.getAttribute("earliestEnd")),
+                     instant: instant,
+                        text: node.getAttribute("title"),
+                 description: description,
+                       image: this._resolveRelativeURL(node.getAttribute("image"), base),
+                        link: this._resolveRelativeURL(node.getAttribute("link") , base),
+                        icon: this._resolveRelativeURL(node.getAttribute("icon") , base),
+                       color: node.getAttribute("color"),
+                   textColor: node.getAttribute("textColor"),
+                   hoverText: node.getAttribute("hoverText"),
+                   classname: node.getAttribute("classname"),
+                   tapeImage: node.getAttribute("tapeImage"),
+                  tapeRepeat: node.getAttribute("tapeRepeat"),
+                     caption: node.getAttribute("caption"),
+                     eventID: node.getAttribute("eventID"),
+                    trackNum: node.getAttribute("trackNum")
+            });
+
+            evt._node = node;
+            evt.getProperty = function(name) {
+                return this._node.getAttribute(name);
+            };
+            evt.setWikiInfo(wikiURL, wikiSection);
+
+            this._events.add(evt);
+
+            added = true;
+        }
+        node = node.nextSibling;
+    }
+
+    if (added) {
+        this._fire("onAddMany", []);
+    }
+};
+
+
+Timeline.DefaultEventSource.prototype.loadJSON = function(data, url) {
+    var base = this._getBaseURL(url);
+    var added = false;
+    if (data && data.events){
+        var wikiURL = ("wikiURL" in data) ? data.wikiURL : null;
+        var wikiSection = ("wikiSection" in data) ? data.wikiSection : null;
+
+        var dateTimeFormat = ("dateTimeFormat" in data) ? data.dateTimeFormat : null;
+        var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+        for (var i=0; i < data.events.length; i++){
+            var event = data.events[i];
+            // Fixing issue 33:
+            // instant event: default (for JSON only) is false. Or use values from isDuration or durationEvent
+            // isDuration was negated (see issue 33, so keep that interpretation
+            var instant = event.isDuration || (event.durationEvent != null && !event.durationEvent);
+
+            var evt = new Timeline.DefaultEventSource.Event({
+                          id: ("id" in event) ? event.id : undefined,
+                       start: parseDateTimeFunction(event.start),
+                         end: parseDateTimeFunction(event.end),
+                 latestStart: parseDateTimeFunction(event.latestStart),
+                 earliestEnd: parseDateTimeFunction(event.earliestEnd),
+                     instant: instant,
+                        text: event.title,
+                 description: event.description,
+                       image: this._resolveRelativeURL(event.image, base),
+                        link: this._resolveRelativeURL(event.link , base),
+                        icon: this._resolveRelativeURL(event.icon , base),
+                       color: event.color,
+                   textColor: event.textColor,
+                   hoverText: event.hoverText,
+                   classname: event.classname,
+                   tapeImage: event.tapeImage,
+                  tapeRepeat: event.tapeRepeat,
+                     caption: event.caption,
+                     eventID: event.eventID,
+                    trackNum: event.trackNum
+            });
+            evt._obj = event;
+            evt.getProperty = function(name) {
+                return this._obj[name];
+            };
+            evt.setWikiInfo(wikiURL, wikiSection);
+
+            this._events.add(evt);
+            added = true;
+        }
+    }
+
+    if (added) {
+        this._fire("onAddMany", []);
+    }
+};
+
+/*
+ *  Contributed by Morten Frederiksen, http://www.wasab.dk/morten/
+ */
+Timeline.DefaultEventSource.prototype.loadSPARQL = function(xml, url) {
+    var base = this._getBaseURL(url);
+
+    var dateTimeFormat = 'iso8601';
+    var parseDateTimeFunction = this._events.getUnit().getParser(dateTimeFormat);
+
+    if (xml == null) {
+        return;
+    }
+
+    /*
+     *  Find <results> tag
+     */
+    var node = xml.documentElement.firstChild;
+    while (node != null && (node.nodeType != 1 || node.nodeName != 'results')) {
+        node = node.nextSibling;
+    }
+
+    var wikiURL = null;
+    var wikiSection = null;
+    if (node != null) {
+        wikiURL = node.getAttribute("wiki-url");
+        wikiSection = node.getAttribute("wiki-section");
+
+        node = node.firstChild;
+    }
+
+    var added = false;
+    while (node != null) {
+        if (node.nodeType == 1) {
+            var bindings = { };
+            var binding = node.firstChild;
+            while (binding != null) {
+                if (binding.nodeType == 1 &&
+                    binding.firstChild != null &&
+                    binding.firstChild.nodeType == 1 &&
+                    binding.firstChild.firstChild != null &&
+                    binding.firstChild.firstChild.nodeType == 3) {
+                    bindings[binding.getAttribute('name')] = binding.firstChild.firstChild.nodeValue;
+                }
+                binding = binding.nextSibling;
+            }
+
+            if (bindings["start"] == null && bindings["date"] != null) {
+                bindings["start"] = bindings["date"];
+            }
+
+            // instant event: default is true. Or use values from isDuration or durationEvent
+            var instant = (bindings["isDuration"]    === null &&
+                           bindings["durationEvent"] === null) ||
+                          bindings["isDuration"] == "false" ||
+                          bindings["durationEvent"] == "false";
+
+            var evt = new Timeline.DefaultEventSource.Event({
+                          id: bindings["id"],
+                       start: parseDateTimeFunction(bindings["start"]),
+                         end: parseDateTimeFunction(bindings["end"]),
+                 latestStart: parseDateTimeFunction(bindings["latestStart"]),
+                 earliestEnd: parseDateTimeFunction(bindings["earliestEnd"]),
+                     instant: instant, // instant
+                        text: bindings["title"], // text
+                 description: bindings["description"],
+                       image: this._resolveRelativeURL(bindings["image"], base),
+                        link: this._resolveRelativeURL(bindings["link"] , base),
+                        icon: this._resolveRelativeURL(bindings["icon"] , base),
+                       color: bindings["color"],
+                   textColor: bindings["textColor"],
+                   hoverText: bindings["hoverText"],
+                     caption: bindings["caption"],
+                   classname: bindings["classname"],
+                   tapeImage: bindings["tapeImage"],
+                  tapeRepeat: bindings["tapeRepeat"],
+                     eventID: bindings["eventID"],
+                    trackNum: bindings["trackNum"]
+            });
+            evt._bindings = bindings;
+            evt.getProperty = function(name) {
+                return this._bindings[name];
+            };
+            evt.setWikiInfo(wikiURL, wikiSection);
+
+            this._events.add(evt);
+            added = true;
+        }
+        node = node.nextSibling;
+    }
+
+    if (added) {
+        this._fire("onAddMany", []);
+    }
+};
+
+Timeline.DefaultEventSource.prototype.add = function(evt) {
+    this._events.add(evt);
+    this._fire("onAddOne", [evt]);
+};
+
+Timeline.DefaultEventSource.prototype.addMany = function(events) {
+    for (var i = 0; i < events.length; i++) {
+        this._events.add(events[i]);
+    }
+    this._fire("onAddMany", []);
+};
+
+Timeline.DefaultEventSource.prototype.clear = function() {
+    this._events.removeAll();
+    this._fire("onClear", []);
+};
+
+Timeline.DefaultEventSource.prototype.getEvent = function(id) {
+    return this._events.getEvent(id);
+};
+
+Timeline.DefaultEventSource.prototype.getEventIterator = function(startDate, endDate) {
+    return this._events.getIterator(startDate, endDate);
+};
+
+Timeline.DefaultEventSource.prototype.getEventReverseIterator = function(startDate, endDate) {
+    return this._events.getReverseIterator(startDate, endDate);
+};
+
+Timeline.DefaultEventSource.prototype.getAllEventIterator = function() {
+    return this._events.getAllIterator();
+};
+
+Timeline.DefaultEventSource.prototype.getCount = function() {
+    return this._events.getCount();
+};
+
+Timeline.DefaultEventSource.prototype.getEarliestDate = function() {
+    return this._events.getEarliestDate();
+};
+
+Timeline.DefaultEventSource.prototype.getLatestDate = function() {
+    return this._events.getLatestDate();
+};
+
+Timeline.DefaultEventSource.prototype._fire = function(handlerName, args) {
+    for (var i = 0; i < this._listeners.length; i++) {
+        var listener = this._listeners[i];
+        if (handlerName in listener) {
+            try {
+                listener[handlerName].apply(listener, args);
+            } catch (e) {
+                SimileAjax.Debug.exception(e);
+            }
+        }
+    }
+};
+
+Timeline.DefaultEventSource.prototype._getBaseURL = function(url) {
+    if (url.indexOf("://") < 0) {
+        var url2 = this._getBaseURL(document.location.href);
+        if (url.substr(0,1) == "/") {
+            url = url2.substr(0, url2.indexOf("/", url2.indexOf("://") + 3)) + url;
+        } else {
+            url = url2 + url;
+        }
+    }
+
+    var i = url.lastIndexOf("/");
+    if (i < 0) {
+        return "";
+    } else {
+        return url.substr(0, i+1);
+    }
+};
+
+Timeline.DefaultEventSource.prototype._resolveRelativeURL = function(url, base) {
+    if (url == null || url == "") {
+        return url;
+    } else if (url.indexOf("://") > 0) {
+        return url;
+    } else if (url.substr(0,1) == "/") {
+        return base.substr(0, base.indexOf("/", base.indexOf("://") + 3)) + url;
+    } else {
+        return base + url;
+    }
+};
+
+
+Timeline.DefaultEventSource.Event = function(args) {
+  //
+  // Attention developers!
+  // If you add a new event attribute, please be sure to add it to
+  // all three load functions: loadXML, loadSPARCL, loadJSON.
+  // Thanks!
+  //
+  // args is a hash/object. It supports the following keys. Most are optional
+  //   id            -- an internal id. Really shouldn't be used by events.
+  //                    Timeline library clients should use eventID
+  //   eventID       -- For use by library client when writing custom painters or
+  //                    custom fillInfoBubble
+  //   start
+  //   end
+  //   latestStart
+  //   earliestEnd
+  //   instant      -- boolean. Controls precise/non-precise logic & duration/instant issues
+  //   text         -- event source attribute 'title' -- used as the label on Timelines and in bubbles.
+  //   description  -- used in bubbles
+  //   image        -- used in bubbles
+  //   link         -- used in bubbles
+  //   icon         -- on the Timeline
+  //   color        -- Timeline label and tape color
+  //   textColor    -- Timeline label color, overrides color attribute
+  //   hoverText    -- deprecated, here for backwards compatibility.
+  //                   Superceeded by caption
+  //   caption      -- tooltip-like caption on the Timeline. Uses HTML title attribute
+  //   classname    -- used to set classname in Timeline. Enables better CSS selector rules
+  //   tapeImage    -- background image of the duration event's tape div on the Timeline
+  //   tapeRepeat   -- repeat attribute for tapeImage. {repeat | repeat-x | repeat-y }
+
+  function cleanArg(arg) {
+      // clean up an arg
+      return (args[arg] != null && args[arg] != "") ? args[arg] : null;
+  }
+
+  var id = args.id ? args.id.trim() : "";
+  this._id = id.length > 0 ? id : Timeline.EventUtils.getNewEventID();
+
+  this._instant = args.instant || (args.end == null);
+
+  this._start = args.start;
+  this._end = (args.end != null) ? args.end : args.start;
+
+  this._latestStart = (args.latestStart != null) ?
+                       args.latestStart : (args.instant ? this._end : this._start);
+  this._earliestEnd = (args.earliestEnd != null) ? args.earliestEnd : this._end;
+
+  // check sanity of dates since incorrect dates will later cause calculation errors
+  // when painting
+  var err=[];
+  if (this._start > this._latestStart) {
+          this._latestStart = this._start;
+          err.push("start is > latestStart");}
+  if (this._start > this._earliestEnd) {
+          this._earliestEnd = this._latestStart;
+          err.push("start is > earliestEnd");}
+  if (this._start > this._end) {
+          this._end = this._earliestEnd;
+          err.push("start is > end");}
+  if (this._latestStart > this._earliestEnd) {
+          this._earliestEnd = this._latestStart;
+          err.push("latestStart is > earliestEnd");}
+  if (this._latestStart > this._end) {
+          this._end = this._earliestEnd;
+          err.push("latestStart is > end");}
+  if (this._earliestEnd > this._end) {
+          this._end = this._earliestEnd;
+          err.push("earliestEnd is > end");}
+
+  this._eventID = cleanArg('eventID');
+  this._text = (args.text != null) ? SimileAjax.HTML.deEntify(args.text) : ""; // Change blank titles to ""
+  if (err.length > 0) {
+          this._text += " PROBLEM: " + err.join(", ");
+  }
+
+  this._description = SimileAjax.HTML.deEntify(args.description);
+  this._image = cleanArg('image');
+  this._link =  cleanArg('link');
+  this._title = cleanArg('hoverText');
+  this._title = cleanArg('caption');
+
+  this._icon = cleanArg('icon');
+  this._color = cleanArg('color');
+  this._textColor = cleanArg('textColor');
+  this._classname = cleanArg('classname');
+  this._tapeImage = cleanArg('tapeImage');
+  this._tapeRepeat = cleanArg('tapeRepeat');
+  this._trackNum = cleanArg('trackNum');
+  if (this._trackNum != null) {
+      this._trackNum = parseInt(this._trackNum);
+  }
+
+  this._wikiURL = null;
+  this._wikiSection = null;
+};
+
+Timeline.DefaultEventSource.Event.prototype = {
+    getID:          function() { return this._id; },
+
+    isInstant:      function() { return this._instant; },
+    isImprecise:    function() { return this._start != this._latestStart || this._end != this._earliestEnd; },
+
+    getStart:       function() { return this._start; },
+    getEnd:         function() { return this._end; },
+    getLatestStart: function() { return this._latestStart; },
+    getEarliestEnd: function() { return this._earliestEnd; },
+
+    getEventID:     function() { return this._eventID; },
+    getText:        function() { return this._text; }, // title
+    getDescription: function() { return this._description; },
+    getImage:       function() { return this._image; },
+    getLink:        function() { return this._link; },
+
+    getIcon:        function() { return this._icon; },
+    getColor:       function() { return this._color; },
+    getTextColor:   function() { return this._textColor; },
+    getClassName:   function() { return this._classname; },
+    getTapeImage:   function() { return this._tapeImage; },
+    getTapeRepeat:  function() { return this._tapeRepeat; },
+    getTrackNum:    function() { return this._trackNum; },
+
+    getProperty:    function(name) { return null; },
+
+    getWikiURL:     function() { return this._wikiURL; },
+    getWikiSection: function() { return this._wikiSection; },
+    setWikiInfo: function(wikiURL, wikiSection) {
+        this._wikiURL = wikiURL;
+        this._wikiSection = wikiSection;
+    },
+
+    fillDescription: function(elmt) {
+        elmt.innerHTML = this._description;
+    },
+    fillWikiInfo: function(elmt) {
+        // Many bubbles will not support a wiki link.
+        //
+        // Strategy: assume no wiki link. If we do have
+        // enough parameters for one, then create it.
+        elmt.style.display = "none"; // default
+
+        if (this._wikiURL == null || this._wikiSection == null) {
+          return; // EARLY RETURN
+        }
+
+        // create the wikiID from the property or from the event text (the title)
+        var wikiID = this.getProperty("wikiID");
+        if (wikiID == null || wikiID.length == 0) {
+            wikiID = this.getText(); // use the title as the backup wiki id
+        }
+
+        if (wikiID == null || wikiID.length == 0) {
+          return; // No wikiID. Thus EARLY RETURN
+        }
+
+        // ready to go...
+        elmt.style.display = "inline";
+        wikiID = wikiID.replace(/\s/g, "_");
+        var url = this._wikiURL + this._wikiSection.replace(/\s/g, "_") + "/" + wikiID;
+        var a = document.createElement("a");
+        a.href = url;
+        a.target = "new";
+        a.innerHTML = Timeline.strings[Timeline.clientLocale].wikiLinkLabel;
+
+        elmt.appendChild(document.createTextNode("["));
+        elmt.appendChild(a);
+        elmt.appendChild(document.createTextNode("]"));
+    },
+
+    fillTime: function(elmt, labeller) {
+        if (this._instant) {
+            if (this.isImprecise()) {
+                elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+                elmt.appendChild(elmt.ownerDocument.createElement("br"));
+                elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+            } else {
+                elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+            }
+        } else {
+            if (this.isImprecise()) {
+                elmt.appendChild(elmt.ownerDocument.createTextNode(
+                    labeller.labelPrecise(this._start) + " ~ " + labeller.labelPrecise(this._latestStart)));
+                elmt.appendChild(elmt.ownerDocument.createElement("br"));
+                elmt.appendChild(elmt.ownerDocument.createTextNode(
+                    labeller.labelPrecise(this._earliestEnd) + " ~ " + labeller.labelPrecise(this._end)));
+            } else {
+                elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._start)));
+                elmt.appendChild(elmt.ownerDocument.createElement("br"));
+                elmt.appendChild(elmt.ownerDocument.createTextNode(labeller.labelPrecise(this._end)));
+            }
+        }
+    },
+
+    fillInfoBubble: function(elmt, theme, labeller) {
+        var doc = elmt.ownerDocument;
+
+        var title = this.getText();
+        var link = this.getLink();
+        var image = this.getImage();
+
+        if (image != null) {
+            var img = doc.createElement("img");
+            img.src = image;
+
+            theme.event.bubble.imageStyler(img);
+            elmt.appendChild(img);
+        }
+
+        var divTitle = doc.createElement("div");
+        var textTitle = doc.createTextNode(title);
+        if (link != null) {
+            var a = doc.createElement("a");
+            a.href = link;
+            a.appendChild(textTitle);
+            divTitle.appendChild(a);
+        } else {
+            divTitle.appendChild(textTitle);
+        }
+        theme.event.bubble.titleStyler(divTitle);
+        elmt.appendChild(divTitle);
+
+        var divBody = doc.createElement("div");
+        this.fillDescription(divBody);
+        theme.event.bubble.bodyStyler(divBody);
+        elmt.appendChild(divBody);
+
+        var divTime = doc.createElement("div");
+        this.fillTime(divTime, labeller);
+        theme.event.bubble.timeStyler(divTime);
+        elmt.appendChild(divTime);
+
+        var divWiki = doc.createElement("div");
+        this.fillWikiInfo(divWiki);
+        theme.event.bubble.wikiStyler(divWiki);
+        elmt.appendChild(divWiki);
+    }
+};
+
+
+/*==================================================
+ *  Original Event Painter
+ *==================================================
+ */
+
+/*==================================================
+ *
+ * To enable a single event listener to monitor everything
+ * on a Timeline, we need a way to map from an event's icon,
+ * label or tape element to the associated timeline, band and
+ * specific event.
+ *
+ * Thus a set format is used for the id's of the
+ * events' elements on the Timeline--
+ *
+ * element id format for labels, icons, tapes:
+ *   labels: label-tl-<timelineID>-<band_index>-<evt.id>
+ *    icons: icon-tl-<timelineID>-<band_index>-<evt.id>
+ *    tapes: tape1-tl-<timelineID>-<band_index>-<evt.id>
+ *           tape2-tl-<timelineID>-<band_index>-<evt.id>
+ *           // some events have more than one tape
+ *    highlight: highlight1-tl-<timelineID>-<band_index>-<evt.id>
+ *               highlight2-tl-<timelineID>-<band_index>-<evt.id>
+ *           // some events have more than one highlight div (future)
+ * You can then retrieve the band/timeline objects and event object
+ * by using Timeline.EventUtils.decodeEventElID
+ *
+ *==================================================
+ */
+
+/*
+ *    eventPaintListener functions receive calls about painting.
+ *    function(band, op, evt, els)
+ *       context: 'this' will be an OriginalEventPainter object.
+ *                It has properties and methods for obtaining
+ *                the relevant band, timeline, etc
+ *       band = the band being painted
+ *       op = 'paintStarting' // the painter is about to remove
+ *            all previously painted events, if any. It will
+ *            then start painting all of the visible events that
+ *            pass the filter.
+ *            evt = null, els = null
+ *       op = 'paintEnded' // the painter has finished painting
+ *            all of the visible events that passed the filter
+ *            evt = null, els = null
+ *       op = 'paintedEvent' // the painter just finished painting an event
+ *            evt = event just painted
+ *            els = array of painted elements' divs. Depending on the event,
+ *                  the array could be just a tape or icon (if no label).
+ *                  Or could include label, multiple tape divs (imprecise event),
+ *                  highlight divs. The array is not ordered. The meaning of
+ *                  each el is available by decoding the el's id
+ *      Note that there may be no paintedEvent calls if no events were visible
+ *      or passed the filter.
+ */
+
+Timeline.OriginalEventPainter = function(params) {
+    this._params = params;
+    this._onSelectListeners = [];
+    this._eventPaintListeners = [];
+
+    this._filterMatcher = null;
+    this._highlightMatcher = null;
+    this._frc = null;
+
+    this._eventIdToElmt = {};
+};
+
+Timeline.OriginalEventPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._backLayer = null;
+    this._eventLayer = null;
+    this._lineLayer = null;
+    this._highlightLayer = null;
+
+    this._eventIdToElmt = null;
+};
+
+Timeline.OriginalEventPainter.prototype.getType = function() {
+    return 'original';
+};
+
+Timeline.OriginalEventPainter.prototype.addOnSelectListener = function(listener) {
+    this._onSelectListeners.push(listener);
+};
+
+Timeline.OriginalEventPainter.prototype.removeOnSelectListener = function(listener) {
+    for (var i = 0; i < this._onSelectListeners.length; i++) {
+        if (this._onSelectListeners[i] == listener) {
+            this._onSelectListeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+Timeline.OriginalEventPainter.prototype.addEventPaintListener = function(listener) {
+    this._eventPaintListeners.push(listener);
+};
+
+Timeline.OriginalEventPainter.prototype.removeEventPaintListener = function(listener) {
+    for (var i = 0; i < this._eventPaintListeners.length; i++) {
+        if (this._eventPaintListeners[i] == listener) {
+            this._eventPaintListeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+Timeline.OriginalEventPainter.prototype.getFilterMatcher = function() {
+    return this._filterMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+    this._filterMatcher = filterMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.getHighlightMatcher = function() {
+    return this._highlightMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+    this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.OriginalEventPainter.prototype.paint = function() {
+    // Paints the events for a given section of the band--what is
+    // visible on screen and some extra.
+    var eventSource = this._band.getEventSource();
+    if (eventSource == null) {
+        return;
+    }
+
+    this._eventIdToElmt = {};
+    this._fireEventPaintListeners('paintStarting', null, null);
+    this._prepareForPainting();
+
+    var metrics = this._computeMetrics();
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    var filterMatcher = (this._filterMatcher != null) ?
+        this._filterMatcher :
+        function(evt) { return true; };
+    var highlightMatcher = (this._highlightMatcher != null) ?
+        this._highlightMatcher :
+        function(evt) { return -1; };
+
+    var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
+    while (iterator.hasNext()) {
+        var evt = iterator.next();
+        if (filterMatcher(evt)) {
+            this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+        }
+    }
+
+    this._highlightLayer.style.display = "block";
+    this._lineLayer.style.display = "block";
+    this._eventLayer.style.display = "block";
+    // update the band object for max number of tracks in this section of the ether
+    this._band.updateEventTrackInfo(this._tracks.length, metrics.trackIncrement);
+    this._fireEventPaintListeners('paintEnded', null, null);
+
+    this._setOrthogonalOffset(metrics);
+};
+
+Timeline.OriginalEventPainter.prototype.softPaint = function() {
+    this._setOrthogonalOffset(this._computeMetrics());
+};
+
+Timeline.OriginalEventPainter.prototype._setOrthogonalOffset = function(metrics) {
+    var actualViewWidth = 2 * metrics.trackOffset + this._tracks.length * metrics.trackIncrement;
+    var minOrthogonalOffset = Math.min(0, this._band.getViewWidth() - actualViewWidth);
+    var orthogonalOffset = Math.max(minOrthogonalOffset, this._band.getViewOrthogonalOffset());
+
+    this._highlightLayer.style.top =
+        this._lineLayer.style.top =
+            this._eventLayer.style.top =
+                orthogonalOffset + "px";
+};
+
+Timeline.OriginalEventPainter.prototype._computeMetrics = function() {
+     var eventTheme = this._params.theme.event;
+     var trackHeight = Math.max(eventTheme.track.height, eventTheme.tape.height +
+                         this._frc.getLineHeight());
+     var metrics = {
+            trackOffset: eventTheme.track.offset,
+            trackHeight: trackHeight,
+               trackGap: eventTheme.track.gap,
+         trackIncrement: trackHeight + eventTheme.track.gap,
+                   icon: eventTheme.instant.icon,
+              iconWidth: eventTheme.instant.iconWidth,
+             iconHeight: eventTheme.instant.iconHeight,
+             labelWidth: eventTheme.label.width,
+           maxLabelChar: eventTheme.label.maxLabelChar,
+    impreciseIconMargin: eventTheme.instant.impreciseIconMargin
+     };
+
+     return metrics;
+};
+
+Timeline.OriginalEventPainter.prototype._prepareForPainting = function() {
+    // Remove everything previously painted: highlight, line and event layers.
+    // Prepare blank layers for painting.
+    var band = this._band;
+
+    if (this._backLayer == null) {
+        this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+        this._backLayer.style.visibility = "hidden";
+
+        var eventLabelPrototype = document.createElement("span");
+        eventLabelPrototype.className = "timeline-event-label";
+        this._backLayer.appendChild(eventLabelPrototype);
+        this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+    }
+    this._frc.update();
+    this._tracks = [];
+
+    if (this._highlightLayer != null) {
+        band.removeLayerDiv(this._highlightLayer);
+    }
+    this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+    this._highlightLayer.style.display = "none";
+
+    if (this._lineLayer != null) {
+        band.removeLayerDiv(this._lineLayer);
+    }
+    this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+    this._lineLayer.style.display = "none";
+
+    if (this._eventLayer != null) {
+        band.removeLayerDiv(this._eventLayer);
+    }
+    this._eventLayer = band.createLayerDiv(115, "timeline-band-events");
+    this._eventLayer.style.display = "none";
+};
+
+Timeline.OriginalEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isInstant()) {
+        this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+    }
+};
+
+Timeline.OriginalEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isImprecise()) {
+        this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+    }
+}
+
+Timeline.OriginalEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isImprecise()) {
+        this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+    }
+}
+
+Timeline.OriginalEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+    var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+    var labelDivClassName = this._getLabelDivClassName(evt);
+    var labelSize = this._frc.computeSize(text, labelDivClassName);
+    var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+    var labelRight = labelLeft + labelSize.width;
+
+    var rightEdge = labelRight;
+    var track = this._findFreeTrack(evt, rightEdge);
+
+    var labelTop = Math.round(
+        metrics.trackOffset + track * metrics.trackIncrement +
+        metrics.trackHeight / 2 - labelSize.height / 2);
+
+    var iconElmtData = this._paintEventIcon(evt, track, iconLeftEdge, metrics, theme, 0);
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
+        labelSize.height, theme, labelDivClassName, highlightIndex);
+    var els = [iconElmtData.elmt, labelElmtData.elmt];
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    var hDiv = this._createHighlightDiv(highlightIndex, iconElmtData, theme, evt);
+    if (hDiv != null) {els.push(hDiv);}
+    this._fireEventPaintListeners('paintedEvent', evt, els);
+
+
+    this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+    this._tracks[track] = iconLeftEdge;
+};
+
+Timeline.OriginalEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var endDate = evt.getEnd();
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+    var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+    var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+    var labelDivClassName = this._getLabelDivClassName(evt);
+    var labelSize = this._frc.computeSize(text, labelDivClassName);
+    var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+    var labelRight = labelLeft + labelSize.width;
+
+    var rightEdge = Math.max(labelRight, endPixel);
+    var track = this._findFreeTrack(evt, rightEdge);
+    var tapeHeight = theme.event.tape.height;
+    var labelTop = Math.round(
+        metrics.trackOffset + track * metrics.trackIncrement + tapeHeight);
+
+    var iconElmtData = this._paintEventIcon(evt, track, iconLeftEdge, metrics, theme, tapeHeight);
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
+                        labelSize.height, theme, labelDivClassName, highlightIndex);
+
+    var color = evt.getColor();
+    color = color != null ? color : theme.event.instant.impreciseColor;
+
+    var tapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel,
+        color, theme.event.instant.impreciseOpacity, metrics, theme, 0);
+    var els = [iconElmtData.elmt, labelElmtData.elmt, tapeElmtData.elmt];
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    var hDiv = this._createHighlightDiv(highlightIndex, iconElmtData, theme, evt);
+    if (hDiv != null) {els.push(hDiv);}
+    this._fireEventPaintListeners('paintedEvent', evt, els);
+
+    this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+    this._tracks[track] = iconLeftEdge;
+};
+
+Timeline.OriginalEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var endDate = evt.getEnd();
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+    var labelDivClassName = this._getLabelDivClassName(evt);
+    var labelSize = this._frc.computeSize(text, labelDivClassName);
+    var labelLeft = startPixel;
+    var labelRight = labelLeft + labelSize.width;
+
+    var rightEdge = Math.max(labelRight, endPixel);
+    var track = this._findFreeTrack(evt, rightEdge);
+    var labelTop = Math.round(
+        metrics.trackOffset + track * metrics.trackIncrement + theme.event.tape.height);
+
+    var color = evt.getColor();
+    color = color != null ? color : theme.event.duration.color;
+
+    var tapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel, color, 100, metrics, theme, 0);
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width,
+      labelSize.height, theme, labelDivClassName, highlightIndex);
+    var els = [tapeElmtData.elmt, labelElmtData.elmt];
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    var hDiv = this._createHighlightDiv(highlightIndex, tapeElmtData, theme, evt);
+    if (hDiv != null) {els.push(hDiv);}
+    this._fireEventPaintListeners('paintedEvent', evt, els);
+
+    this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+    this._tracks[track] = startPixel;
+};
+
+Timeline.OriginalEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var latestStartDate = evt.getLatestStart();
+    var endDate = evt.getEnd();
+    var earliestEndDate = evt.getEarliestEnd();
+
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
+    var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+    var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
+
+    var labelDivClassName = this._getLabelDivClassName(evt);
+    var labelSize = this._frc.computeSize(text, labelDivClassName);
+    var labelLeft = latestStartPixel;
+    var labelRight = labelLeft + labelSize.width;
+
+    var rightEdge = Math.max(labelRight, endPixel);
+    var track = this._findFreeTrack(evt, rightEdge);
+    var labelTop = Math.round(
+        metrics.trackOffset + track * metrics.trackIncrement + theme.event.tape.height);
+
+    var color = evt.getColor();
+    color = color != null ? color : theme.event.duration.color;
+
+    // Imprecise events can have two event tapes
+    // The imprecise dates tape, uses opacity to be dimmer than precise dates
+    var impreciseTapeElmtData = this._paintEventTape(evt, track, startPixel, endPixel,
+        theme.event.duration.impreciseColor,
+        theme.event.duration.impreciseOpacity, metrics, theme, 0);
+    // The precise dates tape, regular (100%) opacity
+    var tapeElmtData = this._paintEventTape(evt, track, latestStartPixel,
+        earliestEndPixel, color, 100, metrics, theme, 1);
+
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop,
+        labelSize.width, labelSize.height, theme, labelDivClassName, highlightIndex);
+    var els = [impreciseTapeElmtData.elmt, tapeElmtData.elmt, labelElmtData.elmt];
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    var hDiv = this._createHighlightDiv(highlightIndex, tapeElmtData, theme, evt);
+    if (hDiv != null) {els.push(hDiv);}
+    this._fireEventPaintListeners('paintedEvent', evt, els);
+
+    this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+    this._tracks[track] = startPixel;
+};
+
+Timeline.OriginalEventPainter.prototype._encodeEventElID = function(elType, evt) {
+    return Timeline.EventUtils.encodeEventElID(this._timeline, this._band, elType, evt);
+};
+
+Timeline.OriginalEventPainter.prototype._findFreeTrack = function(event, rightEdge) {
+    var trackAttribute = event.getTrackNum();
+    if (trackAttribute != null) {
+        return trackAttribute; // early return since event includes track number
+    }
+
+    // normal case: find an open track
+    for (var i = 0; i < this._tracks.length; i++) {
+        var t = this._tracks[i];
+        if (t > rightEdge) {
+            break;
+        }
+    }
+    return i;
+};
+
+Timeline.OriginalEventPainter.prototype._paintEventIcon = function(evt, iconTrack, left, metrics, theme, tapeHeight) {
+    // If no tape, then paint the icon in the middle of the track.
+    // If there is a tape, paint the icon below the tape + impreciseIconMargin
+    var icon = evt.getIcon();
+    icon = icon != null ? icon : metrics.icon;
+
+    var top; // top of the icon
+    if (tapeHeight > 0) {
+        top = metrics.trackOffset + iconTrack * metrics.trackIncrement +
+              tapeHeight + metrics.impreciseIconMargin;
+    } else {
+        var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement +
+                     metrics.trackHeight / 2;
+        top = Math.round(middle - metrics.iconHeight / 2);
+    }
+    var img = SimileAjax.Graphics.createTranslucentImage(icon);
+    var iconDiv = this._timeline.getDocument().createElement("div");
+    iconDiv.className = this._getElClassName('timeline-event-icon', evt, 'icon');
+    iconDiv.id = this._encodeEventElID('icon', evt);
+    iconDiv.style.left = left + "px";
+    iconDiv.style.top = top + "px";
+    iconDiv.appendChild(img);
+
+    if(evt._title != null)
+        iconDiv.title = evt._title;
+
+    this._eventLayer.appendChild(iconDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  metrics.iconWidth,
+        height: metrics.iconHeight,
+        elmt:   iconDiv
+    };
+};
+
+Timeline.OriginalEventPainter.prototype._paintEventLabel = function(evt, text, left, top, width,
+    height, theme, labelDivClassName, highlightIndex) {
+    var doc = this._timeline.getDocument();
+
+    var labelDiv = doc.createElement("div");
+    labelDiv.className = labelDivClassName;
+    labelDiv.id = this._encodeEventElID('label', evt);
+    labelDiv.style.left = left + "px";
+    labelDiv.style.width = width + "px";
+    labelDiv.style.top = top + "px";
+    labelDiv.innerHTML = text;
+
+    if(evt._title != null)
+        labelDiv.title = evt._title;
+
+    var color = evt.getTextColor();
+    if (color == null) {
+        color = evt.getColor();
+    }
+    if (color != null) {
+        labelDiv.style.color = color;
+    }
+    if (theme.event.highlightLabelBackground && highlightIndex >= 0) {
+        labelDiv.style.background = this._getHighlightColor(highlightIndex, theme);
+    }
+
+    this._eventLayer.appendChild(labelDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  width,
+        height: height,
+        elmt:   labelDiv
+    };
+};
+
+Timeline.OriginalEventPainter.prototype._paintEventTape = function(
+    evt, iconTrack, startPixel, endPixel, color, opacity, metrics, theme, tape_index) {
+
+    var tapeWidth = endPixel - startPixel;
+    var tapeHeight = theme.event.tape.height;
+    var top = metrics.trackOffset + iconTrack * metrics.trackIncrement;
+
+    var tapeDiv = this._timeline.getDocument().createElement("div");
+    tapeDiv.className = this._getElClassName('timeline-event-tape', evt, 'tape');
+    tapeDiv.id = this._encodeEventElID('tape' + tape_index, evt);
+    tapeDiv.style.left = startPixel + "px";
+    tapeDiv.style.width = tapeWidth + "px";
+    tapeDiv.style.height = tapeHeight + "px";
+    tapeDiv.style.top = top + "px";
+
+    if(evt._title != null)
+        tapeDiv.title = evt._title;
+
+    if(color != null) {
+        tapeDiv.style.backgroundColor = color;
+    }
+
+    var backgroundImage = evt.getTapeImage();
+    var backgroundRepeat = evt.getTapeRepeat();
+    backgroundRepeat = backgroundRepeat != null ? backgroundRepeat : 'repeat';
+    if(backgroundImage != null) {
+      tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")";
+      tapeDiv.style.backgroundRepeat = backgroundRepeat;
+    }
+
+    SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+    this._eventLayer.appendChild(tapeDiv);
+
+    return {
+        left:   startPixel,
+        top:    top,
+        width:  tapeWidth,
+        height: tapeHeight,
+        elmt:   tapeDiv
+    };
+}
+
+Timeline.OriginalEventPainter.prototype._getLabelDivClassName = function(evt) {
+    return this._getElClassName('timeline-event-label', evt, 'label');
+};
+
+Timeline.OriginalEventPainter.prototype._getElClassName = function(elClassName, evt, prefix) {
+    // Prefix and '_' is added to the event's classname. Set to null for no prefix
+    var evt_classname = evt.getClassName(),
+        pieces = [];
+
+    if (evt_classname) {
+      if (prefix) {pieces.push(prefix + '-' + evt_classname + ' ');}
+      pieces.push(evt_classname + ' ');
+    }
+    pieces.push(elClassName);
+    return(pieces.join(''));
+};
+
+Timeline.OriginalEventPainter.prototype._getHighlightColor = function(highlightIndex, theme) {
+    var highlightColors = theme.event.highlightColors;
+    return highlightColors[Math.min(highlightIndex, highlightColors.length - 1)];
+};
+
+Timeline.OriginalEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme, evt) {
+    var div = null;
+    if (highlightIndex >= 0) {
+        var doc = this._timeline.getDocument();
+        var color = this._getHighlightColor(highlightIndex, theme);
+
+        div = doc.createElement("div");
+        div.className = this._getElClassName('timeline-event-highlight', evt, 'highlight');
+        div.id = this._encodeEventElID('highlight0', evt); // in future will have other
+                                                           // highlight divs for tapes + icons
+        div.style.position = "absolute";
+        div.style.overflow = "hidden";
+        div.style.left =    (dimensions.left - 2) + "px";
+        div.style.width =   (dimensions.width + 4) + "px";
+        div.style.top =     (dimensions.top - 2) + "px";
+        div.style.height =  (dimensions.height + 4) + "px";
+        div.style.background = color;
+
+        this._highlightLayer.appendChild(div);
+    }
+    return div;
+};
+
+Timeline.OriginalEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+    var c = SimileAjax.DOM.getPageCoordinates(icon);
+    this._showBubble(
+        c.left + Math.ceil(icon.offsetWidth / 2),
+        c.top + Math.ceil(icon.offsetHeight / 2),
+        evt
+    );
+    this._fireOnSelect(evt.getID());
+
+    domEvt.cancelBubble = true;
+    SimileAjax.DOM.cancelEvent(domEvt);
+    return false;
+};
+
+Timeline.OriginalEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+    if ("pageX" in domEvt) {
+        var x = domEvt.pageX;
+        var y = domEvt.pageY;
+    } else {
+        var c = SimileAjax.DOM.getPageCoordinates(target);
+        var x = domEvt.offsetX + c.left;
+        var y = domEvt.offsetY + c.top;
+    }
+    this._showBubble(x, y, evt);
+    this._fireOnSelect(evt.getID());
+
+    domEvt.cancelBubble = true;
+    SimileAjax.DOM.cancelEvent(domEvt);
+    return false;
+};
+
+Timeline.OriginalEventPainter.prototype.showBubble = function(evt) {
+    var elmt = this._eventIdToElmt[evt.getID()];
+    if (elmt) {
+        var c = SimileAjax.DOM.getPageCoordinates(elmt);
+        this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, evt);
+    }
+};
+
+Timeline.OriginalEventPainter.prototype._showBubble = function(x, y, evt) {
+    var div = document.createElement("div");
+    var themeBubble = this._params.theme.event.bubble;
+    evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
+
+    SimileAjax.WindowManager.cancelPopups();
+    SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y,
+        themeBubble.width, null, themeBubble.maxHeight);
+};
+
+Timeline.OriginalEventPainter.prototype._fireOnSelect = function(eventID) {
+    for (var i = 0; i < this._onSelectListeners.length; i++) {
+        this._onSelectListeners[i](eventID);
+    }
+};
+
+Timeline.OriginalEventPainter.prototype._fireEventPaintListeners = function(op, evt, els) {
+    for (var i = 0; i < this._eventPaintListeners.length; i++) {
+        this._eventPaintListeners[i](this._band, op, evt, els);
+    }
+};
+/*==================================================
+ *  Detailed Event Painter
+ *==================================================
+ */
+
+// Note: a number of features from original-painter
+//       are not yet implemented in detailed painter.
+//       Eg classname, id attributes for icons, labels, tapes
+
+Timeline.DetailedEventPainter = function(params) {
+    this._params = params;
+    this._onSelectListeners = [];
+
+    this._filterMatcher = null;
+    this._highlightMatcher = null;
+    this._frc = null;
+
+    this._eventIdToElmt = {};
+};
+
+Timeline.DetailedEventPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._backLayer = null;
+    this._eventLayer = null;
+    this._lineLayer = null;
+    this._highlightLayer = null;
+
+    this._eventIdToElmt = null;
+};
+
+Timeline.DetailedEventPainter.prototype.getType = function() {
+    return 'detailed';
+};
+
+Timeline.DetailedEventPainter.prototype.addOnSelectListener = function(listener) {
+    this._onSelectListeners.push(listener);
+};
+
+Timeline.DetailedEventPainter.prototype.removeOnSelectListener = function(listener) {
+    for (var i = 0; i < this._onSelectListeners.length; i++) {
+        if (this._onSelectListeners[i] == listener) {
+            this._onSelectListeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+Timeline.DetailedEventPainter.prototype.getFilterMatcher = function() {
+    return this._filterMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+    this._filterMatcher = filterMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.getHighlightMatcher = function() {
+    return this._highlightMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+    this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.DetailedEventPainter.prototype.paint = function() {
+    var eventSource = this._band.getEventSource();
+    if (eventSource == null) {
+        return;
+    }
+
+    this._eventIdToElmt = {};
+    this._prepareForPainting();
+
+    var eventTheme = this._params.theme.event;
+    var trackHeight = Math.max(eventTheme.track.height, this._frc.getLineHeight());
+    var metrics = {
+        trackOffset:    Math.round(this._band.getViewWidth() / 2 - trackHeight / 2),
+        trackHeight:    trackHeight,
+        trackGap:       eventTheme.track.gap,
+        trackIncrement: trackHeight + eventTheme.track.gap,
+        icon:           eventTheme.instant.icon,
+        iconWidth:      eventTheme.instant.iconWidth,
+        iconHeight:     eventTheme.instant.iconHeight,
+        labelWidth:     eventTheme.label.width
+    }
+
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    var filterMatcher = (this._filterMatcher != null) ?
+        this._filterMatcher :
+        function(evt) { return true; };
+    var highlightMatcher = (this._highlightMatcher != null) ?
+        this._highlightMatcher :
+        function(evt) { return -1; };
+
+    var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
+    while (iterator.hasNext()) {
+        var evt = iterator.next();
+        if (filterMatcher(evt)) {
+            this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+        }
+    }
+
+    this._highlightLayer.style.display = "block";
+    this._lineLayer.style.display = "block";
+    this._eventLayer.style.display = "block";
+    // update the band object for max number of tracks in this section of the ether
+    this._band.updateEventTrackInfo(this._lowerTracks.length + this._upperTracks.length,
+                                 metrics.trackIncrement);
+};
+
+Timeline.DetailedEventPainter.prototype.softPaint = function() {
+};
+
+Timeline.DetailedEventPainter.prototype._prepareForPainting = function() {
+    var band = this._band;
+
+    if (this._backLayer == null) {
+        this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+        this._backLayer.style.visibility = "hidden";
+
+        var eventLabelPrototype = document.createElement("span");
+        eventLabelPrototype.className = "timeline-event-label";
+        this._backLayer.appendChild(eventLabelPrototype);
+        this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+    }
+    this._frc.update();
+    this._lowerTracks = [];
+    this._upperTracks = [];
+
+    if (this._highlightLayer != null) {
+        band.removeLayerDiv(this._highlightLayer);
+    }
+    this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+    this._highlightLayer.style.display = "none";
+
+    if (this._lineLayer != null) {
+        band.removeLayerDiv(this._lineLayer);
+    }
+    this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+    this._lineLayer.style.display = "none";
+
+    if (this._eventLayer != null) {
+        band.removeLayerDiv(this._eventLayer);
+    }
+    this._eventLayer = band.createLayerDiv(110, "timeline-band-events");
+    this._eventLayer.style.display = "none";
+};
+
+Timeline.DetailedEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isInstant()) {
+        this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+    }
+};
+
+Timeline.DetailedEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isImprecise()) {
+        this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+    }
+}
+
+Timeline.DetailedEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isImprecise()) {
+        this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+    }
+}
+
+Timeline.DetailedEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+    var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+    var labelSize = this._frc.computeSize(text);
+    var iconTrack = this._findFreeTrackForSolid(iconRightEdge, startPixel);
+    var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
+
+    var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+    var labelTrack = iconTrack;
+
+    var iconTrackData = this._getTrackData(iconTrack);
+    if (Math.min(iconTrackData.solid, iconTrackData.text) >= labelLeft + labelSize.width) { // label on the same track, to the right of icon
+        iconTrackData.solid = iconLeftEdge;
+        iconTrackData.text = labelLeft;
+    } else { // label on a different track, below icon
+        iconTrackData.solid = iconLeftEdge;
+
+        labelLeft = startPixel + theme.event.label.offsetFromLine;
+        labelTrack = this._findFreeTrackForText(iconTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
+        this._getTrackData(labelTrack).text = iconLeftEdge;
+
+        this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
+    }
+
+    var labelTop = Math.round(
+        metrics.trackOffset + labelTrack * metrics.trackIncrement +
+        metrics.trackHeight / 2 - labelSize.height / 2);
+
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+    this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var endDate = evt.getEnd();
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+    var iconRightEdge = Math.round(startPixel + metrics.iconWidth / 2);
+    var iconLeftEdge = Math.round(startPixel - metrics.iconWidth / 2);
+
+    var labelSize = this._frc.computeSize(text);
+    var iconTrack = this._findFreeTrackForSolid(endPixel, startPixel);
+
+    var tapeElmtData = this._paintEventTape(evt, iconTrack, startPixel, endPixel,
+        theme.event.instant.impreciseColor, theme.event.instant.impreciseOpacity, metrics, theme);
+    var iconElmtData = this._paintEventIcon(evt, iconTrack, iconLeftEdge, metrics, theme);
+
+    var iconTrackData = this._getTrackData(iconTrack);
+    iconTrackData.solid = iconLeftEdge;
+
+    var labelLeft = iconRightEdge + theme.event.label.offsetFromLine;
+    var labelRight = labelLeft + labelSize.width;
+    var labelTrack;
+    if (labelRight < endPixel) {
+        labelTrack = iconTrack;
+    } else {
+        labelLeft = startPixel + theme.event.label.offsetFromLine;
+        labelRight = labelLeft + labelSize.width;
+
+        labelTrack = this._findFreeTrackForText(iconTrack, labelRight, function(t) { t.line = startPixel - 2; });
+        this._getTrackData(labelTrack).text = iconLeftEdge;
+
+        this._paintEventLine(evt, startPixel, iconTrack, labelTrack, metrics, theme);
+    }
+    var labelTop = Math.round(
+        metrics.trackOffset + labelTrack * metrics.trackIncrement +
+        metrics.trackHeight / 2 - labelSize.height / 2);
+
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickInstantEvent(iconElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(iconElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+    this._eventIdToElmt[evt.getID()] = iconElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var endDate = evt.getEnd();
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+
+    var labelSize = this._frc.computeSize(text);
+    var tapeTrack = this._findFreeTrackForSolid(endPixel);
+    var color = evt.getColor();
+    color = color != null ? color : theme.event.duration.color;
+
+    var tapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel, color, 100, metrics, theme);
+
+    var tapeTrackData = this._getTrackData(tapeTrack);
+    tapeTrackData.solid = startPixel;
+
+    var labelLeft = startPixel + theme.event.label.offsetFromLine;
+    var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = startPixel - 2; });
+    this._getTrackData(labelTrack).text = startPixel - 2;
+
+    this._paintEventLine(evt, startPixel, tapeTrack, labelTrack, metrics, theme);
+
+    var labelTop = Math.round(
+        metrics.trackOffset + labelTrack * metrics.trackIncrement +
+        metrics.trackHeight / 2 - labelSize.height / 2);
+
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+
+    this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    var doc = this._timeline.getDocument();
+    var text = evt.getText();
+
+    var startDate = evt.getStart();
+    var latestStartDate = evt.getLatestStart();
+    var endDate = evt.getEnd();
+    var earliestEndDate = evt.getEarliestEnd();
+
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+    var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
+    var endPixel = Math.round(this._band.dateToPixelOffset(endDate));
+    var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
+
+    var labelSize = this._frc.computeSize(text);
+    var tapeTrack = this._findFreeTrackForSolid(endPixel);
+    var color = evt.getColor();
+    color = color != null ? color : theme.event.duration.color;
+
+    var impreciseTapeElmtData = this._paintEventTape(evt, tapeTrack, startPixel, endPixel,
+        theme.event.duration.impreciseColor, theme.event.duration.impreciseOpacity, metrics, theme);
+    var tapeElmtData = this._paintEventTape(evt, tapeTrack, latestStartPixel, earliestEndPixel, color, 100, metrics, theme);
+
+    var tapeTrackData = this._getTrackData(tapeTrack);
+    tapeTrackData.solid = startPixel;
+
+    var labelLeft = latestStartPixel + theme.event.label.offsetFromLine;
+    var labelTrack = this._findFreeTrackForText(tapeTrack, labelLeft + labelSize.width, function(t) { t.line = latestStartPixel - 2; });
+    this._getTrackData(labelTrack).text = latestStartPixel - 2;
+
+    this._paintEventLine(evt, latestStartPixel, tapeTrack, labelTrack, metrics, theme);
+
+    var labelTop = Math.round(
+        metrics.trackOffset + labelTrack * metrics.trackIncrement +
+        metrics.trackHeight / 2 - labelSize.height / 2);
+
+    var labelElmtData = this._paintEventLabel(evt, text, labelLeft, labelTop, labelSize.width, labelSize.height, theme);
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickDurationEvent(tapeElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(tapeElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+    this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+
+    this._eventIdToElmt[evt.getID()] = tapeElmtData.elmt;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeTrackForSolid = function(solidEdge, softEdge) {
+    for (var i = 0; true; i++) {
+        if (i < this._lowerTracks.length) {
+            var t = this._lowerTracks[i];
+            if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
+                return i;
+            }
+        } else {
+            this._lowerTracks.push({
+                solid:  Number.POSITIVE_INFINITY,
+                text:   Number.POSITIVE_INFINITY,
+                line:   Number.POSITIVE_INFINITY
+            });
+
+            return i;
+        }
+
+        if (i < this._upperTracks.length) {
+            var t = this._upperTracks[i];
+            if (Math.min(t.solid, t.text) > solidEdge && (!(softEdge) || t.line > softEdge)) {
+                return -1 - i;
+            }
+        } else {
+            this._upperTracks.push({
+                solid:  Number.POSITIVE_INFINITY,
+                text:   Number.POSITIVE_INFINITY,
+                line:   Number.POSITIVE_INFINITY
+            });
+
+            return -1 - i;
+        }
+    }
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeTrackForText = function(fromTrack, edge, occupiedTrackVisitor) {
+    var extendUp;
+    var index;
+    var firstIndex;
+    var result;
+
+    if (fromTrack < 0) {
+        extendUp = true;
+        firstIndex = -fromTrack;
+
+        index = this._findFreeUpperTrackForText(firstIndex, edge);
+        result = -1 - index;
+    } else if (fromTrack > 0) {
+        extendUp = false;
+        firstIndex = fromTrack + 1;
+
+        index = this._findFreeLowerTrackForText(firstIndex, edge);
+        result = index;
+    } else {
+        var upIndex = this._findFreeUpperTrackForText(0, edge);
+        var downIndex = this._findFreeLowerTrackForText(1, edge);
+
+        if (downIndex - 1 <= upIndex) {
+            extendUp = false;
+            firstIndex = 1;
+            index = downIndex;
+            result = index;
+        } else {
+            extendUp = true;
+            firstIndex = 0;
+            index = upIndex;
+            result = -1 - index;
+        }
+    }
+
+    if (extendUp) {
+        if (index == this._upperTracks.length) {
+            this._upperTracks.push({
+                solid:  Number.POSITIVE_INFINITY,
+                text:   Number.POSITIVE_INFINITY,
+                line:   Number.POSITIVE_INFINITY
+            });
+        }
+        for (var i = firstIndex; i < index; i++) {
+            occupiedTrackVisitor(this._upperTracks[i]);
+        }
+    } else {
+        if (index == this._lowerTracks.length) {
+            this._lowerTracks.push({
+                solid:  Number.POSITIVE_INFINITY,
+                text:   Number.POSITIVE_INFINITY,
+                line:   Number.POSITIVE_INFINITY
+            });
+        }
+        for (var i = firstIndex; i < index; i++) {
+            occupiedTrackVisitor(this._lowerTracks[i]);
+        }
+    }
+    return result;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeLowerTrackForText = function(index, edge) {
+    for (; index < this._lowerTracks.length; index++) {
+        var t = this._lowerTracks[index];
+        if (Math.min(t.solid, t.text) >= edge) {
+            break;
+        }
+    }
+    return index;
+};
+
+Timeline.DetailedEventPainter.prototype._findFreeUpperTrackForText = function(index, edge) {
+    for (; index < this._upperTracks.length; index++) {
+        var t = this._upperTracks[index];
+        if (Math.min(t.solid, t.text) >= edge) {
+            break;
+        }
+    }
+    return index;
+};
+
+Timeline.DetailedEventPainter.prototype._getTrackData = function(index) {
+    return (index < 0) ? this._upperTracks[-index - 1] : this._lowerTracks[index];
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventLine = function(evt, left, startTrack, endTrack, metrics, theme) {
+    var top = Math.round(metrics.trackOffset + startTrack * metrics.trackIncrement + metrics.trackHeight / 2);
+    var height = Math.round(Math.abs(endTrack - startTrack) * metrics.trackIncrement);
+
+    var lineStyle = "1px solid " + theme.event.label.lineColor;
+    var lineDiv = this._timeline.getDocument().createElement("div");
+	lineDiv.style.position = "absolute";
+    lineDiv.style.left = left + "px";
+    lineDiv.style.width = theme.event.label.offsetFromLine + "px";
+    lineDiv.style.height = height + "px";
+    if (startTrack > endTrack) {
+        lineDiv.style.top = (top - height) + "px";
+        lineDiv.style.borderTop = lineStyle;
+    } else {
+        lineDiv.style.top = top + "px";
+        lineDiv.style.borderBottom = lineStyle;
+    }
+    lineDiv.style.borderLeft = lineStyle;
+    this._lineLayer.appendChild(lineDiv);
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventIcon = function(evt, iconTrack, left, metrics, theme) {
+    var icon = evt.getIcon();
+    icon = icon != null ? icon : metrics.icon;
+
+    var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
+    var top = Math.round(middle - metrics.iconHeight / 2);
+
+    var img = SimileAjax.Graphics.createTranslucentImage(icon);
+    var iconDiv = this._timeline.getDocument().createElement("div");
+    iconDiv.style.position = "absolute";
+    iconDiv.style.left = left + "px";
+    iconDiv.style.top = top + "px";
+    iconDiv.appendChild(img);
+    iconDiv.style.cursor = "pointer";
+
+    if(evt._title != null)
+        iconDiv.title = evt._title
+
+    this._eventLayer.appendChild(iconDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  metrics.iconWidth,
+        height: metrics.iconHeight,
+        elmt:   iconDiv
+    };
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventLabel = function(evt, text, left, top, width, height, theme) {
+    var doc = this._timeline.getDocument();
+
+    var labelBackgroundDiv = doc.createElement("div");
+    labelBackgroundDiv.style.position = "absolute";
+    labelBackgroundDiv.style.left = left + "px";
+    labelBackgroundDiv.style.width = width + "px";
+    labelBackgroundDiv.style.top = top + "px";
+    labelBackgroundDiv.style.height = height + "px";
+    labelBackgroundDiv.style.backgroundColor = theme.event.label.backgroundColor;
+    SimileAjax.Graphics.setOpacity(labelBackgroundDiv, theme.event.label.backgroundOpacity);
+    this._eventLayer.appendChild(labelBackgroundDiv);
+
+    var labelDiv = doc.createElement("div");
+    labelDiv.style.position = "absolute";
+    labelDiv.style.left = left + "px";
+    labelDiv.style.width = width + "px";
+    labelDiv.style.top = top + "px";
+    labelDiv.innerHTML = text;
+    labelDiv.style.cursor = "pointer";
+
+    if(evt._title != null)
+        labelDiv.title = evt._title;
+
+    var color = evt.getTextColor();
+    if (color == null) {
+        color = evt.getColor();
+    }
+    if (color != null) {
+        labelDiv.style.color = color;
+    }
+
+    this._eventLayer.appendChild(labelDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  width,
+        height: height,
+        elmt:   labelDiv
+    };
+};
+
+Timeline.DetailedEventPainter.prototype._paintEventTape = function(
+    evt, iconTrack, startPixel, endPixel, color, opacity, metrics, theme) {
+
+    var tapeWidth = endPixel - startPixel;
+    var tapeHeight = theme.event.tape.height;
+    var middle = metrics.trackOffset + iconTrack * metrics.trackIncrement + metrics.trackHeight / 2;
+    var top = Math.round(middle - tapeHeight / 2);
+
+    var tapeDiv = this._timeline.getDocument().createElement("div");
+    tapeDiv.style.position = "absolute";
+    tapeDiv.style.left = startPixel + "px";
+    tapeDiv.style.width = tapeWidth + "px";
+    tapeDiv.style.top = top + "px";
+    tapeDiv.style.height = tapeHeight + "px";
+    tapeDiv.style.backgroundColor = color;
+    tapeDiv.style.overflow = "hidden";
+    tapeDiv.style.cursor = "pointer";
+
+    if(evt._title != null)
+        tapeDiv.title = evt._title;
+
+    SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+    this._eventLayer.appendChild(tapeDiv);
+
+    return {
+        left:   startPixel,
+        top:    top,
+        width:  tapeWidth,
+        height: tapeHeight,
+        elmt:   tapeDiv
+    };
+}
+
+Timeline.DetailedEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+    if (highlightIndex >= 0) {
+        var doc = this._timeline.getDocument();
+        var eventTheme = theme.event;
+
+        var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+        var div = doc.createElement("div");
+        div.style.position = "absolute";
+        div.style.overflow = "hidden";
+        div.style.left =    (dimensions.left - 2) + "px";
+        div.style.width =   (dimensions.width + 4) + "px";
+        div.style.top =     (dimensions.top - 2) + "px";
+        div.style.height =  (dimensions.height + 4) + "px";
+        div.style.background = color;
+
+        this._highlightLayer.appendChild(div);
+    }
+};
+
+Timeline.DetailedEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+    var c = SimileAjax.DOM.getPageCoordinates(icon);
+    this._showBubble(
+        c.left + Math.ceil(icon.offsetWidth / 2),
+        c.top + Math.ceil(icon.offsetHeight / 2),
+        evt
+    );
+    this._fireOnSelect(evt.getID());
+
+    domEvt.cancelBubble = true;
+    SimileAjax.DOM.cancelEvent(domEvt);
+    return false;
+};
+
+Timeline.DetailedEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+    if ("pageX" in domEvt) {
+        var x = domEvt.pageX;
+        var y = domEvt.pageY;
+    } else {
+        var c = SimileAjax.DOM.getPageCoordinates(target);
+        var x = domEvt.offsetX + c.left;
+        var y = domEvt.offsetY + c.top;
+    }
+    this._showBubble(x, y, evt);
+    this._fireOnSelect(evt.getID());
+
+    domEvt.cancelBubble = true;
+    SimileAjax.DOM.cancelEvent(domEvt);
+    return false;
+};
+
+Timeline.DetailedEventPainter.prototype.showBubble = function(evt) {
+    var elmt = this._eventIdToElmt[evt.getID()];
+    if (elmt) {
+        var c = SimileAjax.DOM.getPageCoordinates(elmt);
+        this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, evt);
+    }
+};
+
+Timeline.DetailedEventPainter.prototype._showBubble = function(x, y, evt) {
+    var div = document.createElement("div");
+    var themeBubble = this._params.theme.event.bubble;
+    evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
+
+    SimileAjax.WindowManager.cancelPopups();
+    SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y,
+       themeBubble.width, null, themeBubble.maxHeight);
+};
+
+Timeline.DetailedEventPainter.prototype._fireOnSelect = function(eventID) {
+    for (var i = 0; i < this._onSelectListeners.length; i++) {
+        this._onSelectListeners[i](eventID);
+    }
+};
+/*==================================================
+ *  Overview Event Painter
+ *==================================================
+ */
+
+Timeline.OverviewEventPainter = function(params) {
+    this._params = params;
+    this._onSelectListeners = [];
+
+    this._filterMatcher = null;
+    this._highlightMatcher = null;
+};
+
+Timeline.OverviewEventPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._eventLayer = null;
+    this._highlightLayer = null;
+};
+
+Timeline.OverviewEventPainter.prototype.getType = function() {
+    return 'overview';
+};
+
+Timeline.OverviewEventPainter.prototype.addOnSelectListener = function(listener) {
+    this._onSelectListeners.push(listener);
+};
+
+Timeline.OverviewEventPainter.prototype.removeOnSelectListener = function(listener) {
+    for (var i = 0; i < this._onSelectListeners.length; i++) {
+        if (this._onSelectListeners[i] == listener) {
+            this._onSelectListeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+Timeline.OverviewEventPainter.prototype.getFilterMatcher = function() {
+    return this._filterMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+    this._filterMatcher = filterMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.getHighlightMatcher = function() {
+    return this._highlightMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+    this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.OverviewEventPainter.prototype.paint = function() {
+    var eventSource = this._band.getEventSource();
+    if (eventSource == null) {
+        return;
+    }
+
+    this._prepareForPainting();
+
+    var eventTheme = this._params.theme.event;
+    var metrics = {
+        trackOffset:    eventTheme.overviewTrack.offset,
+        trackHeight:    eventTheme.overviewTrack.height,
+        trackGap:       eventTheme.overviewTrack.gap,
+        trackIncrement: eventTheme.overviewTrack.height + eventTheme.overviewTrack.gap
+    }
+
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    var filterMatcher = (this._filterMatcher != null) ?
+        this._filterMatcher :
+        function(evt) { return true; };
+    var highlightMatcher = (this._highlightMatcher != null) ?
+        this._highlightMatcher :
+        function(evt) { return -1; };
+
+    var iterator = eventSource.getEventReverseIterator(minDate, maxDate);
+    while (iterator.hasNext()) {
+        var evt = iterator.next();
+        if (filterMatcher(evt)) {
+            this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+        }
+    }
+
+    this._highlightLayer.style.display = "block";
+    this._eventLayer.style.display = "block";
+    // update the band object for max number of tracks in this section of the ether
+    this._band.updateEventTrackInfo(this._tracks.length, metrics.trackIncrement);
+};
+
+Timeline.OverviewEventPainter.prototype.softPaint = function() {
+};
+
+Timeline.OverviewEventPainter.prototype._prepareForPainting = function() {
+    var band = this._band;
+
+    this._tracks = [];
+
+    if (this._highlightLayer != null) {
+        band.removeLayerDiv(this._highlightLayer);
+    }
+    this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+    this._highlightLayer.style.display = "none";
+
+    if (this._eventLayer != null) {
+        band.removeLayerDiv(this._eventLayer);
+    }
+    this._eventLayer = band.createLayerDiv(110, "timeline-band-events");
+    this._eventLayer.style.display = "none";
+};
+
+Timeline.OverviewEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isInstant()) {
+        this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+    }
+};
+
+Timeline.OverviewEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    var startDate = evt.getStart();
+    var startPixel = Math.round(this._band.dateToPixelOffset(startDate));
+
+    var color = evt.getColor(),
+        klassName = evt.getClassName();
+    if (klassName) {
+      color = null;
+    } else {
+      color = color != null ? color : theme.event.duration.color;
+    }
+
+    var tickElmtData = this._paintEventTick(evt, startPixel, color, 100, metrics, theme);
+
+    this._createHighlightDiv(highlightIndex, tickElmtData, theme);
+};
+
+Timeline.OverviewEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    var latestStartDate = evt.getLatestStart();
+    var earliestEndDate = evt.getEarliestEnd();
+
+    var latestStartPixel = Math.round(this._band.dateToPixelOffset(latestStartDate));
+    var earliestEndPixel = Math.round(this._band.dateToPixelOffset(earliestEndDate));
+
+    var tapeTrack = 0;
+    for (; tapeTrack < this._tracks.length; tapeTrack++) {
+        if (earliestEndPixel < this._tracks[tapeTrack]) {
+            break;
+        }
+    }
+    this._tracks[tapeTrack] = earliestEndPixel;
+
+    var color = evt.getColor(),
+        klassName = evt.getClassName();
+    if (klassName) {
+      color = null;
+    } else {
+      color = color != null ? color : theme.event.duration.color;
+    }
+
+    var tapeElmtData = this._paintEventTape(evt, tapeTrack, latestStartPixel, earliestEndPixel,
+      color, 100, metrics, theme, klassName);
+
+    this._createHighlightDiv(highlightIndex, tapeElmtData, theme);
+};
+
+Timeline.OverviewEventPainter.prototype._paintEventTape = function(
+    evt, track, left, right, color, opacity, metrics, theme, klassName) {
+
+    var top = metrics.trackOffset + track * metrics.trackIncrement;
+    var width = right - left;
+    var height = metrics.trackHeight;
+
+    var tapeDiv = this._timeline.getDocument().createElement("div");
+    tapeDiv.className = 'timeline-small-event-tape'
+    if (klassName) {tapeDiv.className += ' small-' + klassName;}
+    tapeDiv.style.left = left + "px";
+    tapeDiv.style.width = width + "px";
+    tapeDiv.style.top = top + "px";
+    tapeDiv.style.height = height + "px";
+
+    if (color) {
+      tapeDiv.style.backgroundColor = color; // set color here if defined by event. Else use css
+    }
+ //   tapeDiv.style.overflow = "hidden";   // now set in css
+ //   tapeDiv.style.position = "absolute";
+    if(opacity<100) SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+    this._eventLayer.appendChild(tapeDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  width,
+        height: height,
+        elmt:   tapeDiv
+    };
+}
+
+Timeline.OverviewEventPainter.prototype._paintEventTick = function(
+    evt, left, color, opacity, metrics, theme) {
+
+    var height = theme.event.overviewTrack.tickHeight;
+    var top = metrics.trackOffset - height;
+    var width = 1;
+
+    var tickDiv = this._timeline.getDocument().createElement("div");
+	  tickDiv.className = 'timeline-small-event-icon'
+    tickDiv.style.left = left + "px";
+    tickDiv.style.top = top + "px";
+  //  tickDiv.style.width = width + "px";
+  //  tickDiv.style.position = "absolute";
+  //  tickDiv.style.height = height + "px";
+  //  tickDiv.style.backgroundColor = color;
+  //  tickDiv.style.overflow = "hidden";
+
+    var klassName = evt.getClassName()
+    if (klassName) {tickDiv.className +=' small-' + klassName};
+
+    if(opacity<100) {SimileAjax.Graphics.setOpacity(tickDiv, opacity)};
+
+    this._eventLayer.appendChild(tickDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  width,
+        height: height,
+        elmt:   tickDiv
+    };
+}
+
+Timeline.OverviewEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+    if (highlightIndex >= 0) {
+        var doc = this._timeline.getDocument();
+        var eventTheme = theme.event;
+
+        var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+        var div = doc.createElement("div");
+        div.style.position = "absolute";
+        div.style.overflow = "hidden";
+        div.style.left =    (dimensions.left - 1) + "px";
+        div.style.width =   (dimensions.width + 2) + "px";
+        div.style.top =     (dimensions.top - 1) + "px";
+        div.style.height =  (dimensions.height + 2) + "px";
+        div.style.background = color;
+
+        this._highlightLayer.appendChild(div);
+    }
+};
+
+Timeline.OverviewEventPainter.prototype.showBubble = function(evt) {
+    // not implemented
+};
+/*==================================================
+ *  Compact Event Painter
+ *==================================================
+ */
+
+Timeline.CompactEventPainter = function(params) {
+    this._params = params;
+    this._onSelectListeners = [];
+
+    this._filterMatcher = null;
+    this._highlightMatcher = null;
+    this._frc = null;
+
+    this._eventIdToElmt = {};
+};
+
+Timeline.CompactEventPainter.prototype.getType = function() {
+    return 'compact';
+};
+
+Timeline.CompactEventPainter.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._backLayer = null;
+    this._eventLayer = null;
+    this._lineLayer = null;
+    this._highlightLayer = null;
+
+    this._eventIdToElmt = null;
+};
+
+Timeline.CompactEventPainter.prototype.addOnSelectListener = function(listener) {
+    this._onSelectListeners.push(listener);
+};
+
+Timeline.CompactEventPainter.prototype.removeOnSelectListener = function(listener) {
+    for (var i = 0; i < this._onSelectListeners.length; i++) {
+        if (this._onSelectListeners[i] == listener) {
+            this._onSelectListeners.splice(i, 1);
+            break;
+        }
+    }
+};
+
+Timeline.CompactEventPainter.prototype.getFilterMatcher = function() {
+    return this._filterMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.setFilterMatcher = function(filterMatcher) {
+    this._filterMatcher = filterMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.getHighlightMatcher = function() {
+    return this._highlightMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) {
+    this._highlightMatcher = highlightMatcher;
+};
+
+Timeline.CompactEventPainter.prototype.paint = function() {
+    var eventSource = this._band.getEventSource();
+    if (eventSource == null) {
+        return;
+    }
+
+    this._eventIdToElmt = {};
+    this._prepareForPainting();
+
+    var metrics = this._computeMetrics();
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    var filterMatcher = (this._filterMatcher != null) ?
+        this._filterMatcher :
+        function(evt) { return true; };
+
+    var highlightMatcher = (this._highlightMatcher != null) ?
+        this._highlightMatcher :
+        function(evt) { return -1; };
+
+    var iterator = eventSource.getEventIterator(minDate, maxDate);
+
+    var stackConcurrentPreciseInstantEvents = "stackConcurrentPreciseInstantEvents" in this._params && typeof this._params.stackConcurrentPreciseInstantEvents == "object";
+    var collapseConcurrentPreciseInstantEvents = "collapseConcurrentPreciseInstantEvents" in this._params && this._params.collapseConcurrentPreciseInstantEvents;
+    if (collapseConcurrentPreciseInstantEvents || stackConcurrentPreciseInstantEvents) {
+        var bufferedEvents = [];
+        var previousInstantEvent = null;
+
+        while (iterator.hasNext()) {
+            var evt = iterator.next();
+            if (filterMatcher(evt)) {
+                if (!evt.isInstant() || evt.isImprecise()) {
+                    this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+                } else if (previousInstantEvent != null &&
+                        previousInstantEvent.getStart().getTime() == evt.getStart().getTime()) {
+                    bufferedEvents[bufferedEvents.length - 1].push(evt);
+                } else {
+                    bufferedEvents.push([ evt ]);
+                    previousInstantEvent = evt;
+                }
+            }
+        }
+
+        for (var i = 0; i < bufferedEvents.length; i++) {
+            var compositeEvents = bufferedEvents[i];
+            if (compositeEvents.length == 1) {
+                this.paintEvent(compositeEvents[0], metrics, this._params.theme, highlightMatcher(evt));
+            } else {
+                var match = -1;
+                for (var j = 0; match < 0 && j < compositeEvents.length; j++) {
+                    match = highlightMatcher(compositeEvents[j]);
+                }
+
+                if (stackConcurrentPreciseInstantEvents) {
+                    this.paintStackedPreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
+                } else {
+                    this.paintCompositePreciseInstantEvents(compositeEvents, metrics, this._params.theme, match);
+                }
+            }
+        }
+    } else {
+        while (iterator.hasNext()) {
+            var evt = iterator.next();
+            if (filterMatcher(evt)) {
+                this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt));
+            }
+        }
+    }
+
+    this._highlightLayer.style.display = "block";
+    this._lineLayer.style.display = "block";
+    this._eventLayer.style.display = "block";
+
+    this._setOrthogonalOffset(metrics);
+};
+
+Timeline.CompactEventPainter.prototype.softPaint = function() {
+    this._setOrthogonalOffset(this._computeMetrics());
+};
+
+Timeline.CompactEventPainter.prototype._setOrthogonalOffset = function(metrics) {
+    var actualViewWidth = 2 * metrics.trackOffset + this._tracks.length * metrics.trackHeight;
+    var minOrthogonalOffset = Math.min(0, this._band.getViewWidth() - actualViewWidth);
+    var orthogonalOffset = Math.max(minOrthogonalOffset, this._band.getViewOrthogonalOffset());
+
+    this._highlightLayer.style.top =
+        this._lineLayer.style.top =
+            this._eventLayer.style.top =
+                orthogonalOffset + "px";
+};
+
+Timeline.CompactEventPainter.prototype._computeMetrics = function() {
+    var theme = this._params.theme;
+    var eventTheme = theme.event;
+
+    var metrics = {
+        trackOffset:            "trackOffset" in this._params ? this._params.trackOffset : 10,
+        trackHeight:            "trackHeight" in this._params ? this._params.trackHeight : 10,
+
+        tapeHeight:             theme.event.tape.height,
+        tapeBottomMargin:       "tapeBottomMargin" in this._params ? this._params.tapeBottomMargin : 2,
+
+        labelBottomMargin:      "labelBottomMargin" in this._params ? this._params.labelBottomMargin : 5,
+        labelRightMargin:       "labelRightMargin" in this._params ? this._params.labelRightMargin : 5,
+
+        defaultIcon:            eventTheme.instant.icon,
+        defaultIconWidth:       eventTheme.instant.iconWidth,
+        defaultIconHeight:      eventTheme.instant.iconHeight,
+
+        customIconWidth:        "iconWidth" in this._params ? this._params.iconWidth : eventTheme.instant.iconWidth,
+        customIconHeight:       "iconHeight" in this._params ? this._params.iconHeight : eventTheme.instant.iconHeight,
+
+        iconLabelGap:           "iconLabelGap" in this._params ? this._params.iconLabelGap : 2,
+        iconBottomMargin:       "iconBottomMargin" in this._params ? this._params.iconBottomMargin : 2
+    };
+    if ("compositeIcon" in this._params) {
+        metrics.compositeIcon = this._params.compositeIcon;
+        metrics.compositeIconWidth = this._params.compositeIconWidth || metrics.customIconWidth;
+        metrics.compositeIconHeight = this._params.compositeIconHeight || metrics.customIconHeight;
+    } else {
+        metrics.compositeIcon = metrics.defaultIcon;
+        metrics.compositeIconWidth = metrics.defaultIconWidth;
+        metrics.compositeIconHeight = metrics.defaultIconHeight;
+    }
+    metrics.defaultStackIcon = "icon" in this._params.stackConcurrentPreciseInstantEvents ?
+        this._params.stackConcurrentPreciseInstantEvents.icon : metrics.defaultIcon;
+    metrics.defaultStackIconWidth = "iconWidth" in this._params.stackConcurrentPreciseInstantEvents ?
+        this._params.stackConcurrentPreciseInstantEvents.iconWidth : metrics.defaultIconWidth;
+    metrics.defaultStackIconHeight = "iconHeight" in this._params.stackConcurrentPreciseInstantEvents ?
+        this._params.stackConcurrentPreciseInstantEvents.iconHeight : metrics.defaultIconHeight;
+
+    return metrics;
+};
+
+Timeline.CompactEventPainter.prototype._prepareForPainting = function() {
+    var band = this._band;
+
+    if (this._backLayer == null) {
+        this._backLayer = this._band.createLayerDiv(0, "timeline-band-events");
+        this._backLayer.style.visibility = "hidden";
+
+        var eventLabelPrototype = document.createElement("span");
+        eventLabelPrototype.className = "timeline-event-label";
+        this._backLayer.appendChild(eventLabelPrototype);
+        this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype);
+    }
+    this._frc.update();
+    this._tracks = [];
+
+    if (this._highlightLayer != null) {
+        band.removeLayerDiv(this._highlightLayer);
+    }
+    this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights");
+    this._highlightLayer.style.display = "none";
+
+    if (this._lineLayer != null) {
+        band.removeLayerDiv(this._lineLayer);
+    }
+    this._lineLayer = band.createLayerDiv(110, "timeline-band-lines");
+    this._lineLayer.style.display = "none";
+
+    if (this._eventLayer != null) {
+        band.removeLayerDiv(this._eventLayer);
+    }
+    this._eventLayer = band.createLayerDiv(115, "timeline-band-events");
+    this._eventLayer.style.display = "none";
+};
+
+Timeline.CompactEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isInstant()) {
+        this.paintInstantEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintDurationEvent(evt, metrics, theme, highlightIndex);
+    }
+};
+
+Timeline.CompactEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isImprecise()) {
+        this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex);
+    }
+}
+
+Timeline.CompactEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    if (evt.isImprecise()) {
+        this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex);
+    } else {
+        this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex);
+    }
+}
+
+Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    var commonData = {
+        tooltip: evt.getProperty("tooltip") || evt.getText()
+    };
+
+    var iconData = {
+        url: evt.getIcon()
+    };
+    if (iconData.url == null) {
+        iconData.url = metrics.defaultIcon;
+        iconData.width = metrics.defaultIconWidth;
+        iconData.height = metrics.defaultIconHeight;
+        iconData.className = "timeline-event-icon-default";
+    } else {
+        iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+        iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+    }
+
+    var labelData = {
+        text:       evt.getText(),
+        color:      evt.getTextColor() || evt.getColor(),
+        className:  evt.getClassName()
+    };
+
+    var result = this.paintTapeIconLabel(
+        evt.getStart(),
+        commonData,
+        null, // no tape data
+        iconData,
+        labelData,
+        metrics,
+        theme,
+        highlightIndex
+    );
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+    };
+    SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+
+    this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+};
+
+Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
+    var evt = events[0];
+
+    var tooltips = [];
+    for (var i = 0; i < events.length; i++) {
+        tooltips.push(events[i].getProperty("tooltip") || events[i].getText());
+    }
+    var commonData = {
+        tooltip: tooltips.join("; ")
+    };
+
+    var iconData = {
+        url: metrics.compositeIcon,
+        width: metrics.compositeIconWidth,
+        height: metrics.compositeIconHeight,
+        className: "timeline-event-icon-composite"
+    };
+
+    var labelData = {
+        text: String.substitute(this._params.compositeEventLabelTemplate, [ events.length ])
+    };
+
+    var result = this.paintTapeIconLabel(
+        evt.getStart(),
+        commonData,
+        null, // no tape data
+        iconData,
+        labelData,
+        metrics,
+        theme,
+        highlightIndex
+    );
+
+    var self = this;
+    var clickHandler = function(elmt, domEvt, target) {
+        return self._onClickMultiplePreciseInstantEvent(result.iconElmtData.elmt, domEvt, events);
+    };
+
+    SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+
+    for (var i = 0; i < events.length; i++) {
+        this._eventIdToElmt[events[i].getID()] = result.iconElmtData.elmt;
+    }
+};
+
+Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents = function(events, metrics, theme, highlightIndex) {
+    var limit = "limit" in this._params.stackConcurrentPreciseInstantEvents ?
+        this._params.stackConcurrentPreciseInstantEvents.limit : 10;
+    var moreMessageTemplate = "moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents ?
+        this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate : "%0 More Events";
+    var showMoreMessage = limit <= events.length - 2; // We want at least 2 more events above the limit.
+                                                      // Otherwise we'd need the singular case of "1 More Event"
+
+    var band = this._band;
+    var getPixelOffset = function(date) {
+        return Math.round(band.dateToPixelOffset(date));
+    };
+    var getIconData = function(evt) {
+        var iconData = {
+            url: evt.getIcon()
+        };
+        if (iconData.url == null) {
+            iconData.url = metrics.defaultStackIcon;
+            iconData.width = metrics.defaultStackIconWidth;
+            iconData.height = metrics.defaultStackIconHeight;
+            iconData.className = "timeline-event-icon-stack timeline-event-icon-default";
+        } else {
+            iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+            iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+            iconData.className = "timeline-event-icon-stack";
+        }
+        return iconData;
+    };
+
+    var firstIconData = getIconData(events[0]);
+    var horizontalIncrement = 5;
+    var leftIconEdge = 0;
+    var totalLabelWidth = 0;
+    var totalLabelHeight = 0;
+    var totalIconHeight = 0;
+
+    var records = [];
+    for (var i = 0; i < events.length && (!showMoreMessage || i < limit); i++) {
+        var evt = events[i];
+        var text = evt.getText();
+        var iconData = getIconData(evt);
+        var labelSize = this._frc.computeSize(text);
+        var record = {
+            text:       text,
+            iconData:   iconData,
+            labelSize:  labelSize,
+            iconLeft:   firstIconData.width + i * horizontalIncrement - iconData.width
+        };
+        record.labelLeft = firstIconData.width + i * horizontalIncrement + metrics.iconLabelGap;
+        record.top = totalLabelHeight;
+        records.push(record);
+
+        leftIconEdge = Math.min(leftIconEdge, record.iconLeft);
+        totalLabelHeight += labelSize.height;
+        totalLabelWidth = Math.max(totalLabelWidth, record.labelLeft + labelSize.width);
+        totalIconHeight = Math.max(totalIconHeight, record.top + iconData.height);
+    }
+    if (showMoreMessage) {
+        var moreMessage = String.substitute(moreMessageTemplate, [ events.length - limit ]);
+
+        var moreMessageLabelSize = this._frc.computeSize(moreMessage);
+        var moreMessageLabelLeft = firstIconData.width + (limit - 1) * horizontalIncrement + metrics.iconLabelGap;
+        var moreMessageLabelTop = totalLabelHeight;
+
+        totalLabelHeight += moreMessageLabelSize.height;
+        totalLabelWidth = Math.max(totalLabelWidth, moreMessageLabelLeft + moreMessageLabelSize.width);
+    }
+    totalLabelWidth += metrics.labelRightMargin;
+    totalLabelHeight += metrics.labelBottomMargin;
+    totalIconHeight += metrics.iconBottomMargin;
+
+    var anchorPixel = getPixelOffset(events[0].getStart());
+    var newTracks = [];
+
+    var trackCount = Math.ceil(Math.max(totalIconHeight, totalLabelHeight) / metrics.trackHeight);
+    var rightIconEdge = firstIconData.width + (events.length - 1) * horizontalIncrement;
+    for (var i = 0; i < trackCount; i++) {
+        newTracks.push({ start: leftIconEdge, end: rightIconEdge });
+    }
+    var labelTrackCount = Math.ceil(totalLabelHeight / metrics.trackHeight);
+    for (var i = 0; i < labelTrackCount; i++) {
+        var track = newTracks[i];
+        track.end = Math.max(track.end, totalLabelWidth);
+    }
+
+    var firstTrack = this._fitTracks(anchorPixel, newTracks);
+    var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
+
+    var iconStackDiv = this._timeline.getDocument().createElement("div");
+    iconStackDiv.className = 'timeline-event-icon-stack';
+    iconStackDiv.style.position = "absolute";
+    iconStackDiv.style.overflow = "visible";
+    iconStackDiv.style.left = anchorPixel + "px";
+    iconStackDiv.style.top = verticalPixelOffset + "px";
+    iconStackDiv.style.width = rightIconEdge + "px";
+    iconStackDiv.style.height = totalIconHeight + "px";
+    iconStackDiv.innerHTML = "<div style='position: relative'></div>";
+    this._eventLayer.appendChild(iconStackDiv);
+
+    var self = this;
+    var onMouseOver = function(domEvt) {
+        try {
+            var n = parseInt(this.getAttribute("index"));
+            var childNodes = iconStackDiv.firstChild.childNodes;
+            for (var i = 0; i < childNodes.length; i++) {
+                var child = childNodes[i];
+                if (i == n) {
+                    child.style.zIndex = childNodes.length;
+                } else {
+                    child.style.zIndex = childNodes.length - i;
+                }
+            }
+        } catch (e) {
+        }
+    };
+    var paintEvent = function(index) {
+        var record = records[index];
+        var evt = events[index];
+        var tooltip = evt.getProperty("tooltip") || evt.getText();
+
+        var labelElmtData = self._paintEventLabel(
+            { tooltip: tooltip },
+            { text: record.text },
+            anchorPixel + record.labelLeft,
+            verticalPixelOffset + record.top,
+            record.labelSize.width,
+            record.labelSize.height,
+            theme
+        );
+        labelElmtData.elmt.setAttribute("index", index);
+        labelElmtData.elmt.onmouseover = onMouseOver;
+
+        var img = SimileAjax.Graphics.createTranslucentImage(record.iconData.url);
+        var iconDiv = self._timeline.getDocument().createElement("div");
+        iconDiv.className = 'timeline-event-icon' + ("className" in record.iconData ? (" " + record.iconData.className) : "");
+        iconDiv.style.left = record.iconLeft + "px";
+        iconDiv.style.top = record.top + "px";
+        iconDiv.style.zIndex = (records.length - index);
+        iconDiv.appendChild(img);
+        iconDiv.setAttribute("index", index);
+        iconDiv.onmouseover = onMouseOver;
+
+        iconStackDiv.firstChild.appendChild(iconDiv);
+
+        var clickHandler = function(elmt, domEvt, target) {
+            return self._onClickInstantEvent(labelElmtData.elmt, domEvt, evt);
+        };
+
+        SimileAjax.DOM.registerEvent(iconDiv, "mousedown", clickHandler);
+        SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler);
+
+        self._eventIdToElmt[evt.getID()] = iconDiv;
+    };
+    for (var i = 0; i < records.length; i++) {
+        paintEvent(i);
+    }
+
+    if (showMoreMessage) {
+        var moreEvents = events.slice(limit);
+        var moreMessageLabelElmtData = this._paintEventLabel(
+            { tooltip: moreMessage },
+            { text: moreMessage },
+            anchorPixel + moreMessageLabelLeft,
+            verticalPixelOffset + moreMessageLabelTop,
+            moreMessageLabelSize.width,
+            moreMessageLabelSize.height,
+            theme
+        );
+
+        var moreMessageClickHandler = function(elmt, domEvt, target) {
+            return self._onClickMultiplePreciseInstantEvent(moreMessageLabelElmtData.elmt, domEvt, moreEvents);
+        };
+        SimileAjax.DOM.registerEvent(moreMessageLabelElmtData.elmt, "mousedown", moreMessageClickHandler);
+
+        for (var i = 0; i < moreEvents.length; i++) {
+            this._eventIdToElmt[moreEvents[i].getID()] = moreMessageLabelElmtData.elmt;
+        }
+    }
+    //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+};
+
+Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) {
+    var commonData = {
+        tooltip: evt.getProperty("tooltip") || evt.getText()
+    };
+
+    var tapeData = {
+        start:          evt.getStart(),
+        end:            evt.getEnd(),
+        latestStart:    evt.getLatestStart(),
+        earliestEnd:    evt.getEarliestEnd(),
+        isInstant:      true
+    };
+
+    var iconData = {
+        url: evt.getIcon()
+    };
+    if (iconData.url == null) {
+        iconData = null;
+    } else {
+        iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+        iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+    }
+
+    var labelData = {
+        text:       evt.getText(),
+        color:      evt.getTextColor() || evt.getColor(),
+        className:  evt.getClassName()
+    };
+
+    var result = this.paintTapeIconLabel(
+        evt.getStart(),
+        commonData,
+        tapeData, // no tape data
+        iconData,
+        labelData,
+        metrics,
+        theme,
+        highlightIndex
+    );
+
+    var self = this;
+    var clickHandler = iconData != null ?
+        function(elmt, domEvt, target) {
+            return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+        } :
+        function(elmt, domEvt, target) {
+            return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+        };
+
+    SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(result.impreciseTapeElmtData.elmt, "mousedown", clickHandler);
+
+    if (iconData != null) {
+        SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+        this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+    } else {
+        this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+    }
+};
+
+Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    var commonData = {
+        tooltip: evt.getProperty("tooltip") || evt.getText()
+    };
+
+    var tapeData = {
+        start:          evt.getStart(),
+        end:            evt.getEnd(),
+        isInstant:      false
+    };
+
+    var iconData = {
+        url: evt.getIcon()
+    };
+    if (iconData.url == null) {
+        iconData = null;
+    } else {
+        iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+        iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+    }
+
+    var labelData = {
+        text:       evt.getText(),
+        color:      evt.getTextColor() || evt.getColor(),
+        className:  evt.getClassName()
+    };
+
+    var result = this.paintTapeIconLabel(
+        evt.getLatestStart(),
+        commonData,
+        tapeData, // no tape data
+        iconData,
+        labelData,
+        metrics,
+        theme,
+        highlightIndex
+    );
+
+    var self = this;
+    var clickHandler = iconData != null ?
+        function(elmt, domEvt, target) {
+            return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+        } :
+        function(elmt, domEvt, target) {
+            return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+        };
+
+    SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
+
+    if (iconData != null) {
+        SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+        this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+    } else {
+        this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+    }
+};
+
+Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) {
+    var commonData = {
+        tooltip: evt.getProperty("tooltip") || evt.getText()
+    };
+
+    var tapeData = {
+        start:          evt.getStart(),
+        end:            evt.getEnd(),
+        latestStart:    evt.getLatestStart(),
+        earliestEnd:    evt.getEarliestEnd(),
+        isInstant:      false
+    };
+
+    var iconData = {
+        url: evt.getIcon()
+    };
+    if (iconData.url == null) {
+        iconData = null;
+    } else {
+        iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth;
+        iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight;
+    }
+
+    var labelData = {
+        text:       evt.getText(),
+        color:      evt.getTextColor() || evt.getColor(),
+        className:  evt.getClassName()
+    };
+
+    var result = this.paintTapeIconLabel(
+        evt.getLatestStart(),
+        commonData,
+        tapeData, // no tape data
+        iconData,
+        labelData,
+        metrics,
+        theme,
+        highlightIndex
+    );
+
+    var self = this;
+    var clickHandler = iconData != null ?
+        function(elmt, domEvt, target) {
+            return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt);
+        } :
+        function(elmt, domEvt, target) {
+            return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt);
+        };
+
+    SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler);
+    SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler);
+
+    if (iconData != null) {
+        SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler);
+        this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt;
+    } else {
+        this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt;
+    }
+};
+
+Timeline.CompactEventPainter.prototype.paintTapeIconLabel = function(
+    anchorDate,
+    commonData,
+    tapeData,
+    iconData,
+    labelData,
+    metrics,
+    theme,
+    highlightIndex
+) {
+    var band = this._band;
+    var getPixelOffset = function(date) {
+        return Math.round(band.dateToPixelOffset(date));
+    };
+
+    var anchorPixel = getPixelOffset(anchorDate);
+    var newTracks = [];
+
+    var tapeHeightOccupied = 0;         // how many pixels (vertically) the tape occupies, including bottom margin
+    var tapeTrackCount = 0;             // how many tracks the tape takes up, usually just 1
+    var tapeLastTrackExtraSpace = 0;    // on the last track that the tape occupies, how many pixels are left (for icon and label to occupy as well)
+    if (tapeData != null) {
+        tapeHeightOccupied = metrics.tapeHeight + metrics.tapeBottomMargin;
+        tapeTrackCount = Math.ceil(metrics.tapeHeight / metrics.trackHeight);
+
+        var tapeEndPixelOffset = getPixelOffset(tapeData.end) - anchorPixel;
+        var tapeStartPixelOffset = getPixelOffset(tapeData.start) - anchorPixel;
+
+        for (var t = 0; t < tapeTrackCount; t++) {
+            newTracks.push({ start: tapeStartPixelOffset, end: tapeEndPixelOffset });
+        }
+
+        tapeLastTrackExtraSpace = metrics.trackHeight - (tapeHeightOccupied % metrics.tapeHeight);
+    }
+
+    var iconStartPixelOffset = 0;        // where the icon starts compared to the anchor pixel;
+                                         // this can be negative if the icon is center-aligned around the anchor
+    var iconHorizontalSpaceOccupied = 0; // how many pixels the icon take up from the anchor pixel,
+                                         // including the gap between the icon and the label
+    if (iconData != null) {
+        if ("iconAlign" in iconData && iconData.iconAlign == "center") {
+            iconStartPixelOffset = -Math.floor(iconData.width / 2);
+        }
+        iconHorizontalSpaceOccupied = iconStartPixelOffset + iconData.width + metrics.iconLabelGap;
+
+        if (tapeTrackCount > 0) {
+            newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, iconHorizontalSpaceOccupied);
+        }
+
+        var iconHeight = iconData.height + metrics.iconBottomMargin + tapeLastTrackExtraSpace;
+        while (iconHeight > 0) {
+            newTracks.push({ start: iconStartPixelOffset, end: iconHorizontalSpaceOccupied });
+            iconHeight -= metrics.trackHeight;
+        }
+    }
+
+    var text = labelData.text;
+    var labelSize = this._frc.computeSize(text);
+    var labelHeight = labelSize.height + metrics.labelBottomMargin + tapeLastTrackExtraSpace;
+    var labelEndPixelOffset = iconHorizontalSpaceOccupied + labelSize.width + metrics.labelRightMargin;
+    if (tapeTrackCount > 0) {
+        newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, labelEndPixelOffset);
+    }
+    for (var i = 0; labelHeight > 0; i++) {
+        if (tapeTrackCount + i < newTracks.length) {
+            var track = newTracks[tapeTrackCount + i];
+            track.end = labelEndPixelOffset;
+        } else {
+            newTracks.push({ start: 0, end: labelEndPixelOffset });
+        }
+        labelHeight -= metrics.trackHeight;
+    }
+
+    /*
+     *  Try to fit the new track on top of the existing tracks, then
+     *  render the various elements.
+     */
+    var firstTrack = this._fitTracks(anchorPixel, newTracks);
+    var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset;
+    var result = {};
+
+    result.labelElmtData = this._paintEventLabel(
+        commonData,
+        labelData,
+        anchorPixel + iconHorizontalSpaceOccupied,
+        verticalPixelOffset + tapeHeightOccupied,
+        labelSize.width,
+        labelSize.height,
+        theme
+    );
+
+    if (tapeData != null) {
+        if ("latestStart" in tapeData || "earliestEnd" in tapeData) {
+            result.impreciseTapeElmtData = this._paintEventTape(
+                commonData,
+                tapeData,
+                metrics.tapeHeight,
+                verticalPixelOffset,
+                getPixelOffset(tapeData.start),
+                getPixelOffset(tapeData.end),
+                theme.event.duration.impreciseColor,
+                theme.event.duration.impreciseOpacity,
+                metrics,
+                theme
+            );
+        }
+        if (!tapeData.isInstant && "start" in tapeData && "end" in tapeData) {
+            result.tapeElmtData = this._paintEventTape(
+                commonData,
+                tapeData,
+                metrics.tapeHeight,
+                verticalPixelOffset,
+                anchorPixel,
+                getPixelOffset("earliestEnd" in tapeData ? tapeData.earliestEnd : tapeData.end),
+                tapeData.color,
+                100,
+                metrics,
+                theme
+            );
+        }
+    }
+
+    if (iconData != null) {
+        result.iconElmtData = this._paintEventIcon(
+            commonData,
+            iconData,
+            verticalPixelOffset + tapeHeightOccupied,
+            anchorPixel + iconStartPixelOffset,
+            metrics,
+            theme
+        );
+    }
+    //this._createHighlightDiv(highlightIndex, iconElmtData, theme);
+
+    return result;
+};
+
+Timeline.CompactEventPainter.prototype._fitTracks = function(anchorPixel, newTracks) {
+    var firstTrack;
+    for (firstTrack = 0; firstTrack < this._tracks.length; firstTrack++) {
+        var fit = true;
+        for (var j = 0; j < newTracks.length && (firstTrack + j) < this._tracks.length; j++) {
+            var existingTrack = this._tracks[firstTrack + j];
+            var newTrack = newTracks[j];
+            if (anchorPixel + newTrack.start < existingTrack) {
+                fit = false;
+                break;
+            }
+        }
+
+        if (fit) {
+            break;
+        }
+    }
+    for (var i = 0; i < newTracks.length; i++) {
+        this._tracks[firstTrack + i] = anchorPixel + newTracks[i].end;
+    }
+
+    return firstTrack;
+};
+
+
+Timeline.CompactEventPainter.prototype._paintEventIcon = function(commonData, iconData, top, left, metrics, theme) {
+    var img = SimileAjax.Graphics.createTranslucentImage(iconData.url);
+    var iconDiv = this._timeline.getDocument().createElement("div");
+    iconDiv.className = 'timeline-event-icon' + ("className" in iconData ? (" " + iconData.className) : "");
+    iconDiv.style.left = left + "px";
+    iconDiv.style.top = top + "px";
+    iconDiv.appendChild(img);
+
+    if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+        iconDiv.title = commonData.tooltip;
+    }
+
+    this._eventLayer.appendChild(iconDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  metrics.iconWidth,
+        height: metrics.iconHeight,
+        elmt:   iconDiv
+    };
+};
+
+Timeline.CompactEventPainter.prototype._paintEventLabel = function(commonData, labelData, left, top, width, height, theme) {
+    var doc = this._timeline.getDocument();
+
+    var labelDiv = doc.createElement("div");
+    labelDiv.className = 'timeline-event-label';
+
+    labelDiv.style.left = left + "px";
+    labelDiv.style.width = (width + 1) + "px";
+    labelDiv.style.top = top + "px";
+    labelDiv.innerHTML = labelData.text;
+
+    if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+        labelDiv.title = commonData.tooltip;
+    }
+    if ("color" in labelData && typeof labelData.color == "string") {
+        labelDiv.style.color = labelData.color;
+    }
+    if ("className" in labelData && typeof labelData.className == "string") {
+        labelDiv.className += ' ' + labelData.className;
+    }
+
+    this._eventLayer.appendChild(labelDiv);
+
+    return {
+        left:   left,
+        top:    top,
+        width:  width,
+        height: height,
+        elmt:   labelDiv
+    };
+};
+
+Timeline.CompactEventPainter.prototype._paintEventTape = function(
+    commonData, tapeData, height, top, startPixel, endPixel, color, opacity, metrics, theme) {
+
+    var width = endPixel - startPixel;
+
+    var tapeDiv = this._timeline.getDocument().createElement("div");
+    tapeDiv.className = "timeline-event-tape"
+
+    tapeDiv.style.left = startPixel + "px";
+    tapeDiv.style.top = top + "px";
+    tapeDiv.style.width = width + "px";
+    tapeDiv.style.height = height + "px";
+
+    if ("tooltip" in commonData && typeof commonData.tooltip == "string") {
+        tapeDiv.title = commonData.tooltip;
+    }
+    if (color != null && typeof tapeData.color == "string") {
+        tapeDiv.style.backgroundColor = color;
+    }
+
+    if ("backgroundImage" in tapeData && typeof tapeData.backgroundImage == "string") {
+        tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")";
+        tapeDiv.style.backgroundRepeat =
+            ("backgroundRepeat" in tapeData && typeof tapeData.backgroundRepeat == "string")
+                ? tapeData.backgroundRepeat : 'repeat';
+    }
+
+    SimileAjax.Graphics.setOpacity(tapeDiv, opacity);
+
+    if ("className" in tapeData && typeof tapeData.className == "string") {
+        tapeDiv.className += ' ' + tapeData.className;
+    }
+
+    this._eventLayer.appendChild(tapeDiv);
+
+    return {
+        left:   startPixel,
+        top:    top,
+        width:  width,
+        height: height,
+        elmt:   tapeDiv
+    };
+}
+
+Timeline.CompactEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) {
+    if (highlightIndex >= 0) {
+        var doc = this._timeline.getDocument();
+        var eventTheme = theme.event;
+
+        var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)];
+
+        var div = doc.createElement("div");
+        div.style.position = "absolute";
+        div.style.overflow = "hidden";
+        div.style.left =    (dimensions.left - 2) + "px";
+        div.style.width =   (dimensions.width + 4) + "px";
+        div.style.top =     (dimensions.top - 2) + "px";
+        div.style.height =  (dimensions.height + 4) + "px";
+//        div.style.background = color;
+
+        this._highlightLayer.appendChild(div);
+    }
+};
+
+Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent = function(icon, domEvt, events) {
+    var c = SimileAjax.DOM.getPageCoordinates(icon);
+    this._showBubble(
+        c.left + Math.ceil(icon.offsetWidth / 2),
+        c.top + Math.ceil(icon.offsetHeight / 2),
+        events
+    );
+
+    var ids = [];
+    for (var i = 0; i < events.length; i++) {
+        ids.push(events[i].getID());
+    }
+    this._fireOnSelect(ids);
+
+    domEvt.cancelBubble = true;
+    SimileAjax.DOM.cancelEvent(domEvt);
+
+    return false;
+};
+
+Timeline.CompactEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) {
+    var c = SimileAjax.DOM.getPageCoordinates(icon);
+    this._showBubble(
+        c.left + Math.ceil(icon.offsetWidth / 2),
+        c.top + Math.ceil(icon.offsetHeight / 2),
+        [evt]
+    );
+    this._fireOnSelect([evt.getID()]);
+
+    domEvt.cancelBubble = true;
+    SimileAjax.DOM.cancelEvent(domEvt);
+    return false;
+};
+
+Timeline.CompactEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) {
+    if ("pageX" in domEvt) {
+        var x = domEvt.pageX;
+        var y = domEvt.pageY;
+    } else {
+        var c = SimileAjax.DOM.getPageCoordinates(target);
+        var x = domEvt.offsetX + c.left;
+        var y = domEvt.offsetY + c.top;
+    }
+    this._showBubble(x, y, [evt]);
+    this._fireOnSelect([evt.getID()]);
+
+    domEvt.cancelBubble = true;
+    SimileAjax.DOM.cancelEvent(domEvt);
+    return false;
+};
+
+Timeline.CompactEventPainter.prototype.showBubble = function(evt) {
+    var elmt = this._eventIdToElmt[evt.getID()];
+    if (elmt) {
+        var c = SimileAjax.DOM.getPageCoordinates(elmt);
+        this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, [evt]);
+    }
+};
+
+Timeline.CompactEventPainter.prototype._showBubble = function(x, y, evts) {
+    var div = document.createElement("div");
+
+    evts = ("fillInfoBubble" in evts) ? [evts] : evts;
+    for (var i = 0; i < evts.length; i++) {
+        var div2 = document.createElement("div");
+        div.appendChild(div2);
+
+        evts[i].fillInfoBubble(div2, this._params.theme, this._band.getLabeller());
+    }
+
+    SimileAjax.WindowManager.cancelPopups();
+    SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y, this._params.theme.event.bubble.width);
+};
+
+Timeline.CompactEventPainter.prototype._fireOnSelect = function(eventIDs) {
+    for (var i = 0; i < this._onSelectListeners.length; i++) {
+        this._onSelectListeners[i](eventIDs);
+    }
+};
+/*==================================================
+ *  Span Highlight Decorator
+ *==================================================
+ */
+
+Timeline.SpanHighlightDecorator = function(params) {
+    // When evaluating params, test against null. Not "p in params". Testing against
+    // null enables caller to explicitly request the default. Testing against "in" means
+    // that the param has to be ommitted to get the default.
+    this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
+    this._startDate = (typeof params.startDate == "string") ?
+        this._unit.parseFromObject(params.startDate) : params.startDate;
+    this._endDate = (typeof params.endDate == "string") ?
+        this._unit.parseFromObject(params.endDate) : params.endDate;
+    this._startLabel = params.startLabel != null ? params.startLabel : ""; // not null!
+    this._endLabel   = params.endLabel   != null ? params.endLabel   : ""; // not null!
+    this._color = params.color;
+    this._cssClass = params.cssClass != null ? params.cssClass : null;
+    this._opacity = params.opacity != null ? params.opacity : 100;
+         // Default z is 10, behind everything but background grid.
+         // If inFront, then place just behind events, in front of everything else
+    this._zIndex = (params.inFront != null && params.inFront) ? 113 : 10;
+};
+
+Timeline.SpanHighlightDecorator.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+
+    this._layerDiv = null;
+};
+
+Timeline.SpanHighlightDecorator.prototype.paint = function() {
+    if (this._layerDiv != null) {
+        this._band.removeLayerDiv(this._layerDiv);
+    }
+    this._layerDiv = this._band.createLayerDiv(this._zIndex);
+    this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+    this._layerDiv.style.display = "none";
+
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    if (this._unit.compare(this._startDate, maxDate) < 0 &&
+        this._unit.compare(this._endDate, minDate) > 0) {
+
+        minDate = this._unit.later(minDate, this._startDate);
+        maxDate = this._unit.earlier(maxDate, this._endDate);
+
+        var minPixel = this._band.dateToPixelOffset(minDate);
+        var maxPixel = this._band.dateToPixelOffset(maxDate);
+
+        var doc = this._timeline.getDocument();
+
+        var createTable = function() {
+            var table = doc.createElement("table");
+            table.insertRow(0).insertCell(0);
+            return table;
+        };
+
+        var div = doc.createElement("div");
+        div.className='timeline-highlight-decorator'
+        if(this._cssClass) {
+        	  div.className += ' ' + this._cssClass;
+        }
+        if(this._color != null) {
+        	  div.style.backgroundColor = this._color;
+        }
+        if (this._opacity < 100) {
+            SimileAjax.Graphics.setOpacity(div, this._opacity);
+        }
+        this._layerDiv.appendChild(div);
+
+        var tableStartLabel = createTable();
+        tableStartLabel.className = 'timeline-highlight-label timeline-highlight-label-start'
+        var tdStart =  tableStartLabel.rows[0].cells[0]
+        tdStart.innerHTML = this._startLabel;
+        if (this._cssClass) {
+        	  tdStart.className = 'label_' + this._cssClass;
+        }
+        this._layerDiv.appendChild(tableStartLabel);
+
+        var tableEndLabel = createTable();
+        tableEndLabel.className = 'timeline-highlight-label timeline-highlight-label-end'
+        var tdEnd = tableEndLabel.rows[0].cells[0]
+        tdEnd.innerHTML = this._endLabel;
+        if (this._cssClass) {
+        	   tdEnd.className = 'label_' + this._cssClass;
+        }
+        this._layerDiv.appendChild(tableEndLabel);
+
+        if (this._timeline.isHorizontal()){
+            div.style.left = minPixel + "px";
+            div.style.width = (maxPixel - minPixel) + "px";
+
+            tableStartLabel.style.right = (this._band.getTotalViewLength() - minPixel) + "px";
+            tableStartLabel.style.width = (this._startLabel.length) + "em";
+
+            tableEndLabel.style.left = maxPixel + "px";
+            tableEndLabel.style.width = (this._endLabel.length) + "em";
+
+        } else {
+            div.style.top = minPixel + "px";
+            div.style.height = (maxPixel - minPixel) + "px";
+
+            tableStartLabel.style.bottom = minPixel + "px";
+            tableStartLabel.style.height = "1.5px";
+
+            tableEndLabel.style.top = maxPixel + "px";
+            tableEndLabel.style.height = "1.5px";
+        }
+    }
+    this._layerDiv.style.display = "block";
+};
+
+Timeline.SpanHighlightDecorator.prototype.softPaint = function() {
+};
+
+/*==================================================
+ *  Point Highlight Decorator
+ *==================================================
+ */
+
+Timeline.PointHighlightDecorator = function(params) {
+    this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit;
+    this._date = (typeof params.date == "string") ?
+        this._unit.parseFromObject(params.date) : params.date;
+    this._width = params.width != null ? params.width : 10;
+      // Since the width is used to calculate placements (see minPixel, below), we
+      // specify width here, not in css.
+    this._color = params.color;
+    this._cssClass = params.cssClass != null ? params.cssClass : '';
+    this._opacity = params.opacity != null ? params.opacity : 100;
+};
+
+Timeline.PointHighlightDecorator.prototype.initialize = function(band, timeline) {
+    this._band = band;
+    this._timeline = timeline;
+    this._layerDiv = null;
+};
+
+Timeline.PointHighlightDecorator.prototype.paint = function() {
+    if (this._layerDiv != null) {
+        this._band.removeLayerDiv(this._layerDiv);
+    }
+    this._layerDiv = this._band.createLayerDiv(10);
+    this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging
+    this._layerDiv.style.display = "none";
+
+    var minDate = this._band.getMinDate();
+    var maxDate = this._band.getMaxDate();
+
+    if (this._unit.compare(this._date, maxDate) < 0 &&
+        this._unit.compare(this._date, minDate) > 0) {
+
+        var pixel = this._band.dateToPixelOffset(this._date);
+        var minPixel = pixel - Math.round(this._width / 2);
+
+        var doc = this._timeline.getDocument();
+
+        var div = doc.createElement("div");
+        div.className='timeline-highlight-point-decorator';
+        div.className += ' ' + this._cssClass;
+
+        if(this._color != null) {
+        	  div.style.backgroundColor = this._color;
+        }
+        if (this._opacity < 100) {
+            SimileAjax.Graphics.setOpacity(div, this._opacity);
+        }
+        this._layerDiv.appendChild(div);
+
+        if (this._timeline.isHorizontal()) {
+            div.style.left = minPixel + "px";
+            div.style.width = this._width;
+        } else {
+            div.style.top = minPixel + "px";
+            div.style.height = this._width;
+        }
+    }
+    this._layerDiv.style.display = "block";
+};
+
+Timeline.PointHighlightDecorator.prototype.softPaint = function() {
+};
+/*==================================================
+ *  Default Unit
+ *==================================================
+ */
+
+Timeline.NativeDateUnit = new Object();
+
+Timeline.NativeDateUnit.createLabeller = function(locale, timeZone) {
+    return new Timeline.GregorianDateLabeller(locale, timeZone);
+};
+
+Timeline.NativeDateUnit.makeDefaultValue = function() {
+    return new Date();
+};
+
+Timeline.NativeDateUnit.cloneValue = function(v) {
+    return new Date(v.getTime());
+};
+
+Timeline.NativeDateUnit.getParser = function(format) {
+    if (typeof format == "string") {
+        format = format.toLowerCase();
+    }
+    return (format == "iso8601" || format == "iso 8601") ?
+        Timeline.DateTime.parseIso8601DateTime : 
+        Timeline.DateTime.parseGregorianDateTime;
+};
+
+Timeline.NativeDateUnit.parseFromObject = function(o) {
+    return Timeline.DateTime.parseGregorianDateTime(o);
+};
+
+Timeline.NativeDateUnit.toNumber = function(v) {
+    return v.getTime();
+};
+
+Timeline.NativeDateUnit.fromNumber = function(n) {
+    return new Date(n);
+};
+
+Timeline.NativeDateUnit.compare = function(v1, v2) {
+    var n1, n2;
+    if (typeof v1 == "object") {
+        n1 = v1.getTime();
+    } else {
+        n1 = Number(v1);
+    }
+    if (typeof v2 == "object") {
+        n2 = v2.getTime();
+    } else {
+        n2 = Number(v2);
+    }
+
+    return n1 - n2;
+};
+
+Timeline.NativeDateUnit.earlier = function(v1, v2) {
+    return Timeline.NativeDateUnit.compare(v1, v2) < 0 ? v1 : v2;
+};
+
+Timeline.NativeDateUnit.later = function(v1, v2) {
+    return Timeline.NativeDateUnit.compare(v1, v2) > 0 ? v1 : v2;
+};
+
+Timeline.NativeDateUnit.change = function(v, n) {
+    return new Date(v.getTime() + n);
+};
+
+/*==================================================
+ *  Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["fr"] = {
+    wikiLinkLabel:  "Discute"
+};
+
+/*==================================================
+ *  Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["fr"] = [
+    "jan", "fev", "mar", "avr", "mai", "jui", "jui", "aou", "sep", "oct", "nov", "dec"
+];
+/*==================================================
+ *  Common localization strings
+ *==================================================
+ */
+
+Timeline.strings["en"] = {
+    wikiLinkLabel:  "Discuss"
+};
+
+/*==================================================
+ *  Localization of labellers.js
+ *==================================================
+ */
+
+Timeline.GregorianDateLabeller.monthNames["en"] = [
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+];
+
+Timeline.GregorianDateLabeller.dayNames["en"] = [
+    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+];
--- a/web/data/cubicweb.timeline-ext.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.timeline-ext.js	Wed Apr 15 17:36:09 2009 +0200
@@ -9,7 +9,7 @@
 /* provide our own custom date parser since the default
  * one only understands iso8601 and gregorian dates
  */
-Timeline.NativeDateUnit.getParser = function(format) {
+SimileAjax.NativeDateUnit.getParser = Timeline.NativeDateUnit.getParser = function(format) {
     if (typeof format == "string") {
 	if (format.indexOf('%') != -1) {
 	    return function(datestring) {
--- a/web/data/cubicweb.timetable.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/cubicweb.timetable.css	Wed Apr 15 17:36:09 2009 +0200
@@ -12,7 +12,7 @@
 
 table.timetable th { 
   padding:1pt;
-  align:center;
+  text-align:center;
 }
 
 
@@ -52,7 +52,7 @@
   font-family: Verdana, sans-serif;
   padding-left: 4pt;
   padding-right: 4pt;
-  align: left;
+  text-align: left;
   width: auto;
 }
 
--- a/web/data/jquery.corner.js	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/jquery.corner.js	Wed Apr 15 17:36:09 2009 +0200
@@ -1,1 +1,178 @@
-if(!document.createElement('canvas').getContext){(function(){var m=Math;var y=m.round;var z=m.sin;var A=m.cos;var Z=10;var B=Z/2;function getContext(){if(this.context_){return this.context_}return this.context_=new CanvasRenderingContext2D_(this)}var C=Array.prototype.slice;function bind(f,b,c){var a=C.call(arguments,2);return function(){return f.apply(b,a.concat(C.call(arguments)))}}var D={init:function(a){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var b=a||document;b.createElement('canvas');b.attachEvent('onreadystatechange',bind(this.init_,this,b))}},init_:function(a){if(!a.namespaces['g_vml_']){a.namespaces.add('g_vml_','urn:schemas-microsoft-com:vml')}if(!a.styleSheets['ex_canvas_']){var b=a.createStyleSheet();b.owningElement.id='ex_canvas_';b.cssText='canvas{display:inline-block;overflow:hidden;'+'text-align:left;width:300px;height:150px}'+'g_vml_\\:*{behavior:url(#default#VML)}'}},i:function(a){if(!a.getContext){a.getContext=getContext;a.attachEvent('onpropertychange',onPropertyChange);a.attachEvent('onresize',onResize);var b=a.attributes;if(b.width&&b.width.specified){a.style.width=b.width.nodeValue+'px'}else{a.width=a.clientWidth}if(b.height&&b.height.specified){a.style.height=b.height.nodeValue+'px'}else{a.height=a.clientHeight}}return a}};function onPropertyChange(e){var a=e.srcElement;switch(e.propertyName){case'width':a.style.width=a.attributes.width.nodeValue+'px';a.getContext().clearRect();break;case'height':a.style.height=a.attributes.height.nodeValue+'px';a.getContext().clearRect();break}}function onResize(e){var a=e.srcElement;if(a.firstChild){a.firstChild.style.width=a.clientWidth+'px';a.firstChild.style.height=a.clientHeight+'px'}}D.init();var E=[];for(var i=0;i<16;i++){for(var j=0;j<16;j++){E[i*16+j]=i.toString(16)+j.toString(16)}}function createMatrixIdentity(){return[[1,0,0],[0,1,0],[0,0,1]]}function processStyle(a){var b,alpha=1;a=String(a);if(a.substring(0,3)=='rgb'){var c=a.indexOf('(',3);var d=a.indexOf(')',c+1);var e=a.substring(c+1,d).split(',');b='#';for(var i=0;i<3;i++){b+=E[Number(e[i])]}if(e.length==4&&a.substr(3,1)=='a'){alpha=e[3]}}else{b=a}return[b,alpha]}function processLineCap(a){switch(a){case'butt':return'flat';case'round':return'round';case'square':default:return'square'}}function CanvasRenderingContext2D_(a){this.m_=createMatrixIdentity();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle='#000';this.fillStyle='#000';this.lineWidth=1;this.lineJoin='miter';this.lineCap='butt';this.miterLimit=Z*1;this.globalAlpha=1;this.canvas=a;var b=a.ownerDocument.createElement('div');b.style.width=a.clientWidth+'px';b.style.height=a.clientHeight+'px';b.style.overflow='hidden';b.style.position='absolute';a.appendChild(b);this.element_=b;this.arcScaleX_=1;this.arcScaleY_=1}var F=CanvasRenderingContext2D_.prototype;F.clearRect=function(){this.element_.innerHTML='';this.currentPath_=[]};F.beginPath=function(){this.currentPath_=[]};F.moveTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'moveTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.lineTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'lineTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.bezierCurveTo=function(a,b,c,d,e,f){var p=this.getCoords_(e,f);var g=this.getCoords_(a,b);var h=this.getCoords_(c,d);this.currentPath_.push({type:'bezierCurveTo',cp1x:g.x,cp1y:g.y,cp2x:h.x,cp2y:h.y,x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.fillRect=function(a,b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.fill();this.currentPath_=[]};F.createLinearGradient=function(a,b,c,d){return new CanvasGradient_('gradient')};F.createRadialGradient=function(a,b,c,d,e,f){var g=new CanvasGradient_('gradientradial');g.radius1_=c;g.radius2_=f;g.focus_.x=a;g.focus_.y=b;return g};F.stroke=function(d){var e=[];var f=false;var a=processStyle(d?this.fillStyle:this.strokeStyle);var g=a[0];var h=a[1]*this.globalAlpha;var W=10;var H=10;e.push('<g_vml_:shape',' fillcolor="',g,'"',' filled="',Boolean(d),'"',' style="position:absolute;width:',W,';height:',H,';"',' coordorigin="0 0" coordsize="',Z*W,' ',Z*H,'"',' stroked="',!d,'"',' strokeweight="',this.lineWidth,'"',' strokecolor="',g,'"',' path="');var j=false;var k={x:null,y:null};var l={x:null,y:null};for(var i=0;i<this.currentPath_.length;i++){var p=this.currentPath_[i];var c;switch(p.type){case'moveTo':e.push(' m ');c=p;e.push(y(p.x),',',y(p.y));break;case'lineTo':e.push(' l ');e.push(y(p.x),',',y(p.y));break;case'close':e.push(' x ');p=null;break;case'bezierCurveTo':e.push(' c ');e.push(y(p.cp1x),',',y(p.cp1y),',',y(p.cp2x),',',y(p.cp2y),',',y(p.x),',',y(p.y));break;case'at':case'wa':e.push(' ',p.type,' ');e.push(y(p.x-this.arcScaleX_*p.radius),',',y(p.y-this.arcScaleY_*p.radius),' ',y(p.x+this.arcScaleX_*p.radius),',',y(p.y+this.arcScaleY_*p.radius),' ',y(p.xStart),',',y(p.yStart),' ',y(p.xEnd),',',y(p.yEnd));break}if(p){if(k.x==null||p.x<k.x){k.x=p.x}if(l.x==null||p.x>l.x){l.x=p.x}if(k.y==null||p.y<k.y){k.y=p.y}if(l.y==null||p.y>l.y){l.y=p.y}}}e.push(' ">');if(typeof this.fillStyle=='object'){var m={x:'50%',y:'50%'};var n=l.x-k.x;var o=l.y-k.y;var q=n>o?n:o;m.x=y(this.fillStyle.focus_.x/n*100+50)+'%';m.y=y(this.fillStyle.focus_.y/o*100+50)+'%';var r=[];if(this.fillStyle.type_=='gradientradial'){var s=this.fillStyle.radius1_/q*100;var t=this.fillStyle.radius2_/q*100-s}else{var s=0;var t=100}var u={offset:null,color:null};var v={offset:null,color:null};this.fillStyle.colors_.sort(function(a,b){return a.offset-b.offset});for(var i=0;i<this.fillStyle.colors_.length;i++){var w=this.fillStyle.colors_[i];r.push(w.offset*t+s,'% ',w.color,',');if(w.offset>u.offset||u.offset==null){u.offset=w.offset;u.color=w.color}if(w.offset<v.offset||v.offset==null){v.offset=w.offset;v.color=w.color}}r.pop();e.push('<g_vml_:fill',' color="',v.color,'"',' color2="',u.color,'"',' type="',this.fillStyle.type_,'"',' focusposition="',m.x,', ',m.y,'"',' colors="',r.join(''),'"',' opacity="',h,'" />')}else if(d){e.push('<g_vml_:fill color="',g,'" opacity="',h,'" />')}else{var x=Math.max(this.arcScaleX_,this.arcScaleY_)*this.lineWidth;e.push('<g_vml_:stroke',' opacity="',h,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',processLineCap(this.lineCap),'"',' weight="',x,'px"',' color="',g,'" />')}e.push('</g_vml_:shape>');this.element_.insertAdjacentHTML('beforeEnd',e.join(''))};F.fill=function(){this.stroke(true)};F.closePath=function(){this.currentPath_.push({type:'close'})};F.getCoords_=function(a,b){return{x:Z*(a*this.m_[0][0]+b*this.m_[1][0]+this.m_[2][0])-B,y:Z*(a*this.m_[0][1]+b*this.m_[1][1]+this.m_[2][1])-B}};function CanvasPattern_(){}G_vmlCMjrc=D})()}if(jQuery.browser.msie){document.execCommand("BackgroundImageCache",false,true)}(function($){var N=$.browser.msie;var O=N&&!window.XMLHttpRequest;var P=$.browser.opera;var Q=typeof document.createElement('canvas').getContext=="function";var R=function(i){return parseInt(i,10)||0};var S=function(a,b,c){var x=a,y;if(x.currentStyle){y=x.currentStyle[b]}else if(window.getComputedStyle){if(typeof arguments[2]=="string")b=c;y=document.defaultView.getComputedStyle(x,null).getPropertyValue(b)}return y};var T=function(a,p){return S(a,'border'+p+'Color','border-'+p.toLowerCase()+'-color')};var U=function(a,p){if(a.currentStyle&&!P){w=a.currentStyle['border'+p+'Width'];if(w=='thin')w=2;if(w=='medium'&&!(a.currentStyle['border'+p+'Style']=='none'))w=4;if(w=='thick')w=6}else{p=p.toLowerCase();w=document.defaultView.getComputedStyle(a,null).getPropertyValue('border-'+p+'-width')}return R(w)};var V=function(a,i){return a.tagName.toLowerCase()==i};var W=function(e,a,b,c,d){if(e=='tl')return a;if(e=='tr')return b;if(e=='bl')return c;if(e=='br')return d};var X=function(a,b,c,d,e,f,g){var h,curve_to;if(d.indexOf('rgba')!=-1){var i=/^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/;var j=i.exec(d);if(j){var k=[R(j[1]),R(j[2]),R(j[3])];d='rgb('+k[0]+', '+k[1]+', '+k[2]+')'}}var l=a.getContext('2d');if(b==1||g=='notch'){if(e>0&&b>1){l.fillStyle=f;l.fillRect(0,0,b,b);l.fillStyle=d;h=W(c,[0-e,0-e],[e,0-e],[0-e,e],[e,e]);l.fillRect(h[0],h[1],b,b)}else{l.fillStyle=d;l.fillRect(0,0,b,b)}return a}else if(g=='bevel'){h=W(c,[0,0,0,b,b,0,0,0],[0,0,b,b,b,0,0,0],[0,0,b,b,0,b,0,0],[b,b,b,0,0,b,b,b]);l.fillStyle=d;l.beginPath();l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);l.lineTo(h[4],h[5]);l.lineTo(h[6],h[7]);l.fill();if(e>0&&e<b){l.strokeStyle=f;l.lineWidth=e;l.beginPath();h=W(c,[0,b,b,0],[0,0,b,b],[b,b,0,0],[0,b,b,0]);l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);l.stroke()}return a}h=W(c,[0,0,b,0,b,0,0,b,0,0],[b,0,b,b,b,0,0,0,0,0],[0,b,b,b,0,b,0,0,0,b],[b,b,b,0,b,0,0,b,b,b]);l.fillStyle=d;l.beginPath();l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);if(c=='br')l.bezierCurveTo(h[4],h[5],b,b,h[6],h[7]);else l.bezierCurveTo(h[4],h[5],0,0,h[6],h[7]);l.lineTo(h[8],h[9]);l.fill();if(e>0&&e<b){var m=e/2;var n=b-m;h=W(c,[n,m,n,m,m,n],[n,n,n,m,m,m],[n,n,m,n,m,m,m,n],[n,m,n,m,m,n,n,n]);curve_to=W(c,[0,0],[0,0],[0,0],[b,b]);l.strokeStyle=f;l.lineWidth=e;l.beginPath();l.moveTo(h[0],h[1]);l.bezierCurveTo(h[2],h[3],curve_to[0],curve_to[1],h[4],h[5]);l.stroke()}return a};var Y=function(p,a){var b=document.createElement('canvas');b.setAttribute("height",a);b.setAttribute("width",a);b.style.display="block";b.style.position="absolute";b.className="jrCorner";Z(p,b);if(!Q&&N){if(typeof G_vmlCanvasManager=="object"){b=G_vmlCanvasManager.initElement(b)}else if(typeof G_vmlCMjrc=="object"){b=G_vmlCMjrc.i(b)}else{throw Error('Could not find excanvas');}}return b};var Z=function(p,a){if(p.is("table")){p.children("tbody").children("tr:first").children("td:first").append(a);p.css('display','block')}else if(p.is("td")){if(p.children(".JrcTdContainer").length===0){p.html('<div class="JrcTdContainer" style="padding:0px;position:relative;margin:-1px;zoom:1;">'+p.html()+'</div>');p.css('zoom','1');if(O){p.children(".JrcTdContainer").get(0).style.setExpression("height","this.parentNode.offsetHeight")}}p.children(".JrcTdContainer").append(a)}else{p.append(a)}};if(N){var ba=document.createStyleSheet();ba.media='print';ba.cssText='.jrcIECanvasDiv { display:none !important; }'}var bb=function(D){if(this.length==0||!(Q||N)){return this}if(D=="destroy"){return this.each(function(){var p,elm=$(this);if(elm.is(".jrcRounded")){if(typeof elm.data("ie6tmr.jrc")=='number')window.clearInterval(elm.data("ie6tmr.jrc"));if(elm.is("table"))p=elm.children("tbody").children("tr:first").children("td:first");else if(elm.is("td"))p=elm.children(".JrcTdContainer");else p=elm;p.children(".jrCorner").remove();elm.unbind('mouseleave.jrc').unbind('mouseenter.jrc').removeClass('jrcRounded').removeData('ie6tmr.jrc');if(elm.is("td"))elm.html(elm.children(".JrcTdContainer").html())}})}var o=(D||"").toLowerCase();var E=R((o.match(/(\d+)px/)||[])[1])||"auto";var F=((o.match(/(#[0-9a-f]+)/)||[])[1])||"auto";var G=/round|bevel|notch/;var H=((o.match(G)||['round'])[0]);var I=/hover/.test(o);var J=/oversized/.test(o);var K=o.match("hiddenparent");if(N){var G=/ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/;var L=((o.match(G)||['ie6fixinit'])[0])}var M={tl:/top|left|tl/.test(o),tr:/top|right|tr/.test(o),bl:/bottom|left|bl/.test(o),br:/bottom|right|br/.test(o)};if(!M.tl&&!M.tr&&!M.bl&&!M.br)M={tl:1,tr:1,bl:1,br:1};this.each(function(){var d=$(this),rbg=null,bg,s,b,pr;var a=this;var e=S(this,'display');var f=S(this,'position');var g=S(this,'lineHeight','line-height');if(F=="auto"){s=d.siblings(".jrcRounded:eq(0)");if(s.length>0){b=s.data("rbg.jrc");if(typeof b=="string"){rbg=b}}}if(K||rbg===null){var h=this.parentNode,hidden_parents=new Array(),a=0;while((typeof h=='object')&&!V(h,'html')){if(K&&S(h,'display')=='none'){hidden_parents.push({originalvisibility:S(h,'visibility'),elm:h});h.style.display='block';h.style.visibility='hidden'}var j=S(h,'backgroundColor','background-color');if(rbg===null&&j!="transparent"&&j!="rgba(0, 0, 0, 0)"){rbg=j}h=h.parentNode}if(rbg===null)rbg="#ffffff"}if(F=="auto"){bg=rbg;d.data("rbg.jrc",rbg)}else{bg=F}if(e=='none'){var k=S(this,'visibility');this.style.display='block';this.style.visibility='hidden';var l=true}else{var m=false}var n=d.height();var p=d.width();if(I){var q=o.replace(/hover|ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/g,"");if(L!='ie6nofix')q="ie6fixinit "+q;d.bind("mouseenter.jrc",function(){d.addClass('jrcHover');d.corner(q)});d.bind("mouseleave.jrc",function(){d.removeClass('jrcHover');d.corner(q)})}if(O&&L!='ie6nofix'){this.style.zoom=1;if(L!='ie6fixexpr'){if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}$(window).load(function(){if(L=='ie6fixonload'){if(d.css('height')=='auto')d.height(d.css('height'));if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}else if(L=='ie6fixwidthint'||L=='ie6fixheightint'||L=='ie6fixbothint'){var c,ie6FixFunction;if(L=='ie6fixheightint'){ie6FixFunction=function(){d.height('auto');var a=d.height();if(a%2!=0)a=a+1;d.css({height:a})}}else if(L=='ie6fixwidthint'){ie6FixFunction=function(){d.width('auto');var a=d.width();if(a%2!=0)a=a+1;d.css({width:a});d.data('lastWidth.jrc',d.get(0).offsetWidth)}}else if(L=='ie6fixbothint'){ie6FixFunction=function(){d.width('auto');d.height('auto');var a=d.width();var b=d.height();if(b%2!=0)b=b+1;if(a%2!=0)a=a+1;d.css({width:a,height:b})}}c=window.setInterval(ie6FixFunction,100);d.data("ie6tmr.jrc",c)}})}var r=n<p?this.offsetHeight:this.offsetWidth;if(E=="auto"){E=r/2;if(E>10)E=r/4}if(E>r/2&&!J){E=r/2}E=Math.floor(E);var t=U(this,'Top');var u=U(this,'Right');var v=U(this,'Bottom');var w=U(this,'Left');if(f=='static'&&!V(this,'td')){this.style.position='relative'}else if(f=='fixed'&&N&&!(document.compatMode=='CSS1Compat'&&!O)){this.style.position='absolute'}if(t+u+v+w>0){this.style.overflow='visible'}if(l)d.css({display:'none',visibility:k});if(typeof hidden_parents!="undefined"){for(var i=0;i<hidden_parents.length;i++){hidden_parents[i].elm.style.display='none';hidden_parents[i].elm.style.visibility=hidden_parents[i].originalvisibility}}var x=0-t,p_right=0-u,p_bottom=0-v,p_left=0-w;var y=(d.find("canvas").length>0);if(y){if(V(this,'table'))pr=d.children("tbody").children("tr:first").children("td:first");else if(V(this,'td'))pr=d.children(".JrcTdContainer");else pr=d}if(M.tl){bordersWidth=t<w?t:w;if(y)pr.children("canvas.jrcTL").remove();var z=X(Y(d,E),E,'tl',bg,bordersWidth,T(this,'Top'),H);$(z).css({left:p_left,top:x}).addClass('jrcTL')}if(M.tr){bordersWidth=t<u?t:u;if(y)pr.children("canvas.jrcTR").remove();var A=X(Y(d,E),E,'tr',bg,bordersWidth,T(this,'Top'),H);$(A).css({right:p_right,top:x}).addClass('jrcTR')}if(M.bl){bordersWidth=v<w?v:w;if(y)pr.children("canvas.jrcBL").remove();var B=X(Y(d,E),E,'bl',bg,bordersWidth,T(this,'Bottom'),H);$(B).css({left:p_left,bottom:p_bottom}).addClass('jrcBL')}if(M.br){bordersWidth=v<u?v:u;if(y)pr.children("canvas.jrcBR").remove();var C=X(Y(d,E),E,'br',bg,bordersWidth,T(this,'Bottom'),H);$(C).css({right:p_right,bottom:p_bottom}).addClass('jrcBR')}if(N)d.children('canvas.jrCorner').children('div').addClass('jrcIECanvasDiv');if(O&&L=='ie6fixexpr'){if(M.bl){B.style.setExpression("bottom","this.parentNode.offsetHeight % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])+1)")}if(M.br){C.style.setExpression("right","this.parentNode.offsetWidth  % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderRightWidth']))  : 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])+1)");C.style.setExpression("bottom","this.parentNode.offsetHeight % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])+1)")}if(M.tr){A.style.setExpression("right","this.parentNode.offsetWidth   % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderRightWidth']))  : 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])+1)")}}d.addClass('jrcRounded')});if(typeof arguments[1]=="function")arguments[1](this);return this};$.fn.corner=bb})(jQuery);
\ No newline at end of file
+/*
+ * jQuery corner plugin
+ *
+ * version 1.92 (12/18/2007)
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+/**
+ * The corner() method provides a simple way of styling DOM elements.  
+ *
+ * corner() takes a single string argument:  $().corner("effect corners width")
+ *
+ *   effect:  The name of the effect to apply, such as round or bevel. 
+ *            If you don't specify an effect, rounding is used.
+ *
+ *   corners: The corners can be one or more of top, bottom, tr, tl, br, or bl. 
+ *            By default, all four corners are adorned. 
+ *
+ *   width:   The width specifies the width of the effect; in the case of rounded corners this 
+ *            will be the radius of the width. 
+ *            Specify this value using the px suffix such as 10px, and yes it must be pixels.
+ *
+ * For more details see: http://methvin.com/jquery/jq-corner.html
+ * For a full demo see:  http://malsup.com/jquery/corner/
+ *
+ *
+ * @example $('.adorn').corner();
+ * @desc Create round, 10px corners 
+ *
+ * @example $('.adorn').corner("25px");
+ * @desc Create round, 25px corners 
+ *
+ * @example $('.adorn').corner("notch bottom");
+ * @desc Create notched, 10px corners on bottom only
+ *
+ * @example $('.adorn').corner("tr dog 25px");
+ * @desc Create dogeared, 25px corner on the top-right corner only
+ *
+ * @example $('.adorn').corner("round 8px").parent().css('padding', '4px').corner("round 10px");
+ * @desc Create a rounded border effect by styling both the element and its parent
+ * 
+ * @name corner
+ * @type jQuery
+ * @param String options Options which control the corner style
+ * @cat Plugins/Corner
+ * @return jQuery
+ * @author Dave Methvin (dave.methvin@gmail.com)
+ * @author Mike Alsup (malsup@gmail.com)
+ */
+(function($) { 
+
+$.fn.corner = function(o) {
+    var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent);
+    function sz(el, p) { return parseInt($.css(el,p))||0; };
+    function hex2(s) {
+        var s = parseInt(s).toString(16);
+        return ( s.length < 2 ) ? '0'+s : s;
+    };
+    function gpc(node) {
+        for ( ; node && node.nodeName.toLowerCase() != 'html'; node = node.parentNode ) {
+            var v = $.css(node,'backgroundColor');
+            if ( v.indexOf('rgb') >= 0 ) { 
+                if ($.browser.safari && v == 'rgba(0, 0, 0, 0)')
+                    continue;
+                var rgb = v.match(/\d+/g); 
+                return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
+            }
+            if ( v && v != 'transparent' )
+                return v;
+        }
+        return '#ffffff';
+    };
+    function getW(i) {
+        switch(fx) {
+        case 'round':  return Math.round(width*(1-Math.cos(Math.asin(i/width))));
+        case 'cool':   return Math.round(width*(1+Math.cos(Math.asin(i/width))));
+        case 'sharp':  return Math.round(width*(1-Math.cos(Math.acos(i/width))));
+        case 'bite':   return Math.round(width*(Math.cos(Math.asin((width-i-1)/width))));
+        case 'slide':  return Math.round(width*(Math.atan2(i,width/i)));
+        case 'jut':    return Math.round(width*(Math.atan2(width,(width-i-1))));
+        case 'curl':   return Math.round(width*(Math.atan(i)));
+        case 'tear':   return Math.round(width*(Math.cos(i)));
+        case 'wicked': return Math.round(width*(Math.tan(i)));
+        case 'long':   return Math.round(width*(Math.sqrt(i)));
+        case 'sculpt': return Math.round(width*(Math.log((width-i-1),width)));
+        case 'dog':    return (i&1) ? (i+1) : width;
+        case 'dog2':   return (i&2) ? (i+1) : width;
+        case 'dog3':   return (i&3) ? (i+1) : width;
+        case 'fray':   return (i%2)*width;
+        case 'notch':  return width; 
+        case 'bevel':  return i+1;
+        }
+    };
+    o = (o||"").toLowerCase();
+    var keep = /keep/.test(o);                       // keep borders?
+    var cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]);  // corner color
+    var sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]);  // strip color
+    var width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10; // corner width
+    var re = /round|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dog/;
+    var fx = ((o.match(re)||['round'])[0]);
+    var edges = { T:0, B:1 };
+    var opts = {
+        TL:  /top|tl/.test(o),       TR:  /top|tr/.test(o),
+        BL:  /bottom|bl/.test(o),    BR:  /bottom|br/.test(o)
+    };
+    if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
+        opts = { TL:1, TR:1, BL:1, BR:1 };
+    var strip = document.createElement('div');
+    strip.style.overflow = 'hidden';
+    strip.style.height = '1px';
+    strip.style.backgroundColor = sc || 'transparent';
+    strip.style.borderStyle = 'solid';
+    return this.each(function(index){
+        var pad = {
+            T: parseInt($.css(this,'paddingTop'))||0,     R: parseInt($.css(this,'paddingRight'))||0,
+            B: parseInt($.css(this,'paddingBottom'))||0,  L: parseInt($.css(this,'paddingLeft'))||0
+        };
+
+        if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' in IE
+        if (!keep) this.style.border = 'none';
+        strip.style.borderColor = cc || gpc(this.parentNode);
+        var cssHeight = $.curCSS(this, 'height');
+
+        for (var j in edges) {
+            var bot = edges[j];
+            // only add stips if needed
+            if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) {
+                strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none');
+                var d = document.createElement('div');
+                $(d).addClass('jquery-corner');
+                var ds = d.style;
+
+                bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild);
+
+                if (bot && cssHeight != 'auto') {
+                    if ($.css(this,'position') == 'static')
+                        this.style.position = 'relative';
+                    ds.position = 'absolute';
+                    ds.bottom = ds.left = ds.padding = ds.margin = '0';
+                    if ($.browser.msie)
+                        ds.setExpression('width', 'this.parentNode.offsetWidth');
+                    else
+                        ds.width = '100%';
+                }
+                else if (!bot && $.browser.msie) {
+                    if ($.css(this,'position') == 'static')
+                        this.style.position = 'relative';
+                    ds.position = 'absolute';
+                    ds.top = ds.left = ds.right = ds.padding = ds.margin = '0';
+                    
+                    // fix ie6 problem when blocked element has a border width
+                    var bw = 0;
+                    if (ie6 || !$.boxModel)
+                        bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
+                    ie6 ? ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"') : ds.width = '100%';
+                }
+                else {
+                    ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' : 
+                                        (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px';                
+                }
+
+                for (var i=0; i < width; i++) {
+                    var w = Math.max(0,getW(i));
+                    var e = strip.cloneNode(false);
+                    e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px';
+                    bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild);
+                }
+            }
+        }
+    });
+};
+
+$.fn.uncorner = function(o) { return $('.jquery-corner', this).remove(); };
+    
+})(jQuery);
--- a/web/data/timeline-bundle.css	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/data/timeline-bundle.css	Wed Apr 15 17:36:09 2009 +0200
@@ -1,171 +1,175 @@
-
-
-/*------------------- Horizontal / Vertical lines ----------------*/
-
-/* style for ethers */
-.timeline-ether-lines{border-color:#666; border-style:dotted; position:absolute;}
-
-.timeline-horizontal .timeline-ether-lines{border-width:0 0 0 1px; height:100%; top: 0; width: 1px;}
-
-.timeline-vertical .timeline-ether-lines{border-width:1px 0 0; height:1px; left: 0; width: 100%;}
-
-
-
-
-/*---------------- Weekends ---------------------------*/
-
-.timeline-ether-weekends{
-	position:absolute;
-	background-color:#FFFFE0;
-}
-
-.timeline-vertical .timeline-ether-weekends{left:0;width:100%;}
-
-.timeline-horizontal .timeline-ether-weekends{top:0; height:100%;}
-
-
-
-/*-------------------------- HIGHLIGHT DECORATORS -------------------*/
-.timeline-highlight-decorator,
-.timeline-highlight-point-decorator{
-	position:absolute;
-	overflow:hidden;
-}
-.timeline-horizontal .timeline-highlight-point-decorator,
-.timeline-horizontal .timeline-highlight-decorator{
-	width:10px;
-	top:0;
-    height:100%;
-}
-
-.timeline-vertical .timeline-highlight-point-decorator,
-.timeline-vertical .timeline-highlight-decorator{
-	height:10px;
-	width:100%;
-	left:0;
-}
-
-.timeline-highlight-decorator{background-color:#FFC080;}
-.timeline-highlight-point-decorator{background-color:#ff5;}
-
-
-
-/*---------------------------- LABELS -------------------------*/
-.timeline-highlight-label{position:absolute;overflow:hidden;font-size:200%;font-weight:bold;color:#999;}
-
-
-/*---------------- VERTICAL LABEL -------------------*/
-.timeline-horizontal .timeline-highlight-label{top:0;height:100%;}
-.timeline-horizontal .timeline-highlight-label td{vertical-align:middle;}
-.timeline-horizontal .timeline-highlight-label-start{text-align:right;}
-.timeline-horizontal .timeline-highlight-label-end{text-align:left;}
-
-
-/*---------------- HORIZONTAL LABEL -------------------*/
-.timeline-vertical .timeline-highlight-label{left:0;width:100%;}
-.timeline-vertical .timeline-highlight-label td{vertical-align:top;}
-.timeline-vertical .timeline-highlight-label-start{text-align:center;}
-.timeline-vertical .timeline-highlight-label-end{text-align:center;}
-
-
-
-/*-------------------------------- DATE LABELS --------------------------------*/
-.timeline-date-label{position:absolute; border:solid #aaa; color:#aaa;	width:5em; height:1.5em;}
-.timeline-date-label-em{color:#000;}
-
-/* horizontal */
-.timeline-horizontal .timeline-date-label{padding-left:2px;}
-.timeline-horizontal .timeline-date-label{border-width:0 0 0 1px;}
-.timeline-horizontal .timeline-date-label-em{height:2em}
+div.simileAjax-bubble-container {
+    margin:     0px;
+    padding:    0px;
+    border:     none;
+    position:   absolute;
+    z-index:    1000;
+}
+
+div.simileAjax-bubble-innerContainer {
+    margin:     0px;
+    padding:    0px;
+    border:     none;
+    position:   relative;
+    width:      100%;
+    height:     100%;
+    overflow:   visible;
+}
 
-/* vertical */
-.timeline-vertical .timeline-date-label{padding-top:2px;}
-.timeline-vertical .timeline-date-label{border-width:1px 0 0;}
-.timeline-vertical .timeline-date-label-em{width:7em}
-
-/*------------------------------- Ether.highlight -------------------------*/
-.timeline-ether-highlight{position:absolute; background-color:#fff;}
-.timeline-horizontal .timeline-ether-highlight{top:2px;}
-.timeline-vertical .timeline-ether-highlight{left:2px;}
-
-
-
-/*------------------------------ EVENTS ------------------------------------*/
-.timeline-event-icon, .timeline-event-label,.timeline-event-tape{
-	position:absolute;
-	cursor:pointer;
-}
-
-.timeline-event-tape,
-.timeline-small-event-tape,
-.timeline-small-event-icon{
-	background-color:#58A0DC;
-	overflow:hidden;
-}
-
-.timeline-small-event-tape,
-.timeline-small-event-icon{
-	position:absolute;
-}
-
-.timeline-event-tape{height:4px;}
-
-.timeline-small-event-tape{height:2px;}
-.timeline-small-event-icon{width:1px; height:6px;}
- 
- 
-
-/*--------------------------------- TIMELINE-------------------------*/
-.timeline-ether-bg{width:100%; height:100%;}
-.timeline-band-0 .timeline-ether-bg{background-color:#eee}
-.timeline-band-1 .timeline-ether-bg{background-color:#ddd}
-.timeline-band-2 .timeline-ether-bg{background-color:#ccc}
-.timeline-band-3 .timeline-ether-bg{background-color:#aaa}
-.timeline-duration-event {
-    position: absolute;
-    overflow: hidden;
-    border: 1px solid blue;
-}
-
-.timeline-instant-event2 {
-    position: absolute;
-    overflow: hidden;
-    border-left: 1px solid blue;
-    padding-left: 2px;
-}
-
-.timeline-instant-event {
-    position: absolute;
-    overflow: hidden;
-}
-
-.timeline-event-bubble-title {
-    font-weight: bold;
-    border-bottom: 1px solid #888;
-    margin-bottom: 0.5em;
-}
-
-.timeline-event-bubble-body {
-}
-
-.timeline-event-bubble-wiki {
-    margin:     0.5em;
-    text-align: right;
-    color:      #A0A040;
-}
-.timeline-event-bubble-wiki a {
-    color:      #A0A040;
-}
-
-.timeline-event-bubble-time {
-    color: #aaa;
-}
-
-.timeline-event-bubble-image {
-    float: right;
-    padding-left: 5px;
-    padding-bottom: 5px;
-}.timeline-container {
+div.simileAjax-bubble-contentContainer {
+    margin:     0px;
+    padding:    0px;
+    border:     none;
+    position:   absolute;
+    left:       0px;
+    top:        0px;
+    width:      100%;
+    height:     100%;
+    overflow:   auto;
+    background: white;
+}
+
+div.simileAjax-bubble-border-left {
+    position:   absolute;
+    left:       -50px;
+    top:        0px;
+    width:      50px;
+    height:     100%;
+}
+div.simileAjax-bubble-border-left-pngTranslucent {
+    background: url(../images/bubble-left.png) top right repeat-y;
+}
+
+div.simileAjax-bubble-border-right {
+    position:   absolute;
+    right:      -50px;
+    top:        0px;
+    width:      50px;
+    height:     100%;
+}
+.simileAjax-bubble-border-right-pngTranslucent {
+    background: url(../images/bubble-right.png) top left repeat-y;
+}
+
+div.simileAjax-bubble-border-top {
+    position:   absolute;
+    top:        -50px;
+    left:       0px;
+    width:      100%;
+    height:     50px;
+}
+.simileAjax-bubble-border-top-pngTranslucent {
+    background: url(../images/bubble-top.png) bottom left repeat-x;
+}
+
+div.simileAjax-bubble-border-bottom {
+    position:   absolute;
+    bottom:     -50px;
+    left:       0px;
+    width:      100%;
+    height:     50px;
+}
+.simileAjax-bubble-border-bottom-pngTranslucent {
+    background: url(../images/bubble-bottom.png) top left repeat-x;
+}
+
+div.simileAjax-bubble-border-top-left {
+    position:   absolute;
+    top:        -50px;
+    left:       -50px;
+    width:      50px;
+    height:     50px;
+}
+.simileAjax-bubble-border-top-left-pngTranslucent {
+    background: url(../images/bubble-top-left.png) bottom right no-repeat;
+}
+
+div.simileAjax-bubble-border-top-right {
+    position:   absolute;
+    top:        -50px;
+    right:      -50px;
+    width:      50px;
+    height:     50px;
+}
+.simileAjax-bubble-border-top-right-pngTranslucent {
+    background: url(../images/bubble-top-right.png) bottom left no-repeat;
+}
+
+div.simileAjax-bubble-border-bottom-left {
+    position:   absolute;
+    bottom:     -50px;
+    left:       -50px;
+    width:      50px;
+    height:     50px;
+}
+.simileAjax-bubble-border-bottom-left-pngTranslucent {
+    background: url(../images/bubble-bottom-left.png) top right no-repeat;
+}
+
+div.simileAjax-bubble-border-bottom-right {
+    position:   absolute;
+    bottom:     -50px;
+    right:      -50px;
+    width:      50px;
+    height:     50px;
+}
+.simileAjax-bubble-border-bottom-right-pngTranslucent {
+    background: url(../images/bubble-bottom-right.png) top left no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-left {
+    position:   absolute;
+    left:       -100px;
+    width:      100px;
+    height:     49px;
+}
+.simileAjax-bubble-arrow-point-left-pngTranslucent {
+    background: url(../images/bubble-arrow-point-left.png) center right no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-right {
+    position:   absolute;
+    right:      -100px;
+    width:      100px;
+    height:     49px;
+}
+.simileAjax-bubble-arrow-point-right-pngTranslucent {
+    background: url(../images/bubble-arrow-point-right.png) center left no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-up {
+    position:   absolute;
+    top:        -100px;
+    width:      49px;
+    height:     100px;
+}
+.simileAjax-bubble-arrow-point-up-pngTranslucent {
+    background: url(../images/bubble-arrow-point-up.png) bottom center no-repeat;
+}
+
+div.simileAjax-bubble-arrow-point-down {
+    position:   absolute;
+    bottom:     -100px;
+    width:      49px;
+    height:     100px;
+}
+.simileAjax-bubble-arrow-point-down-pngTranslucent {
+    background: url(../images/bubble-arrow-point-down.png) bottom center no-repeat;
+}
+
+
+div.simileAjax-bubble-close {
+    position:   absolute;
+    right:      -10px;
+    top:        -12px;
+    width:      16px;
+    height:     16px;
+    cursor:     pointer;
+}
+.simileAjax-bubble-close-pngTranslucent {
+    background: url(../images/close-button.png) no-repeat;
+}
+.timeline-container {
     position: relative;
     overflow: hidden;
 }
@@ -230,3 +234,168 @@
     height:     100%;
 }
 
+
+
+/*------------------- Horizontal / Vertical lines ----------------*/
+
+/* style for ethers */
+.timeline-ether-lines{border-color:#666; border-style:dotted; position:absolute;}
+.timeline-horizontal .timeline-ether-lines{border-width:0 0 0 1px; height:100%; top: 0; width: 1px;}
+.timeline-vertical .timeline-ether-lines{border-width:1px 0 0; height:1px; left: 0; width: 100%;}
+
+
+
+/*---------------- Weekends ---------------------------*/
+.timeline-ether-weekends{
+	position:absolute;
+	background-color:#FFFFE0;
+}
+
+.timeline-vertical .timeline-ether-weekends{left:0;width:100%;}
+.timeline-horizontal .timeline-ether-weekends{top:0; height:100%;}
+
+
+/*-------------------------- HIGHLIGHT DECORATORS -------------------*/
+/* Used for decorators, not used for Timeline Highlight              */
+.timeline-highlight-decorator,
+.timeline-highlight-point-decorator{
+	position:absolute;
+	overflow:hidden;
+}
+
+/* Width of horizontal decorators and Height of vertical decorators is
+   set in the decorator function params */
+.timeline-horizontal .timeline-highlight-point-decorator,
+.timeline-horizontal .timeline-highlight-decorator{
+	top:0;
+  height:100%;
+}
+
+.timeline-vertical .timeline-highlight-point-decorator,
+.timeline-vertical .timeline-highlight-decorator{
+	width:100%;
+	left:0;
+}
+
+.timeline-highlight-decorator{background-color:#FFC080;}
+.timeline-highlight-point-decorator{background-color:#ff5;}
+
+
+/*---------------------------- LABELS -------------------------*/
+.timeline-highlight-label {
+  position:absolute; overflow:hidden; font-size:200%;
+  font-weight:bold; color:#999; }
+
+
+/*---------------- VERTICAL LABEL -------------------*/
+.timeline-horizontal .timeline-highlight-label {top:0; height:100%;}
+.timeline-horizontal .timeline-highlight-label td {vertical-align:middle;}
+.timeline-horizontal .timeline-highlight-label-start {text-align:right;}
+.timeline-horizontal .timeline-highlight-label-end {text-align:left;}
+
+
+/*---------------- HORIZONTAL LABEL -------------------*/
+.timeline-vertical .timeline-highlight-label {left:0;width:100%;}
+.timeline-vertical .timeline-highlight-label td {vertical-align:top;}
+.timeline-vertical .timeline-highlight-label-start {text-align:center;}
+.timeline-vertical .timeline-highlight-label-end {text-align:center;}
+
+
+/*-------------------------------- DATE LABELS --------------------------------*/
+.timeline-date-label {
+  position: absolute;
+  border: solid #aaa;
+  color: #aaa;
+  width: 5em;
+  height: 1.5em;}
+.timeline-date-label-em {color: #000;}
+
+/* horizontal */
+.timeline-horizontal .timeline-date-label{padding-left:2px;}
+.timeline-horizontal .timeline-date-label{border-width:0 0 0 1px;}
+.timeline-horizontal .timeline-date-label-em{height:2em}
+
+/* vertical */
+.timeline-vertical .timeline-date-label{padding-top:2px;}
+.timeline-vertical .timeline-date-label{border-width:1px 0 0;}
+.timeline-vertical .timeline-date-label-em{width:7em}
+
+
+/*------------------------------- Ether.highlight -------------------------*/
+.timeline-ether-highlight{position:absolute; background-color:#fff;}
+.timeline-horizontal .timeline-ether-highlight{top:2px;}
+.timeline-vertical .timeline-ether-highlight{left:2px;}
+
+
+/*------------------------------ EVENTS ------------------------------------*/
+.timeline-event-icon, .timeline-event-label,.timeline-event-tape{
+	position:absolute;
+	cursor:pointer;
+}
+
+.timeline-event-tape,
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+	background-color:#58A0DC;
+	overflow:hidden;
+}
+
+.timeline-small-event-tape,
+.timeline-small-event-icon{
+	position:absolute;
+}
+
+.timeline-small-event-icon{width:1px; height:6px;}
+
+  
+/*--------------------------------- TIMELINE-------------------------*/
+.timeline-ether-bg{width:100%; height:100%;}
+.timeline-band-0 .timeline-ether-bg{background-color:#eee}
+.timeline-band-1 .timeline-ether-bg{background-color:#ddd}
+.timeline-band-2 .timeline-ether-bg{background-color:#ccc}
+.timeline-band-3 .timeline-ether-bg{background-color:#aaa}
+.timeline-duration-event {
+    position: absolute;
+    overflow: hidden;
+    border: 1px solid blue;
+}
+
+.timeline-instant-event2 {
+    position: absolute;
+    overflow: hidden;
+    border-left: 1px solid blue;
+    padding-left: 2px;
+}
+
+.timeline-instant-event {
+    position: absolute;
+    overflow: hidden;
+}
+
+.timeline-event-bubble-title {
+    font-weight: bold;
+    border-bottom: 1px solid #888;
+    margin-bottom: 0.5em;
+}
+
+.timeline-event-bubble-body {
+}
+
+.timeline-event-bubble-wiki {
+    margin:     0.5em;
+    text-align: right;
+    color:      #A0A040;
+}
+.timeline-event-bubble-wiki a {
+    color:      #A0A040;
+}
+
+.timeline-event-bubble-time {
+    color: #aaa;
+}
+
+.timeline-event-bubble-image {
+    float: right;
+    padding-left: 5px;
+    padding-bottom: 5px;
+}
\ No newline at end of file
--- a/web/facet.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/facet.py	Wed Apr 15 17:36:09 2009 +0200
@@ -29,7 +29,7 @@
 
 def prepare_facets_rqlst(rqlst, args=None):
     """prepare a syntax tree to generate facet filters
-    
+
     * remove ORDERBY clause
     * cleanup selection (remove everything)
     * undefine unnecessary variables
@@ -64,7 +64,7 @@
 def get_facet(req, facetid, rqlst, mainvar):
     return req.vreg.object_by_id('facets', facetid, req, rqlst=rqlst,
                                  filtered_variable=mainvar)
-    
+
 
 def filter_hiddens(w, **kwargs):
     for key, val in kwargs.items():
@@ -139,7 +139,7 @@
         rqlst.add_group_var(newvar)
     rqlst.add_selected(newvar)
     return newvar, rel
-        
+
 def _remove_relation(rqlst, rel, var):
     """remove a constraint relation from the syntax tree"""
     # remove the relation
@@ -229,10 +229,10 @@
             if ovarname == mainvar.name:
                 continue
             if not has_path(vargraph, ovarname, mainvar.name):
-                toremove.add(rqlst.defined_vars[ovarname])            
+                toremove.add(rqlst.defined_vars[ovarname])
 
-        
-        
+
+
 ## base facet classes #########################################################
 class AbstractFacet(AcceptMixIn, AppRsetObject):
     __registerer__ = priority_registerer
@@ -243,16 +243,16 @@
                            help=_('display the box or not')),
         _('order'):   dict(type='Int', default=99,
                            help=_('display order of the box')),
-        _('context'): dict(type='String', default=None,
+        _('context'): dict(type='String', default='',
                            # None <-> both
-                           vocabulary=(_('tablefilter'), _('facetbox'), None),
+                           vocabulary=(_('tablefilter'), _('facetbox'), ''),
                            help=_('context where this box should be displayed')),
         }
     visible = True
-    context = None
+    context = ''
     needs_update = False
     start_unfolded = True
-    
+
     @classmethod
     def selected(cls, req, rset=None, rqlst=None, context=None,
                  filtered_variable=None):
@@ -280,20 +280,20 @@
     def operator(self):
         # OR between selected values by default
         return self.req.form.get(self.id + '_andor', 'OR')
-    
+
     def get_widget(self):
         """return the widget instance to use to display this facet
         """
         raise NotImplementedError
-    
+
     def add_rql_restrictions(self):
         """add restriction for this facet into the rql syntax tree"""
         raise NotImplementedError
-    
+
 
 class VocabularyFacet(AbstractFacet):
     needs_update = True
-    
+
     def get_widget(self):
         """return the widget instance to use to display this facet
 
@@ -311,12 +311,12 @@
             else:
                 wdg.append(FacetItem(self.req, label, value, value in selected))
         return wdg
-    
+
     def vocabulary(self):
         """return vocabulary for this facet, eg a list of 2-uple (label, value)
         """
         raise NotImplementedError
-    
+
     def possible_values(self):
         """return a list of possible values (as string since it's used to
         compare to a form value in javascript) for this facet
@@ -325,13 +325,13 @@
 
     def support_and(self):
         return False
-    
+
     def rqlexec(self, rql, args=None, cachekey=None):
         try:
             return self.req.execute(rql, args, cachekey)
         except Unauthorized:
             return []
-        
+
 
 class RelationFacet(VocabularyFacet):
     __selectors__ = (one_has_relation, match_context_prop)
@@ -344,10 +344,10 @@
     sortfunc = None
     # ascendant/descendant sorting
     sortasc = True
-    
+
     @property
     def title(self):
-        return display_name(self.req, self.rtype, form=self.role)        
+        return display_name(self.req, self.rtype, form=self.role)
 
     def vocabulary(self):
         """return vocabulary for this facet, eg a list of 2-uple (label, value)
@@ -367,7 +367,7 @@
         finally:
             rqlst.recover()
         return self.rset_vocabulary(rset)
-    
+
     def possible_values(self):
         """return a list of possible values (as string since it's used to
         compare to a form value in javascript) for this facet
@@ -380,7 +380,7 @@
             return [str(x) for x, in self.rqlexec(rqlst.as_string())]
         finally:
             rqlst.recover()
-    
+
     def rset_vocabulary(self, rset):
         _ = self.req._
         return [(_(label), eid) for eid, label in rset]
@@ -432,7 +432,9 @@
 class AttributeFacet(RelationFacet):
     # attribute type
     attrtype = 'String'
-    
+    # type of comparison: default is an exact match on the attribute value
+    comparator = '=' # could be '<', '<=', '>', '>='
+
     def vocabulary(self):
         """return vocabulary for this facet, eg a list of 2-uple (label, value)
         """
@@ -452,14 +454,14 @@
         finally:
             rqlst.recover()
         return self.rset_vocabulary(rset)
-    
+
     def rset_vocabulary(self, rset):
         _ = self.req._
         return [(_(value), value) for value, in rset]
 
     def support_and(self):
         return False
-            
+
     def add_rql_restrictions(self):
         """add restriction for this facet into the rql syntax tree"""
         value = self.req.form.get(self.id)
@@ -467,16 +469,16 @@
             return
         mainvar = self.filtered_variable
         self.rqlst.add_constant_restriction(mainvar, self.rtype, value,
-                                            self.attrtype)
+                                            self.attrtype, self.comparator)
 
 
-        
+
 class FilterRQLBuilder(object):
     """called by javascript to get a rql string from filter form"""
 
     def __init__(self, req):
         self.req = req
-                
+
     def build_rql(self):#, tablefilter=False):
         form = self.req.form
         facetids = form['facets'].split(',')
@@ -490,25 +492,22 @@
                 toupdate.append(facetid)
         return select.as_string(), toupdate
 
-        
+
 ## html widets ################################################################
 
 class FacetVocabularyWidget(HTMLWidget):
-    
+
     def __init__(self, facet):
         self.facet = facet
         self.items = []
 
     def append(self, item):
         self.items.append(item)
-            
+
     def _render(self):
         title = html_escape(self.facet.title)
         facetid = html_escape(self.facet.id)
-        if len(self.items) > 6:
-            self.w(u'<div id="%s" class="facet overflowed">\n' % facetid)
-        else:
-            self.w(u'<div id="%s" class="facet">\n' % facetid)
+        self.w(u'<div id="%s" class="facet">\n' % facetid)
         self.w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
                (html_escape(facetid), title))
         if self.facet.support_and():
@@ -521,13 +520,15 @@
         cssclass = ''
         if not self.facet.start_unfolded:
             cssclass += ' hidden'
+        if len(self.items) > 6:
+            cssclass +=' overflowed'
         self.w(u'<div class="facetBody%s">\n' % cssclass)
         for item in self.items:
             item.render(self.w)
         self.w(u'</div>\n')
         self.w(u'</div>\n')
 
-        
+
 class FacetStringWidget(HTMLWidget):
     def __init__(self, facet):
         self.facet = facet
@@ -558,12 +559,14 @@
         if self.selected:
             cssclass = ' facetValueSelected'
             imgsrc = self.req.datadir_url + self.selected_img
+            imgalt = self.req._('selected')
         else:
             cssclass = ''
-            imgsrc = self.req.datadir_url + self.unselected_img            
+            imgsrc = self.req.datadir_url + self.unselected_img
+            imgalt = self.req._('not selected')
         self.w(u'<div class="facetValue facetCheckBox%s" cubicweb:value="%s">\n'
                % (cssclass, html_escape(unicode(self.value))))
-        self.w(u'<img src="%s" />&nbsp;' % imgsrc)
+        self.w(u'<img src="%s" alt="%s"/>&nbsp;' % (imgsrc, imgalt))
         self.w(u'<a href="javascript: {}">%s</a>' % html_escape(self.label))
         self.w(u'</div>')
 
@@ -571,7 +574,7 @@
 class FacetSeparator(HTMLWidget):
     def __init__(self, label=None):
         self.label = label or u'&nbsp;'
-        
+
     def _render(self):
         pass
 
--- a/web/form.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/form.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,7 +11,7 @@
 from logilab.mtconverter import html_escape
 
 from cubicweb import typed_eid
-from cubicweb.common.selectors import req_form_params_selector
+from cubicweb.common.selectors import match_form_params
 from cubicweb.common.registerers import accepts_registerer
 from cubicweb.common.view import NOINDEX, NOFOLLOW, View, EntityView, AnyRsetView
 from cubicweb.web import stdmsgs
@@ -239,7 +239,7 @@
     should list necessary parameters in the form to be accepted.
     """
     __registerer__ = accepts_registerer
-    __select__ = classmethod(req_form_params_selector)
+    __select__ = classmethod(match_form_params)
 
     form_params = ()
 
--- a/web/htmlwidgets.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/htmlwidgets.py	Wed Apr 15 17:36:09 2009 +0200
@@ -4,7 +4,7 @@
 serialization time
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 
--- a/web/request.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/request.py	Wed Apr 15 17:36:09 2009 +0200
@@ -201,7 +201,7 @@
     def update_search_state(self):
         """update the current search state"""
         searchstate = self.form.get('__mode')
-        if not searchstate:
+        if not searchstate and self.cnx is not None:
             searchstate = self.get_session_data('search_state', 'normal')
         self.set_search_state(searchstate)
 
@@ -212,7 +212,8 @@
         else:
             self.search_state = ('linksearch', searchstate.split(':'))
             assert len(self.search_state[-1]) == 4
-        self.set_session_data('search_state', searchstate)
+        if self.cnx is not None:
+            self.set_session_data('search_state', searchstate)
 
     def update_breadcrumbs(self):
         """stores the last visisted page in session data"""
@@ -640,7 +641,11 @@
     
     def xhtml_browser(self):
         useragent = self.useragent()
-        if useragent and ('MSIE' in useragent or 'KHTML' in useragent):
+        # MSIE does not support xml content-type
+        # quick fix: Opera supports xhtml and handles namespaces
+        # properly but it breaks jQuery.attr()
+        if useragent and ('MSIE' in useragent or 'KHTML' in useragent
+                          or 'Opera' in useragent):
             return False
         return True
 
--- a/web/test/jstest_python.jst	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/test/jstest_python.jst	Wed Apr 15 17:36:09 2009 +0200
@@ -1,11 +1,13 @@
+// run tests with the following command line :
+// $ crosscheck jstest_python.jst
 
 crosscheck.addTest({
 
     setup: function() {
         crosscheck.load("testutils.js");
         crosscheck.load("../data/jquery.js");
-        crosscheck.load("../data/compat.js");
-        crosscheck.load("../data/python.js");
+        crosscheck.load("../data/cubicweb.compat.js");
+        crosscheck.load("../data/cubicweb.python.js");
     },
 
     test_basic_number_parsing: function () {
--- a/web/test/test_views.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/test/test_views.py	Wed Apr 15 17:36:09 2009 +0200
@@ -37,11 +37,11 @@
     def test_manual_tests(self):
         rset = self.execute('Any P,F,S WHERE P is EUser, P firstname F, P surname S')
         self.view('table', rset, template=None, displayfilter=True, displaycols=[0,2])
-        rset = self.execute('Any P,F,S WHERE P is EUser, P firstname F, P surname S LIMIT 1')
+        rset = self.execute('Any P,F,S LIMIT 1 WHERE P is EUser, P firstname F, P surname S')
         rset.req.form['rtype'] = 'firstname'
-        self.view('editrelation', rset, template=None, htmlcheck=False)
+        self.view('editrelation', rset, template=None)
         rset.req.form['rtype'] = 'use_email'
-        self.view('editrelation', rset, template=None, htmlcheck=False)
+        self.view('editrelation', rset, template=None)
         
 
     def test_sortable_js_added(self):
@@ -49,7 +49,7 @@
         # sortable.js should not be included by default
         self.failIf('jquery.tablesorter.js' in self.view('oneline', rset))
         # but should be included by the tableview
-        rset = self.execute('Any P,F,S WHERE P is EUser, P firstname F, P surname S LIMIT 1')
+        rset = self.execute('Any P,F,S LIMIT 1 WHERE P is EUser, P firstname F, P surname S')
         self.failUnless('jquery.tablesorter.js' in self.view('table', rset))
 
     def test_js_added_only_once(self):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/unittest_owl.py	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,4075 @@
+"""unittests for schema2dot"""
+
+import os
+
+from logilab.common.testlib import TestCase, unittest_main
+from logilab.common.compat import set
+from cubicweb.devtools.testlib import WebTest
+
+from lxml import etree
+from StringIO import StringIO
+
+       
+class OWLTC(WebTest):
+    
+    def test_schema2owl(self):
+
+        parser = etree.XMLParser(dtd_validation=True)
+
+        owl= StringIO('''<xsd:schema 
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:owl="http://www.w3.org/2002/07/owl#"
+ targetNamespace="http://www.w3.org/2002/07/owl#"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+
+<!-- The ontology -->
+  
+<xsd:element name="Import">
+  <xsd:complexType>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:anyURI">
+        <xsd:attributeGroup ref="xml:specialAttrs"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="Ontology">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:element ref="owl:Import" minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:group ref="owl:ontologyAnnotations"/>
+      <xsd:group ref="owl:Axiom" minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="ontologyIRI" type="xsd:anyURI" use="optional"/>
+    <xsd:attribute name="versionIRI" type="xsd:anyURI" use="optional"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Entities, anonymous individuals, and literals -->
+
+<xsd:group name="Entity">
+  <xsd:choice>
+    <xsd:element ref="owl:Class"/>
+    <xsd:element ref="owl:Datatype"/>
+    <xsd:element ref="owl:ObjectProperty"/>
+    <xsd:element ref="owl:DataProperty"/>
+    <xsd:element ref="owl:AnnotationProperty"/>
+    <xsd:element ref="owl:NamedIndividual"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="Class">
+  <xsd:complexType>
+    <xsd:attribute name="IRI" type="xsd:anyURI" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="Datatype">
+  <xsd:complexType>
+    <xsd:attribute name="IRI" type="xsd:anyURI" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+ 
+<xsd:element name="ObjectProperty">
+  <xsd:complexType>
+    <xsd:attribute name="IRI" type="xsd:anyURI" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataProperty">
+  <xsd:complexType>
+    <xsd:attribute name="IRI" type="xsd:anyURI" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="AnnotationProperty">
+  <xsd:complexType>
+    <xsd:attribute name="IRI" type="xsd:anyURI" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:group name="Individual">
+  <xsd:choice>
+    <xsd:element ref="owl:NamedIndividual"/>
+    <xsd:element ref="owl:AnonymousIndividual"/>
+  </xsd:choice>
+</xsd:group>
+  
+<xsd:element name="NamedIndividual">
+  <xsd:complexType>
+    <xsd:attribute name="IRI" type="xsd:anyURI" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="AnonymousIndividual">
+  <xsd:complexType>
+    <xsd:attribute name="nodeID" type="xsd:NCName" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="Literal">
+ <xsd:complexType>
+   <xsd:simpleContent>
+     <xsd:extension base="xsd:string">
+       <xsd:attribute name="datatypeIRI" type="xsd:anyURI"/>
+       <xsd:attributeGroup ref="xml:specialAttrs"/>
+     </xsd:extension>
+   </xsd:simpleContent>
+ </xsd:complexType>
+</xsd:element>
+
+<!-- Declarations -->
+
+<xsd:element name="Declaration">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:Entity"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+  
+<!-- Object property expressions -->
+
+<xsd:group name="ObjectPropertyExpression">
+  <xsd:choice>
+    <xsd:element ref="owl:ObjectProperty"/>
+    <xsd:element ref="owl:InverseObjectProperty"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="InverseObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:element ref="owl:ObjectProperty"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Data property expressions -->
+
+<xsd:group name="DataPropertyExpression">
+  <xsd:sequence>
+    <xsd:element ref="owl:DataProperty"/>
+  </xsd:sequence>
+</xsd:group>
+
+<!-- Data ranges -->
+
+<xsd:group name="DataRange">
+  <xsd:choice>
+    <xsd:element ref="owl:Datatype"/>
+    <xsd:element ref="owl:DataIntersectionOf"/>
+    <xsd:element ref="owl:DataUnionOf"/>
+    <xsd:element ref="owl:DataComplementOf"/>
+    <xsd:element ref="owl:DataOneOf"/>
+    <xsd:element ref="owl:DatatypeRestriction"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="DataIntersectionOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataRange" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataUnionOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataRange" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataComplementOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataRange"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataOneOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:element ref="owl:Literal" minOccurs="1" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DatatypeRestriction">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:element ref="owl:Datatype"/>
+      <xsd:element name="FacetRestriction" minOccurs="1" maxOccurs="unbounded">
+        <xsd:complexType>
+          <xsd:sequence>
+            <xsd:element ref="owl:Literal"/>
+          </xsd:sequence>
+          <xsd:attribute name="facet" type="xsd:anyURI" use="required"/>
+        </xsd:complexType>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Class expressions -->
+
+<xsd:group name="ClassExpression">
+  <xsd:choice>
+    <xsd:element ref="owl:Class"/>
+    <xsd:element ref="owl:ObjectIntersectionOf"/>
+    <xsd:element ref="owl:ObjectUnionOf"/>
+    <xsd:element ref="owl:ObjectComplementOf"/>
+    <xsd:element ref="owl:ObjectOneOf"/>
+    <xsd:element ref="owl:ObjectSomeValuesFrom"/>
+    <xsd:element ref="owl:ObjectAllValuesFrom"/>
+    <xsd:element ref="owl:ObjectHasValue"/>
+    <xsd:element ref="owl:ObjectHasSelf"/>
+    <xsd:element ref="owl:ObjectMinCardinality"/>
+    <xsd:element ref="owl:ObjectMaxCardinality"/>
+    <xsd:element ref="owl:ObjectExactCardinality"/>
+    <xsd:element ref="owl:DataSomeValuesFrom"/>
+    <xsd:element ref="owl:DataAllValuesFrom"/>
+    <xsd:element ref="owl:DataHasValue"/>
+    <xsd:element ref="owl:DataMinCardinality"/>
+    <xsd:element ref="owl:DataMaxCardinality"/>
+    <xsd:element ref="owl:DataExactCardinality"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="ObjectIntersectionOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ClassExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectUnionOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ClassExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectComplementOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ClassExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectOneOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:Individual" minOccurs="1" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectSomeValuesFrom">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectAllValuesFrom">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectHasValue">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:Individual"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectHasSelf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectMinCardinality">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="cardinality" type="xsd:nonNegativeInteger" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectMaxCardinality">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="cardinality" type="xsd:nonNegativeInteger" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectExactCardinality">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="cardinality" type="xsd:nonNegativeInteger" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataSomeValuesFrom">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataPropertyExpression" minOccurs="1" maxOccurs="unbounded"/>
+      <xsd:group ref="owl:DataRange"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataAllValuesFrom">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataPropertyExpression" minOccurs="1" maxOccurs="unbounded"/>
+      <xsd:group ref="owl:DataRange"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataHasValue">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:element ref="owl:Literal"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataMinCardinality">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:group ref="owl:DataRange" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="cardinality" type="xsd:nonNegativeInteger" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataMaxCardinality">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:group ref="owl:DataRange" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="cardinality" type="xsd:nonNegativeInteger" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataExactCardinality">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:group ref="owl:DataRange" minOccurs="0" maxOccurs="1"/>
+    </xsd:sequence>
+    <xsd:attribute name="cardinality" type="xsd:nonNegativeInteger" use="required"/>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Axioms -->
+
+<xsd:group name="Axiom">
+  <xsd:choice>
+    <xsd:element ref="owl:Declaration"/>
+    <xsd:group ref="owl:ClassAxiom"/>
+    <xsd:group ref="owl:ObjectPropertyAxiom"/>
+    <xsd:group ref="owl:DataPropertyAxiom"/>
+    <xsd:element ref="owl:HasKey"/>
+    <xsd:group ref="owl:Assertion"/>
+    <xsd:group ref="owl:AnnotationAxiom"/>
+  </xsd:choice>
+</xsd:group>
+
+<!-- Class expression axioms -->
+
+<xsd:group name="ClassAxiom">
+  <xsd:choice>
+    <xsd:element ref="owl:SubClassOf"/>
+    <xsd:element ref="owl:EquivalentClasses"/>
+    <xsd:element ref="owl:DisjointClasses"/>
+    <xsd:element ref="owl:DisjointUnion"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="SubClassOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ClassExpression"/> <!-- This is the subexpression -->
+      <xsd:group ref="owl:ClassExpression"/> <!-- This is the superexpression -->
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="EquivalentClasses">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ClassExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DisjointClasses">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ClassExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DisjointUnion">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:element ref="owl:Class"/>
+      <xsd:group ref="owl:ClassExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Object property axioms -->
+
+<xsd:group name="ObjectPropertyAxiom">
+  <xsd:choice>
+    <xsd:element ref="owl:SubObjectPropertyOf"/>
+    <xsd:element ref="owl:EquivalentObjectProperties"/>
+    <xsd:element ref="owl:DisjointObjectProperties"/>
+    <xsd:element ref="owl:InverseObjectProperties"/>
+    <xsd:element ref="owl:ObjectPropertyDomain"/>
+    <xsd:element ref="owl:ObjectPropertyRange"/>
+    <xsd:element ref="owl:FunctionalObjectProperty"/>
+    <xsd:element ref="owl:InverseFunctionalObjectProperty"/>
+    <xsd:element ref="owl:ReflexiveObjectProperty"/>
+    <xsd:element ref="owl:IrreflexiveObjectProperty"/>
+    <xsd:element ref="owl:SymmetricObjectProperty"/>
+    <xsd:element ref="owl:AsymmetricObjectProperty"/>
+    <xsd:element ref="owl:TransitiveObjectProperty"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="SubObjectPropertyOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:choice> <!-- This is the subproperty expression or the property chain -->
+        <xsd:group ref="owl:ObjectPropertyExpression"/>
+        <xsd:element name="PropertyChain">
+          <xsd:complexType>
+            <xsd:sequence>
+              <xsd:group ref="owl:ObjectPropertyExpression" minOccurs="2" maxOccurs="unbounded"/>
+            </xsd:sequence>
+            <xsd:attributeGroup ref="xml:specialAttrs"/>
+          </xsd:complexType>
+        </xsd:element>
+      </xsd:choice>
+      <xsd:group ref="owl:ObjectPropertyExpression"/> <!-- This is the superproperty expression -->  
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="EquivalentObjectProperties">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DisjointObjectProperties">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectPropertyDomain">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectPropertyRange">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="InverseObjectProperties">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression" minOccurs="2" maxOccurs="2"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="FunctionalObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="InverseFunctionalObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ReflexiveObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="IrreflexiveObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="SymmetricObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="AsymmetricObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+ 
+<xsd:element name="TransitiveObjectProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Data property axioms -->
+
+<xsd:group name="DataPropertyAxiom">
+  <xsd:choice>
+    <xsd:element ref="owl:SubDataPropertyOf"/>
+    <xsd:element ref="owl:EquivalentDataProperties"/>
+    <xsd:element ref="owl:DisjointDataProperties"/>
+    <xsd:element ref="owl:DataPropertyDomain"/>
+    <xsd:element ref="owl:DataPropertyRange"/>
+    <xsd:element ref="owl:FunctionalDataProperty"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="SubDataPropertyOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression"/> <!-- This is the subproperty expression -->
+      <xsd:group ref="owl:DataPropertyExpression"/> <!-- This is the superproperty expression -->
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="EquivalentDataProperties">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DisjointDataProperties">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataPropertyDomain">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:group ref="owl:ClassExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataPropertyRange">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:group ref="owl:DataRange"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="FunctionalDataProperty">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Key axioms -->
+
+<xsd:element name="HasKey">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ClassExpression"/>
+      <xsd:choice minOccurs="1" maxOccurs="unbounded">
+        <xsd:group ref="owl:ObjectPropertyExpression"/>
+        <xsd:group ref="owl:DataPropertyExpression"/>
+      </xsd:choice>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Assertions -->
+
+<xsd:group name="Assertion">
+  <xsd:choice>
+    <xsd:element ref="owl:SameIndividual"/>
+    <xsd:element ref="owl:DifferentIndividuals"/>
+    <xsd:element ref="owl:ClassAssertion"/>
+    <xsd:element ref="owl:ObjectPropertyAssertion"/>
+    <xsd:element ref="owl:NegativeObjectPropertyAssertion"/>
+    <xsd:element ref="owl:DataPropertyAssertion"/>
+    <xsd:element ref="owl:NegativeDataPropertyAssertion"/>
+  </xsd:choice>
+</xsd:group> 
+
+<xsd:element name="SameIndividual">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:Individual" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DifferentIndividuals">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:Individual" minOccurs="2" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ClassAssertion">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ClassExpression"/>
+      <xsd:group ref="owl:Individual"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="ObjectPropertyAssertion">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:Individual"/> <!-- This is the source invididual  -->
+      <xsd:group ref="owl:Individual"/> <!-- This is the target individual -->
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="NegativeObjectPropertyAssertion">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:ObjectPropertyExpression"/>
+      <xsd:group ref="owl:Individual"/> <!-- This is the source invididual  -->
+      <xsd:group ref="owl:Individual"/> <!-- This is the target individual -->
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="DataPropertyAssertion">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:group ref="owl:Individual"/> <!-- This is the source invididual  -->
+      <xsd:element ref="owl:Literal"/> <!-- This is the target value -->
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="NegativeDataPropertyAssertion">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:group ref="owl:DataPropertyExpression"/>
+      <xsd:group ref="owl:Individual"/> <!-- This is the source invididual  -->
+      <xsd:element ref="owl:Literal"/> <!-- This is the target value -->
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<!-- Annotations  -->
+
+<xsd:element name="IRI">
+  <xsd:complexType>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:anyURI">
+        <xsd:attributeGroup ref="xml:specialAttrs"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:group name="AnnotationSubject">
+  <xsd:choice>
+    <xsd:element ref="owl:IRI"/>
+    <xsd:element ref="owl:AnonymousIndividual"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:group name="AnnotationValue">
+  <xsd:choice>
+    <xsd:element ref="owl:IRI"/>
+    <xsd:element ref="owl:AnonymousIndividual"/>
+    <xsd:element ref="owl:Literal"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="Annotation">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:annotationAnnotations"/>
+      <xsd:element ref="owl:AnnotationProperty"/>
+      <xsd:group ref="owl:AnnotationValue"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:group name="axiomAnnotations">
+  <xsd:sequence>
+    <xsd:element ref="owl:Annotation" minOccurs="0" maxOccurs="unbounded"/>
+  </xsd:sequence>
+</xsd:group>
+
+<xsd:group name="ontologyAnnotations">
+  <xsd:sequence>
+    <xsd:element ref="owl:Annotation" minOccurs="0" maxOccurs="unbounded"/>
+  </xsd:sequence>
+</xsd:group>
+
+<xsd:group name="annotationAnnotations">
+  <xsd:sequence>
+    <xsd:element ref="owl:Annotation" minOccurs="0" maxOccurs="unbounded"/>
+  </xsd:sequence>
+</xsd:group>
+
+<!-- Annotation axioms -->
+
+<xsd:group name="AnnotationAxiom">
+  <xsd:choice>
+    <xsd:element ref="owl:AnnotationAssertion"/>
+    <xsd:element ref="owl:SubAnnotationPropertyOf"/>
+    <xsd:element ref="owl:AnnotationPropertyDomain"/>
+    <xsd:element ref="owl:AnnotationPropertyRange"/>
+  </xsd:choice>
+</xsd:group>
+
+<xsd:element name="AnnotationAssertion">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:element ref="owl:AnnotationProperty"/>
+      <xsd:group ref="owl:AnnotationSubject"/>
+      <xsd:group ref="owl:AnnotationValue"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="SubAnnotationPropertyOf">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:element ref="owl:AnnotationProperty"/> <!-- This is the subproperty -->
+      <xsd:element ref="owl:AnnotationProperty"/> <!-- This is the superproperty -->
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="AnnotationPropertyDomain">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:element ref="owl:AnnotationProperty"/>
+      <xsd:element ref="owl:IRI"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+<xsd:element name="AnnotationPropertyRange">
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:group ref="owl:axiomAnnotations"/>
+      <xsd:element ref="owl:AnnotationProperty"/>
+      <xsd:element ref="owl:IRI"/>
+    </xsd:sequence>
+    <xsd:attributeGroup ref="xml:specialAttrs"/>
+  </xsd:complexType>
+</xsd:element>
+
+</xsd:schema>
+
+''')
+
+        rdf = StringIO('''<xsd:schema
+        xmlns:xsd="http://www.w3.org/1999/XMLSchema"
+        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+        targetNamespace="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+      
+        <xsd:element name="RDF">
+                <xsd:complexType  content="elementOnly" >
+                        <xsd:sequence  maxOccurs="*" >
+                                <xsd:choice>
+                                        <xsd:element ref="rdf:TypedNode"   /><!-- abstract !-->
+                                        <xsd:element ref="rdf:Bag" />
+                                        <xsd:element ref="rdf:Seq" />
+                                        <xsd:element ref="rdf:Alt" />
+                                </xsd:choice>
+                        </xsd:sequence>
+                </xsd:complexType>
+        </xsd:element>
+
+        <!-- RDF Typed nodes -->
+       <xsd:complexType   name="TypedNodeType" content="elementOnly" >
+                <xsd:sequence maxOccurs="*" >
+                        <xsd:element ref="rdf:PropertyElt"   /><!--abstract !-->
+                </xsd:sequence>
+                <xsd:attribute  name="id" minOccurs="0" type="ID"  />
+                <xsd:attribute  name="type" minOccurs="0" type="string" />
+                <xsd:attribute name="about" minOccurs="0" type="string" />
+                <xsd:attribute  name="aboutEach" minOccurs="0" type="string" />
+                <xsd:attribute   name="aboutEachPrefix" minOccurs="0" type="string" />
+                <xsd:attribute  name="badID" minOccurs="0" type="ID" />
+        </xsd:complexType>
+        <xsd:element name="TypedNode"  abstract="true"  type="rdf:TypedNodeType" />
+
+        <xsd:element name="Description"
+                type="rdf:TypedNodeType" equivClass="rdf:TypedNode" />
+
+
+        <!-- RDF Property Elements -->
+        <xsd:complexType  name="PropertyEltType" >
+                <xsd:any minOccurs="0" />
+                <xsd:attribute name="id"  minOccurs="0"  type="ID" />
+                <xsd:attribute  name="resource" minOccurs="0"  type="string" />
+                <xsd:attribute  name="value" minOccurs="0"  type="string" />
+                <xsd:attribute  name="badID" minOccurs="0" type="ID"  />
+                <xsd:attribute name="parseType"  minOccurs="0" >
+                        <xsd:simpleType base="NMTOKEN">
+                                 <xsd:enumeration value="Resource"/>
+                                 <xsd:enumeration value="Literal" />
+                       </xsd:simpleType>
+                </xsd:attribute>
+                <xsd:anyAttribute  />
+        </xsd:complexType>
+
+        <xsd:element name="PropertyElt"  abstract="true" type="rdf:PropertyEltType" />
+
+        <xsd:element   name="subject"   equivClass="rdf:PropertyElt"  />
+        <xsd:element name="predicate"   equivClass="rdf:PropertyElt" />
+        <xsd:element name="object"  equivClass="rdf:PropertyElt" />
+        <xsd:element   name="type"  equivClass="rdf:PropertyElt" />
+
+        <xsd:element name="value">
+                <xsd:complexType>
+                        <xsd:any />
+                        <xsd:anyAttribute />
+                </xsd:complexType>
+        </xsd:element>
+
+
+        <!-- RDF Containers -->
+        <xsd:complexType name="Container" abstract="true" content="elementOnly" >
+                <xsd:sequence maxOccurs="*">
+                        <xsd:element name="li">
+                                <xsd:complexType>
+                                        <xsd:any/>
+                                        <xsd:attribute name="id"  minOccurs="0" type="ID" />
+                                        <xsd:attribute name="parseType" minOccurs="0" >
+                                                <xsd:simpleType base="NMTOKEN">
+                                                     <xsd:enumeration value="Resource"/>
+                                                     <xsd:enumeration value="Literal" />
+                                                </xsd:simpleType>
+                                        </xsd:attribute>
+                                        <xsd:anyAttribute />
+                                </xsd:complexType>
+                        </xsd:element>
+                </xsd:sequence>
+                <xsd:attribute name="id" type="ID" />
+                <xsd:anyAttribute />
+        </xsd:complexType>
+
+        <xsd:element name="Alt" type="rdf:Container" />
+        <xsd:element name="Bag" type="rdf:Container" />
+        <xsd:element name="Seq" type="rdf:Container" />
+
+</xsd:schema>
+
+ ''')
+        
+        
+        xmlschema_rdf = etree.parse(rdf)
+        xmlschema_owl = etree.parse(owl)
+        
+        owlschema = etree.XMLSchema(xmlschema_owl)
+        valid = StringIO('''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE rdf:RDF [
+        <!ENTITY owl "http://www.w3.org/2002/07/owl#" >
+        <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
+        <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" >
+        <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
+        <!ENTITY inst_jplorg2 "http://logilab.org/owl/ontologies/inst_jplorg2#" >
+        
+        ]>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns="http://logilab.org/owl/ontologies/inst_jplorg2#" xmlns:inst_jplorg2="http://logilab.org/owl/ontologies/inst_jplorg2#" xml:base="http://logilab.org/owl/ontologies/inst_jplorg2#">
+
+    <owl:Ontology rdf:about="">
+        <rdfs:comment>
+        inst_jplorg2 Cubicweb OWL Ontology                           
+                                        
+        </rdfs:comment>
+        <!-- classes definition --><owl:Class rdf:ID="Blog"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#interested_in"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#entry_of"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#title"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="BlogEntry"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#entry_of"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#filed_under"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#interested_in"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#comments"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#title"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#content_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#content"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="Card"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#filed_under"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#test_case_for"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#test_case_of"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#documented_by"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#instance_of"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#comments"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#title"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#synopsis"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#content_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#content"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#wikiid"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="Email"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#sent_on"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#sender"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#recipients"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#cc"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#parts"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#attachment"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#reply_to"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#cites"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_thread"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#generated_by"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#generated_by"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#comments"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#reply_to"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#cites"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#subject"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#messageid"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#headers"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="EmailThread"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#forked_from"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_thread"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#forked_from"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#title"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="ExtProject"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#filed_under"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#recommends"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#uses"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#name"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#url"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="File"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#filed_under"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#documented_by"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#comments"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#attachment"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#attachment"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#data"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#data_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#data_encoding"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#name"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="Image"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#attachment"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#screenshot"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#data"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#data_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#data_encoding"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#name"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="License"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#license_of"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#name"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#shortdesc"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#longdesc_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#longdesc"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#url"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="Link"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#filed_under"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#comments"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#title"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#url"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#embed"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="MailingList"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#use_email"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#mailinglist_of"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#sent_on"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#name"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#mlid"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#archive"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#homepage"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="Project"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#uses"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#uses"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#recommends"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#recommends"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#documented_by"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#documented_by"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#screenshot"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_state"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#filed_under"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#recommends"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#concerns"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#test_case_of"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#mailinglist_of"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#uses"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#interested_in"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#license_of"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#version_of"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#wf_info_for"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#name"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#summary"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#url"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#vcsurl"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#reporturl"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#downloadurl"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#debian_source_package"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="TestInstance"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#instance_of"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#for_version"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#generate_bug"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_state"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#comments"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#wf_info_for"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#name"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="Ticket"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#see_also"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#concerns"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#appeared_in"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#done_in"/>
+                                <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_state"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#attachment"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#attachment"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#identical_to"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#depends_on"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#depends_on"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#comments"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#generate_bug"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#wf_info_for"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#test_case_for"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#title"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#type"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#priority"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#load"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#load_left"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#debian_bug_number"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><owl:Class rdf:ID="Version"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
+                                <!-- relations --><rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_basket"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#version_of"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#todo_by"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#in_state"/>
+                                <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minCardinality>
+                        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:maxCardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#conflicts"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#depends_on"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#require_permission"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#done_in"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#tags"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#depends_on"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#for_version"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#wf_info_for"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <rdfs:subClassOf>
+                              <owl:Restriction>
+                              <owl:onProperty rdf:resource="#appeared_in"/>
+                                <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">n</owl:cardinality>
+                              </owl:Restriction>
+                           </rdfs:subClassOf>
+                                <!-- attributes --><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#num"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description_format"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#description"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#starting_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#prevision_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#publication_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#creation_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf><rdfs:subClassOf>
+                              <owl:Restriction>
+                                  <owl:onProperty rdf:resource="#modification_date"/>
+                                  <owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
+                              </owl:Restriction>
+                        </rdfs:subClassOf></owl:Class><!-- property definition --><!-- object property --><owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Blog"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="interested_in">
+                              <rdfs:domain rdf:resource="#Blog"/>
+                              <rdfs:range rdf:resource="#EUser"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="entry_of">
+                              <rdfs:domain rdf:resource="#Blog"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="entry_of">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Blog"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="filed_under">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Folder"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="interested_in">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#EUser"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="comments">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#BlogEntry"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="filed_under">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Folder"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="test_case_for">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="test_case_of">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="documented_by">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="instance_of">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#TestInstance"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="comments">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#Card"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="sent_on">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#MailingList"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="sender">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#EmailAddress"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="recipients">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#EmailAddress"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="cc">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#EmailAddress"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="parts">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#EmailPart"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="attachment">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="reply_to">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="cites">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_thread">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#EmailThread"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="generated_by">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#TrInfo"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="generated_by">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="comments">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="reply_to">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="cites">
+                              <rdfs:domain rdf:resource="#Email"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#EmailThread"/>
+                              <rdfs:range rdf:resource="#EmailThread"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="forked_from">
+                              <rdfs:domain rdf:resource="#EmailThread"/>
+                              <rdfs:range rdf:resource="#EmailThread"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#EmailThread"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_thread">
+                              <rdfs:domain rdf:resource="#EmailThread"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="forked_from">
+                              <rdfs:domain rdf:resource="#EmailThread"/>
+                              <rdfs:range rdf:resource="#EmailThread"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="filed_under">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Folder"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="recommends">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="uses">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#ExtProject"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="filed_under">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Folder"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="documented_by">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="comments">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="attachment">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="attachment">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#File"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="attachment">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="screenshot">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#Image"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#License"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="license_of">
+                              <rdfs:domain rdf:resource="#License"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#License"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="filed_under">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Folder"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="comments">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#Link"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#MailingList"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="use_email">
+                              <rdfs:domain rdf:resource="#MailingList"/>
+                              <rdfs:range rdf:resource="#EmailAddress"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="mailinglist_of">
+                              <rdfs:domain rdf:resource="#MailingList"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="sent_on">
+                              <rdfs:domain rdf:resource="#MailingList"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#MailingList"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="uses">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="uses">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="recommends">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="recommends">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="documented_by">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="documented_by">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="screenshot">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_state">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#State"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="filed_under">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Folder"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="recommends">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="concerns">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="test_case_of">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="mailinglist_of">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#MailingList"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="uses">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="interested_in">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#EUser"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="license_of">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#License"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="version_of">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#Version"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="wf_info_for">
+                              <rdfs:domain rdf:resource="#Project"/>
+                              <rdfs:range rdf:resource="#TrInfo"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="instance_of">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="for_version">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#Version"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="generate_bug">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_state">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#State"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="comments">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="wf_info_for">
+                              <rdfs:domain rdf:resource="#TestInstance"/>
+                              <rdfs:range rdf:resource="#TrInfo"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#ExtProject"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#BlogEntry"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Link"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Email"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="see_also">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="concerns">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="appeared_in">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Version"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="done_in">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Version"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_state">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#State"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="attachment">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Image"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="attachment">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#File"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="identical_to">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="depends_on">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="depends_on">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="comments">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Comment"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="generate_bug">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#TestInstance"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="wf_info_for">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#TrInfo"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="test_case_for">
+                              <rdfs:domain rdf:resource="#Ticket"/>
+                              <rdfs:range rdf:resource="#Card"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_basket">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Basket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="version_of">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Project"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="todo_by">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#EUser"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="in_state">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#State"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="conflicts">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Version"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="depends_on">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Version"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="require_permission">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#EPermission"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="done_in">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="tags">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Tag"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="depends_on">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Version"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="for_version">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#TestInstance"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="wf_info_for">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#TrInfo"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <owl:ObjectProperty rdf:ID="appeared_in">
+                              <rdfs:domain rdf:resource="#Version"/>
+                              <rdfs:range rdf:resource="#Ticket"/>
+                           </owl:ObjectProperty>                   
+                             
+                                <!-- datatype property --><owl:DatatypeProperty rdf:ID="title">
+                          <rdfs:domain rdf:resource="#Blog"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#Blog"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Blog"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Blog"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="title">
+                          <rdfs:domain rdf:resource="#BlogEntry"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="content_format">
+                          <rdfs:domain rdf:resource="#BlogEntry"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="content">
+                          <rdfs:domain rdf:resource="#BlogEntry"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#BlogEntry"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#BlogEntry"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="title">
+                          <rdfs:domain rdf:resource="#Card"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="synopsis">
+                          <rdfs:domain rdf:resource="#Card"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="content_format">
+                          <rdfs:domain rdf:resource="#Card"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="content">
+                          <rdfs:domain rdf:resource="#Card"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="wikiid">
+                          <rdfs:domain rdf:resource="#Card"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Card"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Card"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="subject">
+                          <rdfs:domain rdf:resource="#Email"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="date">
+                          <rdfs:domain rdf:resource="#Email"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="messageid">
+                          <rdfs:domain rdf:resource="#Email"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="headers">
+                          <rdfs:domain rdf:resource="#Email"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Email"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Email"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="title">
+                          <rdfs:domain rdf:resource="#EmailThread"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#EmailThread"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#EmailThread"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="name">
+                          <rdfs:domain rdf:resource="#ExtProject"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#ExtProject"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#ExtProject"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="url">
+                          <rdfs:domain rdf:resource="#ExtProject"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#ExtProject"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#ExtProject"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="data">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:byte"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="data_format">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="data_encoding">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="name">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#File"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="data">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:byte"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="data_format">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="data_encoding">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="name">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Image"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="name">
+                          <rdfs:domain rdf:resource="#License"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="shortdesc">
+                          <rdfs:domain rdf:resource="#License"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="longdesc_format">
+                          <rdfs:domain rdf:resource="#License"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="longdesc">
+                          <rdfs:domain rdf:resource="#License"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="url">
+                          <rdfs:domain rdf:resource="#License"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#License"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#License"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="title">
+                          <rdfs:domain rdf:resource="#Link"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="url">
+                          <rdfs:domain rdf:resource="#Link"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="embed">
+                          <rdfs:domain rdf:resource="#Link"/>
+                          <rdfs:range rdf:resource="xsd:boolean"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#Link"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#Link"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Link"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Link"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="name">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="mlid">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="archive">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="homepage">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#MailingList"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="name">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="summary">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="url">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="vcsurl">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="reporturl">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="downloadurl">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="debian_source_package">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Project"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="name">
+                          <rdfs:domain rdf:resource="#TestInstance"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#TestInstance"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#TestInstance"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="title">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="type">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="priority">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="load">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:float"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="load_left">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:float"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="debian_bug_number">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:int"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Ticket"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="num">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description_format">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="description">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:string"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="starting_date">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:date"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="prevision_date">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:date"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="publication_date">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:date"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="creation_date">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty><owl:DatatypeProperty rdf:ID="modification_date">
+                          <rdfs:domain rdf:resource="#Version"/>
+                          <rdfs:range rdf:resource="xsd:dateTime"/>
+                       </owl:DatatypeProperty> </owl:Ontology></rdf:RDF> ''')
+        doc = etree.parse(valid)
+        owlschema.validate(doc)
+
+if __name__ == '__main__':
+    unittest_main()
+
--- a/web/test/unittest_views_baseforms.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/test/unittest_views_baseforms.py	Wed Apr 15 17:36:09 2009 +0200
@@ -18,7 +18,7 @@
         return DateTime(0000, 1, 1)
     widgets.today = widgets.now = _today
 
-def teardown_module(options):
+def teardown_module(options, results):
     widgets.today = orig_today
     widgets.now = orig_now
 
--- a/web/test/unittest_viewselector.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/test/unittest_viewselector.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,6 +1,5 @@
 # -*- coding: iso-8859-1 -*-
 """XXX rename, split, reorganize this
-
 """
 
 import os.path as osp
@@ -10,16 +9,17 @@
 
 
 from cubicweb import CW_SOFTWARE_ROOT as BASE, Binary
-from cubicweb.common.selectors import in_group_selector
+from cubicweb.common.selectors import match_user_group
 
 from cubicweb.web._exceptions import NoSelectableObject
 from cubicweb.web.action import Action
 from cubicweb.web.views import (baseviews, tableview, baseforms, calendar, 
-                             management, embedding, actions, startup, 
-                             euser, schemaentities, xbel, vcard, 
-                             idownloadable, wdoc, debug)
+                                management, embedding, actions, startup, 
+                                euser, schemaentities, xbel, vcard,
+                                treeview, idownloadable, wdoc, debug)
 from cubicweb.entities.lib import Card
 from cubicweb.interfaces import IMileStone
+from cubicweb.web.views import owl
 
 USERACTIONS = [('myprefs', actions.UserPreferencesAction),
                ('myinfos', actions.UserInfoAction),
@@ -75,6 +75,7 @@
                               ('index', startup.IndexView),
                               ('info', management.ProcessInformationView),
                               ('manage', startup.ManageView),
+                              ('owl', owl.OWLView),
                               ('schema', startup.SchemaView),
                               ('systemepropertiesform', management.SystemEpropertiesForm)])
         # no entity but etype
@@ -94,14 +95,18 @@
                              [('csvexport', baseviews.CSVRsetView),
                               ('ecsvexport', baseviews.CSVEntityView),
                               ('editable-table', tableview.EditableTableView),
+                              ('filetree', treeview.FileTreeView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', baseviews.PrimaryView),
+                              ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
                               ('secondary', baseviews.SecondaryView),
                               ('security', management.SecurityManagementView),
                               ('table', tableview.TableView),
                               ('text', baseviews.TextView),
+                              ('treeview', treeview.TreeView),
                               ('xbel', xbel.XbelView),
                               ('xml', baseviews.XmlView),
                               ])
@@ -111,14 +116,18 @@
                              [('csvexport', baseviews.CSVRsetView),
                               ('ecsvexport', baseviews.CSVEntityView),
                               ('editable-table', tableview.EditableTableView),
+                              ('filetree', treeview.FileTreeView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', baseviews.PrimaryView),
+                              ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
                               ('secondary', baseviews.SecondaryView),
                               ('security', management.SecurityManagementView),
                               ('table', tableview.TableView),
                               ('text', baseviews.TextView),
+                              ('treeview', treeview.TreeView),
                               ('xbel', xbel.XbelView),
                               ('xml', baseviews.XmlView),
                               ])
@@ -128,14 +137,18 @@
                              [('csvexport', baseviews.CSVRsetView),
                               ('ecsvexport', baseviews.CSVEntityView),
                               ('editable-table', tableview.EditableTableView),
+                              ('filetree', treeview.FileTreeView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', baseviews.PrimaryView),
+                              ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
                               ('secondary', baseviews.SecondaryView),
                               ('security', management.SecurityManagementView),
                               ('table', tableview.TableView),
                               ('text', baseviews.TextView),
+                              ('treeview', treeview.TreeView),
                               ('xbel', xbel.XbelView),
                               ('xml', baseviews.XmlView),
                               ])
@@ -144,6 +157,7 @@
         self.assertListEqual(self.pviews(req, rset),
                              [('csvexport', baseviews.CSVRsetView),
                               ('editable-table', tableview.EditableTableView),
+                              ('rsetxml', baseviews.XMLRsetView),
                               ('table', tableview.TableView),
                               ])
         # list of euser entities
@@ -152,14 +166,19 @@
                              [('csvexport', baseviews.CSVRsetView),
                               ('ecsvexport', baseviews.CSVEntityView),
                               ('editable-table', tableview.EditableTableView),
+                              ('filetree', treeview.FileTreeView),
+                              ('foaf', euser.FoafView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', euser.EUserPrimaryView),
+                              ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
                               ('secondary', baseviews.SecondaryView),
                               ('security', management.SecurityManagementView),
                               ('table', tableview.TableView),
                               ('text', baseviews.TextView),
+                              ('treeview', treeview.TreeView),
                               ('vcard', vcard.VCardEUserView),
                               ('xbel', xbel.XbelView),
                               ('xml', baseviews.XmlView),
@@ -387,12 +406,12 @@
         
 
 
-    def test_owners_in_group_selector(self):
-        """tests usage of 'owners' group with in_group_selector"""
+    def test_owners_match_user_group(self):
+        """tests usage of 'owners' group with match_user_group"""
         class SomeAction(Action):
             id = 'yo'
             category = 'foo'
-            __selectors__ = (in_group_selector,)
+            __selectors__ = (match_user_group,)
             require_groups = ('owners', )            
         self.vreg.register_vobject_class(SomeAction)
         self.failUnless(SomeAction in self.vreg['actions']['yo'], self.vreg['actions'])
--- a/web/views/actions.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/actions.py	Wed Apr 15 17:36:09 2009 +0200
@@ -6,11 +6,12 @@
 """
 __docformat__ = "restructuredtext en"
 
-from cubicweb import UnknownEid
-from cubicweb.common.selectors import *
+from cubicweb.common.selectors import (searchstate_accept, match_user_group, yes,
+                                       one_line_rset, two_lines_rset, one_etype_rset,
+                                       authenticated_user, none_rset,
+                                       match_search_state, chainfirst, chainall)
 
-from cubicweb.web.action import (Action, EntityAction,  LinkToEntityAction,
-                              LinkToEntityAction2)
+from cubicweb.web.action import Action, EntityAction,  LinkToEntityAction
 from cubicweb.web.views import linksearch_select_url, linksearch_match
 from cubicweb.web.views.baseviews import vid_from_rset
 
@@ -55,7 +56,7 @@
 
 class ViewAction(Action):
     category = 'mainactions'    
-    __selectors__ = (in_group_selector, searchstate_accept)
+    __selectors__ = (match_user_group, searchstate_accept)
     require_groups = ('users', 'managers')
     order = 0
     
@@ -81,7 +82,6 @@
 class ModifyAction(EntityAction):
     category = 'mainactions'
     __selectors__ = (one_line_rset, searchstate_accept)
-    #__selectors__ = searchstate_accept,
     schema_action = 'update'
     order = 10
     
@@ -110,7 +110,7 @@
 
 class MultipleEditAction(EntityAction):
     category = 'mainactions'
-    __selectors__ = (two_lines_rset, oneetyperset_selector,
+    __selectors__ = (two_lines_rset, one_etype_rset,
                      searchstate_accept)
     schema_action = 'update'
     order = 10
@@ -198,7 +198,7 @@
         return 0
     __selectors__ = (match_search_state,
                      chainfirst(etype_rset_selector,
-                                chainall(two_lines_rset, oneetyperset_selector,
+                                chainall(two_lines_rset, one_etype_rset,
                                          has_add_perm_selector)))
 
     @property
@@ -219,7 +219,7 @@
 
 class UserPreferencesAction(Action):
     category = 'useractions'
-    __selectors__ = not_anonymous_selector,
+    __selectors__ = authenticated_user,
     order = 10
     
     id = 'myprefs'
@@ -231,7 +231,7 @@
 
 class UserInfoAction(Action):
     category = 'useractions'
-    __selectors__ = not_anonymous_selector,
+    __selectors__ = authenticated_user,
     order = 20
     
     id = 'myinfos'
@@ -243,7 +243,7 @@
 
 class LogoutAction(Action):
     category = 'useractions'
-    __selectors__ = not_anonymous_selector,
+    __selectors__ = authenticated_user,
     order = 30
     
     id = 'logout'
@@ -258,7 +258,7 @@
 class ManagersAction(Action):
     category = 'siteactions'
     __abstract__ = True
-    __selectors__ = in_group_selector,
+    __selectors__ = match_user_group,
     require_groups = ('managers',)
 
     def url(self):
@@ -301,7 +301,7 @@
         return self.rset.get_entity(self.row or 0, self.col or 0).actual_url()
 
 class UserPreferencesEntityAction(EntityAction):
-    __selectors__ = EntityAction.__selectors__ + (one_line_rset, in_group_selector,)
+    __selectors__ = EntityAction.__selectors__ + (one_line_rset, match_user_group,)
     require_groups = ('owners', 'managers')
     category = 'mainactions'
     accepts = ('EUser',)
@@ -313,3 +313,19 @@
         login = self.rset.get_entity(self.row or 0, self.col or 0).login
         return self.build_url('euser/%s'%login, vid='epropertiesform')
 
+# schema view action
+def schema_view(cls, req, rset, row=None, col=None, view=None,
+                **kwargs):
+    if view is None or not view.id == 'schema':
+        return 0
+    return 1
+
+class DownloadOWLSchemaAction(Action):
+    category = 'mainactions'
+    id = 'download_as_owl'
+    title = _('download schema as owl')
+    __selectors__ = none_rset, schema_view
+   
+    def url(self):
+        return self.build_url('view', vid='owl')
+
--- a/web/views/ajaxedit.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/ajaxedit.py	Wed Apr 15 17:36:09 2009 +0200
@@ -6,8 +6,8 @@
 """
 __docformat__ = "restructuredtext en"
 
-from cubicweb.common.selectors import (chainfirst, req_form_params_selector,
-                                    kwargs_selector)
+from cubicweb.common.selectors import (chainfirst, match_form_params,
+                                    match_kwargs)
 from cubicweb.web.box import EditRelationBoxTemplate
 
 class AddRelationView(EditRelationBoxTemplate):
@@ -18,7 +18,7 @@
     class attributes.
     """
     __registry__ = 'views'
-    __selectors__ = (chainfirst(req_form_params_selector, kwargs_selector),)
+    __selectors__ = (chainfirst(match_form_params, match_kwargs),)
     property_defs = {} # don't want to inherit this from Box
     id = 'xaddrelation'
     expected_kwargs = form_params = ('rtype', 'target')
--- a/web/views/basecomponents.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/basecomponents.py	Wed Apr 15 17:36:09 2009 +0200
@@ -14,10 +14,10 @@
 
 from cubicweb import Unauthorized
 from cubicweb.common.uilib import html_escape, toggle_action
-from cubicweb.common.selectors import yes, nfentity_selector, one_line_rset
+from cubicweb.common.selectors import yes, non_final_entity, one_line_rset
 from cubicweb.schema import display_name
-from cubicweb.common.selectors import (chainfirst, multitype_selector,
-                                    req_form_params_selector)
+from cubicweb.common.selectors import (chainfirst, two_etypes_rset,
+                                    match_form_params)
 
 from cubicweb.web.htmlwidgets import MenuWidget, PopupBoxMenu, BoxSeparator, BoxLink
 from cubicweb.web.component import (VComponent, SingletonVComponent, EntityVComponent, 
@@ -44,11 +44,11 @@
           <form action="%s">
 <fieldset>
 <input type="text" id="rql" name="rql" value="%s"  title="%s" tabindex="%s" accesskey="q" class="searchField" />
-<input type="submit" value="%s" class="searchButton" tabindex="%s" />
+<input type="submit" value="" class="rqlsubmit" tabindex="%s" />
 </fieldset>
 ''' % (not self.propval('visible') and 'hidden' or '', 
        self.build_url('view'), html_escape(rql), req._('full text or RQL query'), req.next_tabindex(),
-       req._('search'), req.next_tabindex()))
+        req.next_tabindex()))
         if self.req.search_state[0] != 'normal':
             self.w(u'<input type="hidden" name="__mode" value="%s"/>'
                    % ':'.join(req.search_state[1]))
@@ -138,9 +138,9 @@
     target = 'subject'
     title = _('Workflow history')
 
-    def call(self, view=None):
+    def cell_call(self, row, col, view=None):
         _ = self.req._
-        eid = self.rset[0][0]
+        eid = self.rset[row][col]
         sel = 'Any FS,TS,WF,D'
         rql = ' ORDERBY D DESC WHERE WF wf_info_for X,'\
               'WF from_state FS, WF to_state TS, WF comment C,'\
@@ -191,7 +191,7 @@
     to be able to filter accordingly.
     """
     id = 'etypenavigation'
-    __select__ = classmethod(chainfirst(multitype_selector, req_form_params_selector))
+    __select__ = classmethod(chainfirst(two_etypes_rset, match_form_params))
     form_params = ('__restrtype', '__restrtypes', '__restrrql')
     visible = False # disabled by default
     
@@ -238,14 +238,14 @@
 
 class RSSFeedURL(VComponent):
     id = 'rss_feed_url'
-    __selectors__ = (nfentity_selector,)
+    __selectors__ = (non_final_entity,)
     
     def feed_url(self):
         return self.build_url(rql=self.limited_rql(), vid='rss')
 
 class RSSEntityFeedURL(VComponent):
     id = 'rss_feed_url'
-    __selectors__ = (nfentity_selector, one_line_rset)
+    __selectors__ = (non_final_entity, one_line_rset)
     
     def feed_url(self):
         return self.entity(0, 0).rss_feed_url()
--- a/web/views/basecontrollers.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/basecontrollers.py	Wed Apr 15 17:36:09 2009 +0200
@@ -60,7 +60,6 @@
     
     def publish(self, rset=None):
         """publish a request, returning an encoded string"""
-        self.req.update_search_state()
         template = self.req.property_value('ui.main-template')
         if template not in self.vreg.registry('templates') :
             template = self.template
@@ -235,7 +234,7 @@
                 stream.write(u'<div id="pageContent">')
                 vtitle = self.req.form.get('vtitle')
                 if vtitle:
-                    w(u'<h1 class="vtitle">%s</h1>\n' % vtitle)
+                    stream.write(u'<h1 class="vtitle">%s</h1>\n' % vtitle)
             view.pagination(req, rset, view.w, not view.need_navigation)
             if divid == 'pageContent':
                 stream.write(u'<div id="contentmain">')
@@ -453,7 +452,14 @@
         # link the new entity to the main entity
         rql = 'SET F %(rel)s T WHERE F eid %(eid_to)s, T eid %(eid_from)s' % {'rel' : rel, 'eid_to' : eid_to, 'eid_from' : eid_from}
         return eid_from
-    
+
+    def js_set_cookie(self, cookiename, cookievalue):
+        # XXX we should consider jQuery.Cookie
+        cookiename, cookievalue = str(cookiename), str(cookievalue)
+        cookies = self.req.get_cookie()
+        cookies[cookiename] = cookievalue
+        self.req.set_cookie(cookies, cookiename)
+
 class SendMailController(Controller):
     id = 'sendmail'
     require_groups = ('managers', 'users')
--- a/web/views/baseforms.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/baseforms.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 or a list of entities of the same type
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -17,9 +17,9 @@
 from cubicweb.interfaces import IWorkflowable
 from cubicweb.common.utils import make_uid
 from cubicweb.common.uilib import cut
-from cubicweb.common.selectors import (etype_form_selector, kwargs_selector,
-                                    one_line_rset, interface_selector,
-                                    req_form_params_selector, accept_selector)
+from cubicweb.common.selectors import (accept_etype, match_kwargs,
+                                    one_line_rset, implement_interface,
+                                    match_form_params, accept)
 from cubicweb.common.view import EntityView
 from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param
 from cubicweb.web.controller import NAV_FORM_PARAMETERS
@@ -33,10 +33,14 @@
     title = _('delete')
     domid = 'deleteconf'
     onsubmit = None
+    # don't use navigation, all entities asked to be deleted should be displayed
+    # else we will only delete the displayed page
+    need_navigation = False
     
     def call(self):
         """ask for confirmation before real deletion"""
         _ = self.req._
+        self.req.add_css('cubicweb.form.css')
         self.req.add_js('cubicweb.edition.js')
         self.w(u'<script type="text/javascript">updateMessage(\'%s\');</script>\n' % _('this action is not reversible!'))
         # XXX above message should have style of a warning
@@ -87,7 +91,7 @@
     id = 'statuschange'
     title = _('status change')
 
-    __selectors__ = (interface_selector, req_form_params_selector)
+    __selectors__ = (implement_interface, match_form_params)
     accepts_interfaces = (IWorkflowable,)
     form_params = ('treid',)
 
@@ -98,6 +102,7 @@
         transition = self.req.eid_rset(self.req.form['treid']).get_entity(0, 0)
         dest = transition.destination()
         self.req.add_js('cubicweb.edition.js')
+        self.req.add_css('cubicweb.form.css')
         _ = self.req._
         self.w(self.error_message())
         self.w(u'<h4>%s %s</h4>\n' % (_(transition.name), entity.view('oneline')))
@@ -150,7 +155,7 @@
 
 class ClickAndEditForm(EntityForm):
     id = 'reledit'
-    __selectors__ = (kwargs_selector, )
+    __selectors__ = (match_kwargs, )
     expected_kwargs = ('rtype',)
 
     #FIXME editableField class could be toggleable from userprefs
@@ -216,7 +221,7 @@
     dynamic default values such as the 'tomorrow' date or the user's login
     being connected
     """    
-    __selectors__ = (one_line_rset, accept_selector)
+    __selectors__ = (one_line_rset, accept)
 
     id = 'edition'
     title = _('edition')
@@ -392,17 +397,20 @@
                 if rschema != 'eid']
     
     def relations_form(self, entity, kwargs):
+        srels_by_cat = entity.srelations_by_category(('generic', 'metadata'), 'add')
+        if not srels_by_cat:
+            return u''
         req = self.req
         _ = self.req._
         label = u'%s :' % _('This %s' % entity.e_schema).capitalize()
         eid = entity.eid
         html = []
-        pendings = list(self.restore_pending_inserts(entity))
         w = html.append
         w(u'<fieldset class="subentity">')
         w(u'<legend class="iformTitle">%s</legend>' % label)
         w(u'<table id="relatedEntities">')
         for row in self.relations_table(entity):
+            # already linked entities
             if row[2]:
                 w(u'<tr><th class="labelCol">%s</th>' % row[0].display_name(req, row[1]))
                 w(u'<td>')
@@ -415,10 +423,12 @@
                 w(u'</ul>')
                 w(u'</td>')
                 w(u'</tr>')
+        pendings = list(self.restore_pending_inserts(entity))
         if not pendings:
             w(u'<tr><th>&nbsp;</th><td>&nbsp;</td></tr>')
         else:
             for row in pendings:
+                # soon to be linked to entities
                 w(u'<tr id="tr%s">' % row[1])
                 w(u'<th>%s</th>' % row[3])
                 w(u'<td>')
@@ -434,7 +444,8 @@
         w(u'<select id="relationSelector_%s" tabindex="%s" onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'
           % (eid, req.next_tabindex(), html_escape(dumps(eid))))
         w(u'<option value="">%s</option>' % _('select a relation'))
-        for i18nrtype, rschema, target in entity.srelations_by_category(('generic', 'metadata'), 'add'):
+        for i18nrtype, rschema, target in srels_by_cat:
+            # more entities to link to
             w(u'<option value="%s_%s">%s</option>' % (rschema, target, i18nrtype))
         w(u'</select>')
         w(u'</th>')
@@ -510,14 +521,13 @@
     def on_submit(self, entity):
         return u'return freezeFormButtons(\'%s\')' % (self.domid)
 
-
     def submited_message(self):
         return self.req._('element edited')
 
 
     
 class CreationForm(EditionForm):
-    __selectors__ = (etype_form_selector, )
+    __selectors__ = (accept_etype, )
     id = 'creation'
     title = _('creation')
     
@@ -630,7 +640,7 @@
 
 class InlineEntityCreationForm(InlineFormMixIn, CreationForm):
     id = 'inline-creation'
-    __selectors__ = (kwargs_selector, etype_form_selector)
+    __selectors__ = (match_kwargs, accept_etype)
     expected_kwargs = ('ptype', 'peid', 'rtype')
     
     EDITION_BODY = u'''\
@@ -669,7 +679,7 @@
 
 class InlineEntityEditionForm(InlineFormMixIn, EditionForm):
     id = 'inline-edition'
-    __selectors__ = (accept_selector, kwargs_selector)
+    __selectors__ = (accept, match_kwargs)
     expected_kwargs = ('ptype', 'peid', 'rtype')
     
     EDITION_BODY = u'''\
@@ -872,7 +882,7 @@
 
 class UnrelatedDivs(EntityView):
     id = 'unrelateddivs'
-    __selectors__ = (req_form_params_selector,)
+    __selectors__ = (match_form_params,)
     form_params = ('relation',)
 
     @property
--- a/web/views/basetemplates.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/basetemplates.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,16 +2,18 @@
 """default templates for CubicWeb web client
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+: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 import NoSelectableObject, ObjectNotFound
 from cubicweb.common.view import Template, MainTemplate,  NOINDEX, NOFOLLOW
 from cubicweb.common.utils import make_uid
+from cubicweb.common.utils import UStringIO
 
 from cubicweb.web.views.baseviews import vid_from_rset
 
@@ -56,8 +58,9 @@
     title = 'logged out'
 
     def content(self, w):
+        # FIXME Deprecated code ?
         msg = self.req._('you have been logged out')
-        w(u'<h1 class="noborder">%s</h1>\n' % msg)
+        w(u'<h2>%s</h2>\n' % msg)
         if self.config['anonymous-user']:
             indexurl = self.build_url('view', vid='index', __message=msg)
             w(u'<p><a href="%s">%s</a><p>' % (
@@ -162,7 +165,10 @@
                                                  self.req, self.rset)
         if etypefilter and etypefilter.propval('visible'):
             etypefilter.dispatch(w=self.w)
-        self.pagination(self.req, self.rset, self.w, not (view and view.need_navigation))
+        self.nav_html = UStringIO()
+        self.pagination(self.req, self.rset, self.nav_html.write,
+                        not (view and view.need_navigation))
+        self.w(_(self.nav_html.getvalue()))
         self.w(u'<div id="contentmain">\n')
     
     def template_html_header(self, content_type, page_title, additional_headers=()):
@@ -194,10 +200,11 @@
         w(u'<div id="pageContent">\n')
         vtitle = self.req.form.get('vtitle')
         if vtitle:
-            w(u'<h1 class="vtitle">%s</h1>\n' % vtitle)
+            w(u'<h1 class="vtitle">%s</h1>\n' % html_escape(vtitle))
             
     def template_footer(self, view=None):
         self.w(u'</div>\n') # close id=contentmain
+        self.w(_(self.nav_html.getvalue()))
         self.w(u'</div>\n') # closes id=pageContent
         self.content_footer(view)
         self.w(u'</td>\n')
@@ -288,7 +295,7 @@
         w(u'<div id="pageContent">\n')
         vtitle = self.req.form.get('vtitle')
         if vtitle:
-            w(u'<h1 class="vtitle">%s</h1>' % (vtitle))
+            w(u'<h1 class="vtitle">%s</h1>' % html_escape(vtitle))
             
     def topleft_header(self):
         self.w(u'<table id="header"><tr>\n')
@@ -418,7 +425,7 @@
                                             req._(ChangeLogView.title).lower()))
         self.w(u'<a href="%s">%s</a> | ' % (req.build_url('doc/about'),
                                             req._('about this site')))
-        self.w(u'© 2001-2008 <a href="http://www.logilab.fr">Logilab S.A.</a>')
+        self.w(u'© 2001-2009 <a href="http://www.logilab.fr">Logilab S.A.</a>')
         self.w(u'</div>')
 
 
--- a/web/views/baseviews.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/baseviews.py	Wed Apr 15 17:36:09 2009 +0200
@@ -8,24 +8,27 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
+#from __future__ import with_statement
+
 __docformat__ = "restructuredtext en"
 
+from warnings import warn
 from time import timezone
 
 from rql import nodes
 
 from logilab.common.decorators import cached
-from logilab.mtconverter import html_escape, TransformError
+from logilab.mtconverter import TransformError, html_escape, xml_escape
 
 from cubicweb import Unauthorized, NoSelectableObject, typed_eid
-from cubicweb.common.selectors import (yes, nonempty_rset, accept_selector,
+from cubicweb.common.selectors import (yes, nonempty_rset, accept,
                                        one_line_rset, match_search_state, 
-                                       req_form_params_selector, accept_rset_selector)
+                                       match_form_params, accept_rset)
 from cubicweb.common.uilib import (cut, printable_value,  UnicodeCSVWriter,
-                                   ajax_replace_url, rql_for_eid)
+                                   ajax_replace_url, rql_for_eid, simple_sgml_tag)
 from cubicweb.common.view import EntityView, AnyRsetView, EmptyRsetView
 from cubicweb.web.httpcache import MaxAgeHTTPCacheManager
 from cubicweb.web.views import vid_from_rset, linksearch_select_url, linksearch_match
@@ -55,34 +58,52 @@
     entities) 
     """
     id = 'final'
+    # record generated i18n catalog messages
+    _('%d&nbsp;years')
+    _('%d&nbsp;months')
+    _('%d&nbsp;weeks')
+    _('%d&nbsp;days')
+    _('%d&nbsp;hours')
+    _('%d&nbsp;minutes')
+    _('%d&nbsp;seconds')
+    _('%d years')
+    _('%d months')
+    _('%d weeks')
+    _('%d days')
+    _('%d hours')
+    _('%d minutes')
+    _('%d seconds')
             
-    def cell_call(self, row, col, props=None, displaytime=False):
+    def cell_call(self, row, col, props=None, displaytime=False, format='text/html'):
         etype = self.rset.description[row][col]
         value = self.rset.rows[row][col]
         if etype == 'String':
             entity, rtype = self.rset.related_entity(row, col)
             if entity is not None:
                 # yes !
-                self.w(entity.printable_value(rtype, value))
+                self.w(entity.printable_value(rtype, value, format=format))
                 return
         if etype in ('Time', 'Interval'):
-            _ = self.req._
             # value is DateTimeDelta but we have no idea about what is the 
             # reference date here, so we can only approximate years and months
+            if format == 'text/html':
+                space = '&nbsp;'
+            else:
+                space = ' '
             if value.days > 730: # 2 years
-                self.w(_('%d years') % (value.days // 365))
+                self.w(self.req.__('%%d%syears' % space) % (value.days // 365))
             elif value.days > 60: # 2 months
-                self.w(_('%d months') % (value.days // 30))
+                self.w(self.req.__('%%d%smonths' % space) % (value.days // 30))
             elif value.days > 14: # 2 weeks
-                self.w(_('%d weeks') % (value.days // 7))
+                self.w(self.req.__('%%d%sweeks' % space) % (value.days // 7))
             elif value.days > 2:
-                self.w(_('%s days') % int(value.days))
+                self.w(self.req.__('%%d%sdays' % space) % int(value.days))
             elif value.hours > 2:
-                self.w(_('%s hours') % int(value.hours))
+                self.w(self.req.__('%%d%shours' % space) % int(value.hours))
             elif value.minutes >= 2:
-                self.w(_('%s minutes') % int(value.minutes))
+                self.w(self.req.__('%%d%sminutes' % space) % int(value.minutes))
             else:
-                self.w(_('%s seconds') % int(value.seconds))
+                self.w(self.req.__('%%d%sseconds' % space) % int(value.seconds))
             return
         self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime))
 
@@ -137,34 +158,34 @@
         self.render_entity_metadata(entity)
         # entity's attributes and relations, excluding meta data
         # if the entity isn't meta itself
-        self.w(u'<table border="0" width="100%">')
-        self.w(u'<tr>')
-        self.w(u'<td valign="top">')
+        self.w(u'<div>')
         self.w(u'<div class="mainInfo">')
         self.render_entity_attributes(entity, siderelations)
         self.w(u'</div>')
-        self.w(u'<div class="navcontenttop">')
-        for comp in self.vreg.possible_vobjects('contentnavigation',
-                                                self.req, self.rset,
-                                                view=self, context='navcontenttop'):
-            comp.dispatch(w=self.w, view=self)
-        self.w(u'</div>')
+        self.content_navigation_components('navcontenttop')
         if self.main_related_section:
             self.render_entity_relations(entity, siderelations)
-        self.w(u'</td>')
+        self.w(u'</div>')
         # side boxes
-        self.w(u'<td valign="top">')
+        self.w(u'<div class="primaryRight">')
         self.render_side_related(entity, siderelations)
-        self.w(u'</td>')
-        self.w(u'</tr>')
-        self.w(u'</table>')        
-        self.w(u'<div class="navcontentbottom">')
+        self.w(u'</div>')
+        self.w(u'<div class="clear"></div>')          
+        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,
-                                                view=self, context='navcontentbottom'):
-            comp.dispatch(w=self.w, view=self)
+                                                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():
             attr = rschema.type
@@ -239,8 +260,10 @@
         non-meta in a first step, meta in a second step
         """
         if hasattr(self, 'get_side_boxes_defs'):
-            for label, rset in self.get_side_boxes_defs(entity):
-                if rset:
+            sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity)
+                         if rset]
+            if sideboxes:
+                for label, rset in sideboxes:
                     self.w(u'<div class="sideRelated">')
                     self.wview('sidebox', rset, title=label)
                     self.w(u'</div>')
@@ -251,15 +274,17 @@
                 #    continue
                 self._render_related_entities(entity, *relatedinfos)
             self.w(u'</div>')
-        for box in self.vreg.possible_vobjects('boxes', self.req, entity.rset,
-                                               col=entity.col, row=entity.row,
-                                               view=self, context='incontext'):
-            try:
-                box.dispatch(w=self.w, col=entity.col, row=entity.row)
-            except NotImplementedError:
-                # much probably a context insensitive box, which only implements
-                # .call() and not cell_call()
-                box.dispatch(w=self.w)
+        boxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+                                                 row=self.row, view=self,
+                                                 context='incontext'))
+        if boxes:
+            for box in boxes:
+                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 \
@@ -350,10 +375,10 @@
         self.w(u'</a>')
 
 class TextView(EntityView):
-    """the simplest text view for an entity
-    """
+    """the simplest text view for an entity"""
     id = 'text'
     title = _('text')
+    content_type = 'text/plain'
     accepts = 'Any',
     def call(self, **kwargs):
         """the view is called for an entire result set, by default loop
@@ -571,8 +596,7 @@
         self.wview(self.item_vid, self.rset, row=row, col=col)
         
     def call(self):
-        """display a list of entities by calling their <item_vid> view
-        """
+        """display a list of entities by calling their <item_vid> view"""
         self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding)
         self.w(u'<%s size="%s">\n' % (self.xml_root, len(self.rset)))
         for i in xrange(self.rset.rowcount):
@@ -599,7 +623,7 @@
                     from base64 import b64encode
                     value = '<![CDATA[%s]]>' % b64encode(value.getvalue())
                 elif isinstance(value, basestring):
-                    value = value.replace('&', '&amp;').replace('<', '&lt;')
+                    value = xml_escape(value)
                 self.w(u'  <%s>%s</%s>\n' % (attr, value, attr))
         self.w(u'</%s>\n' % (entity.e_schema))
 
@@ -619,21 +643,25 @@
         eschema = self.schema.eschema
         labels = self.columns_labels(False)
         w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding)
-        w(u'<%s>\n' % self.xml_root)
+        w(u'<%s query="%s">\n' % (self.xml_root, html_escape(rset.printable_rql())))
         for rowindex, row in enumerate(self.rset):
             w(u' <row>\n')
             for colindex, val in enumerate(row):
                 etype = descr[rowindex][colindex]
                 tag = labels[colindex]
+                attrs = {}
+                if '(' in tag:
+                    attrs['expr'] = tag
+                    tag = 'funccall'
                 if val is not None and not eschema(etype).is_final():
+                    attrs['eid'] = val
                     # csvrow.append(val) # val is eid in that case
-                    content = self.view('textincontext', rset, 
-                                        row=rowindex, col=colindex)
-                    w(u'  <%s eid="%s">%s</%s>\n' % (tag, val, html_escape(content), tag))
+                    val = self.view('textincontext', rset,
+                                    row=rowindex, col=colindex)
                 else:
-                    content = self.view('final', rset, displaytime=True,
-                                        row=rowindex, col=colindex)
-                    w(u'  <%s>%s</%s>\n' % (tag, html_escape(content), tag))
+                    val = self.view('final', rset, displaytime=True,
+                                    row=rowindex, col=colindex, format='text/plain')
+                w(simple_sgml_tag(tag, val, **attrs))
             w(u' </row>\n')
         w(u'</%s>\n' % self.xml_root)
     
@@ -645,18 +673,13 @@
     content_type = 'text/xml'
     http_cache_manager = MaxAgeHTTPCacheManager
     cache_max_age = 60*60*2 # stay in http cache for 2 hours by default 
-    
-    def cell_call(self, row, col):
-        self.wview('rssitem', self.rset, row=row, col=col)
-        
-    def call(self):
-        """display a list of entities by calling their <item_vid> view"""
+
+    def _open(self):
         req = self.req
         self.w(u'<?xml version="1.0" encoding="%s"?>\n' % req.encoding)
-        self.w(u'''<rdf:RDF
+        self.w(u'''<rss version="2.0"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns="http://purl.org/rss/1.0/"
 >''')
         self.w(u'  <channel rdf:about="%s">\n' % html_escape(req.url()))
         self.w(u'    <title>%s RSS Feed</title>\n' % html_escape(self.page_title()))
@@ -664,43 +687,52 @@
         params = req.form.copy()
         params.pop('vid', None)
         self.w(u'    <link>%s</link>\n' % html_escape(self.build_url(**params)))
-        self.w(u'    <items>\n')
-        self.w(u'      <rdf:Seq>\n')
-        for entity in self.rset.entities():
-            self.w(u'      <rdf:li resource="%s" />\n' % html_escape(entity.absolute_url()))
-        self.w(u'      </rdf:Seq>\n')
-        self.w(u'    </items>\n')
+
+    def _close(self):
         self.w(u'  </channel>\n')
+        self.w(u'</rss>')       
+        
+    def call(self):
+        """display a list of entities by calling their <item_vid> view"""
+        self._open()
         for i in xrange(self.rset.rowcount):
             self.cell_call(i, 0)
-        self.w(u'</rdf:RDF>')
+        self._close()
 
+    def cell_call(self, row, col):
+        self.wview('rssitem', self.rset, row=row, col=col)
 
 class RssItemView(EntityView):
     id = 'rssitem'
     date_format = '%%Y-%%m-%%dT%%H:%%M%+03i:00' % (timezone / 3600)
+    add_div_section = False
 
     def cell_call(self, row, col):
         entity = self.complete_entity(row, col)
         self.w(u'<item rdf:about="%s">\n' % html_escape(entity.absolute_url()))
+        self.render_title_link(entity)
+        self._marker('description', html_escape(entity.dc_description()))
+        self._marker('dc:date', entity.dc_date(self.date_format))
+        self.render_entity_creator(entity)
+        self.w(u'</item>\n')
+
+    def render_title_link(self, entity):
         self._marker('title', entity.dc_long_title())
         self._marker('link', entity.absolute_url())
-        self._marker('description', entity.dc_description())
-        self._marker('dc:date', entity.dc_date(self.date_format))
+           
+    def render_entity_creator(self, entity):
         if entity.creator:
-            self.w(u'<author>')
-            self._marker('name', entity.creator.name())
+            self._marker('dc:creator', entity.creator.name())
             email = entity.creator.get_email()
             if email:
-                self._marker('email', email)
-            self.w(u'</author>')
-        self.w(u'</item>\n')
+                self.w(u'<author>')
+                self.w(email)
+                self.w(u'</author>')       
         
     def _marker(self, marker, value):
         if value:
             self.w(u'  <%s>%s</%s>\n' % (marker, html_escape(value), marker))
 
-
 class CSVMixIn(object):
     """mixin class for CSV views"""
     templatable = False
@@ -740,7 +772,8 @@
                     content = self.view('textincontext', rset, 
                                         row=rowindex, col=colindex)
                 else:
-                    content = self.view('final', rset, displaytime=True,
+                    content = self.view('final', rset,
+                                        displaytime=True, format='text/plain',
                                         row=rowindex, col=colindex)
                 csvrow.append(content)                    
             writer.writerow(csvrow)
@@ -785,7 +818,7 @@
     """
     id = 'search-associate'
     title = _('search for association')
-    __selectors__ = (one_line_rset, match_search_state, accept_selector)
+    __selectors__ = (one_line_rset, match_search_state, accept)
     accepts = ('Any',)
     search_states = ('linksearch',)
 
@@ -793,7 +826,7 @@
         rset, vid, divid, paginate = self.filter_box_context_info()
         self.w(u'<div id="%s">' % divid)
         self.pagination(self.req, rset, w=self.w)
-        self.wview(vid, rset)
+        self.wview(vid, rset, 'noresult')
         self.w(u'</div>')
 
     @cached
@@ -842,7 +875,7 @@
     """
     id = 'editrelation'
 
-    __selectors__ = (req_form_params_selector,)
+    __selectors__ = (match_form_params,)
     form_params = ('rtype',)
     
     # TODO: inlineview, multiple edit, (widget view ?)
@@ -855,13 +888,8 @@
         assert rtype is not None, "rtype is mandatory for 'edirelation' view"
         targettype = self.req.form.get('targettype', targettype)
         role = self.req.form.get('role', role)
-        mode = entity.rtags.get_mode(rtype, targettype, role)
-        if mode == 'create':
-            return
         category = entity.rtags.get_category(rtype, targettype, role)
-        if category in ('generated', 'metadata'):
-            return
-        elif category in ('primary', 'secondary'):
+        if category in ('primary', 'secondary') or self.schema.rschema(rtype).is_final():
             if hasattr(entity, '%s_format' % rtype):
                 formatwdg = entity.get_widget('%s_format' % rtype, role)
                 self.w(formatwdg.edit_render(entity))
@@ -872,10 +900,8 @@
             self.w(u'%s %s %s' %
                    (wdg.render_error(entity), wdg.edit_render(entity),
                     wdg.render_help(entity),))
-        elif category == 'generic':
+        else:
             self._render_generic_relation(entity, rtype, role)
-        else:
-            self.error("oops, wrong category %s", category)
 
     def _render_generic_relation(self, entity, relname, role):
         text = self.req.__('add %s %s %s' % (entity.e_schema, relname, role))
@@ -988,7 +1014,8 @@
         else:
             role = 'object'
         rset = self.rset.get_entity(row, col).related(self.rtype, role)
-        self.w(u'<h1>%s</h1>' % self.req._(self.title).capitalize())
+        if self.title:
+            self.w(u'<h1>%s</h1>' % self.req._(self.title).capitalize())
         self.w(u'<div class="mainInfo">')
         self.wview(self.vid, rset, 'noresult')
         self.w(u'</div>')
--- a/web/views/bookmark.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/bookmark.py	Wed Apr 15 17:36:09 2009 +0200
@@ -68,9 +68,9 @@
                 dlink = u'[<a href="javascript:removeBookmark(%s)" title="%s">-</a>]' % (
                     bookmark.eid, _('delete this bookmark'))
                 label = '%s %s' % (dlink, label)
-            box.append(RawBoxItem(label, liclass=u'invisible'))
+            box.append(RawBoxItem(label))
         if eschema.has_perm(req, 'add') and rschema.has_perm(req, 'add', toeid=ueid):
-            boxmenu = BoxMenu(req._('manage bookmarks'), liclass=u'invisible')
+            boxmenu = BoxMenu(req._('manage bookmarks'))
             linkto = 'bookmarked_by:%s:subject' % ueid
             # use a relative path so that we can move the application without
             # loosing bookmarks
--- a/web/views/boxes.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/boxes.py	Wed Apr 15 17:36:09 2009 +0200
@@ -10,31 +10,28 @@
 * startup views box
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+: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.common.selectors import (rset_selector, appobject_selectable)
+from cubicweb.common.selectors import any_rset, appobject_selectable
 from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, BoxHtml, RawBoxItem
 from cubicweb.web.box import BoxTemplate, ExtResourcesBoxTemplate
 
 _ = unicode
-
-
+    
 class EditBox(BoxTemplate):
     """
     box with all actions impacting the entity displayed: edit, copy, delete
     change state, add related entities
     """
-    __selectors__ = (rset_selector,) + BoxTemplate.__selectors__
     id = 'edit_box'
     title = _('actions')
     order = 2
 
-    def call(self, **kwargs):
+    def call(self, view=None, **kwargs):
         _ = self.req._
         title = _(self.title)
         if self.rset:
@@ -45,7 +42,7 @@
                 title = u'%s - %s' % (title, etypelabel.lower())
         box = BoxWidget(title, self.id, _class="greyBoxFrame")
         # build list of actions
-        actions = self.vreg.possible_actions(self.req, self.rset)
+        actions = self.vreg.possible_actions(self.req, self.rset, view=view)
         add_menu = BoxMenu(_('add')) # 'addrelated' category
         other_menu = BoxMenu(_('more actions')) # 'moreactions' category
         searchstate = self.req.search_state[0]
@@ -77,7 +74,7 @@
         self.add_submenu(box, other_menu)
         if not box.is_empty():
             box.render(self.w)
-
+            
     def add_submenu(self, box, submenu, label_prefix=None):
         if len(submenu.items) == 1:
             boxlink = submenu.items[0]
@@ -111,7 +108,7 @@
             if transitions:
                 menu_title = u'%s: %s' % (_('state'), state.view('text'))
                 menu_items = []
-                for tr in state.transitions(entity):
+                for tr in transitions:
                     url = entity.absolute_url(vid='statuschange', treid=tr.eid)
                     menu_items.append(self.mk_action(_(tr.name), url))
                 box.append(BoxMenu(menu_title, menu_items))
@@ -143,7 +140,7 @@
 <input type="hidden" name="__fromsearchbox" value="1" />
 <input type="hidden" name="subvid" value="tsearch" />
 </td><td>
-<input tabindex="%s" type="submit" id="rqlboxsubmit" value="" />
+<input tabindex="%s" type="submit" id="rqlboxsubmit" class="rqlsubmit" value="" />
 </td></tr></table>
 </form>"""
 
@@ -175,17 +172,16 @@
 
     def call(self, **kwargs):
         box = BoxWidget(self.req._(self.title), self.id)
-        actions = [v for v in self.vreg.possible_views(self.req, self.rset)
-                   if v.category != 'startupview']
-        for category, actions in self.sort_actions(actions):
+        views = [v for v in self.vreg.possible_views(self.req, self.rset)
+                 if v.category != 'startupview']
+        for category, views in self.sort_actions(views):
             menu = BoxMenu(category)
-            for action in actions:
-                menu.append(self.box_action(action))
+            for view in views:
+                menu.append(self.box_action(view))
             box.append(menu)
         if not box.is_empty():
             box.render(self.w)
 
-
         
 class RSSIconBox(ExtResourcesBoxTemplate):
     """just display the RSS icon on uniform result set"""
@@ -200,30 +196,13 @@
         urlgetter = self.vreg.select_component('rss_feed_url', self.req, self.rset)
         url = urlgetter.feed_url()
         rss = self.req.external_resource('RSS_LOGO')
-        self.w(u'<a href="%s"><img src="%s" border="0" /></a>\n' % (html_escape(url), rss))
-
+        self.w(u'<a href="%s"><img src="%s" alt="rss"/></a>\n' % (html_escape(url), rss))
 
-## warning("schemabox ne marche plus pour le moment")
-## class SchemaBox(BoxTemplate):
-##     """display a box containing link to list of entities by type"""
-##     id = 'schema_box'
-##     visible = False # disabled by default
-##     title = _('entity list')
-##     order = 60
-        
-##     def call(self, **kwargs):
-##         box = BoxWidget(self.req._(title), self.id)
-##         for etype in self.config.etypes(self.req.user, 'read'):
-##             view = self.vreg.select_view('list', self.req, self.etype_rset(etype))
-##             box.append(self.mk_action(display_name(self.req, etype, 'plural'),
-##                                       view.url(), etype=etype))
-##         if not box.is_empty():
-##             box.render(self.w)
 
 class StartupViewsBox(BoxTemplate):
     """display a box containing links to all startup views"""
     id = 'startup_views_box'
-    visible = False # disabled by default
+    visible = False# disabled by default
     title = _('startup views')
     order = 70
 
--- a/web/views/calendar.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/calendar.py	Wed Apr 15 17:36:09 2009 +0200
@@ -15,7 +15,7 @@
 from cubicweb.interfaces import ICalendarable
 from cubicweb.common.utils import date_range
 from cubicweb.common.uilib import ajax_replace_url
-from cubicweb.common.selectors import interface_selector
+from cubicweb.common.selectors import implement_interface
 from cubicweb.common.registerers import priority_registerer
 from cubicweb.common.view import EntityView
 
@@ -83,7 +83,7 @@
     Does apply to ICalendarable compatible entities
     """
     __registerer__ = priority_registerer
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (ICalendarable,)
     need_navigation = False
     content_type = 'text/calendar'
@@ -114,11 +114,11 @@
     Does apply to ICalendarable compatible entities
     """
     __registerer__ = priority_registerer
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (ICalendarable,)
     need_navigation = False
     title = _('hCalendar')
-    templatable = False
+    #templatable = False
     id = 'hcal'
 
     def call(self):
@@ -146,7 +146,7 @@
 class OneMonthCal(EntityView):
     """At some point, this view will probably replace ampm calendars"""
     __registerer__ = priority_registerer
-    __selectors__ = (interface_selector, )
+    __selectors__ = (implement_interface, )
     accepts_interfaces = (ICalendarable,)
     need_navigation = False
     id = 'onemonthcal'
@@ -331,7 +331,7 @@
 class OneWeekCal(EntityView):
     """At some point, this view will probably replace ampm calendars"""
     __registerer__ = priority_registerer
-    __selectors__ = (interface_selector, )
+    __selectors__ = (implement_interface, )
     accepts_interfaces = (ICalendarable,)
     need_navigation = False
     id = 'oneweekcal'
--- a/web/views/editcontroller.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/editcontroller.py	Wed Apr 15 17:36:09 2009 +0200
@@ -166,13 +166,13 @@
         self.delete_entities(self.req.edited_eids(withtype=True))
         return self.reset()
 
-    def _needs_edition(self, rtype, formparams):
+    def _needs_edition(self, rtype, formparams, entity):
         """returns True and and the new value if `rtype` was edited"""
         editkey = 'edits-%s' % rtype
         if not editkey in formparams:
             return False, None # not edited
         value = formparams.get(rtype) or None
-        if (formparams.get(editkey) or None) == value:
+        if entity.has_eid() and (formparams.get(editkey) or None) == value:
             return False, None # not modified
         if value == INTERNAL_FIELD_VALUE:
             value = None        
@@ -183,7 +183,7 @@
         attribute described by the given schema if necessary
         """
         attr = rschema.type
-        edition_needed, value = self._needs_edition(attr, formparams)
+        edition_needed, value = self._needs_edition(attr, formparams, entity)
         if not edition_needed:
             return
         # test if entity class defines a special handler for this attribute
--- a/web/views/embedding.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/embedding.py	Wed Apr 15 17:36:09 2009 +0200
@@ -18,7 +18,7 @@
 from cubicweb.interfaces import IEmbedable
 from cubicweb.common.uilib import soup2xhtml
 from cubicweb.common.selectors import (one_line_rset, score_entity_selector,
-                                    match_search_state, interface_selector)
+                                    match_search_state, implement_interface)
 from cubicweb.common.view import NOINDEX, NOFOLLOW
 from cubicweb.web.controller import Controller
 from cubicweb.web.action import Action
@@ -82,7 +82,7 @@
     id = 'embed'
     controller = 'embed'
     __selectors__ = (one_line_rset, match_search_state,
-                     interface_selector, score_entity_selector)
+                     implement_interface, score_entity_selector)
     accepts_interfaces = (IEmbedable,)
     
     title = _('embed')
--- a/web/views/euser.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/euser.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,17 +1,18 @@
 """Specific views for users
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+: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 cached
+from logilab.mtconverter import html_escape
 
 from cubicweb.schema import display_name
 from cubicweb.web import INTERNAL_FIELD_VALUE
 from cubicweb.web.form import EntityForm
-from cubicweb.web.views.baseviews import PrimaryView
+from cubicweb.web.views.baseviews import PrimaryView, EntityView
 
 class EUserPrimaryView(PrimaryView):
     accepts = ('EUser',)
@@ -31,8 +32,42 @@
         return  rschema.type in ['interested_in', 'tags', 
                                  'todo_by', 'bookmarked_by',
                                  ]
+class FoafView(EntityView):
+    id = 'foaf'
+    accepts = ('EUser',)
+    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')
+                   
 class EditGroups(EntityForm):
     """displays a simple euser / egroups editable table"""
     
--- a/web/views/facets.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/facets.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """the facets box and some basic facets
 
 :organization: Logilab
-:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -10,9 +10,9 @@
 
 from logilab.mtconverter import html_escape
 
-from cubicweb.common.selectors import (chainfirst, chainall, nfentity_selector,
-                                    two_lines_rset, contextprop_selector,
-                                    yes, one_has_relation_selector)
+from cubicweb.common.selectors import (chainfirst, chainall, non_final_entity,
+                                    two_lines_rset, match_context_prop,
+                                    yes, one_has_relation)
 from cubicweb.web.box import BoxTemplate
 from cubicweb.web.facet import (AbstractFacet, VocabularyFacet, FacetStringWidget,
                              RelationFacet, prepare_facets_rqlst, filter_hiddens)
@@ -28,8 +28,8 @@
     """filter results of a query"""
     id = 'filter_box'
     __selectors__ = (chainfirst(contextview_selector,
-                                chainall(nfentity_selector, two_lines_rset)),
-                     contextprop_selector)
+                                chainall(non_final_entity, two_lines_rset)),
+                     match_context_prop)
     context = 'left'
     title = _('boxes_filter_box')
     visible = True # functionality provided by the search box by default
@@ -153,7 +153,7 @@
 
 
 class HasTextFacet(AbstractFacet):
-    __selectors__ = (one_has_relation_selector, contextprop_selector)
+    __selectors__ = (one_has_relation, match_context_prop)
     id = 'has_text-facet'
     rtype = 'has_text'
     role = 'subject'
--- a/web/views/ibreadcrumbs.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/ibreadcrumbs.py	Wed Apr 15 17:36:09 2009 +0200
@@ -9,8 +9,8 @@
 from logilab.mtconverter import html_escape
 
 from cubicweb.interfaces import IBreadCrumbs
-from cubicweb.common.selectors import (contextprop_selector, one_line_rset, 
-                                    interface_selector)
+from cubicweb.common.selectors import (match_context_prop, one_line_rset, 
+                                    implement_interface)
 from cubicweb.common.view import EntityView
 from cubicweb.common.uilib import cut
 # don't use AnyEntity since this may cause bug with isinstance() due to reloading
@@ -29,7 +29,7 @@
     # register msg not generated since no entity implements IPrevNext in cubicweb itself
     title = _('contentnavigation_breadcrumbs')
     help = _('contentnavigation_breadcrumbs_description')
-    __selectors__ = (one_line_rset, contextprop_selector, interface_selector)
+    __selectors__ = (one_line_rset, match_context_prop, implement_interface)
     accepts_interfaces = (IBreadCrumbs,)
     context = 'navtop'
     order = 5
@@ -73,7 +73,7 @@
 
 class BreadCrumbComponent(BreadCrumbEntityVComponent):
     __registry__ = 'components'
-    __selectors__ = (one_line_rset, interface_selector)
+    __selectors__ = (one_line_rset, implement_interface)
     visible = True
 
 
--- a/web/views/idownloadable.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/idownloadable.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,7 +11,7 @@
 from cubicweb.interfaces import IDownloadable
 from cubicweb.common.mttransforms import ENGINE
 from cubicweb.common.selectors import (one_line_rset, score_entity_selector,
-                                       interface_selector, contextprop_selector)
+                                       implement_interface, match_context_prop)
 from cubicweb.web.box import EntityBoxTemplate
 from cubicweb.web.views import baseviews
 
@@ -35,9 +35,19 @@
     
 class DownloadBox(EntityBoxTemplate):
     id = 'download_box'
-    __selectors__ = (one_line_rset, interface_selector, contextprop_selector)
+    # XXX primary_view selector ?
+    __selectors__ = (one_line_rset, implement_interface, match_context_prop, score_entity_selector)
     accepts_interfaces = (IDownloadable,)
     order = 10
+
+    @classmethod
+    def score_entity(cls, entity):
+        mt = entity.download_content_type()
+        # no download box for images
+        if mt and mt.startswith('image/'):
+            return 0
+        return 1
+    
     def cell_call(self, row, col, title=None, label=None, **kwargs):
         entity = self.entity(row, col)
         download_box(self.w, entity, title, label)
@@ -48,7 +58,7 @@
     of entities providing the necessary interface
     """
     id = 'download'
-    __selectors__ = (one_line_rset, interface_selector)
+    __selectors__ = (one_line_rset, implement_interface)
     accepts_interfaces = (IDownloadable,)
 
     templatable = False
@@ -77,7 +87,7 @@
     """view displaying a link to download the file"""
     id = 'downloadlink'
     title = None # should not be listed in possible views
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
 
     accepts_interfaces = (IDownloadable,)
     
@@ -89,9 +99,10 @@
 
                                                                                 
 class IDownloadablePrimaryView(baseviews.PrimaryView):
-    __selectors__ = (interface_selector,)
-    #skip_attrs = ('eid', 'data',) # XXX
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (IDownloadable,)
+    # XXX File/Image attributes but this is not specified in the IDownloadable interface
+    skip_attrs = baseviews.PrimaryView.skip_attrs + ('data', 'name')
 
     def render_entity_title(self, entity):
         self.w(u'<h1>%s %s</h1>'
@@ -100,12 +111,12 @@
     
     def render_entity_attributes(self, entity, siderelations):
         super(IDownloadablePrimaryView, self).render_entity_attributes(entity, siderelations)
-        self.wview('downloadlink', entity.rset, title=self.req._('download'), row=entity.row)
         self.w(u'<div class="content">')
         contenttype = entity.download_content_type()
         if contenttype.startswith('image/'):
             self.wview('image', entity.rset, row=entity.row)
         else:
+            self.wview('downloadlink', entity.rset, title=self.req._('download'), row=entity.row)
             try:
                 if ENGINE.has_input(contenttype):
                     self.w(entity.printable_value('data'))
@@ -122,7 +133,7 @@
 
 
 class IDownloadableLineView(baseviews.OneLineView):
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     # don't kick default oneline view
     accepts_interfaces = (IDownloadable,)
     
@@ -138,7 +149,7 @@
 
 
 class ImageView(baseviews.EntityView):
-    __selectors__ = (interface_selector, score_entity_selector)
+    __selectors__ = (implement_interface, score_entity_selector)
     id = 'image'
     title = _('image')
     accepts_interfaces = (IDownloadable,)
--- a/web/views/igeocodable.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/igeocodable.py	Wed Apr 15 17:36:09 2009 +0200
@@ -4,7 +4,7 @@
 
 from cubicweb.interfaces import IGeocodable
 from cubicweb.common.view import EntityView
-from cubicweb.common.selectors import interface_selector
+from cubicweb.common.selectors import implement_interface
 
 class GeocodingJsonView(EntityView):
     id = 'geocoding-json'
@@ -12,10 +12,11 @@
     templatable = False
     content_type = 'application/json'
 
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (IGeocodable,)
-    
+
     def call(self):
+        zoomlevel = self.req.form.pop('zoomlevel', 8)
         extraparams = self.req.form.copy()
         extraparams.pop('vid', None)
         extraparams.pop('rql', None)
@@ -26,40 +27,41 @@
             'longitude': sum(marker['longitude'] for marker in markers) / len(markers),
             }
         geodata = {
+            'zoomlevel': int(zoomlevel),
             'center': center,
             'markers': markers,
             }
         self.w(simplejson.dumps(geodata))
-        
+
     def build_marker_data(self, row, extraparams):
         entity = self.entity(row, 0)
         return {'latitude': entity.latitude, 'longitude': entity.longitude,
                 'title': entity.dc_long_title(),
                 #icon defines : (icon._url, icon.size,  icon.iconAncho', icon.shadow)
-                'icon': entity.marker_icon() or (self.req.external_resource('GMARKER_ICON'), (20, 34), (4, 34), None), 
+                'icon': entity.marker_icon() or (self.req.external_resource('GMARKER_ICON'), (20, 34), (4, 34), None),
                 'bubbleUrl': entity.absolute_url(vid='gmap-bubble', __notemplate=1, **extraparams),
                 }
 
 
 class GoogleMapBubbleView(EntityView):
     id = 'gmap-bubble'
-    
-    __selectors__ = (interface_selector,)
+
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (IGeocodable,)
-    
+
     def cell_call(self, row, col):
         entity = self.entity(row, col)
         self.w(u'<div>%s</div>' % entity.view('oneline'))
         # FIXME: we should call something like address-view if available
-        
+
 
 class GoogleMapsView(EntityView):
     id = 'gmap-view'
-    
-    __selectors__ = (interface_selector,)
+
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (IGeocodable,)
     need_navigation = False
-    
+
     def call(self, gmap_key, width=400, height=400, uselabel=True, urlparams=None):
         self.req.add_js('http://maps.google.com/maps?file=api&amp;v=2&amp;key=%s' % gmap_key,
                         localfile=False);
@@ -70,13 +72,13 @@
         else:
             loadurl = self.build_url(rql=rql, vid='geocoding-json', **urlparams)
         self.w(u'<div style="width: %spx; height: %spx;" class="widget gmap" '
-               u'cubicweb:wdgtype="GMapWidget" cubicweb:loadtype="auto" ' 
+               u'cubicweb:wdgtype="GMapWidget" cubicweb:loadtype="auto" '
                u'cubicweb:loadurl="%s" cubicweb:uselabel="%s"> </div>' % (width, height, loadurl, uselabel))
 
-        
+
 class GoogeMapsLegend(EntityView):
     id = 'gmap-legend'
-    
+
     def call(self):
         self.w(u'<ol>')
         for rowidx in xrange(len(self.rset)):
--- a/web/views/iprogress.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/iprogress.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """Specific views for entities implementing IProgress
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 
@@ -12,7 +12,7 @@
 from cubicweb.interfaces import IProgress, IMileStone
 from cubicweb.schema import display_name
 from cubicweb.common.view import EntityView
-from cubicweb.common.selectors import interface_selector, accept_selector
+from cubicweb.common.selectors import implement_interface, accept
 from cubicweb.web.htmlwidgets import ProgressBarWidget
 
 
@@ -35,12 +35,12 @@
     
     id = 'progress_table_view'
     title = _('task progression')
-    __selectors__ = (accept_selector, interface_selector)
+    __selectors__ = (accept, implement_interface)
 
     accepts_interfaces = (IMileStone,)
 
     # default columns of the table
-    columns = (_('project'), _('milestone'), _('state'), _('eta_date'),
+    columns = (_('project'), _('milestone'), _('state'), _('eta_date'), _('planned_delivery'),
                _('cost'), _('progress'), _('todo_by'))
 
 
@@ -133,6 +133,12 @@
             else:
                 formated_date = u'%s %s' % (_('expected:'), eta_date)
         return formated_date
+
+    def build_planned_delivery_cell(self, entity):
+        """``initial_prevision_date`` column cell renderer"""
+        if entity.finished():
+            return self.format_date(entity.completion_date())
+        return self.format_date(entity.initial_prevision_date())
     
     def build_todo_by_cell(self, entity):
         """``todo_by`` column cell renderer"""
@@ -182,7 +188,7 @@
     """displays a progress bar"""
     id = 'progressbar'
     title = _('progress bar')
-    __selectors__ = (accept_selector, interface_selector)
+    __selectors__ = (accept, implement_interface)
 
     accepts_interfaces = (IProgress,)
 
--- a/web/views/management.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/management.py	Wed Apr 15 17:36:09 2009 +0200
@@ -13,17 +13,16 @@
 
 from cubicweb.common.utils import UStringIO
 from cubicweb.common.view import AnyRsetView, StartupView, EntityView
-from cubicweb.common.uilib import (html_traceback, rest_traceback, html_escape,
-                                toggle_link)
+from cubicweb.common.uilib import html_traceback, rest_traceback
 from cubicweb.common.selectors import (yes, one_line_rset,
-                                    accept_rset_selector, none_rset,
-                                    chainfirst, chainall)
+                                       accept_rset, none_rset,
+                                       chainfirst, chainall)
 from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, stdmsgs
 from cubicweb.web.widgets import StaticComboBoxWidget
 from cubicweb.web.form import FormMixIn
 
 _ = unicode
-            
+
 def begin_form(w, entity, redirectvid, redirectpath=None, msg=None):
     w(u'<form method="post" action="%s">\n' % entity.req.build_url('edit'))
     w(u'<fieldset>\n')
@@ -42,10 +41,10 @@
     """display security information for a given entity"""
     id = 'security'
     title = _('security')
-        
+
     def cell_call(self, row, col):
-        self.req.add_js('cubicweb.edition.js')            
-        self.req.add_css('cubicweb.acl.css')            
+        self.req.add_js('cubicweb.edition.js')
+        self.req.add_css('cubicweb.acl.css')
         entity = self.entity(row, col)
         w = self.w
         _ = self.req._
@@ -90,7 +89,7 @@
             w(u'<td>%s</td>' % u'<br/>'.join(expr.expression for expr in rqlexprs))
             w(u'</tr>\n')
         w(u'</table>')
-        
+
     def owned_by_edit_form(self, entity):
         self.w('<h3>%s</h3>' % self.req._('ownership'))
         begin_form(self.w, entity, 'security', msg= _('ownerships have been changed'))
@@ -160,16 +159,18 @@
         w(u'<tr><th>%s</th><th>%s</th><th>%s</th><th>&nbsp;</th></tr>\n'
                % (_("name"), _("label"), _('granted to groups')))
         if getattr(entity, '__permissions__', None):
+            # vocabfunc must be compliant with StaticVocabularyConstraint.vocabulary
+            # which takes only keyword parameters
             wdg = StaticComboBoxWidget(self.vreg, self.schema['EPermission'],
                                        self.schema['name'], self.schema['String'],
-                                       vocabfunc=lambda x: entity.__permissions__)
+                                       vocabfunc=lambda entity, x=entity: x.__permissions__)
         else:
             wdg = newperm.get_widget('name')
         w(u'<tr><td>%s</td>\n' % wdg.edit_render(newperm))
         wdg = newperm.get_widget('label')
         w(u'<td>%s</td>\n' % wdg.edit_render(newperm))
         wdg = newperm.get_widget('require_group')
-        w(u'<td>%s</td>\n' % wdg.edit_render(newperm))            
+        w(u'<td>%s</td>\n' % wdg.edit_render(newperm))
         w(u'<td>%s</td></tr>\n' % self.button_ok())
         w(u'</table>')
         w(u'</fieldset></form>\n')
@@ -178,12 +179,12 @@
         return (u'<input class="validateButton" type="submit" name="submit" value="%s"/>'
                 % self.req._(stdmsgs.BUTTON_OK))
 
-        
+
 class ErrorView(AnyRsetView):
     """default view when no result has been found"""
     __selectors__ = (yes,)
     id = 'error'
-    
+
     def page_title(self):
         """returns a title according to the result set - used for the
         title in the HTML header
@@ -192,11 +193,11 @@
 
     def call(self):
         req = self.req.reset_headers()
-        _ = req._
+        _ = req._; w = self.w
         ex = req.data.get('ex')#_("unable to find exception information"))
         excinfo = req.data.get('excinfo')
         title = _('an error occured')
-        self.w(u'<h2>%s</h2>' % title)
+        w(u'<h2>%s</h2>' % title)
         if 'errmsg' in req.data:
             ex = req.data['errmsg']
             exclass = None
@@ -205,53 +206,53 @@
             ex = exc_message(ex, req.encoding)
         if excinfo is not None and self.config['print-traceback']:
             if exclass is None:
-                self.w(u'<div class="tb">%s</div>'
+                w(u'<div class="tb">%s</div>'
                        % html_escape(ex).replace("\n","<br />"))
             else:
-                self.w(u'<div class="tb">%s: %s</div>'
+                w(u'<div class="tb">%s: %s</div>'
                        % (exclass, html_escape(ex).replace("\n","<br />")))
-            self.w(u'<hr />')
-            self.w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, ''))
+            w(u'<hr />')
+            w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, ''))
         else:
-            self.w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />")))
+            w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />")))
         # if excinfo is not None, it's probably not a bug
         if excinfo is None:
             return
         vcconf = self.config.vc_config()
-        self.w(u"<div>")
+        w(u"<div>")
         eversion = vcconf.get('cubicweb', _('no version information'))
         # NOTE: tuple wrapping needed since eversion is itself a tuple
-        self.w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,))
+        w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,))
         for pkg in self.config.cubes():
             pkgversion = vcconf.get(pkg, _('no version information'))
-            self.w(u"<b>Package %s version:</b> %s<br/>\n" % (pkg, pkgversion))
-        self.w(u"</div>")
+            w(u"<b>Package %s version:</b> %s<br/>\n" % (pkg, pkgversion))
+        w(u"</div>")
         # creates a bug submission link if SUBMIT_URL is set
         submiturl = self.config['submit-url']
         if submiturl:
             binfo = text_error_description(ex, excinfo, req, eversion,
                                            [(pkg, vcconf.get(pkg, _('no version information')))
                                             for pkg in self.config.cubes()])
-            self.w(u'<form action="%s" method="post">\n' % html_escape(submiturl))
-            self.w(u'<fieldset>\n')
-            self.w(u'<textarea class="hidden" name="description">%s</textarea>' % html_escape(binfo))
-            self.w(u'<input type="hidden" name="description_format" value="text/rest"/>')
-            self.w(u'<input type="hidden" name="__bugreporting" value="1"/>')
-            self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report'))
-            self.w(u'</fieldset>\n')
-            self.w(u'</form>\n')
+            w(u'<form action="%s" method="post">\n' % html_escape(submiturl))
+            w(u'<fieldset>\n')
+            w(u'<textarea class="hidden" name="description">%s</textarea>' % html_escape(binfo))
+            w(u'<input type="hidden" name="description_format" value="text/rest"/>')
+            w(u'<input type="hidden" name="__bugreporting" value="1"/>')
+            w(u'<input type="submit" value="%s"/>' % _('Submit bug report'))
+            w(u'</fieldset>\n')
+            w(u'</form>\n')
         submitmail = self.config['submit-mail']
         if submitmail:
             binfo = text_error_description(ex, excinfo, req, eversion,
                                            [(pkg, vcconf.get(pkg, _('no version information')))
                                             for pkg in self.config.cubes()])
-            self.w(u'<form action="%s" method="post">\n' % req.build_url('reportbug'))
-            self.w(u'<fieldset>\n')
-            self.w(u'<input type="hidden" name="description" value="%s"/>' % html_escape(binfo))
-            self.w(u'<input type="hidden" name="__bugreporting" value="1"/>')
-            self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report by mail'))
-            self.w(u'</fieldset>\n')
-            self.w(u'</form>\n')
+            w(u'<form action="%s" method="post">\n' % req.build_url('reportbug'))
+            w(u'<fieldset>\n')
+            w(u'<input type="hidden" name="description" value="%s"/>' % html_escape(binfo))
+            w(u'<input type="hidden" name="__bugreporting" value="1"/>')
+            w(u'<input type="submit" value="%s"/>' % _('Submit bug report by mail'))
+            w(u'</fieldset>\n')
+            w(u'</form>\n')
 
 
 def exc_message(ex, encoding):
@@ -262,7 +263,7 @@
             return unicode(str(ex), encoding, 'replace')
         except:
             return unicode(repr(ex), encoding, 'replace')
-    
+
 def text_error_description(ex, excinfo, req, eversion, cubes):
     binfo = rest_traceback(excinfo, html_escape(ex))
     binfo += u'\n\n:URL: %s\n' % req.url()
@@ -284,23 +285,48 @@
 _('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 SystemEpropertiesForm(FormMixIn, StartupView):
     controller = 'edit'
     id = 'systemepropertiesform'
     title = _('site configuration')
     require_groups = ('managers',)
     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'):
+        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.edition.js')
+        self.req.add_js(('cubicweb.edition.js', 'cubicweb.preferences.js'))
         self.req.add_css('cubicweb.preferences.css')
         vreg = self.vreg
         values = self.defined_keys
@@ -322,7 +348,7 @@
         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._
@@ -330,17 +356,21 @@
         w(self.error_message())
         for label, group, form in sorted((_(g), g, f)
                                          for g, f in mainopts.iteritems()):
+            status = css_class(self._group_status(group)) #'hidden' (collapsed), or '' (open) ?
             w(u'<h2 class="propertiesform">%s</h2>\n' %
-              (toggle_link('fieldset_' + group, label)))
-            w(u'<div id="fieldset_%s" class="hidden">' % group)
+              (make_togglable_link('fieldset_' + group, label,
+                                   self._cookie_name(group))))
+            w(u'<div id="fieldset_%s" %s>' % (group, status))
             w(u'<fieldset class="subentity">')
             w(form)
             w(u'</fieldset></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' %
-              (toggle_link('fieldset_' + group, label)))
-            w(u'<div id="fieldset_%s" class="hidden">' % group)
+              (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">')
@@ -352,21 +382,19 @@
                 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 EProperty, 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:
@@ -391,11 +419,11 @@
             w(u'<input type="hidden" name="__redirectparams" value="%s"/>\n'
               % html_escape(params))
         w(u'<input type="hidden" name="__redirectpath" value="%s"/>\n' % path)
-        #w(u'<input type="hidden" name="__redirectrql" value=""/>\n') 
+        #w(u'<input type="hidden" name="__redirectrql" value=""/>\n')
         w(u'<input type="hidden" name="__message" value="%s"/>\n'
           % self.req._('changes applied'))
         w(u'<table><tr><td>\n')
-       
+
         w(u'<table>\n')
         for key in keys:
             w(u'<tr>\n')
@@ -409,7 +437,7 @@
         w(u'</fieldset>\n')
         w(u'</form>\n')
         return stream.getvalue()
-        
+
     def form_row(self, w, key, splitlabel):
         entity = self.entity_for_key(key)
         eid = entity.eid
@@ -434,13 +462,13 @@
         w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('pkey', eid), key))
         w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('edits-pkey', eid), ''))
 
-        
+
 class EpropertiesForm(SystemEpropertiesForm):
     id = 'epropertiesform'
-    title = _('preferences')    
+    title = _('preferences')
     require_groups = ('users', 'managers') # we don't want guests to be able to come here
     __selectors__ = chainfirst(none_rset,
-                               chainall(one_line_rset, accept_rset_selector)),
+                               chainall(one_line_rset, accept_rset)),
     accepts = ('EUser',)
 
     @classmethod
@@ -449,7 +477,7 @@
             row = 0
         score = super(EpropertiesForm, cls).accept_rset(req, rset, row, col)
         # check current user is the rset user or he is in the managers group
-        if score and (req.user.eid == rset[row][col or 0] 
+        if score and (req.user.eid == rset[row][col or 0]
                       or req.user.matching_groups('managers')):
             return score
         return 0
@@ -459,7 +487,7 @@
         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):
@@ -476,9 +504,9 @@
               % (eid_param('edits-for_user', eid), INTERNAL_FIELD_VALUE))
             w(u'<input type="hidden" name="%s" value="%s"/>'
               % (eid_param('for_user', eid), self.user.eid))
-    
-                   
-    
+
+
+
 
 class ProcessInformationView(StartupView):
     id = 'info'
--- a/web/views/massmailing.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/massmailing.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,14 +11,14 @@
 
 from cubicweb.interfaces import IEmailable
 from cubicweb.common.view import EntityView
-from cubicweb.common.selectors import interface_selector, in_group_selector
+from cubicweb.common.selectors import implement_interface, match_user_group
 from cubicweb.web.action import EntityAction
 from cubicweb.web import stdmsgs
 
 
 class SendEmailAction(EntityAction):
     category = 'mainactions'
-    __selectors__ = (interface_selector, in_group_selector)
+    __selectors__ = (implement_interface, match_user_group)
     accepts_interfaces = (IEmailable,) # XXX should check email is set as well
     require_groups = ('managers', 'users')
 
@@ -35,7 +35,7 @@
 
 class MassMailingForm(EntityView):
     id = 'massmailing'
-    __selectors__ = (interface_selector, in_group_selector)
+    __selectors__ = (implement_interface, match_user_group)
     accepts_interfaces = (IEmailable,)
     require_groups = ('managers', 'users')
     
--- a/web/views/navigation.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/navigation.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,9 +11,9 @@
 from logilab.mtconverter import html_escape
 
 from cubicweb.interfaces import IPrevNext
-from cubicweb.common.selectors import (paginated_rset, sortedrset_selector,
-                                    primaryview_selector, contextprop_selector,
-                                    one_line_rset, interface_selector)
+from cubicweb.common.selectors import (paginated_rset, sorted_rset,
+                                       primary_view, match_context_prop,
+                                       one_line_rset, implement_interface)
 from cubicweb.common.uilib import cut
 from cubicweb.web.component import EntityVComponent, NavigationComponent
 
@@ -36,20 +36,22 @@
         while start < rset.rowcount:
             stop = min(start + page_size - 1, rset.rowcount - 1)
             blocklist.append(self.page_link(basepath, params, start, stop,
-                                            u'%s - %s' % (start+1, stop+1)))
+                                            self.index_display(start, stop)))
             start = stop + 1
         w(u'<div class="pagination">')
         w(u'%s&nbsp;' % self.previous_link(params))
         w(u'[&nbsp;%s&nbsp;]' % u'&nbsp;| '.join(blocklist))
         w(u'&nbsp;%s' % self.next_link(params))
         w(u'</div>')
+        
+    def index_display(self, start, stop):
+        return u'%s - %s' % (start+1, stop+1)
 
-    
 class SortedNavigation(NavigationComponent):
     """sorted navigation apply if navigation is needed (according to page size)
     and if the result set is sorted
     """
-    __selectors__ = (paginated_rset, sortedrset_selector)
+    __selectors__ = (paginated_rset, sorted_rset)
     
     # number of considered chars to build page links
     nb_chars = 5
@@ -142,9 +144,11 @@
         self.w(u'</div>')
 
 
-def limit_rset_using_paged_nav(self, req, rset, w, forcedisplay=False, show_all_option=True):
+def limit_rset_using_paged_nav(self, req, rset, w, forcedisplay=False,
+                               show_all_option=True, page_size = None):
     showall = forcedisplay or req.form.get('__force_display') is not None
-    nav = not showall and self.vreg.select_component('navigation', req, rset)
+    nav = not showall and self.vreg.select_component('navigation', req, rset,
+                                                     page_size=page_size)
     if nav:
         # get boundaries before component rendering
         start, stop = nav.page_boundaries()
@@ -176,8 +180,8 @@
     # itself
     title = _('contentnavigation_prevnext')
     help = _('contentnavigation_prevnext_description')
-    __selectors__ = (one_line_rset, primaryview_selector,
-                     contextprop_selector, interface_selector)
+    __selectors__ = (one_line_rset, primary_view,
+                     match_context_prop, implement_interface)
     accepts_interfaces = (IPrevNext,)
     context = 'navbottom'
     order = 10
--- a/web/views/old_calendar.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/old_calendar.py	Wed Apr 15 17:36:09 2009 +0200
@@ -11,7 +11,7 @@
 
 from cubicweb.interfaces import ICalendarViews
 from cubicweb.common.utils import date_range
-from cubicweb.common.selectors import interface_selector
+from cubicweb.common.selectors import implement_interface
 from cubicweb.common.registerers import priority_registerer
 from cubicweb.common.view import EntityView
 
@@ -33,7 +33,7 @@
 class _CalendarView(EntityView):
     """base calendar view containing helpful methods to build calendar views"""
     __registerer__ = priority_registerer
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (ICalendarViews,)
     need_navigation = False
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/owl.py	Wed Apr 15 17:36:09 2009 +0200
@@ -0,0 +1,211 @@
+from logilab.mtconverter import TransformError, xml_escape
+
+from cubicweb.common.view import StartupView
+from cubicweb.common.view import EntityView
+
+_ = unicode
+
+OWL_CARD_MAP = {'1': '<rdf:type rdf:resource="&owl;FunctionalProperty"/>',                      
+                '?': '<owl:maxCardinality rdf:datatype="&xsd;int">1</owl:maxCardinality>',
+                '+': '<owl:minCardinality rdf:datatype="&xsd;int">1</owl:minCardinality>',
+                '*': ''
+                }
+
+OWL_TYPE_MAP = {'String': 'xsd:string',
+                'Datetime': 'xsd:dateTime',
+                'Bytes': 'xsd:byte',
+                'Float': 'xsd:float',
+                'Boolean': 'xsd:boolean',
+                'Int': 'xsd:int',
+                'Date':'xsd:date',
+                'Time': 'xsd:time',
+                'Password': 'xsd:byte',
+                'Decimal' : 'xsd:decimal',
+                'Interval': 'xsd:duration'
+                }
+
+OWL_OPENING_ROOT = u'''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE rdf:RDF [
+        <!ENTITY owl "http://www.w3.org/2002/07/owl#" >
+        <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
+]>        
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
+    xmlns:owl="http://www.w3.org/2002/07/owl#"
+    xmlns="http://logilab.org/owl/ontologies/%(appid)s#"
+    xmlns:%(appid)s="http://logilab.org/owl/ontologies/%(appid)s#"
+    xmlns:base="http://logilab.org/owl/ontologies/%(appid)s">
+
+  <owl:Ontology rdf:about="">
+    <rdfs:comment>
+    %(appid)s Cubicweb OWL Ontology                           
+    </rdfs:comment>
+  </owl:Ontology>'''
+
+OWL_CLOSING_ROOT = u'</rdf:RDF>'
+
+DEFAULT_SKIP_RELS = frozenset(('is', 'is_instance_of', 'identity',
+                               'owned_by', 'created_by'))
+
+class OWLView(StartupView):
+    """This view export in owl format schema database. It is the TBOX"""
+    id = 'owl'
+    title = _('owl')
+    templatable = False
+    content_type = 'application/xml' # 'text/xml'
+
+    def call(self, writeprefix=True):
+        skipmeta = int(self.req.form.get('skipmeta', True))
+        if writeprefix:
+            self.w(OWL_OPENING_ROOT % {'appid': self.schema.name})
+        self.visit_schema(skipmeta=skipmeta)
+        if writeprefix:
+            self.w(OWL_CLOSING_ROOT)
+        
+    def visit_schema(self, skiprels=DEFAULT_SKIP_RELS, skipmeta=True):
+        """get a layout for a whole schema"""
+        entities = sorted([eschema for eschema in self.schema.entities()
+                           if not eschema.is_final()])
+        if skipmeta:
+            entities = [eschema for eschema in entities
+                        if not eschema.meta]
+        self.w(u'<!-- classes definition -->')
+        for eschema in entities:
+            self.visit_entityschema(eschema, skiprels)
+            self.w(u'<!-- property definition -->')
+            self.visit_property_schema(eschema, skiprels)
+            self.w(u'<!-- datatype property -->')
+            self.visit_property_object_schema(eschema)
+
+    def visit_entityschema(self, eschema, skiprels=()):
+        """get a layout for an entity OWL schema"""
+        self.w(u'<owl:Class rdf:ID="%s">'% eschema)         
+        self.w(u'<!-- relations -->')    
+        for rschema, targetschemas, role in eschema.relation_definitions():
+            if rschema.type in skiprels:
+                continue
+            if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+                continue
+            for oeschema in targetschemas:
+                label = rschema.type
+                if role == 'subject':
+                    card = rschema.rproperty(eschema, oeschema, 'cardinality')[0]
+                else:
+                    card = rschema.rproperty(oeschema, eschema, 'cardinality')[1]
+                cardtag = OWL_CARD_MAP[card]
+                if cardtag:
+                    self.w(u'''<rdfs:subClassOf>
+ <owl:Restriction>
+  <owl:onProperty rdf:resource="#%s"/>
+  %s
+ </owl:Restriction>
+</rdfs:subClassOf>
+''' % (label, cardtag))
+
+        self.w(u'<!-- attributes -->')
+              
+        for rschema, aschema in eschema.attribute_definitions():
+            if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+                continue
+            aname = rschema.type
+            if aname == 'eid':
+                continue
+            self.w(u'''<rdfs:subClassOf>
+  <owl:Restriction>
+   <owl:onProperty rdf:resource="#%s"/>
+   <rdf:type rdf:resource="&owl;FunctionalProperty"/>
+  </owl:Restriction>
+</rdfs:subClassOf>'''                         
+                   % aname)
+        self.w(u'</owl:Class>')
+    
+    def visit_property_schema(self, eschema, skiprels=()):
+        """get a layout for property entity OWL schema"""
+        for rschema, targetschemas, role in eschema.relation_definitions():
+            if rschema.type in skiprels:
+                continue
+            if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+                continue
+            for oeschema in targetschemas:
+                label = rschema.type
+                self.w(u'''<owl:ObjectProperty rdf:ID="%s">
+ <rdfs:domain rdf:resource="#%s"/>
+ <rdfs:range rdf:resource="#%s"/>
+</owl:ObjectProperty>                                                
+''' % (label, eschema, oeschema.type))
+
+    def visit_property_object_schema(self, eschema):
+        for rschema, aschema in eschema.attribute_definitions():
+            if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+                continue
+            aname = rschema.type
+            if aname == 'eid':
+                continue
+            self.w(u'''<owl:DatatypeProperty rdf:ID="%s">
+  <rdfs:domain rdf:resource="#%s"/>
+  <rdfs:range rdf:resource="%s"/>
+</owl:DatatypeProperty>'''
+                   % (aname, eschema, OWL_TYPE_MAP[aschema.type]))
+
+            
+class OWLABOXView(EntityView):
+    '''This view represents a part of the ABOX for a given entity.'''
+    
+    id = 'owlabox'
+    title = _('owlabox')
+    templatable = False
+    accepts = ('Any',)
+    content_type = 'application/xml' # 'text/xml'
+    
+    def call(self):
+        self.w(OWL_OPENING_ROOT % {'appid': self.schema.name})
+        for i in xrange(self.rset.rowcount):
+            self.cell_call(i, 0)
+        self.w(OWL_CLOSING_ROOT)
+
+    def cell_call(self, row, col, skiprels=DEFAULT_SKIP_RELS):
+        self.wview('owlaboxitem', self.rset, row=row, col=col, skiprels=skiprels)
+
+        
+class OWLABOXItemView(EntityView):
+    '''This view represents a part of the ABOX for a given entity.'''
+    
+    id = 'owlaboxitem'
+    templatable = False
+    accepts = ('Any',)
+    content_type = 'application/xml' # 'text/xml'
+
+    def cell_call(self, row, col, skiprels=DEFAULT_SKIP_RELS):
+        entity = self.complete_entity(row, col)
+        eschema = entity.e_schema
+        self.w(u'<%s rdf:ID="%s">' % (eschema, entity.eid))
+        self.w(u'<!--attributes-->')
+        for rschema, aschema in eschema.attribute_definitions():
+            if rschema.type in skiprels:
+                continue
+            if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+                continue
+            aname = rschema.type
+            if aname == 'eid':
+                continue
+            try:
+                attr = entity.printable_value(aname, format='text/plain')
+                if attr:
+                    self.w(u'<%s>%s</%s>' % (aname, xml_escape(attr), aname))
+            except TransformError:
+                pass
+        self.w(u'<!--relations -->')
+        for rschema, targetschemas, role in eschema.relation_definitions():
+            if rschema.type in skiprels:
+                continue
+            if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
+                continue
+            if role == 'object':
+                attr = 'reverse_%s' % rschema.type 
+            else:
+                attr = rschema.type        
+            for x in getattr(entity, attr):
+                self.w(u'<%s>%s %s</%s>' % (attr, x.id, x.eid, attr))
+        self.w(u'</%s>'% eschema)
+
--- a/web/views/startup.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/startup.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 apply to a result set.
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -26,6 +26,7 @@
     
     def call(self, **kwargs):
         """The default view representing the application's management"""
+        self.req.add_css('cubicweb.manageview.css')
         self.w(u'<div>\n')
         if not self.display_folders():
             self._main_index()
--- a/web/views/tableview.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/tableview.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,7 +2,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -14,8 +14,8 @@
 from cubicweb.common.utils import make_uid
 from cubicweb.common.uilib import toggle_action, limitsize, jsonize, htmlescape
 from cubicweb.common.view import EntityView, AnyRsetView
-from cubicweb.common.selectors import (nonempty_rset,  req_form_params_selector,
-                                    accept_rset_selector)
+from cubicweb.common.selectors import (nonempty_rset,  match_form_params,
+                                    accept_rset)
 from cubicweb.web.htmlwidgets import (TableWidget, TableColumn, MenuWidget,
                                    PopupBoxMenu, BoxLink)
 from cubicweb.web.facet import prepare_facets_rqlst, filter_hiddens
@@ -24,8 +24,29 @@
     id = 'table'
     title = _('table')
     finalview = 'final'
+
+    def form_filter(self, divid, displaycols, displayactions, displayfilter,
+                    hidden=True):
+        rqlst = self.rset.syntax_tree()
+        # union not yet supported
+        if len(rqlst.children) != 1:
+            return ()
+        rqlst.save_state()
+        mainvar, baserql = prepare_facets_rqlst(rqlst, self.rset.args)
+        wdgs = [facet.get_widget() for facet in self.vreg.possible_vobjects(
+            'facets', self.req, self.rset, context='tablefilter',
+            filtered_variable=mainvar)]
+        wdgs = [wdg for wdg in wdgs if wdg is not None]
+        rqlst.recover()
+        if wdgs:
+            self._generate_form(divid, baserql, wdgs, hidden,
+                               vidargs={'displaycols': displaycols,
+                                        'displayactions': displayactions,
+                                        'displayfilter': displayfilter})
+            return self.show_hide_actions(divid, not hidden)
+        return ()
     
-    def generate_form(self, divid, baserql, facets, hidden=True, vidargs={}):
+    def _generate_form(self, divid, baserql, fwidgets, hidden=True, vidargs={}):
         """display a form to filter table's content. This should only
         occurs when a context eid is given
         """
@@ -36,15 +57,13 @@
                html_escape(dumps([divid, 'table', False, vidargs])))
         self.w(u'<fieldset id="%sForm" class="%s">' % (divid, hidden and 'hidden' or ''))
         self.w(u'<input type="hidden" name="divid" value="%s" />' % divid)
-        filter_hiddens(self.w, facets=','.join(facet.id for facet in facets), baserql=baserql)
+        filter_hiddens(self.w, facets=','.join(wdg.facet.id for wdg in fwidgets), baserql=baserql)
         self.w(u'<table class="filter">\n')
         self.w(u'<tr>\n')
-        for facet in facets:
-            wdg = facet.get_widget()
-            if wdg is not None:
-                self.w(u'<td>')
-                wdg.render(w=self.w)
-                self.w(u'</td>\n')
+        for wdg in fwidgets:
+            self.w(u'<td>')
+            wdg.render(w=self.w)
+            self.w(u'</td>\n')
         self.w(u'</tr>\n')
         self.w(u'</table>\n')
         self.w(u'</fieldset>\n')
@@ -72,7 +91,7 @@
         return displaycols
     
     def call(self, title=None, subvid=None, displayfilter=None, headers=None,
-             displaycols=None, displayactions=None, actions=(),
+             displaycols=None, displayactions=None, actions=(), divid=None,
              cellvids=None, cellattrs=None):
         """Dumps a table displaying a composite query
 
@@ -84,7 +103,7 @@
         rset = self.rset
         req = self.req
         req.add_js('jquery.tablesorter.js')
-        req.add_css('cubicweb.tablesorter.css')
+        req.add_css(('cubicweb.tablesorter.css', 'cubicweb.tableview.css'))
         rqlst = rset.syntax_tree()
         # get rql description first since the filter form may remove some
         # necessary information
@@ -93,7 +112,7 @@
         hidden = True
         if not subvid and 'subvid' in req.form:
             subvid = req.form.pop('subvid')
-        divid = req.form.get('divid') or 'rs%s' % make_uid(id(rset))
+        divid = divid or req.form.get('divid') or 'rs%s' % make_uid(id(rset))
         actions = list(actions)
         if mainindex is None:
             displayfilter, displayactions = False, False
@@ -117,22 +136,8 @@
             if title:
                 self.w(u'<h2 class="tableTitle">%s</h2>\n' % title)
             if displayfilter:
-                rqlst.save_state()
-                try:
-                    mainvar, baserql = prepare_facets_rqlst(rqlst, rset.args)
-                except NotImplementedError:
-                    # UNION query
-                    facets = None
-                else:
-                    facets = list(self.vreg.possible_vobjects('facets', req, rset,
-                                                              context='tablefilter',
-                                                              filtered_variable=mainvar))
-                    self.generate_form(divid, baserql, facets, hidden,
-                                       vidargs={'displaycols': displaycols,
-                                                'displayfilter': displayfilter,
-                                                'displayactions': displayactions})
-                    actions += self.show_hide_actions(divid, not hidden)
-                rqlst.recover()
+                actions += self.form_filter(divid, displaycols, displayfilter,
+                                            displayactions)
         elif displayfilter:
             actions += self.show_hide_actions(divid, True)
         self.w(u'<div id="%s"' % divid)
@@ -208,7 +213,6 @@
             else:
                 column.append_renderer(subvid or 'incontext', colindex)
 
-
             if cellattrs and colindex in cellattrs:
                 for name, value in cellattrs[colindex].iteritems():
                     column.add_attr(name,value)
@@ -249,7 +253,7 @@
 
     
 class CellView(EntityView):
-    __selectors__ = (nonempty_rset, accept_rset_selector)
+    __selectors__ = (nonempty_rset, accept_rset)
     
     id = 'cell'
     accepts = ('Any',)
@@ -285,13 +289,13 @@
       displayed with default restrictions set
     """
     id = 'initialtable'
-    __selectors__ = nonempty_rset, req_form_params_selector
+    __selectors__ = nonempty_rset, match_form_params
     form_params = ('actualrql',)
     # should not be displayed in possible view since it expects some specific
     # parameters
     title = None
     
-    def call(self, title=None, subvid=None, headers=None,
+    def call(self, title=None, subvid=None, headers=None, divid=None,
              displaycols=None, displayactions=None):
         """Dumps a table displaying a composite query"""
         actrql = self.req.form['actualrql']
@@ -299,6 +303,8 @@
         displaycols = self.displaycols(displaycols)
         if displayactions is None and 'displayactions' in self.req.form:
             displayactions = True
+        if divid is None and 'divid' in self.req.form:
+            divid = self.req.form['divid']
         self.w(u'<div class="section">')
         if not title and 'title' in self.req.form:
             # pop title so it's not displayed by the table view as well
@@ -307,33 +313,19 @@
             self.w(u'<h2>%s</h2>\n' % title)
         mainindex = self.main_var_index()
         if mainindex is not None:
-            rqlst = self.rset.syntax_tree()
-            # union not yet supported
-            if len(rqlst.children) == 1:
-                rqlst.save_state()
-                mainvar, baserql = prepare_facets_rqlst(rqlst, self.rset.args)
-                facets = list(self.vreg.possible_vobjects('facets', self.req, self.rset,
-                                                          context='tablefilter',
-                                                          filtered_variable=mainvar))
-                
-                if facets:
-                    divid = self.req.form.get('divid', 'filteredTable')
-                    self.generate_form(divid, baserql, facets, 
-                                       vidargs={'displaycols': displaycols,
-                                                'displayactions': displayactions,
-                                                'displayfilter': True})
-                    actions = self.show_hide_actions(divid, False)
-                rqlst.recover()
+            actions = self.form_filter(divid, displaycols, displayactions, True)
+        else:
+            actions = ()
         if not subvid and 'subvid' in self.req.form:
             subvid = self.req.form.pop('subvid')
         self.view('table', self.req.execute(actrql),
                   'noresult', w=self.w, displayfilter=False, subvid=subvid,
                   displayactions=displayactions, displaycols=displaycols,
-                  actions=actions, headers=headers)
+                  actions=actions, headers=headers, divid=divid)
         self.w(u'</div>\n')
 
 
-class EditableInitiableTableView(InitialTableView):
+class EditableInitialTableTableView(InitialTableView):
     id = 'editable-initialtable'
     finalview = 'editable-final'
     
--- a/web/views/tabs.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/tabs.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,73 +1,174 @@
 """base classes to handle tabbed views
 
 :organization: Logilab
-:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+: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 monkeypatch
 from logilab.mtconverter import html_escape
 
 from cubicweb import NoSelectableObject, role
+from cubicweb.common.view import EntityView 
 from cubicweb.common.selectors import has_related_entities
-from cubicweb.common.view import EntityView
+from cubicweb.common.utils import HTMLHead
+from cubicweb.common.uilib import rql_for_eid
+
+from cubicweb.web.views.basecontrollers import JSonController
+
+
+class LazyViewMixin(object):
+    """provides two convenience methods for the tab machinery
+    can also be used to lazy-load arbitrary views
+    caveat : lazyview is not recursive, i.e : you can't (successfully)
+    lazyload a view that in turns does the same
+    """
+
+    def _prepare_bindings(self, vid, reloadable):
+        self.req.html_headers.add_onload(u"""
+  jQuery('#lazy-%(vid)s').bind('%(event)s', function(event) {
+     load_now('#lazy-%(vid)s', '#%(vid)s-hole', %(reloadable)s);
+  });""" % {'event': 'load_%s' % vid, 'vid': vid,
+            'reloadable' : str(reloadable).lower()})
 
-class TabsMixIn(object):
-    
-    def active_tab(self, default):
-        cookie = self.req.get_cookie()
-        activetab = cookie.get('active_tab')
+    def lazyview(self, vid, rql=None, eid=None, rset=None, static=False,
+                 reloadable=False, show_spinbox=True, w=None):
+        """a lazy version of wview
+        first version only support lazy viewing for an entity at a time
+        """
+        assert rql or eid or rset or static, \
+            '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'}
+        if rql:
+            urlparams['rql'] = rql
+        elif eid:
+            urlparams['rql'] = rql_for_eid(eid)
+        elif rset:
+            urlparams['rql'] = rset.printable_rql()
+        w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
+            vid, html_escape(self.build_url('json', **urlparams))))
+        if show_spinbox:
+            w(u'<img src="data/loading.gif" id="%s-hole" alt="%s"/>'
+              % (vid, self.req._('loading')))
+        w(u'</div>')
+        self._prepare_bindings(vid, reloadable)
+
+    def forceview(self, vid):
+        """trigger an event that will force immediate loading of the view
+        on dom readyness
+        """
+        self.req.add_js('cubicweb.lazy.js')
+        self.req.html_headers.add_onload("trigger_load('%s');" % vid)
+
+
+class TabsMixin(LazyViewMixin):
+    """a tab mixin
+    """
+
+    @property
+    def cookie_name(self):
+        return str('%s_active_tab' % self.config.appid)
+
+    def active_tab(self, tabs, default):
+        cookies = self.req.get_cookie()
+        cookiename = self.cookie_name
+        activetab = cookies.get(cookiename)
         if activetab is None:
-            cookie['active_tab'] = default
-            self.req.set_cookie(cookie, 'active_tab')
-            return default
-        return activetab.value
+            cookies[cookiename] = default
+            self.req.set_cookie(cookies, cookiename)
+            tab = default
+        else:
+            tab = activetab.value
+        return tab in tabs and tab or default
 
-    def render_tabs(self, tabs, default, **kwargs):
+    def prune_tabs(self, tabs):
+        selected_tabs = []
+        for tab in tabs:
+            try:
+                self.vreg.select_view(tab, self.req, self.rset)
+                selected_tabs.append(tab)
+            except NoSelectableObject:
+                continue
+        return selected_tabs
+
+    def render_tabs(self, tabs, default, entity):
         self.req.add_css('ui.tabs.css')
-        self.req.add_js( ('ui.core.js', 'ui.tabs.js', 'cubicweb.tabs.js') )
-        active_tab = self.active_tab(default)
-        self.req.html_headers.add_post_inline_script(u"""
- jQuery(document).ready(function() {
-   jQuery('#entity-tabs > ul').tabs( { selected: %(tabindex)s });
-   set_tab('%(vid)s');
- });
- """ % {'tabindex' : tabs.index(active_tab),
-        'vid'      : active_tab})
+        self.req.add_js(('ui.core.js', 'ui.tabs.js',
+                         'cubicweb.ajax.js', 'cubicweb.tabs.js', 'cubicweb.lazy.js'))
+        # tabbed views do no support concatenation
+        # hence we delegate to the default tab
+        form = self.req.form
+        if form.get('vid') == 'primary':
+            entity.view(default, w=self.w)
+            return
+        rql = form.get('rql')
+        if rql:
+            self.req.execute(rql).get_entity(0,0).view(default, w=self.w)
+            return
+        # prune tabs : not all are to be shown
+        tabs = self.prune_tabs(tabs)
+        # select a tab
+        active_tab = self.active_tab(tabs, default)
         # build the html structure
         w = self.w
-        w(u'<div id="entity-tabs">')
+        w(u'<div id="entity-tabs-%s">' % entity.eid)
         w(u'<ul>')
-        tabviews = []
         for tab in tabs:
-            try:
-                tabview = self.vreg.select_view(tab, self.req, self.rset, **kwargs)
-            except NoSelectableObject:
-                continue
-            tabviews.append(tabview)
             w(u'<li>')
             w(u'<a href="#as-%s">' % tab)
-            w(u'<span onclick="set_tab(\'%s\')">' % tab)
+            w(u'<span onclick="set_tab(\'%s\', \'%s\')">' % (tab, self.cookie_name))
             w(self.req._(tab))
             w(u'</span>')
             w(u'</a>')
             w(u'</li>')
         w(u'</ul>')
         w(u'</div>')
-        # XXX ajaxify !
-        for tabview in tabviews:
-            w(u'<div id="as-%s">' % tabview.id)
-            tabview.dispatch(w=self.w, **kwargs)
-            w(u'</div>')    
+        for tab in tabs:
+            w(u'<div id="as-%s">' % tab)
+            self.lazyview(tab, eid=entity.eid)
+            w(u'</div>')
+        # call the set_tab() JS function *after* each tab is generated
+        # because the callback binding needs to be done before
+        self.req.html_headers.add_onload(u"""
+   jQuery('#entity-tabs-%(eeid)s > ul').tabs( { selected: %(tabindex)s });
+   set_tab('%(vid)s', '%(cookiename)s');
+ """ % {'tabindex'   : tabs.index(active_tab),
+        'vid'        : active_tab,
+        'eeid'       : entity.eid,
+        'cookiename' : self.cookie_name})
+
 
-  
-class EntityRelationTab(EntityView):
+class EntityRelatedTab(EntityView):
+    """A view you should inherit from leftmost,
+    to wrap another actual view displaying entity related stuff.
+    Such a view _must_ provide the rtype, target and vid attributes :
+
+    Example :
+
+    class ProjectScreenshotsView(EntityRelationView):
+        '''display project's screenshots'''
+        id = title = _('projectscreenshots')
+        accepts = ('Project',)
+        rtype = 'screenshot'
+        target = 'object'
+        vid = 'gallery'
+        __selectors__ = EntityRelationView.__selectors__ + (one_line_rset,)
+
+    This is the view we want to have in a tab, only if there is something to show.
+    Then, just define as below, and declare this being the tab content :
+
+    class ProjectScreenshotTab(EntityRelatedTab, ProjectScreenshotsView):
+        id = 'screenshots_tab'
+    """
     __selectors__ = EntityView.__selectors__ + (has_related_entities,)
     vid = 'list'
 
     def cell_call(self, row, col):
-        rset = self.rset.get_entity(row, col).related(self.rtype, role(self))
+        rset = self.entity(row, col).related(self.rtype, role(self))
         self.w(u'<div class="mainInfo">')
         self.wview(self.vid, rset, 'noresult')
         self.w(u'</div>')
--- a/web/views/timeline.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/timeline.py	Wed Apr 15 17:36:09 2009 +0200
@@ -14,7 +14,7 @@
 
 from cubicweb.interfaces import ICalendarable
 from cubicweb.common.view import EntityView, StartupView
-from cubicweb.common.selectors import interface_selector
+from cubicweb.common.selectors import implement_interface
 
 
 # 
@@ -28,7 +28,7 @@
     templatable = False
     content_type = 'application/json'
 
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (ICalendarable,)
     date_fmt = '%Y/%m/%d'
     
@@ -103,7 +103,7 @@
 class TimelineView(TimelineViewMixIn, EntityView):
     """builds a cubicweb timeline widget node"""
     id = 'timeline'
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (ICalendarable,)
     need_navigation = False
     def call(self, tlunit=None):
--- a/web/views/timetable.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/timetable.py	Wed Apr 15 17:36:09 2009 +0200
@@ -9,7 +9,7 @@
 
 from cubicweb.interfaces import ITimetableViews
 from cubicweb.common.utils import date_range
-from cubicweb.common.selectors import interface_selector
+from cubicweb.common.selectors import implement_interface
 from cubicweb.common.view import AnyRsetView
 
 
@@ -25,7 +25,7 @@
 class TimeTableView(AnyRsetView):
     id = 'timetable'
     title = _('timetable')
-    __selectors__ = (interface_selector,)
+    __selectors__ = (implement_interface,)
     accepts_interfaces = (ITimetableViews,)
     need_navigation = False
 
--- a/web/views/treeview.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/treeview.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,53 +1,61 @@
-from logilab.mtconverter import html_escape
+"""Set of tree-building widgets, based on jQuery treeview plugin
 
+: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.interfaces import ITree
-from cubicweb.common.selectors import interface_selector, yes
+from cubicweb.common.selectors import implement_interface, yes
+from cubicweb.common.utils import make_uid
 from cubicweb.common.view import EntityView
 
-from cubicweb.web.views.baseviews import OneLineView
+def treecookiename(treeid):
+    return str('treestate-%s' % treeid)
 
 class TreeView(EntityView):
     id = 'treeview'
     accepts = ('Any',)
-    fstree = False
     itemvid = 'treeitemview'
-    
-    def call(self, subvid=None):
-        if subvid is None and 'subvid' in self.req.form:
-            subvid = self.req.form.pop('subvid') # consume it
+    css_classes = 'treeview widget'
+    title = _('tree view')
+
+    def call(self, subvid=None, treeid=None, initial_load=True):
         if subvid is None:
-            subvid = 'oneline'
-        self.req.add_css('jquery.treeview.css')
-        self.req.add_js(('cubicweb.ajax.js', 'jquery.treeview.js', 'cubicweb.widgets.js'))
-        css_classes = 'treeview widget'
-        if self.fstree:
-            css_classes += ' filetree'
-        # XXX noautoload is a quick hack to avoid treeview to be rebuilt
-        #     after a json query and avoid double toggling bugs.
-        #     Need to find a way to do that cleanly.
-        if 'noautoload' in self.req.form:
-            self.w(u'<ul class="%s" cubicweb:wdgtype="TreeView">' % css_classes)
-        else:
-            self.w(u'<ul class="%s" cubicweb:loadtype="auto" cubicweb:wdgtype="TreeView">'
-                   % css_classes)
+            if 'subvid' in self.req.form:
+                subvid = self.req.form.pop('subvid') # consume it
+            else:
+                subvid = 'oneline'
+        if treeid is None:
+            if 'treeid' in self.req.form:
+                treeid = self.req.form.pop('treeid')
+            else:
+                treeid = make_uid('throw away uid')
+                self.warning('Tree state won\'t be properly restored after next reload')
+        if initial_load:
+            self.req.add_css('jquery.treeview.css')
+            self.req.add_js(('cubicweb.ajax.js', 'jquery.treeview.js'))
+            self.req.html_headers.add_onload(u"""
+                 jQuery("#tree-%s").treeview({toggle: toggleTree,
+                                              prerendered: true});""" % treeid)
+        self.w(u'<ul id="tree-%s" class="%s">' % (treeid, self.css_classes))
         for rowidx in xrange(len(self.rset)):
             self.wview(self.itemvid, self.rset, row=rowidx, col=0,
-                       vid=subvid, parentvid=self.id)
+                       vid=subvid, parentvid=self.id, treeid=treeid)
         self.w(u'</ul>')
-        
 
 class FileTreeView(TreeView):
     """specific version of the treeview to display file trees
     """
     id = 'filetree'
-    fstree = True
+    css_classes = 'treeview widget filetree'
+    title = _('file tree view')
 
-    def call(self, subvid=None):
-        super(FileTreeView, self).call(subvid='filetree-oneline')
+    def call(self, subvid=None, treeid=None, initial_load=True):
+        super(FileTreeView, self).call(treeid=treeid, subvid='filetree-oneline', initial_load=initial_load)
 
-
-
-class FileItemInnerView(OneLineView):
+class FileItemInnerView(EntityView):
     """inner view used by the TreeItemView instead of oneline view
 
     This view adds an enclosing <span> with some specific CSS classes
@@ -58,10 +66,10 @@
     def cell_call(self, row, col):
         entity = self.entity(row, col)
         if ITree.is_implemented_by(entity.__class__) and not entity.is_leaf():
-            self.w(u'<span class="folder">%s</span>' % entity.view('oneline'))
+            self.w(u'<div class="folder">%s</div>\n' % entity.view('oneline'))
         else:
             # XXX define specific CSS classes according to mime types
-            self.w(u'<span class="file">%s</span>' % entity.view('oneline'))
+            self.w(u'<div class="file">%s</div>\n' % entity.view('oneline'))
 
 
 class DefaultTreeViewItemView(EntityView):
@@ -69,53 +77,104 @@
     """
     id = 'treeitemview'
     accepts = ('Any',)
-    
-    def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
+
+    def cell_call(self, row, col, vid='oneline', parentvid='treeview', treeid=None):
+        assert treeid is not None
         entity = self.entity(row, col)
         itemview = self.view(vid, self.rset, row=row, col=col)
         if row == len(self.rset) - 1:
             self.w(u'<li class="last">%s</li>' % itemview)
         else:
-            self.w(u'<li><span>%s</span></li>' % itemview)
+            self.w(u'<li>%s</li>' % itemview)
 
 
 class TreeViewItemView(EntityView):
     """specific treeitem view for entities which implement ITree
-    
+
     (each item should be exandable if it's not a tree leaf)
     """
     id = 'treeitemview'
     # XXX append yes to make sure we get an higher score than
     #     the default treeitem view
-    __selectors__ = (interface_selector, yes)
+    __selectors__ = (implement_interface, yes)
     accepts_interfaces = (ITree,)
-    
-    def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
+
+    def open_state(self, eeid, treeid):
+        cookies = self.req.get_cookie()
+        treestate = cookies.get(treecookiename(treeid))
+        if treestate:
+            return str(eeid) in treestate.value.split(';')
+        return False
+
+    def cell_call(self, row, col, treeid, vid='oneline', parentvid='treeview'):
+        w = self.w
         entity = self.entity(row, col)
-        cssclasses = []
+        liclasses = []
         is_leaf = False
-        if row == len(self.rset) - 1:
-            is_leaf = True
+        is_last = row == len(self.rset) - 1
+        is_open = self.open_state(entity.eid, treeid)
         if not hasattr(entity, 'is_leaf') or entity.is_leaf():
-            if is_leaf : cssclasses.append('last')
-            self.w(u'<li class="%s">' % u' '.join(cssclasses))
+            if is_last:
+                liclasses.append('last')
+            w(u'<li class="%s">' % u' '.join(liclasses))
         else:
             rql = entity.children_rql() % {'x': entity.eid}
             url = html_escape(self.build_url('json', rql=rql, vid=parentvid,
                                              pageid=self.req.pageid,
-                                             subvid=vid,
-                                             noautoload=True))
-            cssclasses.append('expandable')
-            divclasses = ['hitarea expandable-hitarea']
-            if is_leaf :
-                cssclasses.append('lastExpandable')
-                divclasses.append('lastExpandable-hitarea')
-            self.w(u'<li cubicweb:loadurl="%s" class="%s">' % (url, u' '.join(cssclasses)))
-            self.w(u'<div class="%s"> </div>' % u' '.join(divclasses))
-                
+                                             treeid=treeid,
+                                             subvid=vid))
+            divclasses = ['hitarea']
+            if is_open:
+                liclasses.append('collapsable')
+                divclasses.append('collapsable-hitarea')
+            else:
+                liclasses.append('expandable')
+                divclasses.append('closed-hitarea expandable-hitarea')
+            if is_last:
+                if is_open:
+                    liclasses.append('lastCollapsable')
+                    divclasses.append('lastCollapsable-hitarea')
+                else:
+                    liclasses.append('lastExpandable')
+                    divclasses.append('lastExpandable-hitarea')
+            if is_open:
+                w(u'<li class="%s">' % u' '.join(liclasses))
+            else:
+                w(u'<li cubicweb:loadurl="%s" class="%s">' % (url, u' '.join(liclasses)))
+            if is_leaf:
+                divtail = ''
+            else:
+                divtail = ''' onclick="async_remote_exec('node_clicked', '%s', '%s')"''' % \
+                    (treeid, entity.eid)
+            w(u'<div class="%s"%s></div>' % (u' '.join(divclasses), divtail))
+
             # add empty <ul> because jquery's treeview plugin checks for
             # sublists presence
-            self.w(u'<ul class="placeholder"><li>place holder</li></ul>')
+            if not is_open:
+                w(u'<ul class="placeholder"><li>place holder</li></ul>')
+        # the local node info
         self.wview(vid, self.rset, row=row, col=col)
-        self.w(u'</li>')
+        if is_open: # recurse if needed
+            self.wview(parentvid, self.req.execute(rql), treeid=treeid, initial_load=False)
+        w(u'</li>')
+
+from logilab.common.decorators import monkeypatch
+from cubicweb.web.views.basecontrollers import JSonController
 
+@monkeypatch(JSonController)
+def js_node_clicked(self, treeid, nodeeid):
+    """add/remove eid in treestate cookie"""
+    cookies = self.req.get_cookie()
+    statename = treecookiename(treeid)
+    treestate = cookies.get(statename)
+    if treestate is None:
+        cookies[statename] = nodeeid
+        self.req.set_cookie(cookies, statename)
+    else:
+        marked = set(filter(None, treestate.value.split(';')))
+        if nodeeid in marked:
+            marked.remove(nodeeid)
+        else:
+            marked.add(nodeeid)
+        cookies[statename] = ';'.join(marked)
+        self.req.set_cookie(cookies, statename)
--- a/web/views/wdoc.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/views/wdoc.py	Wed Apr 15 17:36:09 2009 +0200
@@ -15,7 +15,7 @@
 from logilab.common.changelog import ChangeLog
 from logilab.mtconverter import CHARSET_DECL_RGX
 
-from cubicweb.common.selectors import req_form_params_selector
+from cubicweb.common.selectors import match_form_params
 from cubicweb.common.view import StartupView
 from cubicweb.common.uilib import rest_publish
 from cubicweb.web import NotFound
@@ -85,7 +85,7 @@
 # help views ##################################################################
 
 class InlineHelpView(StartupView):
-    __selectors__ = (req_form_params_selector,)
+    __selectors__ = (match_form_params,)
     form_params = ('fid',)
     id = 'wdoc'
     title = _('site documentation')
@@ -163,7 +163,7 @@
 
 
 class InlineHelpImageView(StartupView):
-    __selectors__ = (req_form_params_selector,)
+    __selectors__ = (match_form_params,)
     form_params = ('fid',)
     id = 'wdocimages'
     binary = True
--- a/web/webconfig.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/webconfig.py	Wed Apr 15 17:36:09 2009 +0200
@@ -1,7 +1,7 @@
 """common web configuration for twisted/modpython applications
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -349,6 +349,6 @@
         stream.close()
 
     def static_file_del(self, rpath):
-        if static_file_exists(rpath):
+        if self.static_file_exists(rpath):
             os.remove(join(self.static_directory, rpath))
         
--- a/web/webctl.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/webctl.py	Wed Apr 15 17:36:09 2009 +0200
@@ -2,12 +2,12 @@
 web configuration
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
 
-from cubicweb.toolsutils import CommandHandler
+from cubicweb.toolsutils import CommandHandler, confirm
 
 
 class WebCreateHandler(CommandHandler):
@@ -22,7 +22,10 @@
             print '** repository server configuration'
             print '-' * 72
             config.input_config('pyro-client', inputlevel)
-    
+        if confirm('allow anonymous access', False):
+           config.global_set_option('anonymous-user', 'anon') 
+           config.global_set_option('anonymous-password', 'anon') 
+        
     def postcreate(self):
         """hooks called once application's initialization has been completed"""
         
--- a/web/widgets.py	Thu Jan 15 10:13:25 2009 +0100
+++ b/web/widgets.py	Wed Apr 15 17:36:09 2009 +0200
@@ -449,7 +449,7 @@
 
 
 class YesNoRadioWidget(CheckBoxWidget):
-    
+    html_attributes = Widget.html_attributes | set(('disabled',))
     def _edit_render(self, entity):
         value = self.current_value(entity)
         dvalue = self.current_display_value(entity)
@@ -486,11 +486,15 @@
                     wdgs.append(ewdg.edit_render(entity, includehelp=True))
                     wdgs.append(u'<br/>')
             wdgs.append(u'</div>')
-        if entity.has_eid() and not self.required(entity):
-            # trick to be able to delete an uploaded file
-            wdgs.append(u'<br/>')
-            wdgs.append(checkbox(eid_param('__%s_detach' % self.rname, entity.eid), False))
-            wdgs.append(req._('detach attached file'))
+        if entity.has_eid():
+            if not self.required(entity):
+                # trick to be able to delete an uploaded file
+                wdgs.append(u'<br/>')
+                wdgs.append(checkbox(eid_param('__%s_detach' % self.rname, entity.eid), False))
+                wdgs.append(req._('detach attached file %s' % entity.dc_title()))
+            else:
+                wdgs.append(u'<br/>')
+                wdgs.append(req._('currently attached file: %s' % entity.dc_title()))
         return '\n'.join(wdgs)
     
     def _edit_render(self, entity):
@@ -585,7 +589,7 @@
         self.vocabfunc = vocabfunc
 
     def vocabulary(self, entity):
-        choices = self.vocabfunc(entity)
+        choices = self.vocabfunc(entity=entity)
         if self.sort:
             choices = sorted(choices)
         if self.rschema.rproperty(self.subjtype, self.objtype, 'internationalizable'):
@@ -732,12 +736,13 @@
         formatstr = req.property_value(self.format_key)
         return now().strftime(formatstr)
 
-    def add_localized_infos(self, req):
+    @classmethod
+    def add_localized_infos(cls, req):
         """inserts JS variables defining localized months and days"""
         # import here to avoid dependancy from cubicweb-common to simplejson
         _ = req._
-        monthnames = [_(mname) for mname in self.monthnames]
-        daynames = [_(dname) for dname in self.daynames]
+        monthnames = [_(mname) for mname in cls.monthnames]
+        daynames = [_(dname) for dname in cls.daynames]
         req.html_headers.define_var('MONTHNAMES', monthnames)
         req.html_headers.define_var('DAYNAMES', daynames)