backport oldstable stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 16 May 2011 16:25:33 +0200
branchstable
changeset 7389 c2b29631c1a3
parent 7384 69aa88765db5 (diff)
parent 7388 dc319ece0bd6 (current diff)
child 7390 be2fffc9ec17
backport oldstable
--- a/.hgtags	Mon May 16 16:24:00 2011 +0200
+++ b/.hgtags	Mon May 16 16:25:33 2011 +0200
@@ -188,5 +188,15 @@
 77318f1ec4aae3523d455e884daf3708c3c79af7 cubicweb-debian-version-3.11.1-1
 56ae3cd5f8553678a2b1d4121b61241598d0ca68 cubicweb-version-3.11.2
 954b5b51cd9278eb45d66be1967064d01ab08453 cubicweb-debian-version-3.11.2-1
+fd502219eb76f4bfd239d838a498a1d1e8204baf cubicweb-version-3.12.0
+92b56939b7c77bbf443b893c495a20f19bc30702 cubicweb-debian-version-3.12.0-1
+59701627adba73ee97529f6ea0e250a0f3748e32 cubicweb-version-3.12.1
+07e2c9c7df2617c5ecfa84cb819b3ee8ef91d1f2 cubicweb-debian-version-3.12.1-1
+5a9b6bc5653807500c30a7eb0e95b90fd714fec3 cubicweb-version-3.12.2
+6d418fb3ffed273562aae411efe323d5138b592a cubicweb-debian-version-3.12.2-1
 b7a124f9aed2c7c9c86c6349ddd9f0a07023f0ca cubicweb-version-3.11.3
 b3c6702761a18a41fdbb7bc1083f92aefce07765 cubicweb-debian-version-3.11.3-1
+e712bc6f1f71684f032bfcb9bb151a066c707dec cubicweb-version-3.12.3
+ba8fe4f2e408c3fdf6c297cd42c2577dcac50e71 cubicweb-debian-version-3.12.3-1
+5cd0dbc26882f60e3f11ec55e7f058d94505e7ed cubicweb-version-3.12.4
+7c4d34a5ec57f927a70cbc7af7fa8310c847ac42 cubicweb-debian-version-3.12.4-1
--- a/__pkginfo__.py	Mon May 16 16:24:00 2011 +0200
+++ b/__pkginfo__.py	Mon May 16 16:25:33 2011 +0200
@@ -22,7 +22,7 @@
 
 modname = distname = "cubicweb"
 
-numversion = (3, 11, 3)
+numversion = (3, 12, 4)
 version = '.'.join(str(num) for num in numversion)
 
 description = "a repository of entities / relations for knowledge management"
@@ -43,7 +43,7 @@
     'logilab-common': '>= 0.55.2',
     'logilab-mtconverter': '>= 0.8.0',
     'rql': '>= 0.28.0',
-    'yams': '>= 0.30.4',
+    'yams': '>= 0.32.0',
     'docutils': '>= 0.6',
     #gettext                    # for xgettext, msgcat, etc...
     # web dependancies
@@ -52,7 +52,7 @@
     'Twisted': '',
     # XXX graphviz
     # server dependencies
-    'logilab-database': '>= 1.4.0',
+    'logilab-database': '>= 1.5.0',
     'pysqlite': '>= 2.5.5', # XXX install pysqlite2
     }
 
--- a/cwconfig.py	Mon May 16 16:24:00 2011 +0200
+++ b/cwconfig.py	Mon May 16 16:25:33 2011 +0200
@@ -1070,9 +1070,10 @@
     def instance_md5_version(self):
         import hashlib
         infos = []
-        for pkg in self.cubes():
+        for pkg in sorted(self.cubes()):
             version = self.cube_version(pkg)
             infos.append('%s-%s' % (pkg, version))
+        infos.append('cubicweb-%s' % str(self.cubicweb_version()))
         return hashlib.md5(';'.join(infos)).hexdigest()
 
     def load_configuration(self):
--- a/cwctl.py	Mon May 16 16:24:00 2011 +0200
+++ b/cwctl.py	Mon May 16 16:25:33 2011 +0200
@@ -905,6 +905,7 @@
                 scripts, args = self.cmdline_parser.largs[1:], self.cmdline_parser.rargs
                 for script in scripts:
                     mih.cmd_process_script(script, scriptargs=args)
+                    mih.commit()
             else:
                 mih.interactive_shell()
         finally:
--- a/cwvreg.py	Mon May 16 16:24:00 2011 +0200
+++ b/cwvreg.py	Mon May 16 16:25:33 2011 +0200
@@ -312,6 +312,10 @@
         kwargs['clear'] = True
         super(ETypeRegistry, self).register(obj, **kwargs)
 
+    def iter_classes(self):
+        for etype in self.vreg.schema.entities():
+            yield self.etype_class(etype)
+
     @cached
     def parent_classes(self, etype):
         if etype == 'Any':
@@ -369,6 +373,16 @@
         cls.__initialize__(self.schema)
         return cls
 
+    def fetch_attrs(self, targettypes):
+        """return intersection of fetch_attrs of each entity type in
+        `targettypes`
+        """
+        fetchattrs_list = []
+        for ttype in targettypes:
+            etypecls = self.etype_class(ttype)
+            fetchattrs_list.append(set(etypecls.fetch_attrs))
+        return reduce(set.intersection, fetchattrs_list)
+
 VRegistry.REGISTRY_FACTORY['etypes'] = ETypeRegistry
 
 
@@ -835,18 +849,24 @@
         return self['views'].select(__vid, req, rset=rset, **kwargs)
 
 
+import decimal
 from datetime import datetime, date, time, timedelta
 
-YAMS_TO_PY = {
-    'Boolean':  bool,
+YAMS_TO_PY = { # XXX unify with yams.constraints.BASE_CONVERTERS?
     'String' :  unicode,
+    'Bytes':    Binary,
     'Password': str,
-    'Bytes':    Binary,
+
+    'Boolean':  bool,
     'Int':      int,
     'Float':    float,
-    'Date':     date,
-    'Datetime': datetime,
-    'Time':     time,
-    'Interval': timedelta,
+    'Decimal':  decimal.Decimal,
+
+    'Date':       date,
+    'Datetime':   datetime,
+    'TZDatetime': datetime,
+    'Time':       time,
+    'TZTime':     time,
+    'Interval':   timedelta,
     }
 
--- a/dataimport.py	Mon May 16 16:24:00 2011 +0200
+++ b/dataimport.py	Mon May 16 16:25:33 2011 +0200
@@ -133,7 +133,7 @@
     """
     for idx, item in enumerate(iterable):
         yield item
-        if idx % number:
+        if not idx % number:
             func()
     func()
 
--- a/debian/changelog	Mon May 16 16:24:00 2011 +0200
+++ b/debian/changelog	Mon May 16 16:25:33 2011 +0200
@@ -1,3 +1,33 @@
+cubicweb (3.12.4-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Wed, 11 May 2011 12:28:42 +0200
+
+cubicweb (3.12.3-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Thu, 05 May 2011 16:21:33 +0200
+
+cubicweb (3.12.2-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Nicolas Chauvat <nicolas.chauvat@logilab.fr>  Mon, 11 Apr 2011 22:15:21 +0200
+
+cubicweb (3.12.1-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Wed, 06 Apr 2011 23:25:12 +0200
+
+cubicweb (3.12.0-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Alexandre Fayolle <alexandre.fayolle@logilab.fr>  Fri, 01 Apr 2011 15:59:37 +0200
+
 cubicweb (3.11.3-1) unstable; urgency=low
 
   * new upstream release
@@ -6,7 +36,7 @@
 
 cubicweb (3.11.2-1) unstable; urgency=low
 
-  * new upstream release 
+  * new upstream release
 
  -- Nicolas Chauvat <nicolas.chauvat@logilab.fr>  Mon, 28 Mar 2011 19:18:54 +0200
 
--- a/debian/control	Mon May 16 16:24:00 2011 +0200
+++ b/debian/control	Mon May 16 16:25:33 2011 +0200
@@ -33,7 +33,7 @@
 Conflicts: cubicweb-multisources
 Replaces: cubicweb-multisources
 Provides: cubicweb-multisources
-Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (>= 1.4.0), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2
+Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (>= 1.5.0), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2
 Recommends: pyro (<< 4.0.0), cubicweb-documentation (= ${source:Version})
 Description: server part of the CubicWeb framework
  CubicWeb is a semantic web application framework.
@@ -97,7 +97,7 @@
 Package: cubicweb-common
 Architecture: all
 XB-Python-Version: ${python:Versions}
-Depends: ${misc:Depends}, ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.8.0), python-logilab-common (>= 0.55.2), python-yams (>= 0.30.4), python-rql (>= 0.28.0), python-lxml
+Depends: ${misc:Depends}, ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.8.0), python-logilab-common (>= 0.55.2), python-yams (>= 0.32.0), python-rql (>= 0.28.0), python-lxml
 Recommends: python-simpletal (>= 4.0), python-crypto
 Conflicts: cubicweb-core
 Replaces: cubicweb-core
--- a/devtools/__init__.py	Mon May 16 16:24:00 2011 +0200
+++ b/devtools/__init__.py	Mon May 16 16:25:33 2011 +0200
@@ -384,7 +384,7 @@
 
 
     def get_cnx(self):
-        """return Connection object ont he current repository"""
+        """return Connection object on the current repository"""
         from cubicweb.dbapi import in_memory_cnx
         repo = self.get_repo()
         sources = self.config.sources()
--- a/devtools/fill.py	Mon May 16 16:24:00 2011 +0200
+++ b/devtools/fill.py	Mon May 16 16:25:33 2011 +0200
@@ -1,5 +1,5 @@
 # -*- coding: iso-8859-1 -*-
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -152,6 +152,8 @@
         base = datetime(randint(2000, 2004), randint(1, 12), randint(1, 28), 11, index%60)
         return self._constrained_generate(entity, attrname, base, timedelta(hours=1), index)
 
+    generate_tzdatetime = generate_datetime # XXX implementation should add a timezone
+
     def generate_date(self, entity, attrname, index):
         """generates a random date (format is 'yyyy-mm-dd')"""
         base = date(randint(2000, 2010), 1, 1) + timedelta(randint(1, 365))
@@ -166,6 +168,8 @@
         """generates a random time (format is ' HH:MM')"""
         return time(11, index%60) #'11:%02d' % (index % 60)
 
+    generate_tztime = generate_time # XXX implementation should add a timezone
+
     def generate_bytes(self, entity, attrname, index, format=None):
         fakefile = Binary("%s%s" % (attrname, index))
         fakefile.filename = u"file_%s" % attrname
@@ -441,7 +445,7 @@
         constraints = [c for c in rdef.constraints
                        if isinstance(c, RQLConstraint)]
         if constraints:
-            restrictions = ', '.join(c.restriction for c in constraints)
+            restrictions = ', '.join(c.expression for c in constraints)
             q += ', %s' % restrictions
             # restrict object eids if possible
             # XXX the attempt to restrict below in completely wrong
--- a/devtools/qunit.py	Mon May 16 16:24:00 2011 +0200
+++ b/devtools/qunit.py	Mon May 16 16:25:33 2011 +0200
@@ -5,7 +5,7 @@
 from Queue import Queue, Empty
 from subprocess import Popen, check_call, CalledProcessError
 from shutil import rmtree, copy as copyfile
-from uuid import uuid4 
+from uuid import uuid4
 
 # imported by default to simplify further import statements
 from logilab.common.testlib import unittest_main, with_tempdir, InnerTest, Tags
--- a/devtools/repotest.py	Mon May 16 16:24:00 2011 +0200
+++ b/devtools/repotest.py	Mon May 16 16:25:33 2011 +0200
@@ -371,8 +371,13 @@
 _orig_select_principal = rqlannotation._select_principal
 
 def _select_principal(scope, relations):
+    def sort_key(something):
+        try:
+            return something.r_type
+        except AttributeError:
+            return (something[0].r_type, something[1])
     return _orig_select_principal(scope, relations,
-                                  _sort=lambda rels: sorted(rels, key=lambda x: x.r_type))
+                                  _sort=lambda rels: sorted(rels, key=sort_key))
 
 try:
     from cubicweb.server.msplanner import PartPlanInformation
--- a/devtools/testlib.py	Mon May 16 16:24:00 2011 +0200
+++ b/devtools/testlib.py	Mon May 16 16:25:33 2011 +0200
@@ -30,6 +30,7 @@
 from math import log
 from contextlib import contextmanager
 from warnings import warn
+from types import NoneType
 
 import yams.schema
 
@@ -37,16 +38,15 @@
 from logilab.common.pytest import nocoverage, pause_tracing, resume_tracing
 from logilab.common.debugger import Debugger
 from logilab.common.umessage import message_from_string
-from logilab.common.decorators import cached, classproperty, clear_cache
+from logilab.common.decorators import cached, classproperty, clear_cache, iclassmethod
 from logilab.common.deprecation import deprecated, class_deprecated
 from logilab.common.shellutils import getlogin
 
 from cubicweb import ValidationError, NoSelectableObject, AuthenticationError
-from cubicweb import cwconfig, devtools, web, server
-from cubicweb.dbapi import ProgrammingError, DBAPISession, repo_connect
+from cubicweb import cwconfig, dbapi, devtools, web, server
 from cubicweb.sobjects import notification
 from cubicweb.web import Redirect, application
-from cubicweb.server.session import security_enabled
+from cubicweb.server.session import Session, security_enabled
 from cubicweb.server.hook import SendMailOp
 from cubicweb.devtools import SYSTEM_ENTITIES, SYSTEM_RELATIONS, VIEW_VALIDATORS
 from cubicweb.devtools import BASE_URL, fake, htmlparser, DEFAULT_EMPTY_DB_ID
@@ -252,7 +252,7 @@
         # cnx is now an instance property that use a class protected attributes.
         cls.set_cnx(cnx)
         cls.vreg = cls.repo.vreg
-        cls.websession = DBAPISession(cnx, cls.admlogin)
+        cls.websession = dbapi.DBAPISession(cnx, cls.admlogin)
         cls._orig_cnx = (cnx, cls.websession)
         cls.config.repository = lambda x=None: cls.repo
 
@@ -354,23 +354,64 @@
         else:
             return req.user
 
-    def create_user(self, login, groups=('users',), password=None, req=None,
-                    commit=True, **kwargs):
+    @iclassmethod # XXX turn into a class method
+    def create_user(self, req, login=None, groups=('users',), password=None,
+                    email=None, commit=True, **kwargs):
         """create and return a new user entity"""
+        if isinstance(req, basestring):
+            warn('[3.12] create_user arguments are now (req, login[, groups, password, commit, **kwargs])',
+                 DeprecationWarning, stacklevel=2)
+            if not isinstance(groups, (tuple, list)):
+                password = groups
+                groups = login
+            elif isinstance(login, tuple):
+                groups = login
+            login = req
+            assert not isinstance(self, type)
+            req = self._orig_cnx[0].request()
         if password is None:
             password = login.encode('utf8')
-        if req is None:
-            req = self._orig_cnx[0].request()
         user = req.create_entity('CWUser', login=unicode(login),
                                  upassword=password, **kwargs)
         req.execute('SET X in_group G WHERE X eid %%(x)s, G name IN(%s)'
                     % ','.join(repr(str(g)) for g in groups),
                     {'x': user.eid})
+        if email is not None:
+            req.create_entity('EmailAddress', address=unicode(email),
+                              reverse_primary_email=user)
         user.cw_clear_relation_cache('in_group', 'subject')
         if commit:
-            req.cnx.commit()
+            try:
+                req.commit() # req is a session
+            except AttributeError:
+                req.cnx.commit()
         return user
 
+    @iclassmethod # XXX turn into a class method
+    def grant_permission(self, session, entity, group, pname=None, plabel=None):
+        """insert a permission on an entity. Will have to commit the main
+        connection to be considered
+        """
+        if not isinstance(session, Session):
+            warn('[3.12] grant_permission arguments are now (session, entity, group, pname[, plabel])',
+                 DeprecationWarning, stacklevel=2)
+            plabel = pname
+            pname = group
+            group = entity
+            entity = session
+            assert not isinstance(self, type)
+            session = self.session
+        pname = unicode(pname)
+        plabel = plabel and unicode(plabel) or unicode(group)
+        e = getattr(entity, 'eid', entity)
+        with security_enabled(session, False, False):
+            peid = session.execute(
+            'INSERT CWPermission X: X name %(pname)s, X label %(plabel)s,'
+            'X require_group G, E require_permission X '
+            'WHERE G name %(group)s, E eid %(e)s',
+            locals())[0][0]
+        return peid
+
     def login(self, login, **kwargs):
         """return a connection for the given login/password"""
         if login == self.admlogin:
@@ -380,8 +421,8 @@
         autoclose = kwargs.pop('autoclose', True)
         if not kwargs:
             kwargs['password'] = str(login)
-        self.set_cnx(repo_connect(self.repo, unicode(login), **kwargs))
-        self.websession = DBAPISession(self.cnx)
+        self.set_cnx(dbapi.repo_connect(self.repo, unicode(login), **kwargs))
+        self.websession = dbapi.DBAPISession(self.cnx)
         if login == self.vreg.config.anonymous_user()[0]:
             self.cnx.anonymous_connection = True
         if autoclose:
@@ -423,7 +464,7 @@
     def rollback(self):
         try:
             self.cnx.rollback()
-        except ProgrammingError:
+        except dbapi.ProgrammingError:
             pass # connection closed
         finally:
             self.session.set_pool() # ensure pool still set after commit
@@ -439,21 +480,6 @@
 
     # other utilities #########################################################
 
-    def grant_permission(self, entity, group, pname, plabel=None):
-        """insert a permission on an entity. Will have to commit the main
-        connection to be considered
-        """
-        pname = unicode(pname)
-        plabel = plabel and unicode(plabel) or unicode(group)
-        e = entity.eid
-        with security_enabled(self.session, False, False):
-            peid = self.execute(
-            'INSERT CWPermission X: X name %(pname)s, X label %(plabel)s,'
-            'X require_group G, E require_permission X '
-            'WHERE G name %(group)s, E eid %(e)s',
-            locals())[0][0]
-        return peid
-
     @contextmanager
     def temporary_appobjects(self, *appobjects):
         self.vreg._loadedmods.setdefault(self.__module__, {})
@@ -469,6 +495,10 @@
         entity.cw_attr_cache.pop('modification_date', None)
         self.failUnless(entity.modification_date > olddate)
 
+    def assertItemsEqual(self, it1, it2, *args, **kwargs):
+        it1 = set(getattr(x, 'eid', x) for x in it1)
+        it2 = set(getattr(x, 'eid', x) for x in it2)
+        super(CubicWebTC, self).assertItemsEqual(it1, it2, *args, **kwargs)
 
     # workflow utilities #######################################################
 
@@ -696,9 +726,9 @@
 
     def assertAuthFailure(self, req, nbsessions=0):
         self.app.connect(req)
-        self.assertIsInstance(req.session, DBAPISession)
+        self.assertIsInstance(req.session, dbapi.DBAPISession)
         self.assertEqual(req.session.cnx, None)
-        self.assertEqual(req.cnx, None)
+        self.assertIsInstance(req.cnx, (dbapi._NeedAuthAccessMock, NoneType))
         self.assertEqual(len(self.open_sessions), nbsessions)
         clear_cache(req, 'get_authorization')
 
--- a/doc/book/en/annexes/faq.rst	Mon May 16 16:24:00 2011 +0200
+++ b/doc/book/en/annexes/faq.rst	Mon May 16 16:25:33 2011 +0200
@@ -380,11 +380,14 @@
 You can prefer use a migration script similar to this shell invocation instead::
 
     $ cubicweb-ctl shell <instance>
+    >>> from cubicweb import Binary
     >>> from cubicweb.server.utils import crypt_password
     >>> crypted = crypt_password('joepass')
     >>> rset = rql('Any U WHERE U is CWUser, U login "joe"')
     >>> joe = rset.get_entity(0,0)
-    >>> joe.set_attributes(upassword=crypted)
+    >>> joe.set_attributes(upassword=Binary(crypted))
+
+Please, refer to the script example is provided in the `misc/examples/chpasswd.py` file.
 
 The more experimented people would use RQL request directly::
 
--- a/doc/book/en/devrepo/vreg.rst	Mon May 16 16:24:00 2011 +0200
+++ b/doc/book/en/devrepo/vreg.rst	Mon May 16 16:25:33 2011 +0200
@@ -79,7 +79,7 @@
 .. autoclass:: cubicweb.selectors.has_add_permission
 .. autoclass:: cubicweb.selectors.has_mimetype
 .. autoclass:: cubicweb.selectors.is_in_state
-.. autoclass:: cubicweb.selectors.on_transition
+.. autoclass:: cubicweb.selectors.on_fire_transition
 .. autoclass:: cubicweb.selectors.implements
 
 
--- a/doc/tools/pyjsrest.py	Mon May 16 16:24:00 2011 +0200
+++ b/doc/tools/pyjsrest.py	Mon May 16 16:25:33 2011 +0200
@@ -153,9 +153,6 @@
     'jquery.flot.js',
     'jquery.corner.js',
     'jquery.ui.js',
-    'ui.core.js',
-    'ui.tabs.js',
-    'ui.slider.js',
     'excanvas.js',
     'gmap.utility.labeledmarker.js',
 
--- a/entities/authobjs.py	Mon May 16 16:24:00 2011 +0200
+++ b/entities/authobjs.py	Mon May 16 16:25:33 2011 +0200
@@ -29,9 +29,21 @@
     fetch_attrs, fetch_order = fetch_config(['name'])
     fetch_unrelated_order = fetch_order
 
-    def db_key_name(self):
-        """XXX goa specific"""
-        return self.get('name')
+    def grant_permission(self, entity, pname, plabel=None):
+        """grant local `pname` permission on `entity` to this group using
+        :class:`CWPermission`.
+
+        If a similar permission already exists, add the group to it, else create
+        a new one.
+        """
+        if not self._cw.execute(
+            'SET X require_group G WHERE E eid %(e)s, G eid %(g)s, '
+            'E require_permission X, X name %(name)s, X label %(label)s',
+            {'e': entity.eid, 'g': self.eid,
+             'name': pname, 'label': plabel}):
+            self._cw.create_entity('CWPermission', name=pname, label=plabel,
+                                   require_group=self,
+                                   reverse_require_permission=entity)
 
 
 class CWUser(AnyEntity):
@@ -156,10 +168,6 @@
 
     dc_long_title = name
 
-    def db_key_name(self):
-        """XXX goa specific"""
-        return self.get('login')
-
 from logilab.common.deprecation import class_renamed
 EUser = class_renamed('EUser', CWUser)
 EGroup = class_renamed('EGroup', CWGroup)
--- a/entities/schemaobjs.py	Mon May 16 16:24:00 2011 +0200
+++ b/entities/schemaobjs.py	Mon May 16 16:25:33 2011 +0200
@@ -45,10 +45,6 @@
             return u'%s <<%s>>' % (self.dc_title(), ', '.join(stereotypes))
         return self.dc_title()
 
-    def db_key_name(self):
-        """XXX goa specific"""
-        return self.get('name')
-
 
 class CWRType(AnyEntity):
     __regid__ = 'CWRType'
@@ -87,10 +83,6 @@
                                  "has cardinality=%(card)s")
                 raise ValidationError(self.eid, {qname: msg % locals()})
 
-    def db_key_name(self):
-        """XXX goa specific"""
-        return self.get('name')
-
 
 class CWRelation(AnyEntity):
     __regid__ = 'CWRelation'
--- a/entities/test/unittest_base.py	Mon May 16 16:24:00 2011 +0200
+++ b/entities/test/unittest_base.py	Mon May 16 16:25:33 2011 +0200
@@ -34,7 +34,8 @@
 class BaseEntityTC(CubicWebTC):
 
     def setup_database(self):
-        self.member = self.create_user('member')
+        req = self.request()
+        self.member = self.create_user(req, 'member')
 
 
 
--- a/entities/test/unittest_wfobjs.py	Mon May 16 16:24:00 2011 +0200
+++ b/entities/test/unittest_wfobjs.py	Mon May 16 16:25:33 2011 +0200
@@ -95,13 +95,15 @@
 class WorkflowTC(CubicWebTC):
 
     def setup_database(self):
+        req = self.request()
         rschema = self.schema['in_state']
         for rdef in rschema.rdefs.values():
             self.assertEqual(rdef.cardinality, '1*')
-        self.member = self.create_user('member')
+        self.member = self.create_user(req, 'member')
 
     def test_workflow_base(self):
-        e = self.create_user('toto')
+        req = self.request()
+        e = self.create_user(req, 'toto')
         iworkflowable = e.cw_adapt_to('IWorkflowable')
         self.assertEqual(iworkflowable.state, 'activated')
         iworkflowable.change_state('deactivated', u'deactivate 1')
@@ -170,13 +172,14 @@
         self.assertEqual(trinfo.transition.name, 'deactivate')
 
     def test_goback_transition(self):
+        req = self.request()
         wf = self.session.user.cw_adapt_to('IWorkflowable').current_workflow
         asleep = wf.add_state('asleep')
         wf.add_transition('rest', (wf.state_by_name('activated'),
                                    wf.state_by_name('deactivated')),
                           asleep)
         wf.add_transition('wake up', asleep)
-        user = self.create_user('stduser')
+        user = self.create_user(req, 'stduser')
         iworkflowable = user.cw_adapt_to('IWorkflowable')
         iworkflowable.fire_transition('rest')
         self.commit()
@@ -196,7 +199,8 @@
 
     def _test_stduser_deactivate(self):
         ueid = self.member.eid
-        self.create_user('tutu')
+        req = self.request()
+        self.create_user(req, 'tutu')
         cnx = self.login('tutu')
         req = self.request()
         iworkflowable = req.entity_from_eid(self.member.eid).cw_adapt_to('IWorkflowable')
@@ -393,7 +397,8 @@
 class CustomWorkflowTC(CubicWebTC):
 
     def setup_database(self):
-        self.member = self.create_user('member')
+        req = self.request()
+        self.member = self.create_user(req, 'member')
 
     def test_custom_wf_replace_state_no_history(self):
         """member in inital state with no previous history, state is simply
@@ -493,7 +498,8 @@
 
     def test_auto_transition_fired(self):
         wf = self.setup_custom_wf()
-        user = self.create_user('member')
+        req = self.request()
+        user = self.create_user(req, 'member')
         iworkflowable = user.cw_adapt_to('IWorkflowable')
         self.execute('SET X custom_workflow WF WHERE X eid %(x)s, WF eid %(wf)s',
                      {'wf': wf.eid, 'x': user.eid})
@@ -523,7 +529,8 @@
 
     def test_auto_transition_custom_initial_state_fired(self):
         wf = self.setup_custom_wf()
-        user = self.create_user('member', surname=u'toto')
+        req = self.request()
+        user = self.create_user(req, 'member', surname=u'toto')
         self.execute('SET X custom_workflow WF WHERE X eid %(x)s, WF eid %(wf)s',
                      {'wf': wf.eid, 'x': user.eid})
         self.commit()
@@ -538,7 +545,8 @@
                           type=u'auto', conditions=({'expr': u'X surname "toto"',
                                                      'mainvars': u'X'},))
         self.commit()
-        user = self.create_user('member', surname=u'toto')
+        req = self.request()
+        user = self.create_user(req, 'member', surname=u'toto')
         self.commit()
         iworkflowable = user.cw_adapt_to('IWorkflowable')
         self.assertEqual(iworkflowable.state, 'dead')
@@ -554,7 +562,8 @@
         self.s_deactivated = self.wf.state_by_name('deactivated').eid
         self.s_dummy = self.wf.add_state(u'dummy').eid
         self.wf.add_transition(u'dummy', (self.s_deactivated,), self.s_dummy)
-        ueid = self.create_user('stduser', commit=False).eid
+        req = self.request()
+        ueid = self.create_user(req, 'stduser', commit=False).eid
         # test initial state is set
         rset = self.execute('Any N WHERE S name N, X in_state S, X eid %(x)s',
                             {'x' : ueid})
--- a/entity.py	Mon May 16 16:24:00 2011 +0200
+++ b/entity.py	Mon May 16 16:25:33 2011 +0200
@@ -28,7 +28,7 @@
 
 from rql.utils import rqlvar_maker
 
-from cubicweb import Unauthorized, typed_eid
+from cubicweb import Unauthorized, typed_eid, neg_role
 from cubicweb.rset import ResultSet
 from cubicweb.selectors import yes
 from cubicweb.appobject import AppObject
@@ -157,6 +157,7 @@
     def fetch_rql(cls, user, restriction=None, fetchattrs=None, mainvar='X',
                   settype=True, ordermethod='fetch_order'):
         """return a rql to fetch all entities of the class type"""
+        # XXX update api and implementation to AST manipulation (see unrelated rql)
         restrictions = restriction or []
         if settype:
             restrictions.append('%s is %s' % (mainvar, cls.__regid__))
@@ -165,6 +166,7 @@
         selection = [mainvar]
         orderby = []
         # start from 26 to avoid possible conflicts with X
+        # XXX not enough to be sure it'll be no conflicts
         varmaker = rqlvar_maker(index=26)
         cls._fetch_restrictions(mainvar, varmaker, fetchattrs, selection,
                                 orderby, restrictions, user, ordermethod)
@@ -202,8 +204,6 @@
             restriction = '%s %s %s' % (mainvar, attr, var)
             restrictions.append(restriction)
             if not rschema.final:
-                # XXX this does not handle several destination types
-                desttype = rschema.objects(eschema.type)[0]
                 card = rdef.cardinality[0]
                 if card not in '?1':
                     cls.warning('bad relation %s specified in fetch attrs for %s',
@@ -216,11 +216,17 @@
                 # that case the relation may still be missing. As we miss this
                 # later information here, systematically add it.
                 restrictions[-1] += '?'
+                targettypes = rschema.objects(eschema.type)
                 # XXX user._cw.vreg iiiirk
-                destcls = user._cw.vreg['etypes'].etype_class(desttype)
-                destcls._fetch_restrictions(var, varmaker, destcls.fetch_attrs,
-                                            selection, orderby, restrictions,
-                                            user, ordermethod, visited=visited)
+                etypecls = user._cw.vreg['etypes'].etype_class(targettypes[0])
+                if len(targettypes) > 1:
+                    # find fetch_attrs common to all destination types
+                    fetchattrs = user._cw.vreg['etypes'].fetch_attrs(targettypes)
+                else:
+                    fetchattrs = etypecls.fetch_attrs
+                etypecls._fetch_restrictions(var, varmaker, fetchattrs,
+                                             selection, orderby, restrictions,
+                                             user, ordermethod, visited=visited)
             if ordermethod is not None:
                 orderterm = getattr(cls, ordermethod)(attr, var)
                 if orderterm:
@@ -264,6 +270,7 @@
         restrictions = set()
         pending_relations = []
         eschema = cls.e_schema
+        qargs = {}
         for attr, value in kwargs.items():
             if attr.startswith('reverse_'):
                 attr = attr[len('reverse_'):]
@@ -277,10 +284,11 @@
                     value = iter(value).next()
                 else:
                     # prepare IN clause
-                    del kwargs[attr]
-                    pending_relations.append( (attr, value) )
+                    pending_relations.append( (attr, role, value) )
                     continue
-            if hasattr(value, 'eid'): # non final relation
+            if rschema.final: # attribute
+                relations.append('X %s %%(%s)s' % (attr, attr))
+            else:
                 rvar = attr.upper()
                 if role == 'object':
                     relations.append('%s %s X' % (rvar, attr))
@@ -289,21 +297,21 @@
                 restriction = '%s eid %%(%s)s' % (rvar, attr)
                 if not restriction in restrictions:
                     restrictions.add(restriction)
-                kwargs[attr] = value.eid
-            else: # attribute
-                relations.append('X %s %%(%s)s' % (attr, attr))
+                if hasattr(value, 'eid'):
+                    value = value.eid
+            qargs[attr] = value
         if relations:
             rql = '%s: %s' % (rql, ', '.join(relations))
         if restrictions:
             rql = '%s WHERE %s' % (rql, ', '.join(restrictions))
-        created = execute(rql, kwargs).get_entity(0, 0)
-        for attr, values in pending_relations:
-            if attr.startswith('reverse_'):
-                restr = 'Y %s X' % attr[len('reverse_'):]
+        created = execute(rql, qargs).get_entity(0, 0)
+        for attr, role, values in pending_relations:
+            if role == 'object':
+                restr = 'Y %s X' % attr
             else:
                 restr = 'X %s Y' % attr
             execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % (
-                restr, ','.join(str(r.eid) for r in values)),
+                restr, ','.join(str(getattr(r, 'eid', r)) for r in values)),
                     {'x': created.eid}, build_descr=False)
         return created
 
@@ -728,17 +736,13 @@
             else:
                 restriction += ', X is IN (%s)' % ','.join(targettypes)
             card = greater_card(rschema, targettypes, (self.e_schema,), 1)
+        etypecls = self._cw.vreg['etypes'].etype_class(targettypes[0])
         if len(targettypes) > 1:
-            fetchattrs_list = []
-            for ttype in targettypes:
-                etypecls = self._cw.vreg['etypes'].etype_class(ttype)
-                fetchattrs_list.append(set(etypecls.fetch_attrs))
-            fetchattrs = reduce(set.intersection, fetchattrs_list)
-            rql = etypecls.fetch_rql(self._cw.user, [restriction], fetchattrs,
-                                     settype=False)
+            fetchattrs = self._cw.vreg['etypes'].fetch_attrs(targettypes)
         else:
-            etypecls = self._cw.vreg['etypes'].etype_class(targettypes[0])
-            rql = etypecls.fetch_rql(self._cw.user, [restriction], settype=False)
+            fetchattrs = etypecls.fetch_attrs
+        rql = etypecls.fetch_rql(self._cw.user, [restriction], fetchattrs,
+                                 settype=False)
         # optimisation: remove ORDERBY if cardinality is 1 or ? (though
         # greater_card return 1 for those both cases)
         if card == '1':
@@ -762,7 +766,7 @@
     # generic vocabulary methods ##############################################
 
     def cw_unrelated_rql(self, rtype, targettype, role, ordermethod=None,
-                      vocabconstraints=True):
+                         vocabconstraints=True):
         """build a rql to fetch `targettype` entities unrelated to this entity
         using (rtype, role) relation.
 
@@ -772,58 +776,83 @@
         ordermethod = ordermethod or 'fetch_unrelated_order'
         if isinstance(rtype, basestring):
             rtype = self._cw.vreg.schema.rschema(rtype)
+        rdef = rtype.role_rdef(self.e_schema, targettype, role)
+        rewriter = RQLRewriter(self._cw)
+        # initialize some variables according to the `role` of `self` in the
+        # relation:
+        # * variable for myself (`evar`) and searched entities (`searchvedvar`)
+        # * entity type of the subject (`subjtype`) and of the object
+        #   (`objtype`) of the relation
         if role == 'subject':
             evar, searchedvar = 'S', 'O'
             subjtype, objtype = self.e_schema, targettype
         else:
             searchedvar, evar = 'S', 'O'
             objtype, subjtype = self.e_schema, targettype
+        # initialize some variables according to `self` existance
+        if rdef.role_cardinality(neg_role(role)) in '?1':
+            # if cardinality in '1?', we want a target entity which isn't
+            # already linked using this relation
+            if searchedvar == 'S':
+                restriction = ['NOT S %s ZZ' % rtype]
+            else:
+                restriction = ['NOT ZZ %s O' % rtype]
+        elif self.has_eid():
+            # elif we have an eid, we don't want a target entity which is
+            # already linked to ourself through this relation
+            restriction = ['NOT S %s O' % rtype]
+        else:
+            restriction = []
         if self.has_eid():
-            restriction = ['NOT S %s O' % rtype, '%s eid %%(x)s' % evar]
+            restriction += ['%s eid %%(x)s' % evar]
             args = {'x': self.eid}
             if role == 'subject':
-                securitycheck_args = {'fromeid': self.eid}
+                sec_check_args = {'fromeid': self.eid}
             else:
-                securitycheck_args = {'toeid': self.eid}
+                sec_check_args = {'toeid': self.eid}
+            existant = None # instead of 'SO', improve perfs
         else:
-            restriction = []
             args = {}
-            securitycheck_args = {}
-        rdef = rtype.role_rdef(self.e_schema, targettype, role)
-        insertsecurity = (rdef.has_local_role('add') and not
-                          rdef.has_perm(self._cw, 'add', **securitycheck_args))
-        # XXX consider constraint.mainvars to check if constraint apply
+            sec_check_args = {}
+            existant = searchedvar
+        # retreive entity class for targettype to compute base rql
+        etypecls = self._cw.vreg['etypes'].etype_class(targettype)
+        rql = etypecls.fetch_rql(self._cw.user, restriction,
+                                 mainvar=searchedvar, ordermethod=ordermethod)
+        select = self._cw.vreg.parse(self._cw, rql, args).children[0]
+        # insert RQL expressions for schema constraints into the rql syntax tree
         if vocabconstraints:
             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
             # will be included as well
-            restriction += [cstr.restriction for cstr in rdef.constraints
-                            if isinstance(cstr, RQLVocabularyConstraint)]
+            cstrcls = RQLVocabularyConstraint
         else:
-            restriction += [cstr.restriction for cstr in rdef.constraints
-                            if isinstance(cstr, RQLConstraint)]
-        etypecls = self._cw.vreg['etypes'].etype_class(targettype)
-        rql = etypecls.fetch_rql(self._cw.user, restriction,
-                                 mainvar=searchedvar, ordermethod=ordermethod)
+            cstrcls = RQLConstraint
+        for cstr in rdef.constraints:
+            # consider constraint.mainvars to check if constraint apply
+            if isinstance(cstr, cstrcls) and searchedvar in cstr.mainvars:
+                if not self.has_eid() and evar in cstr.mainvars:
+                    continue
+                # compute a varmap suitable to RQLRewriter.rewrite argument
+                varmap = dict((v, v) for v in 'SO' if v in select.defined_vars
+                              and v in cstr.mainvars)
+                # rewrite constraint by constraint since we want a AND between
+                # expressions.
+                rewriter.rewrite(select, [(varmap, (cstr,))], select.solutions,
+                                 args, existant)
+        # insert security RQL expressions granting the permission to 'add' the
+        # relation into the rql syntax tree, if necessary
+        rqlexprs = rdef.get_rqlexprs('add')
+        if rqlexprs and not rdef.has_perm(self._cw, 'add', **sec_check_args):
+            # compute a varmap suitable to RQLRewriter.rewrite argument
+            varmap = dict((v, v) for v in 'SO' if v in select.defined_vars)
+            # rewrite all expressions at once since we want a OR between them.
+            rewriter.rewrite(select, [(varmap, rqlexprs)], select.solutions,
+                             args, existant)
         # ensure we have an order defined
-        if not ' ORDERBY ' in rql:
-            before, after = rql.split(' WHERE ', 1)
-            rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
-        if insertsecurity:
-            rqlexprs = rdef.get_rqlexprs('add')
-            rewriter = RQLRewriter(self._cw)
-            rqlst = self._cw.vreg.parse(self._cw, rql, args)
-            if not self.has_eid():
-                existant = searchedvar
-            else:
-                existant = None # instead of 'SO', improve perfs
-            for select in rqlst.children:
-                varmap = {}
-                for var in 'SO':
-                    if var in select.defined_vars:
-                        varmap[var] = var
-                rewriter.rewrite(select, [(varmap, rqlexprs)],
-                                 select.solutions, args, existant)
-            rql = rqlst.as_string()
+        if not select.orderby:
+            select.add_sort_var(select.defined_vars[searchedvar])
+        # we're done, turn the rql syntax tree as a string
+        rql = select.as_string()
         return rql, args
 
     def unrelated(self, rtype, targettype, role='subject', limit=None,
@@ -835,6 +864,7 @@
             rql, args = self.cw_unrelated_rql(rtype, targettype, role, ordermethod)
         except Unauthorized:
             return self._cw.empty_rset()
+        # XXX should be set in unrelated rql when manipulating the AST
         if limit is not None:
             before, after = rql.split(' WHERE ', 1)
             rql = '%s LIMIT %s WHERE %s' % (before, limit, after)
@@ -930,8 +960,9 @@
         """add relations to the given object. To set a relation where this entity
         is the object of the relation, use 'reverse_'<relation> as argument name.
 
-        Values may be an entity, a list of entities, or None (meaning that all
-        relations of the given type from or to this object should be deleted).
+        Values may be an entity or eid, a list of entities or eids, or None
+        (meaning that all relations of the given type from or to this object
+        should be deleted).
         """
         # XXX update cache
         _check_cw_unsafe(kwargs)
@@ -946,9 +977,17 @@
                 continue
             if not isinstance(values, (tuple, list, set, frozenset)):
                 values = (values,)
+            eids = []
+            for val in values:
+                try:
+                    eids.append(str(val.eid))
+                except AttributeError:
+                    try:
+                        eids.append(str(typed_eid(val)))
+                    except (ValueError, TypeError):
+                        raise Exception('expected an Entity or eid, got %s' % val)
             self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % (
-                restr, ','.join(str(r.eid) for r in values)),
-                             {'x': self.eid})
+                    restr, ','.join(eids)), {'x': self.eid})
 
     def cw_delete(self, **kwargs):
         assert self.has_eid(), self.eid
--- a/hooks/metadata.py	Mon May 16 16:24:00 2011 +0200
+++ b/hooks/metadata.py	Mon May 16 16:25:33 2011 +0200
@@ -67,13 +67,12 @@
 
     def precommit_event(self):
         session = self.session
-        for eid in self.get_data():
-            if session.deleted_in_transaction(eid):
-                # entity have been created and deleted in the same transaction
-                continue
-            entity = session.entity_from_eid(eid)
-            if not entity.created_by:
-                session.add_relation(eid, 'created_by', session.user.eid)
+        relations = [(eid, session.user.eid) for eid in self.get_data()
+                # don't consider entities that have been created and
+                # deleted in the same transaction
+                if not session.deleted_in_transaction(eid) and \
+                   not session.entity_from_eid(eid).created_by]
+        session.add_relations([('created_by', relations)])
 
 
 class SetOwnershipHook(MetaDataHook):
--- a/hooks/test/unittest_hooks.py	Mon May 16 16:24:00 2011 +0200
+++ b/hooks/test/unittest_hooks.py	Mon May 16 16:25:33 2011 +0200
@@ -42,25 +42,31 @@
 
     def test_html_tidy_hook(self):
         req = self.request()
-        entity = req.create_entity('Workflow', name=u'wf1', description_format=u'text/html',
-                                 description=u'yo')
+        entity = req.create_entity('Workflow', name=u'wf1',
+                                   description_format=u'text/html',
+                                   description=u'yo')
         self.assertEqual(entity.description, u'yo')
-        entity = req.create_entity('Workflow', name=u'wf2', description_format=u'text/html',
-                                 description=u'<b>yo')
+        entity = req.create_entity('Workflow', name=u'wf2',
+                                   description_format=u'text/html',
+                                   description=u'<b>yo')
         self.assertEqual(entity.description, u'<b>yo</b>')
-        entity = req.create_entity('Workflow', name=u'wf3', description_format=u'text/html',
-                                 description=u'<b>yo</b>')
+        entity = req.create_entity('Workflow', name=u'wf3',
+                                   description_format=u'text/html',
+                                   description=u'<b>yo</b>')
         self.assertEqual(entity.description, u'<b>yo</b>')
-        entity = req.create_entity('Workflow', name=u'wf4', description_format=u'text/html',
-                                 description=u'<b>R&D</b>')
+        entity = req.create_entity('Workflow', name=u'wf4',
+                                   description_format=u'text/html',
+                                   description=u'<b>R&D</b>')
         self.assertEqual(entity.description, u'<b>R&amp;D</b>')
-        entity = req.create_entity('Workflow', name=u'wf5', description_format=u'text/html',
-                                 description=u"<div>c&apos;est <b>l'ét&eacute;")
+        entity = req.create_entity('Workflow', name=u'wf5',
+                                   description_format=u'text/html',
+                                   description=u"<div>c&apos;est <b>l'ét&eacute;")
         self.assertEqual(entity.description, u"<div>c'est <b>l'été</b></div>")
 
     def test_nonregr_html_tidy_hook_no_update(self):
-        entity = self.request().create_entity('Workflow', name=u'wf1', description_format=u'text/html',
-                                 description=u'yo')
+        entity = self.request().create_entity('Workflow', name=u'wf1',
+                                              description_format=u'text/html',
+                                              description=u'yo')
         entity.set_attributes(name=u'wf2')
         self.assertEqual(entity.description, u'yo')
         entity.set_attributes(description=u'R&D<p>yo')
@@ -90,7 +96,8 @@
         self.assertEqual(entity.owned_by[0].eid, self.session.user.eid)
 
     def test_user_login_stripped(self):
-        u = self.create_user('  joe  ')
+        req = self.request()
+        u = self.create_user(req, '  joe  ')
         tname = self.execute('Any L WHERE E login L, E eid %(e)s',
                              {'e': u.eid})[0][0]
         self.assertEqual(tname, 'joe')
@@ -104,7 +111,8 @@
 class UserGroupHooksTC(CubicWebTC):
 
     def test_user_synchronization(self):
-        self.create_user('toto', password='hop', commit=False)
+        req = self.request()
+        self.create_user(req, 'toto', password='hop', commit=False)
         self.assertRaises(AuthenticationError,
                           self.repo.connect, u'toto', password='hop')
         self.commit()
@@ -129,7 +137,8 @@
         self.assertEqual(user.groups, set(('managers',)))
 
     def test_user_composite_owner(self):
-        ueid = self.create_user('toto').eid
+        req = self.request()
+        ueid = self.create_user(req, 'toto').eid
         # composite of euser should be owned by the euser regardless of who created it
         self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", U use_email X '
                      'WHERE U login "toto"')
--- a/hooks/test/unittest_syncschema.py	Mon May 16 16:24:00 2011 +0200
+++ b/hooks/test/unittest_syncschema.py	Mon May 16 16:25:33 2011 +0200
@@ -251,7 +251,8 @@
                      'RT name "surname", E name "CWUser"')
         self.commit()
         # should not be able anymore to add cwuser without surname
-        self.assertRaises(ValidationError, self.create_user, "toto")
+        req = self.request()
+        self.assertRaises(ValidationError, self.create_user, req, "toto")
         self.rollback()
         self.execute('SET DEF cardinality "?1" '
                      'WHERE DEF relation_type RT, DEF from_entity E,'
--- a/i18n/de.po	Mon May 16 16:24:00 2011 +0200
+++ b/i18n/de.po	Mon May 16 16:25:33 2011 +0200
@@ -162,7 +162,7 @@
 msgstr ""
 
 #, python-format
-msgid "'%s' action require 'linkattr' option"
+msgid "'%s' action requires 'linkattr' option"
 msgstr ""
 
 msgid "(UNEXISTANT EID)"
@@ -737,6 +737,18 @@
 msgid "Submit bug report by mail"
 msgstr "Diesen Bericht als E-Mail senden"
 
+msgid "TZDatetime"
+msgstr ""
+
+msgid "TZDatetime_plural"
+msgstr ""
+
+msgid "TZTime"
+msgstr ""
+
+msgid "TZTime_plural"
+msgstr ""
+
 #, python-format
 msgid "The view %s can not be applied to this query"
 msgstr "Die Ansicht %s ist auf diese Anfrage nicht anwendbar."
@@ -1049,10 +1061,6 @@
 msgid "add WorkflowTransition transition_of Workflow object"
 msgstr "Workflow-Übergang"
 
-#, python-format
-msgid "add a %s"
-msgstr ""
-
 msgctxt "inlined:CWRelation.from_entity.subject"
 msgid "add a CWEType"
 msgstr "einen Entitätstyp hinzufügen"
@@ -2743,6 +2751,9 @@
 "zeigt an, welcher Zustand standardmäßig benutzt werden soll, wenn eine "
 "Entität erstellt wird"
 
+msgid "indifferent"
+msgstr "gleichgültig"
+
 msgid "info"
 msgstr "Information"
 
--- a/i18n/en.po	Mon May 16 16:24:00 2011 +0200
+++ b/i18n/en.po	Mon May 16 16:25:33 2011 +0200
@@ -154,7 +154,7 @@
 msgstr ""
 
 #, python-format
-msgid "'%s' action require 'linkattr' option"
+msgid "'%s' action requires 'linkattr' option"
 msgstr ""
 
 msgid "(UNEXISTANT EID)"
@@ -711,6 +711,18 @@
 msgid "Submit bug report by mail"
 msgstr ""
 
+msgid "TZDatetime"
+msgstr "International date and time"
+
+msgid "TZDatetime_plural"
+msgstr "International dates and times"
+
+msgid "TZTime"
+msgstr "International time"
+
+msgid "TZTime_plural"
+msgstr "International times"
+
 #, python-format
 msgid "The view %s can not be applied to this query"
 msgstr ""
@@ -1009,10 +1021,6 @@
 msgid "add WorkflowTransition transition_of Workflow object"
 msgstr "workflow-transition"
 
-#, python-format
-msgid "add a %s"
-msgstr ""
-
 msgctxt "inlined:CWRelation.from_entity.subject"
 msgid "add a CWEType"
 msgstr "add an entity type"
@@ -2668,6 +2676,9 @@
 "is created"
 msgstr ""
 
+msgid "indifferent"
+msgstr "indifferent"
+
 msgid "info"
 msgstr ""
 
@@ -3305,7 +3316,7 @@
 msgstr ""
 
 msgid "read_permission"
-msgstr "can be read by"
+msgstr "read permission"
 
 msgctxt "CWAttribute"
 msgid "read_permission"
@@ -3324,11 +3335,11 @@
 
 msgctxt "CWGroup"
 msgid "read_permission_object"
-msgstr "can be read by"
+msgstr "has permission to read"
 
 msgctxt "RQLExpression"
 msgid "read_permission_object"
-msgstr "can be read by"
+msgstr "has permission to read"
 
 msgid "regexp matching host(s) to which this config applies"
 msgstr ""
--- a/i18n/es.po	Mon May 16 16:24:00 2011 +0200
+++ b/i18n/es.po	Mon May 16 16:25:33 2011 +0200
@@ -4,9 +4,9 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: cubicweb 2.46.0\n"
-"PO-Revision-Date: 2010-11-27 07:59+0100\n"
-"Last-Translator: Celso Flores<celso.flores@crealibre.com>, Carlos Balderas "
-"<carlos.balderas@crealibre.com>\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2011-05-03 12:53-0600\n"
+"Last-Translator: CreaLibre <info@crealibre.com>\n"
 "Language-Team: es <contact@logilab.fr>\n"
 "Language: \n"
 "MIME-Version: 1.0\n"
@@ -43,9 +43,12 @@
 #, python-format
 msgid "\"action\" must be specified in options; allowed values are %s"
 msgstr ""
+"\"action\" debe estar especificada en opciones; los valores permitidos son : "
+"%s"
 
 msgid "\"role=subject\" or \"role=object\" must be specified in options"
 msgstr ""
+"\"role=subject\" o \"role=object\" debe ser especificado en las opciones"
 
 #, python-format
 msgid "%(attr)s set to %(newvalue)s"
@@ -61,7 +64,7 @@
 
 #, python-format
 msgid "%(etype)s by %(author)s"
-msgstr ""
+msgstr "%(etype)s por %(author)s"
 
 #, python-format
 msgid "%(firstname)s %(surname)s"
@@ -133,7 +136,7 @@
 
 #, python-format
 msgid "%s could be supported"
-msgstr ""
+msgstr "%s podría ser mantenido"
 
 #, python-format
 msgid "%s error report"
@@ -145,7 +148,7 @@
 
 #, python-format
 msgid "%s relation should not be in mapped"
-msgstr ""
+msgstr "la relación %s no debería estar mapeada"
 
 #, python-format
 msgid "%s software version of the database"
@@ -157,11 +160,11 @@
 
 #, python-format
 msgid "'%s' action doesn't take any options"
-msgstr ""
+msgstr "la acción '%s'  no acepta opciones"
 
 #, python-format
-msgid "'%s' action require 'linkattr' option"
-msgstr ""
+msgid "'%s' action requires 'linkattr' option"
+msgstr "la acción '%s' requiere una opción 'linkattr'"
 
 msgid "(UNEXISTANT EID)"
 msgstr "(EID INEXISTENTE"
@@ -219,7 +222,7 @@
 "div>"
 
 msgid "<not specified>"
-msgstr ""
+msgstr "<no especificado>"
 
 msgid "?*"
 msgstr "0..1 0..n"
@@ -357,28 +360,28 @@
 msgstr "Relaciones"
 
 msgid "CWSource"
-msgstr ""
+msgstr "Fuente de datos"
 
 msgid "CWSourceHostConfig"
-msgstr ""
+msgstr "Configuración de Fuente"
 
 msgid "CWSourceHostConfig_plural"
-msgstr ""
+msgstr "Configuraciones de fuente"
 
 msgid "CWSourceSchemaConfig"
-msgstr ""
+msgstr "Configuraciones de Esquema de Fuente"
 
 msgid "CWSourceSchemaConfig_plural"
-msgstr ""
+msgstr "Configuraciones de Esquema de Fuente"
 
 msgid "CWSource_plural"
-msgstr ""
+msgstr "Fuentes de Datos"
 
 msgid "CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "Restricción de Singularidad"
 
 msgid "CWUniqueTogetherConstraint_plural"
-msgstr ""
+msgstr "Restricciones de Singularidad"
 
 msgid "CWUser"
 msgstr "Usuario"
@@ -436,7 +439,7 @@
 
 #, python-format
 msgid "Data connection graph for %s"
-msgstr ""
+msgstr "Gráfica de conexión de datos para %s"
 
 msgid "Date"
 msgstr "Fecha"
@@ -457,7 +460,7 @@
 msgstr "Decimales"
 
 msgid "Detected problems"
-msgstr ""
+msgstr "Problemas detectados"
 
 msgid "Do you want to delete the following element(s) ?"
 msgstr "Desea eliminar el(los) elemento(s) siguiente(s)"
@@ -479,7 +482,7 @@
 msgstr "Entidades"
 
 msgid "Entity and relation supported by this source"
-msgstr ""
+msgstr "Entidades y relaciones aceptadas por esta fuente"
 
 msgid "ExternalUri"
 msgstr "Uri externo"
@@ -506,7 +509,7 @@
 msgstr "Recolector de basura en memoria"
 
 msgid "Got rhythm?"
-msgstr ""
+msgstr "Tenemos Ritmo?"
 
 msgid "Help"
 msgstr "Ayuda"
@@ -533,7 +536,7 @@
 msgstr "Clases buscadas"
 
 msgid "Manage"
-msgstr ""
+msgstr "Administración"
 
 msgid "Most referenced classes"
 msgstr "Clases más referenciadas"
@@ -575,16 +578,16 @@
 msgstr "Nueva definición de relación final"
 
 msgid "New CWSource"
-msgstr ""
+msgstr "Nueva fuente"
 
 msgid "New CWSourceHostConfig"
-msgstr ""
+msgstr "Nueva configuración de fuente"
 
 msgid "New CWSourceSchemaConfig"
-msgstr ""
+msgstr "Nueva parte de mapeo de fuente"
 
 msgid "New CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "Nueva restricción de singularidad"
 
 msgid "New CWUser"
 msgstr "Agregar usuario"
@@ -685,7 +688,7 @@
 msgstr "Buscar"
 
 msgid "Site information"
-msgstr ""
+msgstr "Información del Sitio"
 
 msgid "SizeConstraint"
 msgstr "Restricción de tamaño"
@@ -695,6 +698,9 @@
 "authorized keys depending on the source's type, overriding values defined on "
 "the source."
 msgstr ""
+"Configuración de la fuente por un \"host\" específico. Una clave=valor por "
+"línea, las claves permitidas dependen del tipo de fuente. Estos valores son "
+"prioritarios a los valores definidos en la fuente."
 
 msgid "Startup views"
 msgstr "Vistas de inicio"
@@ -732,6 +738,18 @@
 msgid "Submit bug report by mail"
 msgstr "Enviar este reporte por email"
 
+msgid "TZDatetime"
+msgstr "Fecha y hora internacional"
+
+msgid "TZDatetime_plural"
+msgstr "Fechas y horas internacionales"
+
+msgid "TZTime"
+msgstr "Hora internacional"
+
+msgid "TZTime_plural"
+msgstr "Horas internacionales"
+
 #, python-format
 msgid "The view %s can not be applied to this query"
 msgstr "La vista %s no puede ser aplicada a esta búsqueda"
@@ -780,16 +798,16 @@
 msgstr "Esta definición de relación no final"
 
 msgid "This CWSource"
-msgstr ""
+msgstr "Esta fuente"
 
 msgid "This CWSourceHostConfig"
-msgstr ""
+msgstr "Esta configuración de fuente"
 
 msgid "This CWSourceSchemaConfig"
-msgstr ""
+msgstr "Esta parte de mapeo de fuente"
 
 msgid "This CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "Esta restricción de singularidad"
 
 msgid "This CWUser"
 msgstr "Este usuario"
@@ -844,6 +862,8 @@
 
 msgid "URLs from which content will be imported. You can put one url per line"
 msgstr ""
+"URLs desde el cual el contenido sera importado. Usted puede incluir un URL "
+"por línea."
 
 msgid "UniqueConstraint"
 msgstr "Restricción de Unicidad"
@@ -1007,10 +1027,10 @@
 msgstr "Definición de relación"
 
 msgid "add CWSourceHostConfig cw_host_config_of CWSource object"
-msgstr ""
+msgstr "configuración del host"
 
 msgid "add CWUniqueTogetherConstraint constraint_of CWEType object"
-msgstr ""
+msgstr "restricción de singularidad"
 
 msgid "add CWUser in_group CWGroup object"
 msgstr "Usuario"
@@ -1051,10 +1071,6 @@
 msgid "add WorkflowTransition transition_of Workflow object"
 msgstr "Transición Workflow"
 
-#, python-format
-msgid "add a %s"
-msgstr ""
-
 msgctxt "inlined:CWRelation.from_entity.subject"
 msgid "add a CWEType"
 msgstr "Agregar un tipo de entidad"
@@ -1068,10 +1084,10 @@
 msgstr "Agregar un tipo de relación"
 
 msgid "add a CWSource"
-msgstr ""
+msgstr "agregar una fuente"
 
 msgid "add a CWSourceSchemaConfig"
-msgstr ""
+msgstr "agregar una parte de mapeo"
 
 msgctxt "inlined:CWUser.use_email.subject"
 msgid "add a EmailAddress"
@@ -1142,7 +1158,7 @@
 msgstr "permite definir un Workflow específico para una entidad"
 
 msgid "allowed options depends on the source type"
-msgstr ""
+msgstr "las opciones permitidas dependen del tipo de fuente"
 
 msgid "allowed transitions from this state"
 msgstr "transiciones autorizadas desde este estado"
@@ -1198,11 +1214,11 @@
 
 #, python-format
 msgid "archive for %(author)s"
-msgstr ""
+msgstr "archivo de %(author)s"
 
 #, python-format
 msgid "archive for %(month)s/%(year)s"
-msgstr ""
+msgstr "archivo del %(month)s/%(year)s"
 
 #, python-format
 msgid "at least one relation %(rtype)s is required on %(etype)s (%(eid)s)"
@@ -1215,6 +1231,8 @@
 
 msgid "attribute/relation can't be mapped, only entity and relation types"
 msgstr ""
+"los atributos y las relaciones no pueden ser mapeados, solamente los tipos "
+"de entidad y de relación"
 
 msgid "august"
 msgstr "Agosto"
@@ -1326,7 +1344,7 @@
 msgstr "no puede modificar el atributo %s"
 
 msgid "can't change this relation"
-msgstr ""
+msgstr "no puede modificar esta relación"
 
 #, python-format
 msgid "can't connect to source %s, some data may be missing"
@@ -1340,10 +1358,10 @@
 msgstr "no puede tener varias salidas en el mismo estado"
 
 msgid "can't mix dontcross and maycross options"
-msgstr ""
+msgstr "no puede mezclar las opciones dontcross y maycross"
 
 msgid "can't mix dontcross and write options"
-msgstr ""
+msgstr "no puede mezclar las opciones dontcross y write"
 
 #, python-format
 msgid "can't parse %(value)r (expected %(format)s)"
@@ -1358,7 +1376,7 @@
 "cardinalidad %(card)s"
 
 msgid "cancel"
-msgstr ""
+msgstr "anular"
 
 msgid "cancel select"
 msgstr "Cancelar la selección"
@@ -1391,7 +1409,7 @@
 msgstr "Ver la entidad creada"
 
 msgid "click here to see edited entity"
-msgstr ""
+msgstr "seleccione aquí para ver la entidad modificada"
 
 msgid "click on the box to cancel the deletion"
 msgstr "Seleccione la zona de edición para cancelar la eliminación"
@@ -1475,15 +1493,15 @@
 msgstr "condiciones"
 
 msgid "config"
-msgstr ""
+msgstr "configuración"
 
 msgctxt "CWSource"
 msgid "config"
-msgstr ""
+msgstr "configuración"
 
 msgctxt "CWSourceHostConfig"
 msgid "config"
-msgstr ""
+msgstr "configuración"
 
 msgid "config mode"
 msgstr "Modo de configuración"
@@ -1516,18 +1534,18 @@
 msgstr "Fábrica de restricciones"
 
 msgid "constraint_of"
-msgstr ""
+msgstr "restricción de"
 
 msgctxt "CWUniqueTogetherConstraint"
 msgid "constraint_of"
-msgstr ""
+msgstr "restricción de"
 
 msgid "constraint_of_object"
-msgstr ""
+msgstr "restringida por"
 
 msgctxt "CWEType"
 msgid "constraint_of_object"
-msgstr ""
+msgstr "restringida por"
 
 msgid "constraints"
 msgstr "Restricciones"
@@ -1622,12 +1640,12 @@
 msgid ""
 "creating CWSourceHostConfig (CWSourceHostConfig cw_host_config_of CWSource "
 "%(linkto)s)"
-msgstr ""
+msgstr "creación de una configuración host para la fuente %(linkto)s"
 
 msgid ""
 "creating CWUniqueTogetherConstraint (CWUniqueTogetherConstraint "
 "constraint_of CWEType %(linkto)s)"
-msgstr ""
+msgstr "creación de una restricción de singularidad en  %(linkto)s"
 
 msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
 msgstr "Creación de un usuario para agregar al grupo %(linkto)s"
@@ -1807,7 +1825,7 @@
 msgstr "Metadatos de la Entidad"
 
 msgid "ctxcomponents_metadata_description"
-msgstr ""
+msgstr "espacio que incluye los metadatos de la entidad actual"
 
 msgid "ctxcomponents_possible_views_box"
 msgstr "Caja de Vistas Posibles"
@@ -1844,10 +1862,10 @@
 msgstr "Muestra las vistas de inicio de la aplicación"
 
 msgid "ctxcomponents_userstatus"
-msgstr ""
+msgstr "estado del usuario"
 
 msgid "ctxcomponents_userstatus_description"
-msgstr ""
+msgstr "establece el estado del usuario"
 
 msgid "ctxcomponents_wfhistory"
 msgstr "Histórico del workflow."
@@ -1867,64 +1885,64 @@
 msgstr "Workflow de"
 
 msgid "cw_for_source"
-msgstr ""
+msgstr "fuente"
 
 msgctxt "CWSourceSchemaConfig"
 msgid "cw_for_source"
-msgstr ""
+msgstr "fuente"
 
 msgid "cw_for_source_object"
-msgstr ""
+msgstr "elemento de mapeo"
 
 msgctxt "CWSource"
 msgid "cw_for_source_object"
-msgstr ""
+msgstr "elemento de mapeo"
 
 msgid "cw_host_config_of"
-msgstr ""
+msgstr "configuración del host de"
 
 msgctxt "CWSourceHostConfig"
 msgid "cw_host_config_of"
-msgstr ""
+msgstr "configuración del host de"
 
 msgid "cw_host_config_of_object"
-msgstr ""
+msgstr "tiene la configuración del host"
 
 msgctxt "CWSource"
 msgid "cw_host_config_of_object"
-msgstr ""
+msgstr "tiene la configuración del host"
 
 msgid "cw_schema"
-msgstr ""
+msgstr "esquema"
 
 msgctxt "CWSourceSchemaConfig"
 msgid "cw_schema"
-msgstr ""
+msgstr "esquema"
 
 msgid "cw_schema_object"
-msgstr ""
+msgstr "mapeado por"
 
 msgctxt "CWAttribute"
 msgid "cw_schema_object"
-msgstr ""
+msgstr "mapeado por"
 
 msgctxt "CWEType"
 msgid "cw_schema_object"
-msgstr ""
+msgstr "mapeado por"
 
 msgctxt "CWRType"
 msgid "cw_schema_object"
-msgstr ""
+msgstr "mapeado por"
 
 msgctxt "CWRelation"
 msgid "cw_schema_object"
-msgstr ""
+msgstr "mapeado por"
 
 msgid "cw_source"
-msgstr ""
+msgstr "desde la fuente de datos"
 
 msgid "cw_source_object"
-msgstr ""
+msgstr "entidades"
 
 msgid "cwetype-box"
 msgstr "Vista \"caja\""
@@ -1954,10 +1972,10 @@
 msgstr "Permisos"
 
 msgid "cwsource-main"
-msgstr ""
+msgstr "descripción"
 
 msgid "cwsource-mapping"
-msgstr ""
+msgstr "mapeo"
 
 msgid "cwuri"
 msgstr "Uri Interna"
@@ -1966,16 +1984,16 @@
 msgstr "Url del repertorio de datos"
 
 msgid "data sources"
-msgstr ""
+msgstr "fuente de datos"
 
 msgid "data sources management"
-msgstr ""
+msgstr "administración de fuentes de datos"
 
 msgid "date"
 msgstr "Fecha"
 
 msgid "day"
-msgstr ""
+msgstr "día"
 
 msgid "deactivate"
 msgstr "Desactivar"
@@ -2066,7 +2084,7 @@
 msgstr "Define como salir de un sub-Workflow"
 
 msgid "defines a sql-level multicolumn unique index"
-msgstr ""
+msgstr "define un índice SQL único a través de varias columnas"
 
 msgid ""
 "defines what's the property is applied for. You must select this first to be "
@@ -2312,6 +2330,8 @@
 
 msgid "entity and relation types can't be mapped, only attributes or relations"
 msgstr ""
+"los tipos de entidad y relación no pueden ser mapeados, solo los atributos y "
+"las relaciones"
 
 msgid "entity copied"
 msgstr "Entidad copiada"
@@ -2354,7 +2374,7 @@
 msgstr "Actualización de la Entidad"
 
 msgid "error"
-msgstr ""
+msgstr "error"
 
 msgid "error while embedding page"
 msgstr "Error durante la inclusión de la página"
@@ -2418,10 +2438,10 @@
 msgstr "Faceta creada por"
 
 msgid "facets_cw_source-facet"
-msgstr ""
+msgstr "faceta \"fuente de datos\""
 
 msgid "facets_cw_source-facet_description"
-msgstr ""
+msgstr "fuente de datos"
 
 msgid "facets_cwfinal-facet"
 msgstr "Faceta \"final\""
@@ -2574,7 +2594,7 @@
 msgstr "Texto indexado"
 
 msgid "gc"
-msgstr ""
+msgstr "fuga de memoria"
 
 msgid "generic plot"
 msgstr "Gráfica Genérica"
@@ -2637,10 +2657,10 @@
 msgstr "Contiene el texto"
 
 msgid "header-left"
-msgstr ""
+msgstr "encabezado (izquierdo)"
 
 msgid "header-right"
-msgstr ""
+msgstr "encabezado (derecho)"
 
 msgid "hide filter form"
 msgstr "Esconder el filtro"
@@ -2773,6 +2793,9 @@
 msgstr ""
 "Indica cual estado deberá ser utilizado por defecto al crear una entidad"
 
+msgid "indifferent"
+msgstr "indifferente"
+
 msgid "info"
 msgstr "Información del Sistema"
 
@@ -2807,6 +2830,8 @@
 #, python-format
 msgid "inlined relation %(rtype)s of %(etype)s should be supported"
 msgstr ""
+"la relación %(rtype)s del tipo de entidad %(etype)s debe ser aceptada "
+"('inlined')"
 
 msgid "instance home"
 msgstr "Repertorio de la Instancia"
@@ -2912,17 +2937,17 @@
 msgstr "Fecha de la última modificación de una entidad "
 
 msgid "latest synchronization time"
-msgstr ""
+msgstr "fecha de la última sincronización"
 
 msgid "latest update on"
 msgstr "Actualizado el"
 
 msgid "latest_retrieval"
-msgstr ""
+msgstr "última sincronización"
 
 msgctxt "CWSource"
 msgid "latest_retrieval"
-msgstr ""
+msgstr "fecha de la última sincronización de la fuente"
 
 msgid "left"
 msgstr "izquierda"
@@ -2980,7 +3005,7 @@
 msgstr "Usuario"
 
 msgid "login / password"
-msgstr ""
+msgstr "usuario / contraseña"
 
 msgid "login or email"
 msgstr "Usuario o dirección de correo"
@@ -2999,7 +3024,7 @@
 msgstr "Informaciones Generales"
 
 msgid "main_tab"
-msgstr ""
+msgstr "descripción"
 
 msgid "mainvars"
 msgstr "Variables principales"
@@ -3030,11 +3055,11 @@
 msgstr "Marzo"
 
 msgid "match_host"
-msgstr ""
+msgstr "para el host"
 
 msgctxt "CWSourceHostConfig"
 msgid "match_host"
-msgstr ""
+msgstr "para el host"
 
 msgid "maximum number of characters in short description"
 msgstr "Máximo de caracteres en las descripciones cortas"
@@ -3062,7 +3087,7 @@
 msgstr "Parámetros faltantes a la entidad %s"
 
 msgid "modification"
-msgstr ""
+msgstr "modificación"
 
 msgid "modification_date"
 msgstr "Fecha de modificación"
@@ -3074,7 +3099,7 @@
 msgstr "Lunes"
 
 msgid "month"
-msgstr ""
+msgstr "mes"
 
 msgid "more actions"
 msgstr "Más acciones"
@@ -3121,7 +3146,7 @@
 
 msgctxt "CWSource"
 msgid "name"
-msgstr ""
+msgstr "nombre"
 
 msgctxt "State"
 msgid "name"
@@ -3150,7 +3175,7 @@
 "selección de ser necesario (separarlas con comas)"
 
 msgid "name of the source"
-msgstr ""
+msgstr "nombre de la fuente"
 
 msgid "name or identifier of the permission"
 msgstr "Nombre o identificador del permiso"
@@ -3267,7 +3292,7 @@
 
 msgctxt "CWSourceSchemaConfig"
 msgid "options"
-msgstr ""
+msgstr "opciones"
 
 msgid "order"
 msgstr "Orden"
@@ -3308,14 +3333,16 @@
 msgstr "Página no encontrada."
 
 msgid "parser"
-msgstr ""
+msgstr "analizador (parser)"
 
 msgctxt "CWSource"
 msgid "parser"
-msgstr ""
+msgstr "analizador (parser)"
 
 msgid "parser to use to extract entities from content retrieved at given URLs."
 msgstr ""
+"analizador (parser) que sirve para extraer entidades y relaciones del "
+"contenido recuperado de las URLs."
 
 msgid "password"
 msgstr "Contraseña"
@@ -3396,7 +3423,7 @@
 msgstr "Dirección principal de correo electrónico de"
 
 msgid "profile"
-msgstr ""
+msgstr "perfil"
 
 msgid "progress"
 msgstr "Progreso"
@@ -3414,7 +3441,7 @@
 msgstr "Permisos"
 
 msgid "rdf"
-msgstr ""
+msgstr "rdf"
 
 msgid "read"
 msgstr "Lectura"
@@ -3447,6 +3474,8 @@
 
 msgid "regexp matching host(s) to which this config applies"
 msgstr ""
+"expresión regular de los nombres de hosts a los cuales esta configuración "
+"aplica"
 
 msgid "registry"
 msgstr "Registro"
@@ -3469,18 +3498,24 @@
 "relation %(rtype)s with %(etype)s as %(role)s is supported but no target "
 "type supported"
 msgstr ""
+"la relación %(rtype)s con %(etype)s como %(role)s es aceptada pero ningún "
+"tipo target es aceptado"
 
 #, python-format
 msgid ""
 "relation %(type)s with %(etype)s as %(role)s and target type %(target)s is "
 "mandatory but not supported"
 msgstr ""
+"la relación %(type)s con %(etype)s como %(role)s y tipo objetivo %(target)s "
+"es obligatoria pero no mantenida"
 
 #, python-format
 msgid ""
 "relation %s is supported but none if its definitions matches supported "
 "entities"
 msgstr ""
+"la relación %s es aceptada pero ninguna de sus definiciones corresponden a "
+"los tipos de entidades aceptadas"
 
 msgid "relation add"
 msgstr "Agregar Relación"
@@ -3507,21 +3542,21 @@
 msgstr "Definición de Relaciones"
 
 msgid "relations"
-msgstr ""
+msgstr "relaciones"
 
 msgctxt "CWUniqueTogetherConstraint"
 msgid "relations"
-msgstr ""
+msgstr "relaciones"
 
 msgid "relations deleted"
 msgstr "Relaciones Eliminadas"
 
 msgid "relations_object"
-msgstr ""
+msgstr "relaciones de"
 
 msgctxt "CWRType"
 msgid "relations_object"
-msgstr ""
+msgstr "relaciones de"
 
 msgid "relative url of the bookmarked page"
 msgstr "Url relativa de la página"
@@ -3633,7 +3668,7 @@
 msgstr "Seguridad"
 
 msgid "see more"
-msgstr ""
+msgstr "ver más"
 
 msgid "see them all"
 msgstr "Ver todos"
@@ -3728,7 +3763,7 @@
 msgstr "Una propiedad específica al Sistema no puede ser propia al usuario"
 
 msgid "siteinfo"
-msgstr ""
+msgstr "información"
 
 msgid "some errors occurred:"
 msgstr "Algunos errores encontrados :"
@@ -3744,6 +3779,8 @@
 "source's configuration. One key=value per line, authorized keys depending on "
 "the source's type"
 msgstr ""
+"configuración de fuentes. Una clave=valor por línea, las claves permitidas "
+"dependen del tipo de la fuente."
 
 msgid "sparql xml"
 msgstr "XML Sparql"
@@ -3767,7 +3804,7 @@
 
 #, python-format
 msgid "specifying %s is mandatory"
-msgstr ""
+msgstr "especificar %s es obligatorio"
 
 msgid "startup views"
 msgstr "Vistas de inicio"
@@ -3899,7 +3936,7 @@
 msgstr "Simétrico"
 
 msgid "synchronization-interval must be greater than 1 minute"
-msgstr ""
+msgstr "synchronization-interval debe ser mayor a 1 minuto"
 
 msgid "table"
 msgstr "Tabla"
@@ -3933,6 +3970,7 @@
 
 msgid "the system source has its configuration stored on the file-system"
 msgstr ""
+"el sistema fuente tiene su configuración almacenada en el sistema de archivos"
 
 #, python-format
 msgid "the value \"%s\" is already used, use another one"
@@ -3945,13 +3983,13 @@
 msgstr "Esta Entidad es propiedad de"
 
 msgid "this parser doesn't use a mapping"
-msgstr ""
+msgstr "este analizador (parser) no utiliza mapeo"
 
 msgid "this resource does not exist"
 msgstr "Este recurso no existe"
 
 msgid "this source doesn't use a mapping"
-msgstr ""
+msgstr "esta fuente no utiliza mapeo"
 
 msgid "thursday"
 msgstr "Jueves"
@@ -4022,7 +4060,7 @@
 msgstr "Transición hacia este Estado"
 
 msgid "today"
-msgstr ""
+msgstr "hoy"
 
 msgid "todo_by"
 msgstr "Asignada a"
@@ -4031,11 +4069,11 @@
 msgstr "Cambiar valor"
 
 msgid "tr_count"
-msgstr ""
+msgstr "n° de transición"
 
 msgctxt "TrInfo"
 msgid "tr_count"
-msgstr ""
+msgstr "n° de transición"
 
 msgid "transaction undoed"
 msgstr "Transacciones Anuladas"
@@ -4090,7 +4128,7 @@
 
 msgctxt "CWSource"
 msgid "type"
-msgstr ""
+msgstr "tipo"
 
 msgctxt "Transition"
 msgid "type"
@@ -4104,7 +4142,7 @@
 msgstr "Escriba aquí su consulta en Sparql"
 
 msgid "type of the source"
-msgstr ""
+msgstr "tipo de la fuente"
 
 msgid "ui"
 msgstr "Interfaz Genérica"
@@ -4159,18 +4197,18 @@
 
 #, python-format
 msgid "unknown option(s): %s"
-msgstr ""
+msgstr "opcion(es) desconocida(s): %s"
 
 #, python-format
 msgid "unknown options %s"
-msgstr ""
+msgstr "opciones desconocidas: %s"
 
 #, python-format
 msgid "unknown property key %s"
 msgstr "Clave de Propiedad desconocida: %s"
 
 msgid "unknown source type"
-msgstr ""
+msgstr "tipo de fuente desconocida"
 
 msgid "unknown vocabulary:"
 msgstr "Vocabulario desconocido: "
@@ -4225,11 +4263,11 @@
 msgstr "URI"
 
 msgid "url"
-msgstr ""
+msgstr "url"
 
 msgctxt "CWSource"
 msgid "url"
-msgstr ""
+msgstr "url"
 
 msgid "use template languages"
 msgstr "Utilizar plantillas de lenguaje"
@@ -4297,10 +4335,10 @@
 msgstr "Usuarios"
 
 msgid "users and groups"
-msgstr ""
+msgstr "usuarios y grupos"
 
 msgid "users and groups management"
-msgstr ""
+msgstr "usuarios y grupos de administradores"
 
 msgid "users using this bookmark"
 msgstr "Usuarios utilizando este Favorito"
@@ -4377,13 +4415,13 @@
 
 #, python-format
 msgid "violates unique_together constraints (%s)"
-msgstr ""
+msgstr "viola el principio (o restricción) de singularidad (%s)"
 
 msgid "visible"
 msgstr "Visible"
 
 msgid "warning"
-msgstr ""
+msgstr "atención"
 
 msgid "we are not yet ready to handle this query"
 msgstr "Aún no podemos manejar este tipo de consulta Sparql"
@@ -4482,77 +4520,16 @@
 
 #, python-format
 msgid "you may want to specify something for %s"
-msgstr ""
+msgstr "usted desea quizás especificar algo para la relación %s"
 
 msgid "you should probably delete that property"
-msgstr "Debería probablamente suprimir esta propriedad"
+msgstr "probablamente debería  suprimir esta propriedad"
 
 #, python-format
 msgid "you should un-inline relation %s which is supported and may be crossed "
 msgstr ""
-
-#~ msgid "Attributes with non default permissions:"
-#~ msgstr "Atributos con permisos no estándares"
-
-#~ msgid "Entity types"
-#~ msgstr "Tipos de entidades"
-
-#~ msgid "Index"
-#~ msgstr "Índice"
-
-#~ msgid "Permissions for entity types"
-#~ msgstr "Permisos por tipos de entidad"
-
-#~ msgid "Permissions for relations"
-#~ msgstr "Permisos por las relaciones"
-
-#~ msgid "Relation types"
-#~ msgstr "Tipos de relación"
-
-#~ msgid "am/pm calendar (month)"
-#~ msgstr "calendario am/pm (mes)"
-
-#~ msgid "am/pm calendar (semester)"
-#~ msgstr "calendario am/pm (semestre)"
-
-#~ msgid "am/pm calendar (week)"
-#~ msgstr "calendario am/pm (semana)"
-
-#~ msgid "am/pm calendar (year)"
-#~ msgstr "calendario am/pm (año)"
-
-#~ msgid "application entities"
-#~ msgstr "Entidades de la aplicación"
-
-#~ msgid "calendar (month)"
-#~ msgstr "calendario (mensual)"
-
-#~ msgid "calendar (semester)"
-#~ msgstr "calendario (semestral)"
-
-#~ msgid "calendar (week)"
-#~ msgstr "calendario (semanal)"
-
-#~ msgid "calendar (year)"
-#~ msgstr "calendario (anual)"
-
-#~ msgid "create an index page"
-#~ msgstr "Crear una página de inicio"
-
-#~ msgid "edit the index page"
-#~ msgstr "Modificar la página de inicio"
-
-#~ msgid "schema entities"
-#~ msgstr "Entidades del esquema"
-
-#~ msgid "schema-security"
-#~ msgstr "Seguridad"
-
-#~ msgid "system entities"
-#~ msgstr "Entidades del sistema"
-
-#~ msgid "timestamp of the latest source synchronization."
-#~ msgstr "Fecha de la última sincronización de la fuente."
-
-#~ msgid "up"
-#~ msgstr "Arriba"
+"usted debe  quitar la puesta en línea de la relación %s que es aceptada y "
+"puede ser cruzada"
+
+#~ msgid "add a %s"
+#~ msgstr "agregar un %s"
--- a/i18n/fr.po	Mon May 16 16:24:00 2011 +0200
+++ b/i18n/fr.po	Mon May 16 16:25:33 2011 +0200
@@ -162,7 +162,7 @@
 msgstr "l'action '%s' ne prend pas d'option"
 
 #, python-format
-msgid "'%s' action require 'linkattr' option"
+msgid "'%s' action requires 'linkattr' option"
 msgstr "l'action '%s' nécessite une option 'linkattr'"
 
 msgid "(UNEXISTANT EID)"
@@ -449,7 +449,7 @@
 msgstr "Date et heure"
 
 msgid "Datetime_plural"
-msgstr "Date et heure"
+msgstr "Dates et heures"
 
 msgid "Decimal"
 msgstr "Nombre décimal"
@@ -736,6 +736,18 @@
 msgid "Submit bug report by mail"
 msgstr "Soumettre ce rapport par email"
 
+msgid "TZDatetime"
+msgstr "Date et heure internationale"
+
+msgid "TZDatetime_plural"
+msgstr "Dates et heures internationales"
+
+msgid "TZTime"
+msgstr "Heure internationale"
+
+msgid "TZTime_plural"
+msgstr "Heures internationales"
+
 #, python-format
 msgid "The view %s can not be applied to this query"
 msgstr "La vue %s ne peut être appliquée à cette requête"
@@ -1057,10 +1069,6 @@
 msgid "add WorkflowTransition transition_of Workflow object"
 msgstr "transition workflow"
 
-#, python-format
-msgid "add a %s"
-msgstr "ajouter un %s"
-
 msgctxt "inlined:CWRelation.from_entity.subject"
 msgid "add a CWEType"
 msgstr "ajouter un type d'entité sujet"
@@ -1934,10 +1942,10 @@
 msgstr "mappé par"
 
 msgid "cw_source"
-msgstr "from data source"
+msgstr "source"
 
 msgid "cw_source_object"
-msgstr "entities"
+msgstr "entités"
 
 msgid "cwetype-box"
 msgstr "vue \"boîte\""
@@ -2783,6 +2791,9 @@
 msgstr ""
 "indique quel état devrait être utilisé par défaut lorsqu'une entité est créée"
 
+msgid "indifferent"
+msgstr "indifférent"
+
 msgid "info"
 msgstr "information"
 
@@ -4535,6 +4546,9 @@
 #~ msgid "Relation types"
 #~ msgstr "Types de relation"
 
+#~ msgid "add a %s"
+#~ msgstr "ajouter un %s"
+
 #~ msgid "am/pm calendar (month)"
 #~ msgstr "calendrier am/pm (mois)"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.12.0_Any.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,2 @@
+add_entity_type('TZDatetime')
+add_entity_type('TZTime')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/scripts/chpasswd.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,48 @@
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import getpass
+
+from cubicweb import Binary
+from cubicweb.server.utils import crypt_password
+
+
+if __args__:
+    login = __args__.pop()
+else:
+    login = raw_input("login ? ")
+
+rset = rql('Any U WHERE U is CWUser, U login %(login)s', {'login': login})
+
+if len(rset) != 1:
+    sys.exit("user '%s' does not exist!" % login)
+
+pass1 = getpass.getpass(prompt='Enter new password ? ')
+pass2 = getpass.getpass(prompt='Confirm ? ')
+
+if pass1 != pass2:
+    sys.exit("passwords don't match!")
+
+crypted = crypt_password(pass1)
+
+cwuser = rset.get_entity(0,0)
+cwuser.set_attributes(upassword=Binary(crypted))
+commit()
+
+print("password updated.")
--- a/schema.py	Mon May 16 16:24:00 2011 +0200
+++ b/schema.py	Mon May 16 16:25:33 2011 +0200
@@ -28,6 +28,7 @@
 from logilab.common.decorators import cached, clear_cache, monkeypatch
 from logilab.common.logging_ext import set_log_methods
 from logilab.common.deprecation import deprecated, class_moved
+from logilab.common.textutils import splitstrip
 from logilab.common.graph import get_cycles
 from logilab.common.compat import any
 
@@ -179,35 +180,6 @@
 __builtins__['display_name'] = deprecated('[3.4] display_name should be imported from cubicweb.schema')(display_name)
 
 
-# rql expression utilities function ############################################
-
-def guess_rrqlexpr_mainvars(expression):
-    defined = set(split_expression(expression))
-    mainvars = []
-    if 'S' in defined:
-        mainvars.append('S')
-    if 'O' in defined:
-        mainvars.append('O')
-    if 'U' in defined:
-        mainvars.append('U')
-    if not mainvars:
-        raise Exception('unable to guess selection variables')
-    return ','.join(sorted(mainvars))
-
-def split_expression(rqlstring):
-    for expr in rqlstring.split(','):
-        for noparen in expr.split('('):
-            for word in noparen.split():
-                yield word
-
-def normalize_expression(rqlstring):
-    """normalize an rql expression to ease schema synchronization (avoid
-    suppressing and reinserting an expression if only a space has been added/removed
-    for instance)
-    """
-    return u', '.join(' '.join(expr.split()) for expr in rqlstring.split(','))
-
-
 # Schema objects definition ###################################################
 
 def ERSchema_display_name(self, req, form='', context=None):
@@ -640,175 +612,57 @@
     def schema_by_eid(self, eid):
         return self._eid_index[eid]
 
-
-# Possible constraints ########################################################
-
-class BaseRQLConstraint(BaseConstraint):
-    """base class for rql constraints
-    """
-    distinct_query = None
-
-    def __init__(self, restriction, mainvars=None):
-        self.restriction = normalize_expression(restriction)
-        if mainvars is None:
-            mainvars = guess_rrqlexpr_mainvars(restriction)
-        else:
-            normmainvars = []
-            for mainvar in mainvars.split(','):
-                mainvar = mainvar.strip()
-                if not mainvar.isalpha():
-                    raise Exception('bad mainvars %s' % mainvars)
-                normmainvars.append(mainvar)
-            assert mainvars, 'bad mainvars %s' % mainvars
-            mainvars = ','.join(sorted(normmainvars))
-        self.mainvars = mainvars
-
-    def serialize(self):
-        # start with a comma for bw compat, see below
-        return ';' + self.mainvars + ';' + self.restriction
-
-    @classmethod
-    def deserialize(cls, value):
-        # XXX < 3.5.10 bw compat
-        if not value.startswith(';'):
-            return cls(value)
-        _, mainvars, restriction = value.split(';', 2)
-        return cls(restriction, mainvars)
-
-    def check(self, entity, rtype, value):
-        """return true if the value satisfy the constraint, else false"""
-        # implemented as a hook in the repository
-        return 1
-
-    def repo_check(self, session, eidfrom, rtype, eidto):
-        """raise ValidationError if the relation doesn't satisfy the constraint
-        """
-        pass # this is a vocabulary constraint, not enforce XXX why?
-
-    def __str__(self):
-        if self.distinct_query:
-            selop = 'Any'
-        else:
-            selop = 'DISTINCT Any'
-        return '%s(%s %s WHERE %s)' % (self.__class__.__name__, selop,
-                                       self.mainvars, self.restriction)
-
-    def __repr__(self):
-        return '<%s @%#x>' % (self.__str__(), id(self))
-
-
-class RQLVocabularyConstraint(BaseRQLConstraint):
-    """the rql vocabulary constraint :
-
-    limit the proposed values to a set of entities returned by a rql query,
-    but this is not enforced at the repository level
-
-     restriction is additional rql restriction that will be added to
-     a predefined query, where the S and O variables respectivly represent
-     the subject and the object of the relation
-
-     mainvars is a string that should be used as selection variable (eg
-     `'Any %s WHERE ...' % mainvars`). If not specified, an attempt will be
-     done to guess it according to variable used in the expression.
-    """
-
-
-class RepoEnforcedRQLConstraintMixIn(object):
+# Bases for manipulating RQL in schema #########################################
 
-    def __init__(self, restriction, mainvars=None, msg=None):
-        super(RepoEnforcedRQLConstraintMixIn, self).__init__(restriction, mainvars)
-        self.msg = msg
-
-    def serialize(self):
-        # start with a semicolon for bw compat, see below
-        return ';%s;%s\n%s' % (self.mainvars, self.restriction,
-                               self.msg or '')
-
-    def deserialize(cls, value):
-        # XXX < 3.5.10 bw compat
-        if not value.startswith(';'):
-            return cls(value)
-        value, msg = value.split('\n', 1)
-        _, mainvars, restriction = value.split(';', 2)
-        return cls(restriction, mainvars, msg)
-    deserialize = classmethod(deserialize)
+def guess_rrqlexpr_mainvars(expression):
+    defined = set(split_expression(expression))
+    mainvars = set()
+    if 'S' in defined:
+        mainvars.add('S')
+    if 'O' in defined:
+        mainvars.add('O')
+    if 'U' in defined:
+        mainvars.add('U')
+    if not mainvars:
+        raise Exception('unable to guess selection variables')
+    return mainvars
 
-    def repo_check(self, session, eidfrom, rtype, eidto=None):
-        """raise ValidationError if the relation doesn't satisfy the constraint
-        """
-        if not self.match_condition(session, eidfrom, eidto):
-            # XXX at this point if both or neither of S and O are in mainvar we
-            # dunno if the validation error `occurred` on eidfrom or eidto (from
-            # user interface point of view)
-            #
-            # possible enhancement: check entity being created, it's probably
-            # the main eid unless this is a composite relation
-            if eidto is None or 'S' in self.mainvars or not 'O' in self.mainvars:
-                maineid = eidfrom
-                qname = role_name(rtype, 'subject')
-            else:
-                maineid = eidto
-                qname = role_name(rtype, 'object')
-            if self.msg:
-                msg = session._(self.msg)
-            else:
-                msg = '%(constraint)s %(restriction)s failed' % {
-                    'constraint':  session._(self.type()),
-                    'restriction': self.restriction}
-            raise ValidationError(maineid, {qname: msg})
+def split_expression(rqlstring):
+    for expr in rqlstring.split(','):
+        for noparen in expr.split('('):
+            for word in noparen.split():
+                yield word
 
-    def exec_query(self, session, eidfrom, eidto):
-        if eidto is None:
-            # checking constraint for an attribute relation
-            restriction = 'S eid %(s)s, ' + self.restriction
-            args = {'s': eidfrom}
-        else:
-            restriction = 'S eid %(s)s, O eid %(o)s, ' + self.restriction
-            args = {'s': eidfrom, 'o': eidto}
-        rql = 'Any %s WHERE %s' % (self.mainvars,  restriction)
-        if self.distinct_query:
-            rql = 'DISTINCT ' + rql
-        return session.execute(rql, args, build_descr=False)
-
-
-class RQLConstraint(RepoEnforcedRQLConstraintMixIn, RQLVocabularyConstraint):
-    """the rql constraint is similar to the RQLVocabularyConstraint but
-    are also enforced at the repository level
+def normalize_expression(rqlstring):
+    """normalize an rql expression to ease schema synchronization (avoid
+    suppressing and reinserting an expression if only a space has been
+    added/removed for instance)
     """
-    distinct_query = False
-
-    def match_condition(self, session, eidfrom, eidto):
-        return self.exec_query(session, eidfrom, eidto)
-
-
-class RQLUniqueConstraint(RepoEnforcedRQLConstraintMixIn, BaseRQLConstraint):
-    """the unique rql constraint check that the result of the query isn't
-    greater than one.
-
-    You *must* specify mainvars when instantiating the constraint since there is
-    no way to guess it correctly (e.g. if using S,O or U the constraint will
-    always be satisfied because we've to use a DISTINCT query).
-    """
-    # XXX turns mainvars into a required argument in __init__
-    distinct_query = True
-
-    def match_condition(self, session, eidfrom, eidto):
-        return len(self.exec_query(session, eidfrom, eidto)) <= 1
+    return u', '.join(' '.join(expr.split()) for expr in rqlstring.split(','))
 
 
 class RQLExpression(object):
+    """Base class for RQL expression used in schema (constraints and
+    permissions)
+    """
+    # these are overridden by set_log_methods below
+    # only defining here to prevent pylint from complaining
+    info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
 
     def __init__(self, expression, mainvars, eid):
         self.eid = eid # eid of the entity representing this rql expression
-        if not isinstance(mainvars, unicode):
-            mainvars = unicode(mainvars)
+        assert mainvars, 'bad mainvars %s' % mainvars
+        if isinstance(mainvars, basestring):
+            mainvars = set(splitstrip(mainvars))
+        elif not isinstance(mainvars, set):
+            mainvars = set(mainvars)
         self.mainvars = mainvars
         self.expression = normalize_expression(expression)
         try:
             self.rqlst = parse(self.full_rql, print_errors=False).children[0]
         except RQLSyntaxError:
             raise RQLSyntaxError(expression)
-        for mainvar in mainvars.split(','):
+        for mainvar in mainvars:
             if len(self.rqlst.defined_vars[mainvar].references()) <= 2:
                 _LOGGER.warn('You did not use the %s variable in your RQL '
                              'expression %s', mainvar, self)
@@ -832,6 +686,8 @@
     def __setstate__(self, state):
         self.__init__(*state)
 
+    # permission rql expression specific stuff #################################
+
     @cached
     def transform_has_permission(self):
         found = None
@@ -942,12 +798,10 @@
 
     @property
     def minimal_rql(self):
-        return 'Any %s WHERE %s' % (self.mainvars, self.expression)
+        return 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)),
+                                    self.expression)
 
-    # these are overridden by set_log_methods below
-    # only defining here to prevent pylint from complaining
-    info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
-
+# rql expressions for use in permission definition #############################
 
 class ERQLExpression(RQLExpression):
     def __init__(self, expression, mainvars=None, eid=None):
@@ -1024,12 +878,153 @@
             kwargs['o'] = toeid
         return self._check(session, **kwargs)
 
+
 # in yams, default 'update' perm for attributes granted to managers and owners.
 # Within cw, we want to default to users who may edit the entity holding the
 # attribute.
 ybo.DEFAULT_ATTRPERMS['update'] = (
     'managers', ERQLExpression('U has_update_permission X'))
 
+# additional cw specific constraints ###########################################
+
+class BaseRQLConstraint(RRQLExpression, BaseConstraint):
+    """base class for rql constraints"""
+    distinct_query = None
+
+    def serialize(self):
+        # start with a comma for bw compat,see below
+        return ';' + ','.join(sorted(self.mainvars)) + ';' + self.expression
+
+    @classmethod
+    def deserialize(cls, value):
+        # XXX < 3.5.10 bw compat
+        if not value.startswith(';'):
+            return cls(value)
+        _, mainvars, expression = value.split(';', 2)
+        return cls(expression, mainvars)
+
+    def check(self, entity, rtype, value):
+        """return true if the value satisfy the constraint, else false"""
+        # implemented as a hook in the repository
+        return 1
+
+    def __str__(self):
+        if self.distinct_query:
+            selop = 'Any'
+        else:
+            selop = 'DISTINCT Any'
+        return '%s(%s %s WHERE %s)' % (self.__class__.__name__, selop,
+                                       ','.join(sorted(self.mainvars)),
+                                       self.expression)
+
+    def __repr__(self):
+        return '<%s @%#x>' % (self.__str__(), id(self))
+
+
+class RQLVocabularyConstraint(BaseRQLConstraint):
+    """the rql vocabulary constraint:
+
+    limit the proposed values to a set of entities returned by a rql query,
+    but this is not enforced at the repository level
+
+     `expression` is additional rql restriction that will be added to
+     a predefined query, where the S and O variables respectivly represent
+     the subject and the object of the relation
+
+     `mainvars` is a set of variables that should be used as selection variable
+     (eg `'Any %s WHERE ...' % mainvars`). If not specified, an attempt will be
+     done to guess it according to variable used in the expression.
+    """
+
+    def repo_check(self, session, eidfrom, rtype, eidto):
+        """raise ValidationError if the relation doesn't satisfy the constraint
+        """
+        pass # this is a vocabulary constraint, not enforce 
+
+
+class RepoEnforcedRQLConstraintMixIn(object):
+
+    def __init__(self, expression, mainvars=None, msg=None):
+        super(RepoEnforcedRQLConstraintMixIn, self).__init__(expression, mainvars)
+        self.msg = msg
+
+    def serialize(self):
+        # start with a semicolon for bw compat, see below
+        return ';%s;%s\n%s' % (','.join(sorted(self.mainvars)), self.expression,
+                               self.msg or '')
+
+    def deserialize(cls, value):
+        # XXX < 3.5.10 bw compat
+        if not value.startswith(';'):
+            return cls(value)
+        value, msg = value.split('\n', 1)
+        _, mainvars, expression = value.split(';', 2)
+        return cls(expression, mainvars, msg)
+    deserialize = classmethod(deserialize)
+
+    def repo_check(self, session, eidfrom, rtype, eidto=None):
+        """raise ValidationError if the relation doesn't satisfy the constraint
+        """
+        if not self.match_condition(session, eidfrom, eidto):
+            # XXX at this point if both or neither of S and O are in mainvar we
+            # dunno if the validation error `occurred` on eidfrom or eidto (from
+            # user interface point of view)
+            #
+            # possible enhancement: check entity being created, it's probably
+            # the main eid unless this is a composite relation
+            if eidto is None or 'S' in self.mainvars or not 'O' in self.mainvars:
+                maineid = eidfrom
+                qname = role_name(rtype, 'subject')
+            else:
+                maineid = eidto
+                qname = role_name(rtype, 'object')
+            if self.msg:
+                msg = session._(self.msg)
+            else:
+                msg = '%(constraint)s %(expression)s failed' % {
+                    'constraint':  session._(self.type()),
+                    'expression': self.expression}
+            raise ValidationError(maineid, {qname: msg})
+
+    def exec_query(self, session, eidfrom, eidto):
+        if eidto is None:
+            # checking constraint for an attribute relation
+            expression = 'S eid %(s)s, ' + self.expression
+            args = {'s': eidfrom}
+        else:
+            expression = 'S eid %(s)s, O eid %(o)s, ' + self.expression
+            args = {'s': eidfrom, 'o': eidto}
+        rql = 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)), expression)
+        if self.distinct_query:
+            rql = 'DISTINCT ' + rql
+        return session.execute(rql, args, build_descr=False)
+
+
+class RQLConstraint(RepoEnforcedRQLConstraintMixIn, RQLVocabularyConstraint):
+    """the rql constraint is similar to the RQLVocabularyConstraint but
+    are also enforced at the repository level
+    """
+    distinct_query = False
+
+    def match_condition(self, session, eidfrom, eidto):
+        return self.exec_query(session, eidfrom, eidto)
+
+
+class RQLUniqueConstraint(RepoEnforcedRQLConstraintMixIn, BaseRQLConstraint):
+    """the unique rql constraint check that the result of the query isn't
+    greater than one.
+
+    You *must* specify `mainvars` when instantiating the constraint since there
+    is no way to guess it correctly (e.g. if using S,O or U the constraint will
+    always be satisfied because we've to use a DISTINCT query).
+    """
+    # XXX turns mainvars into a required argument in __init__
+    distinct_query = True
+
+    def match_condition(self, session, eidfrom, eidto):
+        return len(self.exec_query(session, eidfrom, eidto)) <= 1
+
+
 # workflow extensions #########################################################
 
 from yams.buildobjs import _add_relation as yams_add_relation
--- a/selectors.py	Mon May 16 16:24:00 2011 +0200
+++ b/selectors.py	Mon May 16 16:25:33 2011 +0200
@@ -196,7 +196,7 @@
 from warnings import warn
 from operator import eq
 
-from logilab.common.deprecation import class_renamed
+from logilab.common.deprecation import class_renamed, deprecated
 from logilab.common.compat import all, any
 from logilab.common.interface import implements as implements_iface
 
@@ -1160,9 +1160,12 @@
     See :class:`~cubicweb.selectors.EntitySelector` documentation for entity
     lookup / score rules according to the input context.
     """
-    def __init__(self, expression, once_is_enough=False):
+    def __init__(self, expression, once_is_enough=False, user_condition=False):
         super(rql_condition, self).__init__(once_is_enough)
-        if 'U' in frozenset(split_expression(expression)):
+        self.user_condition = user_condition
+        if user_condition:
+            rql = 'Any COUNT(U) WHERE U eid %%(u)s, %s' % expression
+        elif 'U' in frozenset(split_expression(expression)):
             rql = 'Any COUNT(X) WHERE X eid %%(x)s, U eid %%(u)s, %s' % expression
         else:
             rql = 'Any COUNT(X) WHERE X eid %%(x)s, %s' % expression
@@ -1171,13 +1174,30 @@
     def __str__(self):
         return '%s(%r)' % (self.__class__.__name__, self.rql)
 
-    def score(self, req, rset, row, col):
+    @lltrace
+    def __call__(self, cls, req, **kwargs):
+        if self.user_condition:
+            try:
+                return req.execute(self.rql, {'u': req.user.eid})[0][0]
+            except Unauthorized:
+                return 0
+        else:
+            return super(rql_condition, self).__call__(cls, req, **kwargs)
+
+    def _score(self, req, eid):
         try:
-            return req.execute(self.rql, {'x': rset[row][col],
-                                          'u': req.user.eid})[0][0]
+            return req.execute(self.rql, {'x': eid, 'u': req.user.eid})[0][0]
         except Unauthorized:
             return 0
 
+    def score(self, req, rset, row, col):
+        return self._score(req, rset[row][col])
+
+    def score_entity(self, entity):
+        return self._score(entity._cw, entity.eid)
+
+
+# workflow selectors ###########################################################
 
 class is_in_state(score_entity):
     """Return 1 if entity is in one of the states given as argument list
@@ -1189,9 +1209,8 @@
     * you must use the latest tr info thru the workflow adapter for repository
       side checking of the current state
 
-    In debug mode, this selector can raise:
-    :raises: :exc:`ValueError` for unknown states names
-        (etype workflow only not checked in custom workflow)
+    In debug mode, this selector can raise :exc:`ValueError` for unknown states names
+    (only checked on entities without a custom workflow)
 
     :rtype: int
     """
@@ -1231,40 +1250,46 @@
                            ','.join(str(s) for s in self.expected))
 
 
-class on_transition(is_in_state):
-    """Return 1 if entity is in one of the transitions given as argument list
-
-    Especially useful to match passed transition to enable notifications when
-    your workflow allows several transition to the same states.
+def on_fire_transition(etype, tr_name, from_state_name=None):
+    """Return 1 when entity of the type `etype` is going through transition of
+    the name `tr_name`. If `from_state_name` is specified, this selector will
+    also check the incoming state.
 
-    Note that if workflow `change_state` adapter method is used, this selector
-    will not be triggered.
-
-    You should use this instead of your own :class:`score_entity` selector to
-    avoid some gotchas:
-
-    * possible views gives a fake entity with no state
-    * you must use the latest tr info thru the workflow adapter for repository
-      side checking of the current state
+    You should use this selector on 'after_add_entity' hook, since it's actually
+    looking for addition of `TrInfo` entities. Hence in the hook, `self.entity`
+    will reference the matching `TrInfo` entity, allowing to get all the
+    transition details (including the entity to which is applied the transition
+    but also its original state, transition, destination state, user...).  See
+    :class:`cubicweb.entities.wfobjs.TrInfo` for more information.
+    """
+    def match_etype_and_transition(trinfo):
+        # take care trinfo.transition is None when calling change_state
+        return (trinfo.transition and trinfo.transition.name == tr_name
+                # is_instance() first two arguments are 'cls' (unused, so giving
+                # None is fine) and the request/session
+                and is_instance(etype)(None, trinfo._cw, entity=trinfo.for_entity))
 
-    In debug mode, this selector can raise:
-    :raises: :exc:`ValueError` for unknown transition names
-        (etype workflow only not checked in custom workflow)
+    return is_instance('TrInfo') & score_entity(match_etype_and_transition)
+
 
-    :rtype: int
+class match_transition(ExpectedValueSelector):
+    """Return 1 if `transition` argument is found in the input context which has
+    a `.name` attribute matching one of the expected names given to the
+    initializer.
+
+    This selector is expected to be used to customise the status change form in
+    the web ui.
     """
-    def _score(self, adapted):
-        trinfo = adapted.latest_trinfo()
-        if trinfo and trinfo.by_transition:
-            return trinfo.by_transition[0].name in self.expected
-
-    def _validate(self, adapted):
-        wf = adapted.current_workflow
-        valid = [n.name for n in wf.reverse_transition_of]
-        unknown = sorted(self.expected.difference(valid))
-        if unknown:
-            raise ValueError("%s: unknown transition(s): %s"
-                             % (wf.name, ",".join(unknown)))
+    @lltrace
+    def __call__(self, cls, req, transition=None, **kwargs):
+        # XXX check this is a transition that apply to the object?
+        if transition is None:
+            treid = req.form.get('treid', None)
+            if treid:
+                transition = req.entity_from_eid(treid)
+        if transition is not None and getattr(transition, 'name', None) in self.expected:
+            return 1
+        return 0
 
 
 # logged user selectors ########################################################
@@ -1504,23 +1529,6 @@
 
 # Other selectors ##############################################################
 
-# XXX deprecated ? maybe use on_transition selector instead ?
-class match_transition(ExpectedValueSelector):
-    """Return 1 if `transition` argument is found in the input context which has
-    a `.name` attribute matching one of the expected names given to the
-    initializer.
-    """
-    @lltrace
-    def __call__(self, cls, req, transition=None, **kwargs):
-        # XXX check this is a transition that apply to the object?
-        if transition is None:
-            treid = req.form.get('treid', None)
-            if treid:
-                transition = req.entity_from_eid(treid)
-        if transition is not None and getattr(transition, 'name', None) in self.expected:
-            return 1
-        return 0
-
 
 class match_exception(ExpectedValueSelector):
     """Return 1 if a view is specified an as its registry id is in one of the
@@ -1544,6 +1552,47 @@
 
 ## deprecated stuff ############################################################
 
+
+class on_transition(is_in_state):
+    """Return 1 if entity is in one of the transitions given as argument list
+
+    Especially useful to match passed transition to enable notifications when
+    your workflow allows several transition to the same states.
+
+    Note that if workflow `change_state` adapter method is used, this selector
+    will not be triggered.
+
+    You should use this instead of your own :class:`score_entity` selector to
+    avoid some gotchas:
+
+    * possible views gives a fake entity with no state
+    * you must use the latest tr info thru the workflow adapter for repository
+      side checking of the current state
+
+    In debug mode, this selector can raise:
+    :raises: :exc:`ValueError` for unknown transition names
+        (etype workflow only not checked in custom workflow)
+
+    :rtype: int
+    """
+    @deprecated('[3.12] on_transition is deprecated, you should rather use '
+                'on_fire_transition(etype, trname)')
+    def __init__(self, *expected):
+        super(on_transition, self).__init__(*expected)
+
+    def _score(self, adapted):
+        trinfo = adapted.latest_trinfo()
+        if trinfo and trinfo.by_transition:
+            return trinfo.by_transition[0].name in self.expected
+
+    def _validate(self, adapted):
+        wf = adapted.current_workflow
+        valid = [n.name for n in wf.reverse_transition_of]
+        unknown = sorted(self.expected.difference(valid))
+        if unknown:
+            raise ValueError("%s: unknown transition(s): %s"
+                             % (wf.name, ",".join(unknown)))
+
 entity_implements = class_renamed('entity_implements', is_instance)
 
 class _but_etype(EntitySelector):
--- a/server/hook.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/hook.py	Mon May 16 16:25:33 2011 +0200
@@ -270,13 +270,17 @@
                     'session_open', 'session_close'))
 ALL_HOOKS = ENTITIES_HOOKS | RELATIONS_HOOKS | SYSTEM_HOOKS
 
-def _iter_kwargs(entities, kwargs):
-    if not entities:
+def _iter_kwargs(entities, eids_from_to, kwargs):
+    if not entities and not eids_from_to:
         yield kwargs
-    else:
+    elif entities:
         for entity in entities:
             kwargs['entity'] = entity
             yield kwargs
+    else:
+        for subject, object in eids_from_to:
+            kwargs.update({'eidfrom': subject, 'eidto': object})
+            yield kwargs
 
 
 class HooksRegistry(CWRegistry):
@@ -304,12 +308,19 @@
             if 'entities' in kwargs:
                 assert 'entity' not in kwargs, \
                        'can\'t pass "entities" and "entity" arguments simultaneously'
+                assert 'eids_from_to' not in kwargs, \
+                       'can\'t pass "entities" and "eids_from_to" arguments simultaneously'
                 entities = kwargs.pop('entities')
+                eids_from_to = []
+            elif 'eids_from_to' in kwargs:
+                entities = []
+                eids_from_to = kwargs.pop('eids_from_to')
             else:
                 entities = []
+                eids_from_to = []
             # by default, hooks are executed with security turned off
             with security_enabled(session, read=False):
-                for _kwargs in _iter_kwargs(entities, kwargs):
+                for _kwargs in _iter_kwargs(entities, eids_from_to, kwargs):
                     hooks = sorted(self.possible_objects(session, **_kwargs),
                                    key=lambda x: x.order)
                     with security_enabled(session, write=False):
--- a/server/migractions.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/migractions.py	Mon May 16 16:25:33 2011 +0200
@@ -162,7 +162,7 @@
 
     # server specific migration methods ########################################
 
-    def backup_database(self, backupfile=None, askconfirm=True):
+    def backup_database(self, backupfile=None, askconfirm=True, format='native'):
         config = self.config
         repo = self.repo_connect()
         # paths
@@ -185,16 +185,24 @@
         # backup
         tmpdir = tempfile.mkdtemp()
         try:
+            failed = False
             for source in repo.sources:
                 try:
-                    source.backup(osp.join(tmpdir, source.uri), self.confirm)
+                    source.backup(osp.join(tmpdir, source.uri), self.confirm, format=format)
                 except Exception, ex:
                     print '-> error trying to backup %s [%s]' % (source.uri, ex)
                     if not self.confirm('Continue anyway?', default='n'):
                         raise SystemExit(1)
                     else:
-                        break
-            else:
+                        failed = True
+            with open(osp.join(tmpdir, 'format.txt'), 'w') as format_file:
+                format_file.write('%s\n' % format)
+            with open(osp.join(tmpdir, 'versions.txt'), 'w') as version_file:
+                versions = repo.get_versions()
+                for cube, version in versions.iteritems():
+                    version_file.write('%s %s\n' % (cube, version))
+                    
+            if not failed:
                 bkup = tarfile.open(backupfile, 'w|gz')
                 for filename in os.listdir(tmpdir):
                     bkup.add(osp.join(tmpdir, filename), filename)
@@ -207,7 +215,7 @@
             shutil.rmtree(tmpdir)
 
     def restore_database(self, backupfile, drop=True, systemonly=True,
-                         askconfirm=True):
+                         askconfirm=True, format='native'):
         # check
         if not osp.exists(backupfile):
             raise ExecutionError("Backup file %s doesn't exist" % backupfile)
@@ -229,13 +237,18 @@
             bkup = tarfile.open(backupfile, 'r|gz')
             bkup.extractall(path=tmpdir)
             bkup.close()
+        if osp.isfile(osp.join(tmpdir, 'format.txt')):
+            with open(osp.join(tmpdir, 'format.txt')) as format_file:
+                written_format = format_file.readline().strip()
+                if written_format in ('portable', 'native'):
+                    format = written_format
         self.config.open_connections_pools = False
         repo = self.repo_connect()
         for source in repo.sources:
             if systemonly and source.uri != 'system':
                 continue
             try:
-                source.restore(osp.join(tmpdir, source.uri), self.confirm, drop)
+                source.restore(osp.join(tmpdir, source.uri), self.confirm, drop, format)
             except Exception, exc:
                 print '-> error trying to restore %s [%s]' % (source.uri, exc)
                 if not self.confirm('Continue anyway?', default='n'):
@@ -438,7 +451,8 @@
                                  'X expression %%(expr)s, X mainvars %%(vars)s, T %s X '
                                  'WHERE T eid %%(x)s' % perm,
                                  {'expr': expr, 'exprtype': exprtype,
-                                  'vars': expression.mainvars, 'x': teid},
+                                  'vars': u','.join(sorted(expression.mainvars)),
+                                  'x': teid},
                                  ask_confirm=False)
 
     def _synchronize_rschema(self, rtype, syncrdefs=True,
@@ -757,9 +771,9 @@
         targeted type is known
         """
         instschema = self.repo.schema
-        assert not etype in instschema, \
+        eschema = self.fs_schema.eschema(etype)
+        assert eschema.final or not etype in instschema, \
                '%s already defined in the instance schema' % etype
-        eschema = self.fs_schema.eschema(etype)
         confirm = self.verbosity >= 2
         groupmap = self.group_mapping()
         cstrtypemap = self.cstrtype_mapping()
@@ -1248,6 +1262,12 @@
             self.commit()
         return wf
 
+    def cmd_get_workflow_for(self, etype):
+        """return default workflow for the given entity type"""
+        rset = self.rqlexec('Workflow X WHERE ET default_workflow X, ET name %(et)s',
+                            {'et': etype})
+        return rset.get_entity(0, 0)
+
     # XXX remove once cmd_add_[state|transition] are removed
     def _get_or_create_wf(self, etypes):
         if not isinstance(etypes, (list, tuple)):
--- a/server/msplanner.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/msplanner.py	Mon May 16 16:25:33 2011 +0200
@@ -483,7 +483,12 @@
             else:
                 var = vref.variable
                 for rel in var.stinfo['relations'] - var.stinfo['rhsrelations']:
-                    if rel.r_type in ('eid', 'name'):
+                    # skip neged eid relation since it's the kind of query
+                    # generated when clearing old value of '?1" relation,
+                    # cw_source included. See
+                    # unittest_ldapuser.test_copy_to_system_source
+                    if rel.r_type == 'name' or \
+                       (rel.r_type == 'eid' and not rel.neged(strict=True)):
                         if rel.r_type == 'eid':
                             slist = sourceeids
                         else:
--- a/server/querier.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/querier.py	Mon May 16 16:25:33 2011 +0200
@@ -556,6 +556,8 @@
     def insert_relation_defs(self):
         session = self.session
         repo = session.repo
+        edited_entities = {}
+        relations = {}
         for subj, rtype, obj in self.relation_defs():
             # if a string is given into args instead of an int, we get it here
             if isinstance(subj, basestring):
@@ -567,12 +569,21 @@
             elif not isinstance(obj, (int, long)):
                 obj = obj.entity.eid
             if repo.schema.rschema(rtype).inlined:
-                entity = session.entity_from_eid(subj)
-                edited = EditedEntity(entity)
+                if subj not in edited_entities:
+                    entity = session.entity_from_eid(subj)
+                    edited = EditedEntity(entity)
+                    edited_entities[subj] = edited
+                else:
+                    edited = edited_entities[subj]
                 edited.edited_attribute(rtype, obj)
-                repo.glob_update_entity(session, edited)
             else:
-                repo.glob_add_relation(session, subj, rtype, obj)
+                if rtype in relations:
+                    relations[rtype].append((subj, obj))
+                else:
+                    relations[rtype] = [(subj, obj)]
+        repo.glob_add_relations(session, relations)
+        for edited in edited_entities.itervalues():
+            repo.glob_update_entity(session, edited)
 
 
 class QuerierHelper(object):
--- a/server/repository.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/repository.py	Mon May 16 16:25:33 2011 +0200
@@ -59,13 +59,18 @@
      security_enabled
 from cubicweb.server.ssplanner import EditedEntity
 
+NO_CACHE_RELATIONS = set( [('require_permission', 'object'),
+                           ('owned_by', 'object'),
+                           ('created_by', 'object'),
+                           ('cw_source', 'object'),
+                           ])
 
 def prefill_entity_caches(entity, relations):
     session = entity._cw
     # prefill entity relation caches
     for rschema in entity.e_schema.subject_relations():
         rtype = str(rschema)
-        if rtype in schema.VIRTUAL_RTYPES:
+        if rtype in schema.VIRTUAL_RTYPES or (rtype, 'subject') in NO_CACHE_RELATIONS:
             continue
         if rschema.final:
             entity.cw_attr_cache.setdefault(rtype, None)
@@ -74,7 +79,7 @@
                                          session.empty_rset())
     for rschema in entity.e_schema.object_relations():
         rtype = str(rschema)
-        if rtype in schema.VIRTUAL_RTYPES:
+        if rtype in schema.VIRTUAL_RTYPES or (rtype, 'object') in NO_CACHE_RELATIONS:
             continue
         entity.cw_set_relation_cache(rtype, 'object', session.empty_rset())
     # set inlined relation cache before call to after_add_entity
@@ -178,8 +183,8 @@
             # information (eg dump/restore/...)
             config._cubes = ()
             # only load hooks and entity classes in the registry
-            config.cube_appobject_path = set(('hooks', 'entities'))
-            config.cubicweb_appobject_path = set(('hooks', 'entities'))
+            config.__class__.cube_appobject_path = set(('hooks', 'entities'))
+            config.__class__.cubicweb_appobject_path = set(('hooks', 'entities'))
             self.set_schema(config.load_schema())
             config['connections-pool-size'] = 1
             # will be reinitialized later from cubes found in the database
@@ -1375,19 +1380,45 @@
 
     def glob_add_relation(self, session, subject, rtype, object):
         """add a relation to the repository"""
-        if server.DEBUG & server.DBG_REPO:
-            print 'ADD relation', subject, rtype, object
-        source = self.locate_relation_source(session, subject, rtype, object)
-        if source.should_call_hooks:
-            del_existing_rel_if_needed(session, subject, rtype, object)
-            self.hm.call_hooks('before_add_relation', session,
-                               eidfrom=subject, rtype=rtype, eidto=object)
-        source.add_relation(session, subject, rtype, object)
-        rschema = self.schema.rschema(rtype)
-        session.update_rel_cache_add(subject, rtype, object, rschema.symmetric)
-        if source.should_call_hooks:
-            self.hm.call_hooks('after_add_relation', session,
-                               eidfrom=subject, rtype=rtype, eidto=object)
+        self.glob_add_relations(session, {rtype: [(subject, object)]})
+
+    def glob_add_relations(self, session, relations):
+        """add several relations to the repository
+
+        relations is a dictionary rtype: [(subj_eid, obj_eid), ...]
+        """
+        sources = {}
+        for rtype, eids_subj_obj in relations.iteritems():
+            if server.DEBUG & server.DBG_REPO:
+                for subject, object in relations:
+                    print 'ADD relation', subject, rtype, object
+            for subject, object in eids_subj_obj:
+                source = self.locate_relation_source(session, subject, rtype, object)
+                if source not in sources:
+                    relations_by_rtype = {}
+                    sources[source] = relations_by_rtype
+                else:
+                    relations_by_rtype = sources[source]
+                if rtype in relations_by_rtype:
+                    relations_by_rtype[rtype].append((subject, object))
+                else:
+                    relations_by_rtype[rtype] = [(subject, object)]
+        for source, relations_by_rtype in sources.iteritems():
+            if source.should_call_hooks:
+                for rtype, source_relations in relations_by_rtype.iteritems():
+                    for subject, object in source_relations:
+                        del_existing_rel_if_needed(session, subject, rtype, object)
+                    self.hm.call_hooks('before_add_relation', session,
+                                    rtype=rtype, eids_from_to=source_relations)
+            for rtype, source_relations in relations_by_rtype.iteritems():
+                source.add_relations(session, rtype, source_relations)
+                rschema = self.schema.rschema(rtype)
+                for subject, object in source_relations:
+                    session.update_rel_cache_add(subject, rtype, object, rschema.symmetric)
+            if source.should_call_hooks:
+                for rtype, source_relations in relations_by_rtype.iteritems():
+                    self.hm.call_hooks('after_add_relation', session,
+                                       rtype=rtype, eids_from_to=source_relations)
 
     def glob_delete_relation(self, session, subject, rtype, object):
         """delete a relation from the repository"""
--- a/server/rqlannotation.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/rqlannotation.py	Mon May 16 16:25:33 2011 +0200
@@ -78,18 +78,19 @@
                 continue
             lhs, rhs = rel.get_parts()
             onlhs = ref is lhs
+            role = 'subject' if onlhs else 'object'
             if rel.r_type == 'eid':
                 if not (onlhs and len(stinfo['relations']) > 1):
                     break
                 if not stinfo['constnode']:
-                    joins.add(rel)
+                    joins.add( (rel, role) )
                 continue
             elif rel.r_type == 'identity':
                 # identity can't be used as principal, so check other relation are used
                 # XXX explain rhs.operator == '='
                 if rhs.operator != '=' or len(stinfo['relations']) <= 1: #(stinfo['constnode'] and rhs.operator == '='):
                     break
-                joins.add(rel)
+                joins.add( (rel, role) )
                 continue
             rschema = getrschema(rel.r_type)
             if rel.optional:
@@ -116,7 +117,7 @@
                     # need join anyway if the variable appears in a final or
                     # inlined relation
                     break
-                joins.add(rel)
+                joins.add( (rel, role) )
                 continue
             if not stinfo['constnode']:
                 if rschema.inlined and rel.neged(strict=True):
@@ -129,7 +130,7 @@
                         break
                 elif rschema.symmetric and stinfo['selected']:
                     break
-            joins.add(rel)
+            joins.add( (rel, role) )
         else:
             # if there is at least one ambigous relation and no other to
             # restrict types, can't be invariant since we need to filter out
@@ -169,10 +170,15 @@
     diffscope_rels = {}
     ored_rels = set()
     diffscope_rels = set()
-    for rel in _sort(relations):
+    for rel, role in _sort(relations):
         # note: only eid and has_text among all final relations may be there
         if rel.r_type in ('eid', 'identity'):
             continue
+        if rel.optional is not None and len(relations) > 1:
+            if role == 'subject' and rel.optional == 'right':
+                continue
+            if role == 'object' and rel.optional == 'left':
+                continue
         if rel.ored(traverse_scope=True):
             ored_rels.add(rel)
         elif rel.scope is scope:
--- a/server/schemaserial.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/schemaserial.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -566,7 +566,7 @@
                 yield ('INSERT RQLExpression E: E expression %%(e)s, E exprtype %%(t)s, '
                        'E mainvars %%(v)s, X %s_permission E WHERE X eid %%(x)s' % action,
                        {'e': unicode(rqlexpr.expression),
-                        'v': unicode(rqlexpr.mainvars),
+                        'v': unicode(','.join(sorted(rqlexpr.mainvars))),
                         't': unicode(rqlexpr.__class__.__name__)})
 
 # update functions
--- a/server/serverctl.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/serverctl.py	Mon May 16 16:25:33 2011 +0200
@@ -691,19 +691,20 @@
         'Continue anyway?' % filename):
         raise ExecutionError('Error while deleting remote dump at /tmp/%s' % filename)
 
-def _local_dump(appid, output):
+
+def _local_dump(appid, output, format='native'):
     config = ServerConfiguration.config_for(appid)
     config.quick_start = True
     mih = config.migration_handler(connect=False, verbosity=1)
-    mih.backup_database(output, askconfirm=False)
+    mih.backup_database(output, askconfirm=False, format=format)
     mih.shutdown()
 
-def _local_restore(appid, backupfile, drop, systemonly=True):
+def _local_restore(appid, backupfile, drop, systemonly=True, format='native'):
     config = ServerConfiguration.config_for(appid)
     config.verbosity = 1 # else we won't be asked for confirmation on problems
     config.quick_start = True
     mih = config.migration_handler(connect=False, verbosity=1)
-    mih.restore_database(backupfile, drop, systemonly, askconfirm=False)
+    mih.restore_database(backupfile, drop, systemonly, askconfirm=False, format=format)
     repo = mih.repo_connect()
     # version of the database
     dbversions = repo.get_versions()
@@ -777,6 +778,12 @@
           'default' : False,
           'help': 'Use sudo on the remote host.'}
          ),
+        ('format',
+         {'short': 'f', 'default': 'native', 'type': 'choice',
+          'choices': ('native', 'portable'),
+          'help': '"native" format uses db backend utilities to dump the database. '
+                  '"portable" format uses a database independent format'}
+         ),
         )
 
     def run(self, args):
@@ -785,7 +792,9 @@
             host, appid = appid.split(':')
             _remote_dump(host, appid, self.config.output, self.config.sudo)
         else:
-            _local_dump(appid, self.config.output)
+            _local_dump(appid, self.config.output, format=self.config.format)
+
+
 
 
 class DBRestoreCommand(Command):
@@ -811,13 +820,33 @@
           'instance data. In that case, <backupfile> is expected to be the '
           'timestamp of the backup to restore, not a file'}
          ),
+        ('format',
+         {'short': 'f', 'default': 'native', 'type': 'choice',
+          'choices': ('native', 'portable'),
+          'help': 'the format used when dumping the database'}),
         )
 
     def run(self, args):
         appid, backupfile = args
+        if self.config.format == 'portable':
+            # we need to ensure a DB exist before restoring from portable format
+            if not self.config.no_drop:
+                try:
+                    CWCTL.run(['db-create', '--automatic', appid])
+                except SystemExit, exc:
+                    # continue if the command exited with status 0 (success)
+                    if exc.code:
+                        raise
         _local_restore(appid, backupfile,
                        drop=not self.config.no_drop,
-                       systemonly=not self.config.restore_all)
+                       systemonly=not self.config.restore_all,
+                       format=self.config.format)
+        if self.config.format == 'portable':
+            try:
+                CWCTL.run(['db-rebuild-fti', appid])
+            except SystemExit, exc:
+                if exc.code:
+                    raise
 
 
 class DBCopyCommand(Command):
@@ -850,6 +879,12 @@
           'default' : False,
           'help': 'Use sudo on the remote host.'}
          ),
+        ('format',
+         {'short': 'f', 'default': 'native', 'type': 'choice',
+          'choices': ('native', 'portable'),
+          'help': '"native" format uses db backend utilities to dump the database. '
+                  '"portable" format uses a database independent format'}
+         ),
         )
 
     def run(self, args):
@@ -861,8 +896,9 @@
             host, srcappid = srcappid.split(':')
             _remote_dump(host, srcappid, output, self.config.sudo)
         else:
-            _local_dump(srcappid, output)
-        _local_restore(destappid, output, not self.config.no_drop)
+            _local_dump(srcappid, output, format=self.config.format)
+        _local_restore(destappid, output, not self.config.no_drop,
+                       self.config.format)
         if self.config.keep_dump:
             print '-> you can get the dump file at', output
         else:
--- a/server/session.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/session.py	Mon May 16 16:25:33 2011 +0200
@@ -33,12 +33,14 @@
 from yams import BASE_TYPES
 
 from cubicweb import Binary, UnknownEid, QueryError, schema
+from cubicweb.selectors import objectify_selector
 from cubicweb.req import RequestSessionBase
 from cubicweb.dbapi import ConnectionProperties
 from cubicweb.utils import make_uid, RepeatList
 from cubicweb.rqlrewrite import RQLRewriter
 from cubicweb.server.edition import EditedEntity
 
+
 ETYPE_PYOBJ_MAP[Binary] = 'Bytes'
 
 NO_UNDO_TYPES = schema.SCHEMA_TYPES.copy()
@@ -58,6 +60,20 @@
         description.append(term.get_type(solution, args))
     return description
 
+@objectify_selector
+def is_user_session(cls, req, **kwargs):
+    """repository side only selector returning 1 if the session is a regular
+    user session and not an internal session
+    """
+    return not req.is_internal_session
+
+@objectify_selector
+def is_internal_session(cls, req, **kwargs):
+    """repository side only selector returning 1 if the session is not a regular
+    user session but an internal session
+    """
+    return req.is_internal_session
+
 
 class hooks_control(object):
     """context manager to control activated hooks categories.
@@ -166,6 +182,7 @@
         self.__threaddata = threading.local()
         self._threads_in_transaction = set()
         self._closed = False
+        self._closed_lock = threading.Lock()
 
     def __unicode__(self):
         return '<%ssession %s (%s 0x%x)>' % (
@@ -213,14 +230,34 @@
         You may use this in hooks when you know both eids of the relation you
         want to add.
         """
+        self.add_relations([(rtype, [(fromeid,  toeid)])])
+
+    def add_relations(self, relations):
+        '''set many relation using a shortcut similar to the one in add_relation
+        
+        relations is a list of 2-uples, the first element of each
+        2-uple is the rtype, and the second is a list of (fromeid,
+        toeid) tuples
+        '''
+        edited_entities = {}
+        relations_dict = {}
         with security_enabled(self, False, False):
-            if self.vreg.schema[rtype].inlined:
-                entity = self.entity_from_eid(fromeid)
-                edited = EditedEntity(entity)
-                edited.edited_attribute(rtype, toeid)
+            for rtype, eids in relations:
+                if self.vreg.schema[rtype].inlined:
+                    for fromeid, toeid in eids:
+                        if fromeid not in edited_entities:
+                            entity = self.entity_from_eid(fromeid)
+                            edited = EditedEntity(entity)
+                            edited_entities[fromeid] = edited
+                        else:
+                            edited = edited_entities[fromeid]
+                        edited.edited_attribute(rtype, toeid)
+                else:
+                    relations_dict[rtype] = eids
+            self.repo.glob_add_relations(self, relations_dict)
+            for edited in edited_entities.itervalues():
                 self.repo.glob_update_entity(self, edited)
-            else:
-                self.repo.glob_add_relation(self, fromeid, rtype, toeid)
+
 
     def delete_relation(self, fromeid, rtype, toeid):
         """provide direct access to the repository method to delete a relation.
@@ -582,21 +619,22 @@
 
     def set_pool(self):
         """the session need a pool to execute some queries"""
-        if self._closed:
-            self.reset_pool(True)
-            raise Exception('try to set pool on a closed session')
-        if self.pool is None:
-            # get pool first to avoid race-condition
-            self._threaddata.pool = pool = self.repo._get_pool()
-            try:
-                pool.pool_set()
-            except:
-                self._threaddata.pool = None
-                self.repo._free_pool(pool)
-                raise
-            self._threads_in_transaction.add(
-                (threading.currentThread(), pool) )
-        return self._threaddata.pool
+        with self._closed_lock:
+            if self._closed:
+                self.reset_pool(True)
+                raise Exception('try to set pool on a closed session')
+            if self.pool is None:
+                # get pool first to avoid race-condition
+                self._threaddata.pool = pool = self.repo._get_pool()
+                try:
+                    pool.pool_set()
+                except:
+                    self._threaddata.pool = None
+                    self.repo._free_pool(pool)
+                    raise
+                self._threads_in_transaction.add(
+                    (threading.currentThread(), pool) )
+            return self._threaddata.pool
 
     def _free_thread_pool(self, thread, pool, force_close=False):
         try:
@@ -834,7 +872,8 @@
 
     def close(self):
         """do not close pool on session close, since they are shared now"""
-        self._closed = True
+        with self._closed_lock:
+            self._closed = True
         # copy since _threads_in_transaction maybe modified while waiting
         for thread, pool in self._threads_in_transaction.copy():
             if thread is threading.currentThread():
--- a/server/sources/__init__.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/sources/__init__.py	Mon May 16 16:25:33 2011 +0200
@@ -139,11 +139,11 @@
             return -1
         return cmp(self.uri, other.uri)
 
-    def backup(self, backupfile, confirm):
+    def backup(self, backupfile, confirm, format='native'):
         """method called to create a backup of source's data"""
         pass
 
-    def restore(self, backupfile, confirm, drop):
+    def restore(self, backupfile, confirm, drop, format='native'):
         """method called to restore a backup of source's data"""
         pass
 
@@ -434,6 +434,13 @@
         """add a relation to the source"""
         raise NotImplementedError()
 
+    def add_relations(self, session,  rtype, subj_obj_list):
+        """add a relations to the source"""
+        # override in derived classes if you feel you can
+        # optimize
+        for subject, object in subj_obj_list:
+            self.add_relation(session, subject, rtype, object)
+
     def delete_relation(self, session, subject, rtype, object):
         """delete a relation from the source"""
         raise NotImplementedError()
--- a/server/sources/datafeed.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/sources/datafeed.py	Mon May 16 16:25:33 2011 +0200
@@ -120,7 +120,7 @@
             return False
         return datetime.now() < (self.latest_retrieval + self.synchro_interval)
 
-    def pull_data(self, session, force=False):
+    def pull_data(self, session, force=False, raise_on_error=False):
         if not force and self.fresh():
             return {}
         if self.config['delete-entities']:
@@ -135,6 +135,8 @@
                 if parser.process(url):
                     error = True
             except IOError, exc:
+                if raise_on_error:
+                    raise
                 self.error('could not pull data while processing %s: %s',
                            url, exc)
                 error = True
--- a/server/sources/native.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/sources/native.py	Mon May 16 16:25:33 2011 +0200
@@ -28,21 +28,29 @@
 
 __docformat__ = "restructuredtext en"
 
-from pickle import loads, dumps
+try:
+    from cPickle import loads, dumps
+    import cPickle as pickle
+except ImportError:
+    from pickle import loads, dumps
+    import pickle
 from threading import Lock
 from datetime import datetime
 from base64 import b64decode, b64encode
 from contextlib import contextmanager
-from os.path import abspath
+from os.path import abspath, basename
 import re
 import itertools
+import zipfile
+import logging
+import sys
 
 from logilab.common.compat import any
 from logilab.common.cache import Cache
 from logilab.common.decorators import cached, clear_cache
 from logilab.common.configuration import Method
 from logilab.common.shellutils import getlogin
-from logilab.database import get_db_helper
+from logilab.database import get_db_helper, sqlgen
 
 from yams import schema2sql as y2sql
 from yams.schema import role_name
@@ -354,24 +362,44 @@
                 _pool.pool_reset()
                 self.repo._free_pool(_pool)
 
-    def backup(self, backupfile, confirm):
+    def backup(self, backupfile, confirm, format='native'):
         """method called to create a backup of the source's data"""
-        self.close_pool_connections()
-        try:
-            self.backup_to_file(backupfile, confirm)
-        finally:
-            self.open_pool_connections()
+        if format == 'portable':
+            self.repo.fill_schema()
+            self.set_schema(self.repo.schema)
+            helper = DatabaseIndependentBackupRestore(self)
+            self.close_pool_connections()
+            try:
+                helper.backup(backupfile)
+            finally:
+                self.open_pool_connections()
+        elif format == 'native':
+            self.close_pool_connections()
+            try:
+                self.backup_to_file(backupfile, confirm)
+            finally:
+                self.open_pool_connections()
+        else:
+            raise ValueError('Unknown format %r' % format)
 
-    def restore(self, backupfile, confirm, drop):
+
+    def restore(self, backupfile, confirm, drop, format='native'):
         """method called to restore a backup of source's data"""
         if self.repo.config.open_connections_pools:
             self.close_pool_connections()
         try:
-            self.restore_from_file(backupfile, confirm, drop=drop)
+            if format == 'portable':
+                helper = DatabaseIndependentBackupRestore(self)
+                helper.restore(backupfile)
+            elif format == 'native':
+                self.restore_from_file(backupfile, confirm, drop=drop)
+            else:
+                raise ValueError('Unknown format %r' % format)
         finally:
             if self.repo.config.open_connections_pools:
                 self.open_pool_connections()
 
+
     def init(self, activated, source_entity):
         self.init_creating(source_entity._cw.pool)
 
@@ -628,22 +656,42 @@
 
     def add_relation(self, session, subject, rtype, object, inlined=False):
         """add a relation to the source"""
-        self._add_relation(session, subject, rtype, object, inlined)
+        self._add_relations(session,  rtype, [(subject, object)], inlined)
         if session.undoable_action('A', rtype):
             self._record_tx_action(session, 'tx_relation_actions', 'A',
                                    eid_from=subject, rtype=rtype, eid_to=object)
 
-    def _add_relation(self, session, subject, rtype, object, inlined=False):
+    def add_relations(self, session,  rtype, subj_obj_list, inlined=False):
+        """add a relations to the source"""
+        self._add_relations(session, rtype, subj_obj_list, inlined)
+        if session.undoable_action('A', rtype):
+            for subject, object in subj_obj_list:
+                self._record_tx_action(session, 'tx_relation_actions', 'A',
+                                       eid_from=subject, rtype=rtype, eid_to=object)
+                
+    def _add_relations(self, session, rtype, subj_obj_list, inlined=False):
         """add a relation to the source"""
+        sql = []
         if inlined is False:
-            attrs = {'eid_from': subject, 'eid_to': object}
-            sql = self.sqlgen.insert('%s_relation' % rtype, attrs)
+            attrs = [{'eid_from': subject, 'eid_to': object}
+                     for subject, object in subj_obj_list]
+            sql.append((self.sqlgen.insert('%s_relation' % rtype, attrs[0]), attrs))
         else: # used by data import
-            etype = session.describe(subject)[0]
-            attrs = {'cw_eid': subject, SQL_PREFIX + rtype: object}
-            sql = self.sqlgen.update(SQL_PREFIX + etype, attrs,
-                                     ['cw_eid'])
-        self.doexec(session, sql, attrs)
+            etypes = {}
+            for subject, object in subj_obj_list:
+                etype = session.describe(subject)[0]
+                if etype in etypes:
+                    etypes[etype].append((subject, object))
+                else:
+                    etypes[etype] = [(subject, object)]
+            for subj_etype, subj_obj_list in etypes.iteritems():
+                attrs = [{'cw_eid': subject, SQL_PREFIX + rtype: object}
+                         for subject, object in subj_obj_list]
+                sql.append((self.sqlgen.update(SQL_PREFIX + etype, attrs[0],
+                                     ['cw_eid']),
+                            attrs))
+        for statement, attrs in sql:
+            self.doexecmany(session, statement, attrs)
 
     def delete_relation(self, session, subject, rtype, object):
         """delete a relation from the source"""
@@ -1232,7 +1280,7 @@
             self.repo.hm.call_hooks('before_add_relation', session,
                                     eidfrom=subj, rtype=rtype, eidto=obj)
             # add relation in the database
-            self._add_relation(session, subj, rtype, obj, rdef.rtype.inlined)
+            self._add_relations(session, rtype, [(subj, obj)], rdef.rtype.inlined)
             # set related cache
             session.update_rel_cache_add(subj, rtype, obj, rdef.rtype.symmetric)
             self.repo.hm.call_hooks('after_add_relation', session,
@@ -1544,3 +1592,218 @@
         login = rset.rows[0][0]
         authinfo['email_auth'] = True
         return self.source.repo.check_auth_info(session, login, authinfo)
+
+class DatabaseIndependentBackupRestore(object):
+    """Helper class to perform db backend agnostic backup and restore
+
+    The backup and restore methods are used to dump / restore the
+    system database in a database independent format. The file is a
+    Zip archive containing the following files:
+
+    * format.txt: the format of the archive. Currently '1.0'
+    * tables.txt: list of filenames in the archive tables/ directory
+    * sequences.txt: list of filenames in the archive sequences/ directory
+    * versions.txt: the list of cube versions from CWProperty
+    * tables/<tablename>.<chunkno>: pickled data
+    * sequences/<sequencename>: pickled data
+
+    The pickled data format for tables and sequences is a tuple of 3 elements:
+    * the table name
+    * a tuple of column names
+    * a list of rows (as tuples with one element per column)
+
+    Tables are saved in chunks in different files in order to prevent
+    a too high memory consumption. 
+    """
+    def __init__(self, source):
+        """
+        :param: source an instance of the system source
+        """
+        self._source = source
+        self.logger = logging.getLogger('cubicweb.ctl')
+        self.logger.setLevel(logging.INFO)
+        self.logger.addHandler(logging.StreamHandler(sys.stdout))
+        self.schema = self._source.schema
+        self.dbhelper = self._source.dbhelper
+        self.cnx = None
+        self.cursor = None
+        self.sql_generator = sqlgen.SQLGenerator()
+
+    def get_connection(self):
+        return self._source.get_connection()
+
+    def backup(self, backupfile):
+        archive=zipfile.ZipFile(backupfile, 'w')
+        self.cnx = self.get_connection()
+        try:
+            self.cursor = self.cnx.cursor()
+            self.cursor.arraysize=100
+            self.logger.info('writing metadata')
+            self.write_metadata(archive)
+            for seq in self.get_sequences():
+                self.logger.info('processing sequence %s', seq)
+                self.write_sequence(archive, seq)
+            for table in self.get_tables():
+                self.logger.info('processing table %s', table)
+                self.write_table(archive, table)
+        finally:
+            archive.close()
+            self.cnx.close()
+        self.logger.info('done')
+
+    def get_tables(self):
+        non_entity_tables = ['entities',
+                             'deleted_entities',
+                             'transactions',
+                             'tx_entity_actions',
+                             'tx_relation_actions',
+                             ]
+        etype_tables = []
+        relation_tables = []
+        prefix = 'cw_'
+        for etype in self.schema.entities():
+            eschema = self.schema.eschema(etype)
+            print etype, eschema.final
+            if eschema.final:
+                continue
+            etype_tables.append('%s%s'%(prefix, etype))
+        for rtype in self.schema.relations():
+            rschema = self.schema.rschema(rtype)
+            if rschema.final or rschema.inlined:
+                continue
+            relation_tables.append('%s_relation' % rtype)
+        return non_entity_tables + etype_tables + relation_tables
+
+    def get_sequences(self):
+        return ['entities_id_seq']
+
+    def write_metadata(self, archive):
+        archive.writestr('format.txt', '1.0')
+        archive.writestr('tables.txt', '\n'.join(self.get_tables()))
+        archive.writestr('sequences.txt', '\n'.join(self.get_sequences()))
+        versions = self._get_versions()
+        versions_str = '\n'.join('%s %s' % (k,v)
+                                 for k,v in versions)
+        archive.writestr('versions.txt', versions_str)
+
+    def write_sequence(self, archive, seq):
+        sql = self.dbhelper.sql_sequence_current_state(seq)
+        columns, rows_iterator = self._get_cols_and_rows(sql)
+        rows = list(rows_iterator)
+        serialized = self._serialize(seq, columns, rows)
+        archive.writestr('sequences/%s' % seq, serialized)
+
+    def write_table(self, archive, table):
+        sql = 'SELECT * FROM %s' % table
+        columns, rows_iterator = self._get_cols_and_rows(sql)
+        self.logger.info('number of rows: %d', self.cursor.rowcount)
+        if table.startswith('cw_'): # entities
+            blocksize = 2000
+        else: # relations and metadata
+            blocksize = 10000
+        if self.cursor.rowcount > 0:
+            for i, start in enumerate(xrange(0, self.cursor.rowcount, blocksize)):
+                rows = list(itertools.islice(rows_iterator, blocksize))
+                serialized = self._serialize(table, columns, rows)
+                archive.writestr('tables/%s.%04d' % (table, i), serialized)
+                self.logger.debug('wrote rows %d to %d (out of %d) to %s.%04d',
+                                  start, start+len(rows)-1,
+                                  self.cursor.rowcount,
+                                  table, i)
+        else:
+            rows = []
+            serialized = self._serialize(table, columns, rows)
+            archive.writestr('tables/%s.%04d' % (table, 0), serialized)
+
+    def _get_cols_and_rows(self, sql):
+        process_result = self._source.iter_process_result
+        self.cursor.execute(sql)
+        columns = (d[0] for d in self.cursor.description)
+        rows = process_result(self.cursor)
+        return tuple(columns), rows
+
+    def _serialize(self, name, columns, rows):
+        return dumps((name, columns, rows), pickle.HIGHEST_PROTOCOL)
+
+    def restore(self, backupfile):
+        archive = zipfile.ZipFile(backupfile, 'r')
+        self.cnx = self.get_connection()
+        self.cursor = self.cnx.cursor()
+        sequences, tables, table_chunks = self.read_metadata(archive, backupfile)
+        for seq in sequences:
+            self.logger.info('restoring sequence %s', seq)
+            self.read_sequence(archive, seq)
+        for table in tables:
+            self.logger.info('restoring table %s', table)
+            self.read_table(archive, table, sorted(table_chunks[table]))
+        self.cnx.close()
+        archive.close()
+        self.logger.info('done')
+
+    def read_metadata(self, archive, backupfile):
+        formatinfo = archive.read('format.txt')
+        self.logger.info('checking metadata')
+        if formatinfo.strip() != "1.0":
+            self.logger.critical('Unsupported format in archive: %s', formatinfo)
+            raise ValueError('Unknown format in %s: %s' % (backupfile, formatinfo))
+        tables = archive.read('tables.txt').splitlines()
+        sequences = archive.read('sequences.txt').splitlines()
+        file_versions = self._parse_versions(archive.read('versions.txt'))
+        versions = set(self._get_versions())
+        if file_versions != versions:
+            self.logger.critical('Unable to restore : versions do not match')
+            self.logger.critical('Expected:\n%s', '\n'.join(list(sorted(versions))))
+            self.logger.critical('Found:\n%s', '\n'.join(list(sorted(file_versions))))
+            raise ValueError('Unable to restore : versions do not match')
+        table_chunks = {}
+        for name in archive.namelist():
+            if not name.startswith('tables/'):
+                continue
+            filename = basename(name)
+            tablename, _ext = filename.rsplit('.', 1)
+            table_chunks.setdefault(tablename, []).append(name)
+        return sequences, tables, table_chunks
+
+    def read_sequence(self, archive, seq):
+        seqname, columns, rows = loads(archive.read('sequences/%s' % seq))
+        assert seqname == seq
+        assert len(rows) == 1
+        assert len(rows[0]) == 1
+        value = rows[0][0]
+        sql = self.dbhelper.sql_restart_sequence(seq, value)
+        self.cursor.execute(sql)
+        self.cnx.commit()
+
+    def read_table(self, archive, table, filenames):
+        merge_args = self._source.merge_args
+        self.cursor.execute('DELETE FROM %s' % table)
+        self.cnx.commit()
+        row_count = 0
+        for filename in filenames:
+            tablename, columns, rows = loads(archive.read(filename))
+            assert tablename == table
+            if not rows:
+                continue
+            insert = self.sql_generator.insert(table,
+                                               dict(zip(columns, rows[0])))
+            for row in rows:
+                self.cursor.execute(insert, merge_args(dict(zip(columns, row)), {}))
+            row_count += len(rows)
+            self.cnx.commit()
+        self.logger.info('inserted %d rows', row_count)
+
+
+    def _parse_versions(self, version_str):
+        versions = set()
+        for line in version_str.splitlines():
+            versions.add(tuple(line.split()))
+        return versions
+
+    def _get_versions(self):
+        version_sql = 'SELECT cw_pkey, cw_value FROM cw_CWProperty'
+        versions = []
+        self.cursor.execute(version_sql)
+        for pkey, value in self.cursor.fetchall():
+            if pkey.startswith(u'system.version'):
+                versions.append((pkey, value))
+        return versions
--- a/server/sources/rql2sql.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/sources/rql2sql.py	Mon May 16 16:25:33 2011 +0200
@@ -50,7 +50,9 @@
 __docformat__ = "restructuredtext en"
 
 import threading
+from datetime import datetime, time
 
+from logilab.common.date import utcdatetime, utctime
 from logilab.database import FunctionDescr, SQL_FUNCTIONS_REGISTRY
 
 from rql import BadRQLQuery, CoercionError
@@ -82,6 +84,7 @@
         newvar.prepare_annotation()
         newvar.stinfo['scope'] = select
         newvar._q_invariant = False
+        select.selection.append(VariableRef(newvar))
     return newvar
 
 def _fill_to_wrap_rel(var, newselect, towrap, schema):
@@ -91,10 +94,12 @@
             towrap.add( (var, rel) )
             for vref in rel.children[1].iget_nodes(VariableRef):
                 newivar = _new_var(newselect, vref.name)
-                newselect.selection.append(VariableRef(newivar))
                 _fill_to_wrap_rel(vref.variable, newselect, towrap, schema)
         elif rschema.final:
             towrap.add( (var, rel) )
+            for vref in rel.children[1].iget_nodes(VariableRef):
+                newivar = _new_var(newselect, vref.name)
+                newivar.stinfo['attrvar'] = (var, rel.r_type)
 
 def rewrite_unstable_outer_join(select, solutions, unstable, schema):
     """if some optional variables are unstable, they should be selected in a
@@ -114,11 +119,6 @@
         # extract aliases / selection
         newvar = _new_var(newselect, var.name)
         newselect.selection = [VariableRef(newvar)]
-        for avar in select.defined_vars.itervalues():
-            if avar.stinfo['attrvar'] is var:
-                newavar = _new_var(newselect, avar.name)
-                newavar.stinfo['attrvar'] = newvar
-                newselect.selection.append(VariableRef(newavar))
         towrap_rels = set()
         _fill_to_wrap_rel(var, newselect, towrap_rels, schema)
         # extract relations
@@ -588,16 +588,16 @@
                 rconditions.append(condition)
             else:
                 lconditions.append(condition)
-        else:
-            if louter is not None:
-                raise BadRQLQuery()
+        elif louter is None:
             # merge chains
             self.outer_chains.remove(lchain)
+            rchain += lchain
             self.mark_as_used_in_outer_join(leftalias)
-            rchain += lchain
             for alias, (aouter, aconditions, achain) in outer_tables.iteritems():
                 if achain is lchain:
                     outer_tables[alias] = (aouter, aconditions, rchain)
+        else:
+            raise BadRQLQuery()
 
     # sql generation helpers ###################################################
 
@@ -1424,6 +1424,14 @@
                 _id = value
                 if isinstance(_id, unicode):
                     _id = _id.encode()
+                # convert timestamp to utc.
+                # expect SET TiME ZONE to UTC at connection opening time.
+                # This shouldn't change anything for datetime without TZ.
+                value = self._args[_id]
+                if isinstance(value, datetime) and value.tzinfo is not None:
+                    self._query_attrs[_id] = utcdatetime(value)
+                elif isinstance(value, time) and value.tzinfo is not None:
+                    self._query_attrs[_id] = utctime(value)
         else:
             _id = str(id(constant)).replace('-', '', 1)
             self._query_attrs[_id] = value
--- a/server/sqlutils.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/sqlutils.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -25,7 +25,7 @@
 
 from logilab import database as db, common as lgc
 from logilab.common.shellutils import ProgressBar
-from logilab.common.date import todate, todatetime
+from logilab.common.date import todate, todatetime, utcdatetime, utctime
 from logilab.database.sqlgen import SQLGenerator
 
 from cubicweb import Binary, ConfigurationError
@@ -204,6 +204,12 @@
     def process_result(self, cursor, column_callbacks=None, session=None):
         """return a list of CubicWeb compliant values from data in the given cursor
         """
+        return list(self.iter_process_result(cursor, column_callbacks, session))
+
+    def iter_process_result(self, cursor, column_callbacks=None, session=None):
+        """return a iterator on tuples of CubicWeb compliant values from data
+        in the given cursor
+        """
         # use two different implementations to avoid paying the price of
         # callback lookup for each *cell* in results when there is nothing to
         # lookup
@@ -219,16 +225,19 @@
         process_value = self._process_value
         binary = Binary
         # /end
-        results = cursor.fetchall()
-        for i, line in enumerate(results):
-            result = []
-            for col, value in enumerate(line):
-                if value is None:
-                    result.append(value)
-                    continue
-                result.append(process_value(value, descr[col], encoding, binary))
-            results[i] = result
-        return results
+        cursor.arraysize = 100
+        while True:
+            results = cursor.fetchmany()
+            if not results:
+                break
+            for line in results:
+                result = []
+                for col, value in enumerate(line):
+                    if value is None:
+                        result.append(value)
+                        continue
+                    result.append(process_value(value, descr[col], encoding, binary))
+                yield result
 
     def _cb_process_result(self, cursor, column_callbacks, session):
         # begin bind to locals for optimization
@@ -237,22 +246,25 @@
         process_value = self._process_value
         binary = Binary
         # /end
-        results = cursor.fetchall()
-        for i, line in enumerate(results):
-            result = []
-            for col, value in enumerate(line):
-                if value is None:
+        cursor.arraysize = 100
+        while True:
+            results = cursor.fetchmany()
+            if not results:
+                break
+            for line in results:
+                result = []
+                for col, value in enumerate(line):
+                    if value is None:
+                        result.append(value)
+                        continue
+                    cbstack = column_callbacks.get(col, None)
+                    if cbstack is None:
+                        value = process_value(value, descr[col], encoding, binary)
+                    else:
+                        for cb in cbstack:
+                            value = cb(self, session, value)
                     result.append(value)
-                    continue
-                cbstack = column_callbacks.get(col, None)
-                if cbstack is None:
-                    value = process_value(value, descr[col], encoding, binary)
-                else:
-                    for cb in cbstack:
-                        value = cb(self, session, value)
-                result.append(value)
-            results[i] = result
-        return results
+                yield result
 
     def preprocess_entity(self, entity):
         """return a dictionary to use as extra argument to cursor.execute
@@ -274,10 +286,15 @@
                         value = crypt_password(value)
                     value = self._binary(value)
                 # XXX needed for sqlite but I don't think it is for other backends
-                elif atype == 'Datetime' and isinstance(value, date):
+                # Note: use is __class__ since issubclass(datetime, date)
+                elif atype in ('Datetime', 'TZDatetime') and type(value) is date:
                     value = todatetime(value)
                 elif atype == 'Date' and isinstance(value, datetime):
                     value = todate(value)
+                elif atype == 'TZDatetime' and getattr(value, 'tzinfo', None):
+                    value = utcdatetime(value)
+                elif atype == 'TZTime' and getattr(value, 'tzinfo', None):
+                    value = utctime(value)
                 elif isinstance(value, Binary):
                     value = self._binary(value.getvalue())
             attrs[SQL_PREFIX+str(attr)] = value
@@ -326,3 +343,13 @@
 
 sqlite_hooks = SQL_CONNECT_HOOKS.setdefault('sqlite', [])
 sqlite_hooks.append(init_sqlite_connexion)
+
+
+def init_postgres_connexion(cnx):
+    cnx.cursor().execute('SET TIME ZONE UTC')
+    # commit is needed, else setting are lost if the connection is first
+    # rollbacked
+    cnx.commit()
+
+postgres_hooks = SQL_CONNECT_HOOKS.setdefault('postgres', [])
+postgres_hooks.append(init_postgres_connexion)
--- a/server/ssplanner.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/ssplanner.py	Mon May 16 16:25:33 2011 +0200
@@ -559,6 +559,7 @@
         session = self.plan.session
         repo = session.repo
         edefs = {}
+        relations = {}
         # insert relations
         if self.children:
             result = self.execute_child()
@@ -578,9 +579,14 @@
                         edefs[eid] = edited = EditedEntity(edef)
                     edited.edited_attribute(str(rschema), rhsval)
                 else:
-                    repo.glob_add_relation(session, lhsval, str(rschema), rhsval)
+                    str_rschema = str(rschema)
+                    if str_rschema in relations:
+                        relations[str_rschema].append((lhsval, rhsval))
+                    else:
+                        relations[str_rschema] = [(lhsval, rhsval)]
             result[i] = newrow
         # update entities
+        repo.glob_add_relations(session, relations)
         for eid, edited in edefs.iteritems():
             repo.glob_update_entity(session, edited)
         return result
--- a/server/test/data/schema.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/data/schema.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -18,7 +18,7 @@
 
 from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
                             SubjectRelation, RichString, String, Int, Float,
-                            Boolean, Datetime)
+                            Boolean, Datetime, TZDatetime)
 from yams.constraints import SizeConstraint
 from cubicweb.schema import (WorkflowableEntityType,
                              RQLConstraint, RQLUniqueConstraint,
@@ -114,6 +114,7 @@
     tel    = Int()
     fax    = Int()
     datenaiss = Datetime()
+    tzdatenaiss = TZDatetime()
     test   = Boolean(__permissions__={
         'read': ('managers', 'users', 'guests'),
         'update': ('managers',),
@@ -219,3 +220,26 @@
 class require_state(RelationDefinition):
     subject = 'CWPermission'
     object = 'State'
+
+class personne_composite(RelationDefinition):
+    subject='Personne'
+    object='Personne'
+    composite='subject'
+
+class personne_inlined(RelationDefinition):
+    subject='Personne'
+    object='Personne'
+    cardinality='?*'
+    inlined=True
+
+
+class login_user(RelationDefinition):
+    subject = 'Personne'
+    object = 'CWUser'
+    cardinality = '??'
+
+class ambiguous_inlined(RelationDefinition):
+    subject = ('Affaire', 'Note')
+    object = 'CWUser'
+    inlined = True
+    cardinality = '?*'
--- a/server/test/data/sources_fti	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-[system]
-
-db-driver   = postgres
-db-host     = localhost
-db-port     = 
-adapter     = native
-db-name     = cw_fti_test
-db-encoding = UTF-8
-db-user     = syt
-db-password = syt
-
-[admin]
-login = admin
-password = gingkow
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/data/sources_postgres	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,14 @@
+[system]
+
+db-driver   = postgres
+db-host     = localhost
+db-port     = 5433
+adapter     = native
+db-name     = cw_fti_test
+db-encoding = UTF-8
+db-user     = syt
+db-password = syt
+
+[admin]
+login = admin
+password = gingkow
--- a/server/test/unittest_fti.py	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-from __future__ import with_statement
-
-import socket
-
-from logilab.common.testlib import SkipTest
-
-from cubicweb.devtools import ApptestConfiguration
-from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.selectors import is_instance
-from cubicweb.entities.adapters import IFTIndexableAdapter
-
-AT_LOGILAB = socket.gethostname().endswith('.logilab.fr')
-
-
-class PostgresFTITC(CubicWebTC):
-    config = ApptestConfiguration('data', sourcefile='sources_fti')
-
-    @classmethod
-    def setUpClass(cls):
-        if not AT_LOGILAB:
-            raise SkipTest('XXX %s: require logilab configuration' % cls.__name__)
-
-    def test_occurence_count(self):
-        req = self.request()
-        c1 = req.create_entity('Card', title=u'c1',
-                               content=u'cubicweb cubicweb cubicweb')
-        c2 = req.create_entity('Card', title=u'c3',
-                               content=u'cubicweb')
-        c3 = req.create_entity('Card', title=u'c2',
-                               content=u'cubicweb cubicweb')
-        self.commit()
-        self.assertEqual(req.execute('Card X ORDERBY FTIRANK(X) DESC WHERE X has_text "cubicweb"').rows,
-                          [[c1.eid], [c3.eid], [c2.eid]])
-
-
-    def test_attr_weight(self):
-        class CardIFTIndexableAdapter(IFTIndexableAdapter):
-            __select__ = is_instance('Card')
-            attr_weight = {'title': 'A'}
-        with self.temporary_appobjects(CardIFTIndexableAdapter):
-            req = self.request()
-            c1 = req.create_entity('Card', title=u'c1',
-                                   content=u'cubicweb cubicweb cubicweb')
-            c2 = req.create_entity('Card', title=u'c2',
-                                   content=u'cubicweb cubicweb')
-            c3 = req.create_entity('Card', title=u'cubicweb',
-                                   content=u'autre chose')
-            self.commit()
-            self.assertEqual(req.execute('Card X ORDERBY FTIRANK(X) DESC WHERE X has_text "cubicweb"').rows,
-                              [[c3.eid], [c1.eid], [c2.eid]])
-
-    def test_entity_weight(self):
-        class PersonneIFTIndexableAdapter(IFTIndexableAdapter):
-            __select__ = is_instance('Personne')
-            entity_weight = 2.0
-        with self.temporary_appobjects(PersonneIFTIndexableAdapter):
-            req = self.request()
-            c1 = req.create_entity('Personne', nom=u'c1', prenom=u'cubicweb')
-            c2 = req.create_entity('Comment', content=u'cubicweb cubicweb', comments=c1)
-            c3 = req.create_entity('Comment', content=u'cubicweb cubicweb cubicweb', comments=c1)
-            self.commit()
-            self.assertEqual(req.execute('Any X ORDERBY FTIRANK(X) DESC WHERE X has_text "cubicweb"').rows,
-                              [[c1.eid], [c3.eid], [c2.eid]])
-
-
-if __name__ == '__main__':
-    from logilab.common.testlib import unittest_main
-    unittest_main()
--- a/server/test/unittest_ldapuser.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_ldapuser.py	Mon May 16 16:25:33 2011 +0200
@@ -260,7 +260,8 @@
         self.sexecute('Any X, Y WHERE X copain Y, X login "comme", Y login "cochon"')
 
     def test_multiple_entities_from_different_sources(self):
-        self.create_user('cochon')
+        req = self.request()
+        self.create_user(req, 'cochon')
         self.failUnless(self.sexecute('Any X,Y WHERE X login %(syt)s, Y login "cochon"', {'syt': SYT}))
 
     def test_exists1(self):
@@ -274,16 +275,18 @@
         self.assertEqual(rset.rows, [['admin', 'activated'], [SYT, 'activated']])
 
     def test_exists2(self):
-        self.create_user('comme')
-        self.create_user('cochon')
+        req = self.request()
+        self.create_user(req, 'comme')
+        self.create_user(req, 'cochon')
         self.sexecute('SET X copain Y WHERE X login "comme", Y login "cochon"')
         rset = self.sexecute('Any GN ORDERBY GN WHERE X in_group G, G name GN, '
                              '(G name "managers" OR EXISTS(X copain T, T login in ("comme", "cochon")))')
         self.assertEqual(rset.rows, [['managers'], ['users']])
 
     def test_exists3(self):
-        self.create_user('comme')
-        self.create_user('cochon')
+        req = self.request()
+        self.create_user(req, 'comme')
+        self.create_user(req, 'cochon')
         self.sexecute('SET X copain Y WHERE X login "comme", Y login "cochon"')
         self.failUnless(self.sexecute('Any X, Y WHERE X copain Y, X login "comme", Y login "cochon"'))
         self.sexecute('SET X copain Y WHERE X login %(syt)s, Y login "cochon"', {'syt': SYT})
@@ -293,9 +296,10 @@
         self.assertEqual(sorted(rset.rows), [['managers', 'admin'], ['users', 'comme'], ['users', SYT]])
 
     def test_exists4(self):
-        self.create_user('comme')
-        self.create_user('cochon', groups=('users', 'guests'))
-        self.create_user('billy')
+        req = self.request()
+        self.create_user(req, 'comme')
+        self.create_user(req, 'cochon', groups=('users', 'guests'))
+        self.create_user(req, 'billy')
         self.sexecute('SET X copain Y WHERE X login "comme", Y login "cochon"')
         self.sexecute('SET X copain Y WHERE X login "cochon", Y login "cochon"')
         self.sexecute('SET X copain Y WHERE X login "comme", Y login "billy"')
@@ -315,9 +319,10 @@
         self.assertEqual(sorted(rset.rows), sorted(all.rows))
 
     def test_exists5(self):
-        self.create_user('comme')
-        self.create_user('cochon', groups=('users', 'guests'))
-        self.create_user('billy')
+        req = self.request()
+        self.create_user(req, 'comme')
+        self.create_user(req, 'cochon', groups=('users', 'guests'))
+        self.create_user(req, 'billy')
         self.sexecute('SET X copain Y WHERE X login "comme", Y login "cochon"')
         self.sexecute('SET X copain Y WHERE X login "cochon", Y login "cochon"')
         self.sexecute('SET X copain Y WHERE X login "comme", Y login "billy"')
@@ -347,7 +352,8 @@
                           sorted(r[0] for r in afeids + ueids))
 
     def _init_security_test(self):
-        self.create_user('iaminguestsgrouponly', groups=('guests',))
+        req = self.request()
+        self.create_user(req, 'iaminguestsgrouponly', groups=('guests',))
         cnx = self.login('iaminguestsgrouponly')
         return cnx.cursor()
 
--- a/server/test/unittest_migractions.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_migractions.py	Mon May 16 16:25:33 2011 +0200
@@ -364,8 +364,9 @@
             'X from_entity FE, FE name "Personne",'
             'X ordernum O')]
         expected = [u'nom', u'prenom', u'sexe', u'promo', u'ass', u'adel', u'titre',
-                    u'web', u'tel', u'fax', u'datenaiss', u'test', 'description', u'firstname',
-                    u'creation_date', 'cwuri', u'modification_date']
+                    u'web', u'tel', u'fax', u'datenaiss', u'tzdatenaiss', u'test',
+                    u'description', u'firstname',
+                    u'creation_date', u'cwuri', u'modification_date']
         self.assertEqual(rinorder, expected)
 
         # test permissions synchronization ####################################
--- a/server/test/unittest_msplanner.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_msplanner.py	Mon May 16 16:25:33 2011 +0200
@@ -1991,12 +1991,12 @@
                     ])
 
     def test_source_specified_2_0(self):
-        self._test('Card X WHERE X cw_source S, NOT S eid 1',
-                   [('OneFetchStep', [('Any X WHERE X is Card',
-                                       [{'X': 'Card'}])],
-                     None, None,
-                     [self.cards],{}, [])
-                    ])
+        # self._test('Card X WHERE X cw_source S, NOT S eid 1',
+        #            [('OneFetchStep', [('Any X WHERE X is Card',
+        #                                [{'X': 'Card'}])],
+        #              None, None,
+        #              [self.cards],{}, [])
+        #             ])
         self._test('Card X WHERE NOT X cw_source S, S eid 1',
                    [('OneFetchStep', [('Any X WHERE X is Card',
                                        [{'X': 'Card'}])],
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/unittest_postgres.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,83 @@
+from __future__ import with_statement
+
+import socket
+from datetime import datetime
+
+from logilab.common.testlib import SkipTest
+
+from cubicweb.devtools import ApptestConfiguration
+from cubicweb.devtools.testlib import CubicWebTC
+from cubicweb.selectors import is_instance
+from cubicweb.entities.adapters import IFTIndexableAdapter
+
+AT_LOGILAB = socket.gethostname().endswith('.logilab.fr') # XXX
+
+from unittest_querier import FixedOffset
+
+class PostgresFTITC(CubicWebTC):
+    @classmethod
+    def setUpClass(cls):
+        if not AT_LOGILAB: # XXX here until we can raise SkipTest in setUp to detect we can't connect to the db
+            raise SkipTest('XXX %s: require logilab configuration' % cls.__name__)
+        cls.config = ApptestConfiguration('data', sourcefile='sources_postgres',
+                                          apphome=cls.datadir)
+
+    def test_occurence_count(self):
+        req = self.request()
+        c1 = req.create_entity('Card', title=u'c1',
+                               content=u'cubicweb cubicweb cubicweb')
+        c2 = req.create_entity('Card', title=u'c3',
+                               content=u'cubicweb')
+        c3 = req.create_entity('Card', title=u'c2',
+                               content=u'cubicweb cubicweb')
+        self.commit()
+        self.assertEqual(req.execute('Card X ORDERBY FTIRANK(X) DESC WHERE X has_text "cubicweb"').rows,
+                          [[c1.eid], [c3.eid], [c2.eid]])
+
+
+    def test_attr_weight(self):
+        class CardIFTIndexableAdapter(IFTIndexableAdapter):
+            __select__ = is_instance('Card')
+            attr_weight = {'title': 'A'}
+        with self.temporary_appobjects(CardIFTIndexableAdapter):
+            req = self.request()
+            c1 = req.create_entity('Card', title=u'c1',
+                                   content=u'cubicweb cubicweb cubicweb')
+            c2 = req.create_entity('Card', title=u'c2',
+                                   content=u'cubicweb cubicweb')
+            c3 = req.create_entity('Card', title=u'cubicweb',
+                                   content=u'autre chose')
+            self.commit()
+            self.assertEqual(req.execute('Card X ORDERBY FTIRANK(X) DESC WHERE X has_text "cubicweb"').rows,
+                              [[c3.eid], [c1.eid], [c2.eid]])
+
+    def test_entity_weight(self):
+        class PersonneIFTIndexableAdapter(IFTIndexableAdapter):
+            __select__ = is_instance('Personne')
+            entity_weight = 2.0
+        with self.temporary_appobjects(PersonneIFTIndexableAdapter):
+            req = self.request()
+            c1 = req.create_entity('Personne', nom=u'c1', prenom=u'cubicweb')
+            c2 = req.create_entity('Comment', content=u'cubicweb cubicweb', comments=c1)
+            c3 = req.create_entity('Comment', content=u'cubicweb cubicweb cubicweb', comments=c1)
+            self.commit()
+            self.assertEqual(req.execute('Any X ORDERBY FTIRANK(X) DESC WHERE X has_text "cubicweb"').rows,
+                              [[c1.eid], [c3.eid], [c2.eid]])
+
+
+    def test_tz_datetime(self):
+        self.execute("INSERT Personne X: X nom 'bob', X tzdatenaiss %(date)s",
+                     {'date': datetime(1977, 6, 7, 2, 0, tzinfo=FixedOffset(1))})
+        datenaiss = self.execute("Any XD WHERE X nom 'bob', X tzdatenaiss XD")[0][0]
+        self.assertEqual(datenaiss.tzinfo, None)
+        self.assertEqual(datenaiss.utctimetuple()[:5], (1977, 6, 7, 1, 0))
+        self.commit()
+        self.execute("INSERT Personne X: X nom 'boby', X tzdatenaiss %(date)s",
+                     {'date': datetime(1977, 6, 7, 2, 0)})
+        datenaiss = self.execute("Any XD WHERE X nom 'boby', X tzdatenaiss XD")[0][0]
+        self.assertEqual(datenaiss.tzinfo, None)
+        self.assertEqual(datenaiss.utctimetuple()[:5], (1977, 6, 7, 2, 0))
+
+if __name__ == '__main__':
+    from logilab.common.testlib import unittest_main
+    unittest_main()
--- a/server/test/unittest_querier.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_querier.py	Mon May 16 16:25:33 2011 +0200
@@ -18,7 +18,7 @@
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 """unit tests for modules cubicweb.server.querier and cubicweb.server.ssplanner
 """
-from datetime import date, datetime
+from datetime import date, datetime, timedelta, tzinfo
 
 from logilab.common.testlib import TestCase, unittest_main
 from rql import BadRQLQuery, RQLSyntaxError
@@ -32,6 +32,14 @@
 from cubicweb.devtools.repotest import tuplify, BaseQuerierTC
 from unittest_session import Variable
 
+class FixedOffset(tzinfo):
+    def __init__(self, hours=0):
+        self.hours = hours
+    def utcoffset(self, dt):
+        return timedelta(hours=self.hours)
+    def dst(self, dt):
+        return timedelta(0)
+
 
 # register priority/severity sorting registered procedure
 from rql.utils import register_function, FunctionDescr
@@ -761,18 +769,20 @@
         rset = self.execute('Any N WHERE X is CWEType, X name N, X final %(val)s',
                             {'val': True})
         self.assertEqual(sorted(r[0] for r in rset.rows), ['Boolean', 'Bytes',
-                                                            'Date', 'Datetime',
-                                                            'Decimal', 'Float',
-                                                            'Int', 'Interval',
-                                                            'Password', 'String',
-                                                            'Time'])
+                                                           'Date', 'Datetime',
+                                                           'Decimal', 'Float',
+                                                           'Int', 'Interval',
+                                                           'Password', 'String',
+                                                           'TZDatetime', 'TZTime',
+                                                           'Time'])
         rset = self.execute('Any N WHERE X is CWEType, X name N, X final TRUE')
         self.assertEqual(sorted(r[0] for r in rset.rows), ['Boolean', 'Bytes',
-                                                            'Date', 'Datetime',
-                                                            'Decimal', 'Float',
-                                                            'Int', 'Interval',
-                                                            'Password', 'String',
-                                                            'Time'])
+                                                           'Date', 'Datetime',
+                                                           'Decimal', 'Float',
+                                                           'Int', 'Interval',
+                                                           'Password', 'String',
+                                                           'TZDatetime', 'TZTime',
+                                                           'Time'])
 
     def test_select_constant(self):
         rset = self.execute('Any X, "toto" ORDERBY X WHERE X is CWGroup')
@@ -1213,11 +1223,11 @@
         self.assertEqual(rset.description, [('CWUser',)])
 
     def test_update_upassword(self):
-        cursor = self.pool['system']
         rset = self.execute("INSERT CWUser X: X login 'bob', X upassword %(pwd)s", {'pwd': 'toto'})
         self.assertEqual(rset.description[0][0], 'CWUser')
         rset = self.execute("SET X upassword %(pwd)s WHERE X is CWUser, X login 'bob'",
                             {'pwd': 'tutu'})
+        cursor = self.pool['system']
         cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'"
                        % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
         passwd = str(cursor.fetchone()[0])
@@ -1227,7 +1237,16 @@
         self.assertEqual(len(rset.rows), 1)
         self.assertEqual(rset.description, [('CWUser',)])
 
-    # non regression tests ####################################################
+    # ZT datetime tests ########################################################
+
+    def test_tz_datetime(self):
+        self.execute("INSERT Personne X: X nom 'bob', X tzdatenaiss %(date)s",
+                     {'date': datetime(1977, 6, 7, 2, 0, tzinfo=FixedOffset(1))})
+        datenaiss = self.execute("Any XD WHERE X nom 'bob', X tzdatenaiss XD")[0][0]
+        self.assertEqual(datenaiss.tzinfo, None)
+        self.assertEqual(datenaiss.utctimetuple()[:5], (1977, 6, 7, 1, 0))
+
+    # non regression tests #####################################################
 
     def test_nonregr_1(self):
         teid = self.execute("INSERT Tag X: X name 'tag'")[0][0]
--- a/server/test/unittest_repository.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_repository.py	Mon May 16 16:25:33 2011 +0200
@@ -69,11 +69,12 @@
             cu = self.session.system_sql('SELECT %s FROM %s WHERE %s=%%(final)s ORDER BY %s'
                                          % (namecol, table, finalcol, namecol), {'final': 'TRUE'})
             self.assertEqual(cu.fetchall(), [(u'Boolean',), (u'Bytes',),
-                                              (u'Date',), (u'Datetime',),
-                                              (u'Decimal',),(u'Float',),
-                                              (u'Int',),
-                                              (u'Interval',), (u'Password',),
-                                              (u'String',), (u'Time',)])
+                                             (u'Date',), (u'Datetime',),
+                                             (u'Decimal',),(u'Float',),
+                                             (u'Int',),
+                                             (u'Interval',), (u'Password',),
+                                             (u'String',),
+                                             (u'TZDatetime',), (u'TZTime',), (u'Time',)])
             sql = ("SELECT etype.cw_eid, etype.cw_name, cstr.cw_eid, rel.eid_to "
                    "FROM cw_CWUniqueTogetherConstraint as cstr, "
                    "     relations_relation as rel, "
@@ -276,13 +277,16 @@
         cnxid = repo.connect(self.admlogin, password=self.admpassword)
         repo.execute(cnxid, 'INSERT CWUser X: X login "toto", X upassword "tutu", X in_group G WHERE G name "users"')
         repo.commit(cnxid)
+        lock = threading.Lock()
+        lock.acquire()
         # close has to be in the thread due to sqlite limitations
         def close_in_a_few_moment():
-            time.sleep(0.1)
+            lock.acquire()
             repo.close(cnxid)
         t = threading.Thread(target=close_in_a_few_moment)
         t.start()
         def run_transaction():
+            lock.release()
             repo.execute(cnxid, 'DELETE CWUser X WHERE X login "toto"')
             repo.commit(cnxid)
         try:
@@ -327,7 +331,7 @@
         self.assertEqual(len(constraints), 1)
         cstr = constraints[0]
         self.assert_(isinstance(cstr, RQLConstraint))
-        self.assertEqual(cstr.restriction, 'O final TRUE')
+        self.assertEqual(cstr.expression, 'O final TRUE')
 
         ownedby = schema.rschema('owned_by')
         self.assertEqual(ownedby.objects('CWEType'), ('CWUser',))
@@ -684,5 +688,160 @@
             req.cnx.commit()
         self.assertEqual(cm.exception.errors, {'inline1-subject': u'RQLUniqueConstraint S type T, S inline1 A1, A1 todo_by C, Y type T, Y inline1 A2, A2 todo_by C failed'})
 
+    def test_add_relations_at_creation_with_del_existing_rel(self):
+        req = self.request()
+        person = req.create_entity('Personne', nom=u'Toto', prenom=u'Lanturlu', sexe=u'M')
+        users_rql = 'Any U WHERE U is CWGroup, U name "users"'
+        users = self.execute(users_rql).get_entity(0, 0)
+        req.create_entity('CWUser',
+                      login=u'Toto',
+                      upassword=u'firstname',
+                      firstname=u'firstname',
+                      surname=u'surname',
+                      reverse_login_user=person,
+                      in_group=users)
+        self.commit()
+
+
+class PerformanceTest(CubicWebTC):
+    def setup_database(self):
+        import logging
+        logger = logging.getLogger('cubicweb.session')
+        #logger.handlers = [logging.StreamHandler(sys.stdout)]
+        logger.setLevel(logging.INFO)
+        self.info = logger.info
+
+    def test_composite_deletion(self):
+        req = self.request()
+        personnes = []
+        t0 = time.time()
+        for i in xrange(2000):
+            p = req.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
+            personnes.append(p)
+        abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
+        for j in xrange(0, 2000, 100):
+            abraham.set_relations(personne_composite=personnes[j:j+100])
+        t1 = time.time()
+        self.info('creation: %.2gs', (t1 - t0))
+        req.cnx.commit()
+        t2 = time.time()
+        self.info('commit creation: %.2gs', (t2 - t1))
+        self.execute('DELETE Personne P WHERE P eid %(eid)s', {'eid': abraham.eid})
+        t3 = time.time()
+        self.info('deletion: %.2gs', (t3 - t2))
+        req.cnx.commit()
+        t4 = time.time()
+        self.info("commit deletion: %2gs", (t4 - t3))
+
+    def test_add_relation_non_inlined(self):
+        req = self.request()
+        personnes = []
+        for i in xrange(2000):
+            p = req.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
+            personnes.append(p)
+        req.cnx.commit()
+        t0 = time.time()
+        abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M',
+                                    personne_composite=personnes[:100])
+        t1 = time.time()
+        self.info('creation: %.2gs', (t1 - t0))
+        for j in xrange(100, 2000, 100):
+            abraham.set_relations(personne_composite=personnes[j:j+100])
+        t2 = time.time()
+        self.info('more relations: %.2gs', (t2-t1))
+        req.cnx.commit()
+        t3 = time.time()
+        self.info('commit creation: %.2gs', (t3 - t2))
+
+    def test_add_relation_inlined(self):
+        req = self.request()
+        personnes = []
+        for i in xrange(2000):
+            p = req.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
+            personnes.append(p)
+        req.cnx.commit()
+        t0 = time.time()
+        abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M',
+                                    personne_inlined=personnes[:100])
+        t1 = time.time()
+        self.info('creation: %.2gs', (t1 - t0))
+        for j in xrange(100, 2000, 100):
+            abraham.set_relations(personne_inlined=personnes[j:j+100])
+        t2 = time.time()
+        self.info('more relations: %.2gs', (t2-t1))
+        req.cnx.commit()
+        t3 = time.time()
+        self.info('commit creation: %.2gs', (t3 - t2))
+
+
+    def test_session_add_relation(self):
+        """ to be compared with test_session_add_relations"""
+        req = self.request()
+        personnes = []
+        for i in xrange(2000):
+            p = req.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
+            personnes.append(p)
+        abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
+        req.cnx.commit()
+        t0 = time.time()
+        add_relation = self.session.add_relation
+        for p in personnes:
+            add_relation(abraham.eid, 'personne_composite', p.eid)
+        req.cnx.commit()
+        t1 = time.time()
+        self.info('add relation: %.2gs', t1-t0)
+
+    def test_session_add_relations (self):
+        """ to be compared with test_session_add_relation"""
+        req = self.request()
+        personnes = []
+        for i in xrange(2000):
+            p = req.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
+            personnes.append(p)
+        abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
+        req.cnx.commit()
+        t0 = time.time()
+        add_relations = self.session.add_relations
+        relations = [('personne_composite', [(abraham.eid, p.eid) for p in personnes])]
+        add_relations(relations)
+        req.cnx.commit()
+        t1 = time.time()
+        self.info('add relations: %.2gs', t1-t0)
+    def test_session_add_relation_inlined(self):
+        """ to be compared with test_session_add_relations"""
+        req = self.request()
+        personnes = []
+        for i in xrange(2000):
+            p = req.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
+            personnes.append(p)
+        abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
+        req.cnx.commit()
+        t0 = time.time()
+        add_relation = self.session.add_relation
+        for p in personnes:
+            add_relation(abraham.eid, 'personne_inlined', p.eid)
+        req.cnx.commit()
+        t1 = time.time()
+        self.info('add relation (inlined): %.2gs', t1-t0)
+
+    def test_session_add_relations_inlined (self):
+        """ to be compared with test_session_add_relation"""
+        req = self.request()
+        personnes = []
+        for i in xrange(2000):
+            p = req.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
+            personnes.append(p)
+        abraham = req.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
+        req.cnx.commit()
+        t0 = time.time()
+        add_relations = self.session.add_relations
+        relations = [('personne_inlined', [(abraham.eid, p.eid) for p in personnes])]
+        add_relations(relations)
+        req.cnx.commit()
+        t1 = time.time()
+        self.info('add relations (inlined): %.2gs', t1-t0)
+
+
+
 if __name__ == '__main__':
     unittest_main()
--- a/server/test/unittest_rql2sql.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_rql2sql.py	Mon May 16 16:25:33 2011 +0200
@@ -835,9 +835,9 @@
 WHERE _X.cw_eid=12'''
     ),
     ("Any P WHERE X eid 12, P? concerne X, X todo_by S",
-     '''SELECT rel_concerne0.eid_from
-FROM todo_by_relation AS rel_todo_by1 LEFT OUTER JOIN concerne_relation AS rel_concerne0 ON (rel_concerne0.eid_to=12)
-WHERE rel_todo_by1.eid_from=12'''
+     '''SELECT rel_concerne1.eid_from
+FROM todo_by_relation AS rel_todo_by0 LEFT OUTER JOIN concerne_relation AS rel_concerne1 ON (rel_concerne1.eid_to=12)
+WHERE rel_todo_by0.eid_from=12'''
     ),
 
     ('Any GN, TN ORDERBY GN WHERE T tags G?, T name TN, G name GN',
@@ -909,7 +909,32 @@
     ('Any O,AD  WHERE NOT S inline1 O, S eid 123, O todo_by AD?',
      '''SELECT _O.cw_eid, rel_todo_by0.eid_to
 FROM cw_Note AS _S, cw_Affaire AS _O LEFT OUTER JOIN todo_by_relation AS rel_todo_by0 ON (rel_todo_by0.eid_from=_O.cw_eid)
-WHERE (_S.cw_inline1 IS NULL OR _S.cw_inline1!=_O.cw_eid) AND _S.cw_eid=123''')
+WHERE (_S.cw_inline1 IS NULL OR _S.cw_inline1!=_O.cw_eid) AND _S.cw_eid=123'''),
+
+    ('Any X,AE WHERE X multisource_inlined_rel S?, S ambiguous_inlined A, A modification_date AE',
+     '''SELECT _X.cw_eid, _T0.C2
+FROM cw_Card AS _X LEFT OUTER JOIN (SELECT _S.cw_eid AS C0, _A.cw_eid AS C1, _A.cw_modification_date AS C2
+FROM cw_Affaire AS _S, cw_CWUser AS _A
+WHERE _S.cw_ambiguous_inlined=_A.cw_eid
+UNION ALL
+SELECT _S.cw_eid AS C0, _A.cw_eid AS C1, _A.cw_modification_date AS C2
+FROM cw_CWUser AS _A, cw_Note AS _S
+WHERE _S.cw_ambiguous_inlined=_A.cw_eid) AS _T0 ON (_X.cw_multisource_inlined_rel=_T0.C0)
+UNION ALL
+SELECT _X.cw_eid, _T0.C2
+FROM cw_Note AS _X LEFT OUTER JOIN (SELECT _S.cw_eid AS C0, _A.cw_eid AS C1, _A.cw_modification_date AS C2
+FROM cw_Affaire AS _S, cw_CWUser AS _A
+WHERE _S.cw_ambiguous_inlined=_A.cw_eid
+UNION ALL
+SELECT _S.cw_eid AS C0, _A.cw_eid AS C1, _A.cw_modification_date AS C2
+FROM cw_CWUser AS _A, cw_Note AS _S
+WHERE _S.cw_ambiguous_inlined=_A.cw_eid) AS _T0 ON (_X.cw_multisource_inlined_rel=_T0.C0)'''
+    ),
+
+    ('Any X,T,OT WHERE X tags T, OT? tags X, X is Tag, X eid 123',
+     '''SELECT rel_tags0.eid_from, rel_tags0.eid_to, rel_tags1.eid_from
+FROM tags_relation AS rel_tags0 LEFT OUTER JOIN tags_relation AS rel_tags1 ON (rel_tags1.eid_to=123)
+WHERE rel_tags0.eid_from=123'''),
     ]
 
 VIRTUAL_VARS = [
@@ -1225,9 +1250,13 @@
             yield self._check, rql, sql
 
     def _checkall(self, rql, sql):
+        if isinstance(rql, tuple):
+            rql, args = rql
+        else:
+            args = None
         try:
             rqlst = self._prepare(rql)
-            r, args, cbs = self.o.generate(rqlst)
+            r, args, cbs = self.o.generate(rqlst, args)
             self.assertEqual((r.strip(), args), sql)
         except Exception, ex:
             print rql
@@ -1239,7 +1268,7 @@
         return
 
     def test1(self):
-        self._checkall('Any count(RDEF) WHERE RDEF relation_type X, X eid %(x)s',
+        self._checkall(('Any count(RDEF) WHERE RDEF relation_type X, X eid %(x)s', {'x': None}),
                        ("""SELECT COUNT(T1.C0) FROM (SELECT _RDEF.cw_eid AS C0
 FROM cw_CWAttribute AS _RDEF
 WHERE _RDEF.cw_relation_type=%(x)s
@@ -1250,7 +1279,7 @@
                        )
 
     def test2(self):
-        self._checkall('Any X WHERE C comments X, C eid %(x)s',
+        self._checkall(('Any X WHERE C comments X, C eid %(x)s', {'x': None}),
                        ('''SELECT rel_comments0.eid_to
 FROM comments_relation AS rel_comments0
 WHERE rel_comments0.eid_from=%(x)s''', {})
@@ -1576,7 +1605,7 @@
                     '''SELECT 1
 WHERE NOT (EXISTS(SELECT 1 FROM in_group_relation AS rel_in_group0))''')
 
-    def test_nonregr_subquery_missing_join(self):
+    def test_nonregr_outer_join_multiple(self):
         self._check('Any COUNT(P1148),G GROUPBY G '
                     'WHERE G owned_by D, D eid 1122, K1148 bookmarked_by P1148, '
                     'K1148 eid 1148, P1148? in_group G',
@@ -1586,7 +1615,7 @@
 GROUP BY _G.cw_eid'''
                     )
 
-    def test_nonregr_subquery_missing_join2(self):
+    def test_nonregr_outer_join_multiple2(self):
         self._check('Any COUNT(P1148),G GROUPBY G '
                     'WHERE G owned_by D, D eid 1122, K1148 bookmarked_by P1148?, '
                     'K1148 eid 1148, P1148? in_group G',
--- a/server/test/unittest_security.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_security.py	Mon May 16 16:25:33 2011 +0200
@@ -29,7 +29,8 @@
 
     def setup_database(self):
         super(BaseSecurityTC, self).setup_database()
-        self.create_user('iaminusersgrouponly')
+        req = self.request()
+        self.create_user(req, 'iaminusersgrouponly')
         readoriggroups = self.schema['Personne'].permissions['read']
         addoriggroups = self.schema['Personne'].permissions['add']
         def fix_perm():
@@ -260,7 +261,8 @@
 
 
     def test_user_can_change_its_upassword(self):
-        ueid = self.create_user('user').eid
+        req = self.request()
+        ueid = self.create_user(req, 'user').eid
         cnx = self.login('user')
         cu = cnx.cursor()
         cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s',
@@ -271,7 +273,8 @@
         cnx.close()
 
     def test_user_cant_change_other_upassword(self):
-        ueid = self.create_user('otheruser').eid
+        req = self.request()
+        ueid = self.create_user(req, 'otheruser').eid
         cnx = self.login('iaminusersgrouponly')
         cu = cnx.cursor()
         cu.execute('SET X upassword %(passwd)s WHERE X eid %(x)s',
--- a/server/test/unittest_undo.py	Mon May 16 16:24:00 2011 +0200
+++ b/server/test/unittest_undo.py	Mon May 16 16:25:33 2011 +0200
@@ -23,9 +23,11 @@
 
 class UndoableTransactionTC(CubicWebTC):
 
+        
     def setup_database(self):
+        req = self.request()
         self.session.undo_actions = set('CUDAR')
-        self.toto = self.create_user('toto', password='toto', groups=('users',),
+        self.toto = self.create_user(req, 'toto', password='toto', groups=('users',),
                                      commit=False)
         self.txuuid = self.commit()
 
@@ -246,7 +248,8 @@
 
     def test_undo_creation_integrity_1(self):
         session = self.session
-        tutu = self.create_user('tutu', commit=False)
+        req = self.request()
+        tutu = self.create_user(req, 'tutu', commit=False)
         txuuid = self.commit()
         email = self.request().create_entity('EmailAddress', address=u'tutu@cubicweb.org')
         prop = self.request().create_entity('CWProperty', pkey=u'ui.default-text-format',
--- a/sobjects/parsers.py	Mon May 16 16:24:00 2011 +0200
+++ b/sobjects/parsers.py	Mon May 16 16:25:33 2011 +0200
@@ -15,7 +15,21 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""datafeed parser for xml generated by cubicweb"""
+"""datafeed parser for xml generated by cubicweb
+
+Example of mapping for CWEntityXMLParser::
+
+  {u'CWUser': {                                        # EntityType
+      (u'in_group', u'subject', u'link'): [            # (rtype, role, action)
+          (u'CWGroup', {u'linkattr': u'name'})],       #   -> rules = [(EntityType, options), ...]
+      (u'tags', u'object', u'link-or-create'): [       # (...)
+          (u'Tag', {u'linkattr': u'name'})],           #   -> ...
+      (u'use_email', u'subject', u'copy'): [           # (...)
+          (u'EmailAddress', {})]                       #   -> ...
+      }
+   }
+
+"""
 
 import urllib2
 import StringIO
@@ -34,11 +48,12 @@
 from cubicweb import ValidationError, typed_eid
 from cubicweb.server.sources import datafeed
 
-def ensure_str_keys(dict):
-    for key in dict:
-        dict[str(key)] = dict.pop(key)
+def ensure_str_keys(dic):
+    for key in dic:
+        dic[str(key)] = dic.pop(key)
 
-# see cubicweb.web.views.xmlrss.SERIALIZERS
+# XXX see cubicweb.cwvreg.YAMS_TO_PY
+# XXX see cubicweb.web.views.xmlrss.SERIALIZERS
 DEFAULT_CONVERTERS = BASE_CONVERTERS.copy()
 DEFAULT_CONVERTERS['String'] = unicode
 DEFAULT_CONVERTERS['Password'] = lambda x: x.encode('utf8')
@@ -76,7 +91,7 @@
             typeddict[rschema.type] = converters[attrtype](stringdict[rschema])
     return typeddict
 
-def _entity_etree(parent):
+def _parse_entity_etree(parent):
     for node in list(parent):
         try:
             item = {'cwtype': unicode(node.tag),
@@ -92,20 +107,18 @@
         rels = {}
         for child in node:
             role = child.get('role')
-            if child.get('role'):
+            if role:
                 # relation
                 related = rels.setdefault(role, {}).setdefault(child.tag, [])
-                related += [ritem for ritem, _ in _entity_etree(child)]
+                related += [ritem for ritem, _ in _parse_entity_etree(child)]
             else:
                 # attribute
                 item[child.tag] = unicode(child.text)
         yield item, rels
 
 def build_search_rql(etype, attrs):
-    restrictions = []
-    for attr in attrs:
-        restrictions.append('X %(attr)s %%(%(attr)s)s' % {'attr': attr})
-    return 'Any X WHERE X is %s, %s' % (etype, ','.join(restrictions))
+    restrictions = ['X %(attr)s %%(%(attr)s)s'%{'attr': attr} for attr in attrs]
+    return 'Any X WHERE X is %s, %s' % (etype, ', '.join(restrictions))
 
 def rtype_role_rql(rtype, role):
     if role == 'object':
@@ -121,7 +134,7 @@
 
 def _check_linkattr_option(action, options, eid, _):
     if not 'linkattr' in options:
-        msg = _("'%s' action require 'linkattr' option") % action
+        msg = _("'%s' action requires 'linkattr' option") % action
         raise ValidationError(eid, {rn('options', 'subject'): msg})
 
 
@@ -230,19 +243,12 @@
                     break
             self.source.info('GET %s', url)
             stream = _OPENER.open(url)
-        return _entity_etree(etree.parse(stream).getroot())
-
-    def process_one(self, url):
-        # XXX assert len(root.children) == 1
-        for item, rels in self.parse(url):
-            return self.process_item(item, rels)
+        return _parse_entity_etree(etree.parse(stream).getroot())
 
     def process_item(self, item, rels):
-        entity = self.extid2entity(str(item.pop('cwuri')),
-                                   item.pop('cwtype'),
+        entity = self.extid2entity(str(item.pop('cwuri')),  item.pop('cwtype'),
                                    item=item)
-        if not (self.created_during_pull(entity)
-                or self.updated_during_pull(entity)):
+        if not (self.created_during_pull(entity) or self.updated_during_pull(entity)):
             self.notify_updated(entity)
             item.pop('eid')
             # XXX check modification date
@@ -250,16 +256,16 @@
             entity.set_attributes(**attrs)
         for (rtype, role, action), rules in self.source.mapping.get(entity.__regid__, {}).iteritems():
             try:
-                rel = rels[role][rtype]
+                related_items = rels[role][rtype]
             except KeyError:
-                self.source.error('relation %s-%s doesn\'t seem exported in %s xml',
+                self.source.error('relation %s-%s not found in xml export of %s',
                                   rtype, role, entity.__regid__)
                 continue
             try:
                 actionmethod = self.action_methods[action]
             except KeyError:
                 raise Exception('Unknown action %s' % action)
-            actionmethod(entity, rtype, role, rel, rules)
+            actionmethod(entity, rtype, role, related_items, rules)
         return entity
 
     def before_entity_copy(self, entity, sourceparams):
@@ -267,89 +273,89 @@
         attrs = extract_typed_attrs(entity.e_schema, sourceparams['item'])
         entity.cw_edited.update(attrs)
 
-    def related_copy(self, entity, rtype, role, value, rules):
+    def related_copy(self, entity, rtype, role, others, rules):
         """implementation of 'copy' action
 
         Takes no option.
         """
         assert not any(x[1] for x in rules), "'copy' action takes no option"
         ttypes = set([x[0] for x in rules])
-        value = [item for item in value if item['cwtype'] in ttypes]
+        others = [item for item in others if item['cwtype'] in ttypes]
         eids = [] # local eids
-        if not value:
+        if not others:
             self._clear_relation(entity, rtype, role, ttypes)
             return
-        for item in value:
-            eids.append(self.process_one(self._complete_url(item)).eid)
+        for item in others:
+            item, _rels = self._complete_item(item)
+            other_entity = self.process_item(item, [])
+            eids.append(other_entity.eid)
         self._set_relation(entity, rtype, role, eids)
 
-    def related_link(self, entity, rtype, role, value, rules):
+    def related_link(self, entity, rtype, role, others, rules):
         """implementation of 'link' action
 
         requires an options to control search of the linked entity.
         """
         for ttype, options in rules:
             assert 'linkattr' in options, (
-                "'link-or-create' action require a list of attributes used to "
+                "'link' action requires a list of attributes used to "
                 "search if the entity already exists")
-            self._related_link(entity, rtype, role, ttype, value, [options['linkattr']],
-                               self._log_not_found)
+            self._related_link(entity, rtype, role, ttype, others, [options['linkattr']],
+                               create_when_not_found=False)
 
-    def related_link_or_create(self, entity, rtype, role, value, rules):
+    def related_link_or_create(self, entity, rtype, role, others, rules):
         """implementation of 'link-or-create' action
 
         requires an options to control search of the linked entity.
         """
         for ttype, options in rules:
             assert 'linkattr' in options, (
-                "'link-or-create' action require a list of attributes used to "
+                "'link-or-create' action requires a list of attributes used to "
                 "search if the entity already exists")
-            self._related_link(entity, rtype, role, ttype, value, [options['linkattr']],
-                               self._create_not_found)
-
-    def _log_not_found(self, entity, rtype, role, ritem, searchvalues):
-        self.source.error('can find %s entity with attributes %s',
-                          ritem['cwtype'], searchvalues)
+            self._related_link(entity, rtype, role, ttype, others, [options['linkattr']],
+                               create_when_not_found=True)
 
-    def _create_not_found(self, entity, rtype, role, ritem, searchvalues):
-        ensure_str_keys(searchvalues) # XXX necessary with python < 2.6
-        return self._cw.create_entity(ritem['cwtype'], **searchvalues).eid
-
-    def _related_link(self, entity, rtype, role, ttype, value, searchattrs,
-                      notfound_callback):
+    def _related_link(self, entity, rtype, role, ttype, others, searchattrs,
+                      create_when_not_found):
+        def issubset(x,y):
+            return all(z in y for z in x)
         eids = [] # local eids
-        for item in value:
+        for item in others:
             if item['cwtype'] != ttype:
                 continue
-            if not all(attr in item for attr in searchattrs):
-                # need to fetch related entity's xml
-                ritems = list(self.parse(self._complete_url(item, False)))
-                assert len(ritems) == 1, 'unexpected xml'
-                ritem = ritems[0][0] # list of 2-uples
-                assert all(attr in ritem for attr in searchattrs), \
-                       'missing attribute, got %s expected keys %s' % (item, searchattrs)
-            else:
-                ritem = item
-            kwargs = dict((attr, ritem[attr]) for attr in searchattrs)
+            if not issubset(searchattrs, item):
+                item, _rels = self._complete_item(item, False)
+                if not issubset(searchattrs, item):
+                    self.source.error('missing attribute, got %s expected keys %s'
+                                      % item, searchattrs)
+                    continue
+            kwargs = dict((attr, item[attr]) for attr in searchattrs)
             rql = build_search_rql(item['cwtype'], kwargs)
             rset = self._cw.execute(rql, kwargs)
-            if rset:
-                assert len(rset) == 1
+            if len(rset) > 1:
+                self.source.error('ambiguous link: found %s entity %s with attributes %s',
+                                  len(rset), item['cwtype'], kwargs)
+            elif len(rset) == 1:
                 eids.append(rset[0][0])
+            elif create_when_not_found:
+                ensure_str_keys(kwargs) # XXX necessary with python < 2.6
+                eids.append(self._cw.create_entity(item['cwtype'], **kwargs).eid)
             else:
-                eid = notfound_callback(entity, rtype, role, ritem, kwargs)
-                if eid is not None:
-                    eids.append(eid)
+                self.source.error('can not find %s entity with attributes %s',
+                                  item['cwtype'], kwargs)
         if not eids:
             self._clear_relation(entity, rtype, role, (ttype,))
         else:
             self._set_relation(entity, rtype, role, eids)
 
-    def _complete_url(self, item, add_relations=True):
+    def _complete_item(self, item, add_relations=True):
         itemurl = item['cwuri'] + '?vid=xml'
-        for rtype, role, _ in self.source.mapping.get(item['cwtype'], ()):
-            itemurl += '&relation=%s_%s' % (rtype, role)
-        return itemurl
+        if add_relations:
+            for rtype, role, _ in self.source.mapping.get(item['cwtype'], ()):
+                itemurl += '&relation=%s_%s' % (rtype, role)
+        item_rels = list(self.parse(itemurl))
+        assert len(item_rels) == 1
+        return item_rels[0]
 
     def _clear_relation(self, entity, rtype, role, ttypes):
         if entity.eid not in self.stats['created']:
@@ -361,15 +367,18 @@
                              {'x': entity.eid})
 
     def _set_relation(self, entity, rtype, role, eids):
-        eidstr = ','.join(str(eid) for eid in eids)
-        rql = rtype_role_rql(rtype, role)
-        self._cw.execute('DELETE %s, NOT Y eid IN (%s)' % (rql, eidstr),
-                         {'x': entity.eid})
-        if role == 'object':
-            rql = 'SET %s, Y eid IN (%s), NOT Y %s X' % (rql, eidstr, rtype)
-        else:
-            rql = 'SET %s, Y eid IN (%s), NOT X %s Y' % (rql, eidstr, rtype)
+        rqlbase = rtype_role_rql(rtype, role)
+        rql = 'DELETE %s' % rqlbase
+        if eids:
+            eidstr = ','.join(str(eid) for eid in eids)
+            rql += ', NOT Y eid IN (%s)' % eidstr
         self._cw.execute(rql, {'x': entity.eid})
+        if eids:
+            if role == 'object':
+                rql = 'SET %s, Y eid IN (%s), NOT Y %s X' % (rqlbase, eidstr, rtype)
+            else:
+                rql = 'SET %s, Y eid IN (%s), NOT X %s Y' % (rqlbase, eidstr, rtype)
+            self._cw.execute(rql, {'x': entity.eid})
 
 def registration_callback(vreg):
     vreg.register_all(globals().values(), __name__)
--- a/sobjects/test/unittest_email.py	Mon May 16 16:24:00 2011 +0200
+++ b/sobjects/test/unittest_email.py	Mon May 16 16:25:33 2011 +0200
@@ -54,7 +54,8 @@
         self.failIf(rset.rowcount != 1, rset)
 
     def test_security_check(self):
-        self.create_user('toto')
+        req = self.request()
+        self.create_user(req, 'toto')
         email1 = self.execute('INSERT EmailAddress E: E address "client@client.com", U use_email E WHERE U login "admin"')[0][0]
         self.commit()
         cnx = self.login('toto')
--- a/sobjects/test/unittest_notification.py	Mon May 16 16:24:00 2011 +0200
+++ b/sobjects/test/unittest_notification.py	Mon May 16 16:25:33 2011 +0200
@@ -84,7 +84,7 @@
 
     def test_status_change_view(self):
         req = self.request()
-        u = self.create_user('toto', req=req)
+        u = self.create_user(req, 'toto')
         u.cw_adapt_to('IWorkflowable').fire_transition('deactivate', comment=u'yeah')
         self.failIf(MAILBOX)
         self.commit()
--- a/sobjects/test/unittest_parsers.py	Mon May 16 16:24:00 2011 +0200
+++ b/sobjects/test/unittest_parsers.py	Mon May 16 16:25:33 2011 +0200
@@ -129,7 +129,7 @@
                              }
                           })
         session = self.repo.internal_session()
-        stats = dfsource.pull_data(session, force=True)
+        stats = dfsource.pull_data(session, force=True, raise_on_error=True)
         self.assertEqual(sorted(stats.keys()), ['created', 'updated'])
         self.assertEqual(len(stats['created']), 2)
         self.assertEqual(stats['updated'], set())
@@ -156,12 +156,12 @@
         self.assertEqual(tag.cwuri, 'http://testing.fr/cubicweb/%s' % tag.eid)
         self.assertEqual(tag.cw_source[0].name, 'system')
 
-        stats = dfsource.pull_data(session, force=True)
+        stats = dfsource.pull_data(session, force=True, raise_on_error=True)
         self.assertEqual(stats['created'], set())
         self.assertEqual(len(stats['updated']), 2)
         self.repo._type_source_cache.clear()
         self.repo._extid_cache.clear()
-        stats = dfsource.pull_data(session, force=True)
+        stats = dfsource.pull_data(session, force=True, raise_on_error=True)
         self.assertEqual(stats['created'], set())
         self.assertEqual(len(stats['updated']), 2)
 
--- a/test/data/schema.py	Mon May 16 16:24:00 2011 +0200
+++ b/test/data/schema.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -15,13 +15,11 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""
-
-"""
 
 from yams.buildobjs import (EntityType, String, SubjectRelation,
                             RelationDefinition)
-from cubicweb.schema import  WorkflowableEntityType
+from cubicweb.schema import (WorkflowableEntityType,
+                             RQLConstraint, RQLVocabularyConstraint)
 
 class Personne(EntityType):
     nom = String(required=True)
@@ -29,7 +27,14 @@
     type = String()
     travaille = SubjectRelation('Societe')
     evaluee = SubjectRelation(('Note', 'Personne'))
-    connait = SubjectRelation('Personne', symmetric=True)
+    connait = SubjectRelation(
+        'Personne', symmetric=True,
+        constraints=[
+            RQLConstraint('NOT S identity O'),
+            # conflicting constraints, see cw_unrelated_rql tests in
+            # unittest_entity.py
+            RQLVocabularyConstraint('NOT (S connait P, P nom "toto")'),
+            RQLVocabularyConstraint('S travaille P, P nom "tutu"')])
 
 class Societe(EntityType):
     nom = String()
--- a/test/unittest_entity.py	Mon May 16 16:24:00 2011 +0200
+++ b/test/unittest_entity.py	Mon May 16 16:25:33 2011 +0200
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -19,7 +19,7 @@
 """unit tests for cubicweb.web.views.entities module"""
 
 from datetime import datetime
-
+from logilab.common import tempattr
 from cubicweb import Binary, Unauthorized
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.mttransforms import HAS_TAL
@@ -29,6 +29,17 @@
 
 class EntityTC(CubicWebTC):
 
+    def setUp(self):
+        super(EntityTC, self).setUp()
+        self.backup_dict = {}
+        for cls in self.vreg['etypes'].iter_classes():
+            self.backup_dict[cls] = (cls.fetch_attrs, cls.fetch_order)
+
+    def tearDown(self):
+        super(EntityTC, self).tearDown()
+        for cls in self.vreg['etypes'].iter_classes():
+            cls.fetch_attrs, cls.fetch_order = self.backup_dict[cls]
+
     def test_boolean_value(self):
         e = self.vreg['etypes'].etype_class('CWUser')(self.request())
         self.failUnless(e)
@@ -128,6 +139,27 @@
         self.assertEqual(len(p.related('tags', 'object', limit=2)), 2)
         self.assertEqual(len(p.related('tags', 'object')), 4)
 
+    def test_cw_instantiate_relation(self):
+        req = self.request()
+        p1 = req.create_entity('Personne', nom=u'di')
+        p2 = req.create_entity('Personne', nom=u'mascio')
+        t = req.create_entity('Tag', name=u't1', tags=p1)
+        self.assertItemsEqual(t.tags, [p1])
+        t = req.create_entity('Tag', name=u't2', tags=p1.eid)
+        self.assertItemsEqual(t.tags, [p1])
+        t = req.create_entity('Tag', name=u't3', tags=[p1, p2.eid])
+        self.assertItemsEqual(t.tags, [p1, p2])
+
+    def test_cw_instantiate_reverse_relation(self):
+        req = self.request()
+        t1 = req.create_entity('Tag', name=u't1')
+        t2 = req.create_entity('Tag', name=u't2')
+        p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=t1)
+        self.assertItemsEqual(p.reverse_tags, [t1])
+        p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=t1.eid)
+        self.assertItemsEqual(p.reverse_tags, [t1])
+        p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=[t1, t2.eid])
+        self.assertItemsEqual(p.reverse_tags, [t1, t2])
 
     def test_fetch_rql(self):
         user = self.user()
@@ -136,17 +168,19 @@
         Note = self.vreg['etypes'].etype_class('Note')
         peschema = Personne.e_schema
         seschema = Societe.e_schema
-        peschema.subjrels['travaille'].rdef(peschema, seschema).cardinality = '1*'
-        peschema.subjrels['connait'].rdef(peschema, peschema).cardinality = '11'
-        peschema.subjrels['evaluee'].rdef(peschema, Note.e_schema).cardinality = '1*'
-        seschema.subjrels['evaluee'].rdef(seschema, Note.e_schema).cardinality = '1*'
-        # testing basic fetch_attrs attribute
-        self.assertEqual(Personne.fetch_rql(user),
-                          'Any X,AA,AB,AC ORDERBY AA ASC '
-                          'WHERE X is Personne, X nom AA, X prenom AB, X modification_date AC')
-        pfetch_attrs = Personne.fetch_attrs
-        sfetch_attrs = Societe.fetch_attrs
+        torestore = []
+        for rdef, card in [(peschema.subjrels['travaille'].rdef(peschema, seschema), '1*'),
+                           (peschema.subjrels['connait'].rdef(peschema, peschema), '11'),
+                           (peschema.subjrels['evaluee'].rdef(peschema, Note.e_schema), '1*'),
+                           (seschema.subjrels['evaluee'].rdef(seschema, Note.e_schema), '1*')]:
+            cm = tempattr(rdef, 'cardinality', card)
+            cm.__enter__()
+            torestore.append(cm)
         try:
+            # testing basic fetch_attrs attribute
+            self.assertEqual(Personne.fetch_rql(user),
+                              'Any X,AA,AB,AC ORDERBY AA ASC '
+                              'WHERE X is Personne, X nom AA, X prenom AB, X modification_date AC')
             # testing unknown attributes
             Personne.fetch_attrs = ('bloug', 'beep')
             self.assertEqual(Personne.fetch_rql(user), 'Any X WHERE X is Personne')
@@ -158,9 +192,9 @@
             # testing two non final relations
             Personne.fetch_attrs = ('nom', 'prenom', 'travaille', 'evaluee')
             self.assertEqual(Personne.fetch_rql(user),
-                              'Any X,AA,AB,AC,AD,AE,AF ORDERBY AA ASC,AF DESC '
-                              'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
-                              'X evaluee AE?, AE modification_date AF')
+                             'Any X,AA,AB,AC,AD,AE ORDERBY AA ASC '
+                             'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
+                             'X evaluee AE?')
             # testing one non final relation with recursion
             Personne.fetch_attrs = ('nom', 'prenom', 'travaille')
             Societe.fetch_attrs = ('nom', 'evaluee')
@@ -185,8 +219,9 @@
                               'Any X,AA,AB ORDERBY AA ASC WHERE X is Personne, X nom AA, X prenom AB')
             # XXX test unauthorized attribute
         finally:
-            Personne.fetch_attrs = pfetch_attrs
-            Societe.fetch_attrs = sfetch_attrs
+            # fetch_attrs restored by generic tearDown
+            for cm in torestore:
+                cm.__exit__(None, None, None)
 
     def test_related_rql_base(self):
         Personne = self.vreg['etypes'].etype_class('Personne')
@@ -227,52 +262,90 @@
         user = self.request().user
         rql = user.cw_unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
         self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
-                         'WHERE NOT S use_email O, S eid %(x)s, '
+                         'WHERE NOT EXISTS(ZZ use_email O), S eid %(x)s, '
                          'O is EmailAddress, O address AA, O alias AB, O modification_date AC')
 
     def test_unrelated_rql_security_1_user(self):
-        self.create_user('toto')
+        req = self.request()
+        self.create_user(req, 'toto')
         self.login('toto')
-        user = self.request().user
+        user = req.user
         rql = user.cw_unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
         self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
-                          'WHERE NOT S use_email O, S eid %(x)s, '
+                         'WHERE NOT EXISTS(ZZ use_email O), S eid %(x)s, '
                          'O is EmailAddress, O address AA, O alias AB, O modification_date AC')
         user = self.execute('Any X WHERE X login "admin"').get_entity(0, 0)
         rql = user.cw_unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
-        self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
-                         'NOT EXISTS(S use_email O), S eid %(x)s, '
-                         'O is EmailAddress, O address AA, O alias AB, O modification_date AC, '
-                         'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
+        self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
+                         'WHERE NOT EXISTS(ZZ use_email O, ZZ is CWUser), S eid %(x)s, '
+                         'O is EmailAddress, O address AA, O alias AB, O modification_date AC, A eid %(B)s, '
+                         'EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
 
     def test_unrelated_rql_security_1_anon(self):
         self.login('anon')
         user = self.request().user
         rql = user.cw_unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
-        self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
-                         'NOT EXISTS(S use_email O), S eid %(x)s, '
-                         'O is EmailAddress, O address AA, O alias AB, O modification_date AC, '
-                         'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
+        self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
+                         'WHERE NOT EXISTS(ZZ use_email O, ZZ is CWUser), S eid %(x)s, '
+                         'O is EmailAddress, O address AA, O alias AB, O modification_date AC, A eid %(B)s, '
+                         'EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
 
     def test_unrelated_rql_security_2(self):
         email = self.execute('INSERT EmailAddress X: X address "hop"').get_entity(0, 0)
         rql = email.cw_unrelated_rql('use_email', 'CWUser', 'object')[0]
-        self.assertEqual(rql, 'Any S,AA,AB,AC,AD ORDERBY AA ASC '
-                          'WHERE NOT S use_email O, O eid %(x)s, S is CWUser, S login AA, S firstname AB, S surname AC, S modification_date AD')
+        self.assertEqual(rql, 'Any S,AA,AB,AC,AD ORDERBY AA '
+                         'WHERE NOT EXISTS(S use_email O), O eid %(x)s, S is CWUser, '
+                         'S login AA, S firstname AB, S surname AC, S modification_date AD')
         self.login('anon')
         email = self.execute('Any X WHERE X eid %(x)s', {'x': email.eid}).get_entity(0, 0)
         rql = email.cw_unrelated_rql('use_email', 'CWUser', 'object')[0]
         self.assertEqual(rql, 'Any S,AA,AB,AC,AD ORDERBY AA '
-                          'WHERE NOT EXISTS(S use_email O), O eid %(x)s, S is CWUser, S login AA, S firstname AB, S surname AC, S modification_date AD, '
-                          'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
+                         'WHERE NOT EXISTS(S use_email O), O eid %(x)s, S is CWUser, '
+                         'S login AA, S firstname AB, S surname AC, S modification_date AD, '
+                         'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
 
     def test_unrelated_rql_security_nonexistant(self):
         self.login('anon')
         email = self.vreg['etypes'].etype_class('EmailAddress')(self.request())
         rql = email.cw_unrelated_rql('use_email', 'CWUser', 'object')[0]
         self.assertEqual(rql, 'Any S,AA,AB,AC,AD ORDERBY AA '
-                          'WHERE S is CWUser, S login AA, S firstname AB, S surname AC, S modification_date AD, '
-                          'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
+                         'WHERE S is CWUser, '
+                         'S login AA, S firstname AB, S surname AC, S modification_date AD, '
+                         'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
+
+    def test_unrelated_rql_constraints_creation_subject(self):
+        person = self.vreg['etypes'].etype_class('Personne')(self.request())
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'subject')[0]
+        self.assertEqual(
+            rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
+            'O is Personne, O nom AA, O prenom AB, O modification_date AC')
+
+    def test_unrelated_rql_constraints_creation_object(self):
+        person = self.vreg['etypes'].etype_class('Personne')(self.request())
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'object')[0]
+        self.assertEqual(
+            rql, 'Any S,AA,AB,AC ORDERBY AC DESC WHERE '
+            'S is Personne, S nom AA, S prenom AB, S modification_date AC, '
+            'NOT (S connait A, A nom "toto"), A is Personne, EXISTS(S travaille B, B nom "tutu")')
+
+    def test_unrelated_rql_constraints_edition_subject(self):
+        person = self.request().create_entity('Personne', nom=u'sylvain')
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'subject')[0]
+        self.assertEqual(
+            rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
+            'NOT EXISTS(S connait O), S eid %(x)s, O is Personne, '
+            'O nom AA, O prenom AB, O modification_date AC, '
+            'NOT S identity O')
+
+    def test_unrelated_rql_constraints_edition_object(self):
+        person = self.request().create_entity('Personne', nom=u'sylvain')
+        rql = person.cw_unrelated_rql('connait', 'Personne', 'object')[0]
+        self.assertEqual(
+            rql, 'Any S,AA,AB,AC ORDERBY AC DESC WHERE '
+            'NOT EXISTS(S connait O), O eid %(x)s, S is Personne, '
+            'S nom AA, S prenom AB, S modification_date AC, '
+            'NOT S identity O, NOT (S connait A, A nom "toto"), '
+            'EXISTS(S travaille B, B nom "tutu")')
 
     def test_unrelated_base(self):
         req = self.request()
@@ -302,7 +375,8 @@
         user = self.request().user
         rset = user.unrelated('use_email', 'EmailAddress', 'subject')
         self.assertEqual([x.address for x in rset.entities()], [u'hop'])
-        self.create_user('toto')
+        req = self.request()
+        self.create_user(req, 'toto')
         self.login('toto')
         email = self.execute('Any X WHERE X eid %(x)s', {'x': email.eid}).get_entity(0, 0)
         rset = email.unrelated('use_email', 'CWUser', 'object')
@@ -511,6 +585,15 @@
         self.assertEqual(person.prenom, u'sylvain')
         self.assertEqual(person.nom, u'thénault')
 
+    def test_set_relations(self):
+        req = self.request()
+        person = req.create_entity('Personne', nom=u'chauvat', prenom=u'nicolas')
+        note = req.create_entity('Note', type=u'x')
+        note.set_relations(ecrit_par=person)
+        note = req.create_entity('Note', type=u'y')
+        note.set_relations(ecrit_par=person.eid)
+        self.assertEqual(len(person.reverse_ecrit_par), 2)
+
     def test_metainformation_and_external_absolute_url(self):
         req = self.request()
         note = req.create_entity('Note', type=u'z')
--- a/test/unittest_rqlrewrite.py	Mon May 16 16:24:00 2011 +0200
+++ b/test/unittest_rqlrewrite.py	Mon May 16 16:25:33 2011 +0200
@@ -353,14 +353,21 @@
         self.failUnlessEqual(rqlst.as_string(),
                              u"Any C WHERE C is Card, EXISTS(C owned_by A, A is CWUser)")
 
-    def test_rqlexpr_not_relation1(self):
+    def test_rqlexpr_not_relation_1_1(self):
         constraint = RRQLExpression('X owned_by Z, Z login "hop"', 'X')
         rqlst = parse('Affaire A WHERE NOT EXISTS(A documented_by C)')
         rewrite(rqlst, {('C', 'X'): (constraint,)}, {}, 'X')
         self.failUnlessEqual(rqlst.as_string(),
                              u'Any A WHERE NOT EXISTS(A documented_by C, EXISTS(C owned_by B, B login "hop", B is CWUser), C is Card), A is Affaire')
 
-    def test_rqlexpr_not_relation2(self):
+    def test_rqlexpr_not_relation_1_2(self):
+        constraint = RRQLExpression('X owned_by Z, Z login "hop"', 'X')
+        rqlst = parse('Affaire A WHERE NOT EXISTS(A documented_by C)')
+        rewrite(rqlst, {('A', 'X'): (constraint,)}, {}, 'X')
+        self.failUnlessEqual(rqlst.as_string(),
+                             u'Any A WHERE NOT EXISTS(A documented_by C, C is Card), A is Affaire, EXISTS(A owned_by B, B login "hop", B is CWUser)')
+
+    def test_rqlexpr_not_relation_2(self):
         constraint = RRQLExpression('X owned_by Z, Z login "hop"', 'X')
         rqlst = rqlhelper.parse('Affaire A WHERE NOT A documented_by C', annotate=False)
         rewrite(rqlst, {('C', 'X'): (constraint,)}, {}, 'X')
--- a/test/unittest_rset.py	Mon May 16 16:24:00 2011 +0200
+++ b/test/unittest_rset.py	Mon May 16 16:25:33 2011 +0200
@@ -114,7 +114,6 @@
                        description=[['CWUser', 'String']] * 3)
         rs.req = self.request()
         rs.vreg = self.vreg
-
         self.assertEqual(rs.limit(2).rows, [[12000, 'adim'], [13000, 'syt']])
         rs2 = rs.limit(2, offset=1)
         self.assertEqual(rs2.rows, [[13000, 'syt'], [14000, 'nico']])
--- a/test/unittest_schema.py	Mon May 16 16:24:00 2011 +0200
+++ b/test/unittest_schema.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -169,7 +169,7 @@
                              'Password', 'Personne',
                              'RQLExpression',
                              'Societe', 'State', 'StateFull', 'String', 'SubNote', 'SubWorkflowExitPoint',
-                             'Tag', 'Time', 'Transition', 'TrInfo',
+                             'Tag', 'TZDatetime', 'TZTime', 'Time', 'Transition', 'TrInfo',
                              'Workflow', 'WorkflowTransition']
         self.assertListEqual(sorted(expected_entities), entities)
         relations = sorted([str(r) for r in schema.relations()])
@@ -239,7 +239,7 @@
         self.failUnlessEqual(len(constraints), 1, constraints)
         constraint = constraints[0]
         self.failUnless(isinstance(constraint, RQLConstraint))
-        self.failUnlessEqual(constraint.restriction, 'O final TRUE')
+        self.failUnlessEqual(constraint.expression, 'O final TRUE')
 
     def test_fulltext_container(self):
         schema = loader.load(config)
@@ -315,7 +315,7 @@
 class GuessRrqlExprMainVarsTC(TestCase):
     def test_exists(self):
         mainvars = guess_rrqlexpr_mainvars(normalize_expression('NOT EXISTS(O team_competition C, C level < 3)'))
-        self.assertEqual(mainvars, 'O')
+        self.assertEqual(mainvars, set(['O']))
 
 
 if __name__ == '__main__':
--- a/test/unittest_selectors.py	Mon May 16 16:24:00 2011 +0200
+++ b/test/unittest_selectors.py	Mon May 16 16:25:33 2011 +0200
@@ -26,7 +26,7 @@
 from cubicweb.appobject import Selector, AndSelector, OrSelector
 from cubicweb.selectors import (is_instance, adaptable, match_user_groups,
                                 multi_lines_rset, score_entity, is_in_state,
-                                on_transition)
+                                on_transition, rql_condition)
 from cubicweb.web import action
 
 
@@ -221,7 +221,7 @@
     def test_is_in_state(self):
         for state in ('created', 'validated', 'abandoned'):
             selector = is_in_state(state)
-            self.assertEqual(selector(None, self.req, self.rset),
+            self.assertEqual(selector(None, self.req, rset=self.rset),
                              state=="created")
 
         self.adapter.fire_transition('validate')
@@ -229,75 +229,75 @@
         self.assertEqual(self.adapter.state, 'validated')
 
         selector = is_in_state('created')
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         selector = is_in_state('validated')
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
         selector = is_in_state('validated', 'abandoned')
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
         selector = is_in_state('abandoned')
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
 
         self.adapter.fire_transition('forsake')
         self._commit()
         self.assertEqual(self.adapter.state, 'abandoned')
 
         selector = is_in_state('created')
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         selector = is_in_state('validated')
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         selector = is_in_state('validated', 'abandoned')
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
         self.assertEqual(self.adapter.state, 'abandoned')
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
 
     def test_is_in_state_unvalid_names(self):
         selector = is_in_state("unknown")
         with self.assertRaises(ValueError) as cm:
-            selector(None, self.req, self.rset)
+            selector(None, self.req, rset=self.rset)
         self.assertEqual(str(cm.exception),
                          "wf_test: unknown state(s): unknown")
         selector = is_in_state("weird", "unknown", "created", "weird")
         with self.assertRaises(ValueError) as cm:
-            selector(None, self.req, self.rset)
+            selector(None, self.req, rset=self.rset)
         self.assertEqual(str(cm.exception),
                          "wf_test: unknown state(s): unknown,weird")
 
     def test_on_transition(self):
         for transition in ('validate', 'forsake'):
             selector = on_transition(transition)
-            self.assertEqual(selector(None, self.req, self.rset), 0)
+            self.assertEqual(selector(None, self.req, rset=self.rset), 0)
 
         self.adapter.fire_transition('validate')
         self._commit()
         self.assertEqual(self.adapter.state, 'validated')
 
         selector = on_transition("validate")
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
         selector = on_transition("validate", "forsake")
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
         selector = on_transition("forsake")
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
 
         self.adapter.fire_transition('forsake')
         self._commit()
         self.assertEqual(self.adapter.state, 'abandoned')
 
         selector = on_transition("validate")
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         selector = on_transition("validate", "forsake")
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
         selector = on_transition("forsake")
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
 
     def test_on_transition_unvalid_names(self):
         selector = on_transition("unknown")
         with self.assertRaises(ValueError) as cm:
-            selector(None, self.req, self.rset)
+            selector(None, self.req, rset=self.rset)
         self.assertEqual(str(cm.exception),
                          "wf_test: unknown transition(s): unknown")
         selector = on_transition("weird", "unknown", "validate", "weird")
         with self.assertRaises(ValueError) as cm:
-            selector(None, self.req, self.rset)
+            selector(None, self.req, rset=self.rset)
         self.assertEqual(str(cm.exception),
                          "wf_test: unknown transition(s): unknown,weird")
 
@@ -308,11 +308,11 @@
         self.assertEqual(self.adapter.state, 'validated')
 
         selector = on_transition("validate")
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         selector = on_transition("validate", "forsake")
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         selector = on_transition("forsake")
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
 
 
 class MatchUserGroupsTC(CubicWebTC):
@@ -328,7 +328,8 @@
         self.failUnless(SomeAction in self.vreg['actions']['yo'], self.vreg['actions'])
         try:
             # login as a simple user
-            self.create_user('john')
+            req = self.request()
+            self.create_user(req, 'john')
             self.login('john')
             # it should not be possible to use SomeAction not owned objects
             req = self.request()
@@ -361,13 +362,13 @@
     def test_default_op_in_selector(self):
         expected = len(self.rset)
         selector = multi_lines_rset(expected)
-        self.assertEqual(selector(None, self.req, self.rset), 1)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 1)
         self.assertEqual(selector(None, self.req, None), 0)
         selector = multi_lines_rset(expected + 1)
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         self.assertEqual(selector(None, self.req, None), 0)
         selector = multi_lines_rset(expected - 1)
-        self.assertEqual(selector(None, self.req, self.rset), 0)
+        self.assertEqual(selector(None, self.req, rset=self.rset), 0)
         self.assertEqual(selector(None, self.req, None), 0)
 
     def test_without_rset(self):
@@ -398,7 +399,7 @@
 
         for (expected, operator, assertion) in testdata:
             selector = multi_lines_rset(expected, operator)
-            yield self.assertEqual, selector(None, self.req, self.rset), assertion
+            yield self.assertEqual, selector(None, self.req, rset=self.rset), assertion
 
 
 class ScoreEntitySelectorTC(CubicWebTC):
@@ -407,17 +408,31 @@
         req = self.request()
         rset = req.execute('Any E WHERE E eid 1')
         selector = score_entity(lambda x: None)
-        self.assertEqual(selector(None, req, rset), 0)
+        self.assertEqual(selector(None, req, rset=rset), 0)
         selector = score_entity(lambda x: "something")
-        self.assertEqual(selector(None, req, rset), 1)
+        self.assertEqual(selector(None, req, rset=rset), 1)
         selector = score_entity(lambda x: object)
-        self.assertEqual(selector(None, req, rset), 1)
+        self.assertEqual(selector(None, req, rset=rset), 1)
         rset = req.execute('Any G LIMIT 2 WHERE G is CWGroup')
         selector = score_entity(lambda x: 10)
-        self.assertEqual(selector(None, req, rset), 20)
+        self.assertEqual(selector(None, req, rset=rset), 20)
         selector = score_entity(lambda x: 10, once_is_enough=True)
-        self.assertEqual(selector(None, req, rset), 10)
+        self.assertEqual(selector(None, req, rset=rset), 10)
 
+    def test_rql_condition_entity(self):
+        req = self.request()
+        selector = rql_condition('X identity U')
+        rset = req.user.as_rset()
+        self.assertEqual(selector(None, req, rset=rset), 1)
+        self.assertEqual(selector(None, req, entity=req.user), 1)
+        self.assertEqual(selector(None, req), 0)
+
+    def test_rql_condition_user(self):
+        req = self.request()
+        selector = rql_condition('U login "admin"', user_condition=True)
+        self.assertEqual(selector(None, req), 1)
+        selector = rql_condition('U login "toto"', user_condition=True)
+        self.assertEqual(selector(None, req), 0)
 
 if __name__ == '__main__':
     unittest_main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/ajax_url0.html	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,3 @@
+<div id="ajaxroot">
+  <h1>Hello</h1>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/ajax_url1.html	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,6 @@
+<div id="ajaxroot">
+  <div class="ajaxHtmlHead">
+    <script src="http://foo.js" type="text/javascript"> </script>
+  </div>
+  <h1>Hello</h1>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/ajax_url2.html	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,7 @@
+<div id="ajaxroot">
+  <div class="ajaxHtmlHead">
+    <script src="http://foo.js" type="text/javascript"> </script>
+    <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
+  </div>
+  <h1>Hello</h1>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/ajaxresult.json	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,1 @@
+['foo', 'bar']
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/test_ajax.html	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <!-- dependencies -->
+    <script type="text/javascript" src="../../data/jquery.js"></script>
+    <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.dom.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.ajax.js" type="text/javascript"></script>
+    <!-- qunit files -->
+    <script type="text/javascript" src="../../../devtools/data/qunit.js"></script>
+    <link rel="stylesheet" type="text/css" media="all" href="../../../devtools/data/qunit.css" />
+    <!-- test suite -->
+    <script src="cwmock.js" type="text/javascript"></script>
+    <script src="test_ajax.js" type="text/javascript"></script>
+  </head>
+  <body>
+    <div id="main"> </div>
+    <h1 id="qunit-header">cubicweb.ajax.js functions tests</h1>
+    <h2 id="qunit-banner"></h2>
+    <ol id="qunit-tests">
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/test_ajax.js	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,244 @@
+$(document).ready(function() {
+
+    module("ajax", {
+        setup: function() {
+          this.scriptsLength = $('head script[src]').length-1;
+          this.cssLength = $('head link[rel=stylesheet]').length-1;
+          // re-initialize cw loaded cache so that each tests run in a
+          // clean environment, have a lookt at _loadAjaxHtmlHead implementation
+          // in cubicweb.ajax.js for more information.
+          cw.loaded_src = [];
+          cw.loaded_href = [];
+        },
+        teardown: function() {
+          $('head script[src]:gt(' + this.scriptsLength + ')').remove();
+          $('head link[rel=stylesheet]:gt(' + this.cssLength + ')').remove();
+        }
+      });
+
+    function jsSources() {
+        return $.map($('head script[src]'), function(script) {
+            return script.getAttribute('src');
+        });
+    }
+
+    test('test simple h1 inclusion (ajax_url0.html)', function() {
+        expect(3);
+        equals(jQuery('#main').children().length, 0);
+        stop();
+        jQuery('#main').loadxhtml('/../ajax_url0.html', {
+            callback: function() {
+                equals(jQuery('#main').children().length, 1);
+                equals(jQuery('#main h1').html(), 'Hello');
+                start();
+            }
+        });
+    });
+
+    test('test simple html head inclusion (ajax_url1.html)', function() {
+        expect(6);
+        var scriptsIncluded = jsSources();
+        equals(jQuery.inArray('http://foo.js', scriptsIncluded), - 1);
+        stop();
+        jQuery('#main').loadxhtml('/../ajax_url1.html', {
+            callback: function() {
+                var origLength = scriptsIncluded.length;
+                scriptsIncluded = jsSources();
+                // check that foo.js has been *appended* to <head>
+                equals(scriptsIncluded.length, origLength + 1);
+                equals(scriptsIncluded[origLength].indexOf('http://foo.js'), 0);
+                // check that <div class="ajaxHtmlHead"> has been removed
+                equals(jQuery('#main').children().length, 1);
+                equals(jQuery('div.ajaxHtmlHead').length, 0);
+                equals(jQuery('#main h1').html(), 'Hello');
+                start();
+            }
+        });
+    });
+
+    test('test addCallback', function() {
+        expect(3);
+        equals(jQuery('#main').children().length, 0);
+        stop();
+        var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
+        d.addCallback(function() {
+            equals(jQuery('#main').children().length, 1);
+            equals(jQuery('#main h1').html(), 'Hello');
+            start();
+        });
+    });
+
+    test('test callback after synchronous request', function() {
+        expect(1);
+        var deferred = new Deferred();
+        var result = jQuery.ajax({
+            url: './ajax_url0.html',
+            async: false,
+            beforeSend: function(xhr) {
+                deferred._req = xhr;
+            },
+            success: function(data, status) {
+                deferred.success(data);
+            }
+        });
+        stop();
+        deferred.addCallback(function() {
+            // add an assertion to ensure the callback is executed
+            ok(true, "callback is executed");
+            start();
+        });
+    });
+
+    test('test addCallback with parameters', function() {
+        expect(3);
+        equals(jQuery('#main').children().length, 0);
+        stop();
+        var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
+        d.addCallback(function(data, req, arg1, arg2) {
+            equals(arg1, 'Hello');
+            equals(arg2, 'world');
+            start();
+        },
+        'Hello', 'world');
+    });
+
+    test('test callback after synchronous request with parameters', function() {
+        var deferred = new Deferred();
+        var result = jQuery.ajax({
+            url: '/../ajax_url0.html',
+            async: false,
+            beforeSend: function(xhr) {
+                deferred._req = xhr;
+            },
+            success: function(data, status) {
+                deferred.success(data);
+            }
+        });
+        deferred.addCallback(function(data, req, arg1, arg2) {
+            // add an assertion to ensure the callback is executed
+            ok(true, "callback is executed");
+            equals(arg1, 'Hello');
+            equals(arg2, 'world');
+        },
+        'Hello', 'world');
+    });
+
+  test('test addErrback', function() {
+        expect(1);
+        stop();
+        var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
+        d.addCallback(function() {
+            // throw an exception to start errback chain
+            throw new Error();
+        });
+        d.addErrback(function() {
+            ok(true, "errback is executed");
+            start();
+        });
+    });
+
+    test('test callback / errback execution order', function() {
+        expect(4);
+        var counter = 0;
+        stop();
+        var d = jQuery('#main').loadxhtml('/../ajax_url0.html', {
+            callback: function() {
+                equals(++counter, 1); // should be executed first
+                start();
+            }
+        });
+        d.addCallback(function() {
+            equals(++counter, 2); // should be executed and break callback chain
+            throw new Error();
+        });
+        d.addCallback(function() {
+            // should not be executed since second callback raised an error
+            ok(false, "callback is executed");
+        });
+        d.addErrback(function() {
+            // should be executed after the second callback
+            equals(++counter, 3);
+        });
+        d.addErrback(function() {
+            // should be executed after the first errback
+            equals(++counter, 4);
+        });
+    });
+
+    test('test already included resources are ignored (ajax_url1.html)', function() {
+        expect(10);
+        var scriptsIncluded = jsSources();
+        // NOTE:
+        equals(jQuery.inArray('http://foo.js', scriptsIncluded), -1);
+        equals(jQuery('head link').length, 1);
+        /* use endswith because in pytest context we have an absolute path */
+        ok(jQuery('head link').attr('href').endswith('/qunit.css'));
+        stop();
+        jQuery('#main').loadxhtml('/../ajax_url1.html', {
+            callback: function() {
+                var origLength = scriptsIncluded.length;
+                scriptsIncluded = jsSources();
+                try {
+                    // check that foo.js has been inserted in <head>
+                    equals(scriptsIncluded.length, origLength + 1);
+                    equals(scriptsIncluded[origLength].indexOf('http://foo.js'), 0);
+                    // check that <div class="ajaxHtmlHead"> has been removed
+                    equals(jQuery('#main').children().length, 1);
+                    equals(jQuery('div.ajaxHtmlHead').length, 0);
+                    equals(jQuery('#main h1').html(), 'Hello');
+                    // qunit.css is not added twice
+                    equals(jQuery('head link').length, 1);
+                    /* use endswith because in pytest context we have an absolute path */
+                    ok(jQuery('head link').attr('href').endswith('/qunit.css'));
+                } finally {
+                    start();
+                }
+            }
+        });
+    });
+
+    test('test synchronous request loadRemote', function() {
+        var res = loadRemote('/../ajaxresult.json', {},
+        'GET', true);
+        same(res, ['foo', 'bar']);
+    });
+
+    test('test event on CubicWeb', function() {
+        expect(1);
+        stop();
+        var events = null;
+        jQuery(CubicWeb).bind('server-response', function() {
+            // check that server-response event on CubicWeb is triggered
+            events = 'CubicWeb';
+        });
+        jQuery('#main').loadxhtml('/../ajax_url0.html', {
+            callback: function() {
+                equals(events, 'CubicWeb');
+                start();
+            }
+        });
+    });
+
+    test('test event on node', function() {
+        expect(3);
+        stop();
+        var nodes = [];
+        jQuery('#main').bind('server-response', function() {
+            nodes.push('node');
+        });
+        jQuery(CubicWeb).bind('server-response', function() {
+            nodes.push('CubicWeb');
+        });
+        jQuery('#main').loadxhtml('/../ajax_url0.html', {
+            callback: function() {
+                equals(nodes.length, 2);
+                // check that server-response event on CubicWeb is triggered
+                // only once and event server-response on node is triggered
+                equals(nodes[0], 'CubicWeb');
+                equals(nodes[1], 'node');
+                start();
+            }
+        });
+    });
+});
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/test_htmlhelpers.html	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,21 @@
+<html>
+  <head>
+    <script type="text/javascript" src="../../data/jquery.js"></script>
+    <script src="../../data/cubicweb.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
+    <script type="text/javascript" src="qunit.js"></script>
+    <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
+    <script src="cwmock.js" type="text/javascript"></script>
+    <script src="test_htmlhelpers.js" type="text/javascript"></script>
+  </head>
+  <body>
+    <div id="main">
+    </div>
+    <h1 id="qunit-header">cubicweb.htmlhelpers.js functions tests</h1>
+    <h2 id="qunit-banner"></h2>
+    <h2 id="qunit-userAgent"></h2>
+    <ol id="qunit-tests">
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/test_htmlhelpers.js	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,36 @@
+$(document).ready(function() {
+
+    module("module2", {
+      setup: function() {
+        $('#main').append('<select id="theselect" multiple="multiple" size="2">' +
+    			'</select>');
+      }
+    });
+
+    test("test first selected", function() {
+        $('#theselect').append('<option value="foo">foo</option>' +
+    			     '<option selected="selected" value="bar">bar</option>' +
+    			     '<option value="baz">baz</option>' +
+    			     '<option selected="selecetd"value="spam">spam</option>');
+        var selected = firstSelected(document.getElementById("theselect"));
+        equals(selected.value, 'bar');
+    });
+
+    test("test first selected 2", function() {
+        $('#theselect').append('<option value="foo">foo</option>' +
+    			     '<option value="bar">bar</option>' +
+    			     '<option value="baz">baz</option>' +
+    			     '<option value="spam">spam</option>');
+        var selected = firstSelected(document.getElementById("theselect"));
+        equals(selected, null);
+    });
+
+    module("visibilty");
+    test('toggleVisibility', function() {
+        $('#main').append('<div id="foo"></div>');
+        toggleVisibility('foo');
+        ok($('#foo').hasClass('hidden'), 'check hidden class is set');
+    });
+
+});
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/test_utils.html	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,22 @@
+<html>
+  <head>
+    <script type="text/javascript" src="../../data/jquery.js"></script>
+    <script src="../../data/jquery.corner.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
+    <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+    <script src="utils.js" type="text/javascript"></script>
+    <script type="text/javascript" src="qunit.js"></script>
+    <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
+    <script src="cwmock.js" type="text/javascript"></script>
+    <script src="test_utils.js" type="text/javascript"></script>
+  </head>
+  <body>
+    <div id="main">
+    </div>
+    <h1 id="qunit-header">cw.utils functions tests</h1>
+    <h2 id="qunit-banner"></h2>
+    <h2 id="qunit-userAgent"></h2>
+    <ol id="qunit-tests">
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/test_utils.js	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,92 @@
+$(document).ready(function() {
+
+  module("datetime");
+
+  test("test full datetime", function() {
+      equals(cw.utils.toISOTimestamp(new Date(1986, 3, 18, 10, 30, 0, 0)),
+	     '1986-04-18 10:30:00');
+  });
+
+  test("test only date", function() {
+      equals(cw.utils.toISOTimestamp(new Date(1986, 3, 18)), '1986-04-18 00:00:00');
+  });
+
+  test("test null", function() {
+      equals(cw.utils.toISOTimestamp(null), null);
+  });
+
+  module("parsing");
+  test("test basic number parsing", function() {
+      var d = strptime('2008/08/08', '%Y/%m/%d');
+      same(datetuple(d), [2008, 8, 8, 0, 0]);
+      d = strptime('2008/8/8', '%Y/%m/%d');
+      same(datetuple(d), [2008, 8, 8, 0, 0]);
+      d = strptime('8/8/8', '%Y/%m/%d');
+      same(datetuple(d), [8, 8, 8, 0, 0]);
+      d = strptime('0/8/8', '%Y/%m/%d');
+      same(datetuple(d), [0, 8, 8, 0, 0]);
+      d = strptime('-10/8/8', '%Y/%m/%d');
+      same(datetuple(d), [-10, 8, 8, 0, 0]);
+      d = strptime('-35000', '%Y');
+      same(datetuple(d), [-35000, 1, 1, 0, 0]);
+  });
+
+  test("test custom format parsing", function() {
+      var d = strptime('2008-08-08', '%Y-%m-%d');
+      same(datetuple(d), [2008, 8, 8, 0, 0]);
+      d = strptime('2008 - !  08: 08', '%Y - !  %m: %d');
+      same(datetuple(d), [2008, 8, 8, 0, 0]);
+      d = strptime('2008-08-08 12:14', '%Y-%m-%d %H:%M');
+      same(datetuple(d), [2008, 8, 8, 12, 14]);
+      d = strptime('2008-08-08 1:14', '%Y-%m-%d %H:%M');
+      same(datetuple(d), [2008, 8, 8, 1, 14]);
+      d = strptime('2008-08-08 01:14', '%Y-%m-%d %H:%M');
+      same(datetuple(d), [2008, 8, 8, 1, 14]);
+  });
+
+  module("sliceList");
+  test("test slicelist", function() {
+      var list = ['a', 'b', 'c', 'd', 'e', 'f'];
+      same(sliceList(list, 2),  ['c', 'd', 'e', 'f']);
+      same(sliceList(list, 2, -2), ['c', 'd']);
+      same(sliceList(list, -3), ['d', 'e', 'f']);
+      same(sliceList(list, 0, -2), ['a', 'b', 'c', 'd']);
+      same(sliceList(list),  list);
+  });
+
+  module("formContents", {
+    setup: function() {
+      $('#main').append('<form id="test-form"></form>');
+    }
+  });
+  // XXX test fckeditor
+  test("test formContents", function() {
+      $('#test-form').append('<input name="input-text" ' +
+			     'type="text" value="toto" />');
+      $('#test-form').append('<textarea rows="10" cols="30" '+
+			     'name="mytextarea">Hello World!</textarea> ');
+      $('#test-form').append('<input name="choice" type="radio" ' +
+			     'value="yes" />');
+      $('#test-form').append('<input name="choice" type="radio" ' +
+			     'value="no" checked="checked"/>');
+      $('#test-form').append('<input name="check" type="checkbox" ' +
+			     'value="yes" />');
+      $('#test-form').append('<input name="check" type="checkbox" ' +
+			     'value="no" checked="checked"/>');
+      $('#test-form').append('<select id="theselect" name="theselect" ' +
+			     'multiple="multiple" size="2"></select>');
+      $('#theselect').append('<option selected="selected" ' +
+			     'value="foo">foo</option>' +
+  			     '<option value="bar">bar</option>');
+      //Append an unchecked radio input : should not be in formContents list
+      $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
+			     'value="one" />');
+      $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
+			     'value="two"/>');
+      same(formContents($('#test-form')[0]), [
+	['input-text', 'mytextarea', 'choice', 'check', 'theselect'],
+	['toto', 'Hello World!', 'no', 'no', 'foo']
+      ]);
+  });
+});
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/jstests/utils.js	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,29 @@
+function datetuple(d) {
+    return [d.getFullYear(), d.getMonth()+1, d.getDate(),
+	    d.getHours(), d.getMinutes()];
+}
+
+function pprint(obj) {
+    print('{');
+    for(k in obj) {
+	print('  ' + k + ' = ' + obj[k]);
+    }
+    print('}');
+}
+
+function arrayrepr(array) {
+    return '[' + array.join(', ') + ']';
+}
+
+function assertArrayEquals(array1, array2) {
+    if (array1.length != array2.length) {
+	throw new crosscheck.AssertionFailure(array1.join(', ') + ' != ' + array2.join(', '));
+    }
+    for (var i=0; i<array1.length; i++) {
+	if (array1[i] != array2[i]) {
+
+	    throw new crosscheck.AssertionFailure(arrayrepr(array1) + ' and ' + arrayrepr(array2)
+						 + ' differs at index ' + i);
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/test_jscript.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,42 @@
+from cubicweb.devtools.qunit import QUnitTestCase, unittest_main
+
+from os import path as osp
+
+
+class JScript(QUnitTestCase):
+
+    all_js_tests = (
+        ("jstests/test_utils.js", (
+            "../../web/data/cubicweb.js",
+            "../../web/data/cubicweb.compat.js",
+            "../../web/data/cubicweb.python.js",
+            "jstests/utils.js",
+            ),
+         ),
+
+        ("jstests/test_htmlhelpers.js", (
+            "../../web/data/cubicweb.js",
+            "../../web/data/cubicweb.compat.js",
+            "../../web/data/cubicweb.python.js",
+            "../../web/data/cubicweb.htmlhelpers.js",
+            ),
+         ),
+
+        ("jstests/test_ajax.js", (
+            "../../web/data/cubicweb.python.js",
+            "../../web/data/cubicweb.js",
+            "../../web/data/cubicweb.compat.js",
+            "../../web/data/cubicweb.htmlhelpers.js",
+            "../../web/data/cubicweb.ajax.js",
+            ), (
+            "jstests/ajax_url0.html",
+            "jstests/ajax_url1.html",
+            "jstests/ajax_url2.html",
+            "jstests/ajaxresult.json",
+            ),
+         ),
+    )
+
+
+if __name__ == '__main__':
+    unittest_main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/test_windmill.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,12 @@
+# Run all scenarii found in windmill directory
+from os.path import join, dirname
+from cubicweb.devtools.cwwindmill import (CubicWebWindmillUseCase,
+                                          unittest_main)
+
+class CubicWebWindmillUseCase(CubicWebWindmillUseCase):
+    #test_dir = join(dirname(__file__), "windmill/test_edit_relation.py")
+    pass
+
+
+if __name__ == '__main__':
+    unittest_main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/windmill/test_connexion.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,41 @@
+from cubicweb.devtools import DEFAULT_SOURCES
+LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
+
+# Generated by the windmill services transformer
+from windmill.authoring import WindmillTestClient
+
+def test_connect():
+    client = WindmillTestClient(__name__)
+
+    client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
+    client.type(text=LOGIN, id=u'__login')
+    client.type(text=PASSWORD, id=u'__password')
+
+    client.execJS(js=u"$('#loginForm').submit()")
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.sleep(milliseconds=u'5000')
+    client.asserts.assertJS(js=u'$(\'.message\').text() == "welcome %s !"' % LOGIN)
+    client.open(url=u'/logout')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
+
+
+def test_wrong_connect():
+    client = WindmillTestClient(__name__)
+
+    client.open(url=u'/')
+    # XXX windmill wants to use its proxy internally on 403 :-(
+    #client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
+    #client.type(text=LOGIN, id=u'__login')
+    #client.type(text=u'novalidpassword', id=u'__password')
+    #client.click(value=u'log in')
+    client.open(url=u'/?__login=user&__password=nopassword')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertTextIn(validator=u'authentication failure', id=u'loginBox')
+    client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/windmill/test_creation.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,58 @@
+from cubicweb.devtools import DEFAULT_SOURCES
+LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
+
+# Generated by the windmill services transformer
+from windmill.authoring import WindmillTestClient
+
+def test_creation():
+    client = WindmillTestClient(__name__)
+
+    client.open(url=u'/')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.type(text=LOGIN, id=u'__login')
+    client.type(text=PASSWORD, id=u'__password')
+    client.click(value=u'log in')
+    client.waits.forPageLoad(timeout=u'20000')
+
+    # pre-condition
+    client.open(url=u'/cwuser/myuser')
+    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "this resource does not exist"')
+    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
+    client.asserts.assertJS(js=u'$(\'.searchMessage strong\').text() == "No result matching query"')
+
+    client.open(url=u'/manage')
+    client.open(url=u'/add/CWUser')
+    client.type(text=u'myuser', id=u'login-subject:A')
+    client.type(text=u'myuser', id=u'upassword-subject:A')
+    client.type(text=u'myuser', name=u'upassword-subject-confirm:A')
+    client.type(text=u'myuser', id=u'firstname-subject:A')
+    client.select(option=u'managers', id=u'from_in_group-subject:A')
+    client.click(id=u'cwinoutadd')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.click(id=u'adduse_email:Alink')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.type(text=u'myuser@logilab.fr', id=u'address-subject:B')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.sleep(milliseconds=u'5000')
+    client.asserts.assertJS(js=u'$(\'.message\').text() == "entity created"')
+    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "myuser"')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.open(url=u'/cwuser/myuser?vid=sameetypelist')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.asserts.assertJS(js=u'$(\'#contentmain a\').text() == "myuser"')
+    client.open(url=u'/cwuser/myuser?vid=text')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.asserts.assertJS(js=u'$(\'#contentmain\').text() == "\\nmyuser"')
+    client.open(url=u'/cwuser/myuser?vid=deleteconf')
+    client.waits.forElement(timeout=u'8000', value=u'button_delete')
+    client.click(value=u'button_delete')
+    client.waits.forPageLoad(timeout=u'8000')
+    client.open(url=u'/cwuser/myuser')
+    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "this resource does not exist"')
+    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
+    client.asserts.assertJS(js=u'$(\'.searchMessage strong\').text() == "No result matching query"')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testfunc/test/windmill/test_edit_relation.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,82 @@
+from cubicweb.devtools import DEFAULT_SOURCES
+LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
+
+# Generated by the windmill services transformer
+from windmill.authoring import WindmillTestClient
+
+
+def test_edit_relation():
+    client = WindmillTestClient(__name__)
+
+    client.open(url=u'/logout')
+    client.open(url=u'/')
+    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
+    client.type(text=LOGIN, id=u'__login')
+    client.type(text=PASSWORD, id=u'__password')
+    client.execJS(js=u"$('#loginForm').submit()")
+    client.waits.forPageLoad(timeout=u'20000')
+    client.open(url=u'/add/Folder')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(timeout=u'8000', id=u'name-subject:A')
+    client.click(id=u'name-subject:A')
+    client.type(text=u'folder1', id=u'name-subject:A')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(link=u'add add Folder filed_under Folder object', timeout=u'8000')
+    client.click(link=u'add add Folder filed_under Folder object')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(timeout=u'8000', id=u'name-subject:A')
+    client.click(id=u'name-subject:A')
+    client.type(text=u'subfolder1', id=u'name-subject:A')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(link=u'more actions', timeout=u'8000')
+    client.click(link=u'more actions')
+    client.click(link=u'copy')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.type(text=u'folder2', id=u'name-subject:A')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(link=u'modify', timeout=u'8000')
+    client.click(link=u'modify')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(timeout=u'8000', id=u'footer')
+    client.click(link=u'x')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(link=u'add add Folder filed_under Folder object', timeout=u'8000')
+    client.click(link=u'add add Folder filed_under Folder object')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.type(text=u'subfolder2', id=u'name-subject:A')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(link=u'subfolder2', timeout=u'8000')
+    client.click(link=u'subfolder2')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(link=u'modify', timeout=u'8000')
+    client.click(link=u'modify')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(timeout=u'8000', id=u'footer')
+    client.click(link=u'x')
+    client.select(xpath=u'//select', index=u'1')
+    #client.execJQuery(jquery=u'("select").trigger(\'change\')') # BUGGY freeze UI..
+    client.execJS(js=u'$("select").trigger(\'change\')')
+    client.waits.sleep(milliseconds=u'2000')
+    client.select(jquery=u'(\'select:contains("Search")\')[0]', option=u'Search for folder')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.click(link=u'folder1')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.waits.forElement(timeout=u'8000', value=u'button_ok')
+    client.click(value=u'button_ok')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertText(xpath=u'//h1', validator=u'subfolder2')
+    client.waits.forElement(link=u'folder_plural', timeout=u'8000')
+    client.click(link=u'folder_plural')
+    client.waits.forPageLoad(timeout=u'20000')
+    client.asserts.assertText(jquery=u"('#contentmain div a')[0]", validator=u'folder1')
+    client.asserts.assertText(jquery=u"('#contentmain div a')[1]", validator=u'folder2')
+    client.asserts.assertText(jquery=u"('#contentmain div a')[2]", validator=u'subfolder1')
+    client.asserts.assertText(jquery=u"('#contentmain div a')[3]", validator=u'subfolder2')
+    client.click(link=u'subfolder2')
+    client.click(link=u'modify')
+    client.click(link=u'folder1')
--- a/uilib.py	Mon May 16 16:24:00 2011 +0200
+++ b/uilib.py	Mon May 16 16:25:33 2011 +0200
@@ -62,9 +62,9 @@
         return value
     if attrtype == 'Date':
         return ustrftime(value, req.property_value('ui.date-format'))
-    if attrtype == 'Time':
+    if attrtype in ('Time', 'TZTime'):
         return ustrftime(value, req.property_value('ui.time-format'))
-    if attrtype == 'Datetime':
+    if attrtype in ('Datetime', 'TZDatetime'):
         if displaytime:
             return ustrftime(value, req.property_value('ui.datetime-format'))
         return ustrftime(value, req.property_value('ui.date-format'))
@@ -72,8 +72,9 @@
         if value:
             return req._('yes')
         return req._('no')
-    if attrtype == 'Float':
+    if attrtype in ('Float', 'Decimal'):
         value = req.property_value('ui.float-format') % value
+    # XXX Interval
     return unicode(value)
 
 
--- a/utils.py	Mon May 16 16:24:00 2011 +0200
+++ b/utils.py	Mon May 16 16:25:33 2011 +0200
@@ -364,17 +364,43 @@
         self.doctype = u''
         # xmldecl and html opening tag
         self.xmldecl = u'<?xml version="1.0" encoding="%s"?>\n' % req.encoding
-        self.htmltag = u'<html xmlns="http://www.w3.org/1999/xhtml" ' \
-                       'xmlns:cubicweb="http://www.logilab.org/2008/cubicweb" ' \
-                       'xml:lang="%s" lang="%s">' % (req.lang, req.lang)
+        self._namespaces = [('xmlns', 'http://www.w3.org/1999/xhtml'),
+                            ('xmlns:cubicweb','http://www.logilab.org/2008/cubicweb')]
+        self._htmlattrs = [('xml:lang', req.lang),
+                           ('lang', req.lang)]
         # keep main_stream's reference on req for easier text/html demoting
         req.main_stream = self
 
+    def add_namespace(self, prefix, uri):
+        self._namespaces.append( (prefix, uri) )
+
+    def set_namespaces(self, namespaces):
+        self._namespaces = namespaces
+
+    def add_htmlattr(self, attrname, attrvalue):
+        self._htmlattrs.append( (attrname, attrvalue) )
+
+    def set_htmlattrs(self, attrs):
+        self._htmlattrs = attrs
+
+    def set_doctype(self, doctype, reset_xmldecl=True):
+        self.doctype = doctype
+        if reset_xmldecl:
+            self.xmldecl = u''
+
     def write(self, data):
         """StringIO interface: this method will be assigned to self.w
         """
         self.body.write(data)
 
+    @property
+    def htmltag(self):
+        attrs = ' '.join('%s="%s"' % (attr, xml_escape(value))
+                         for attr, value in (self._namespaces + self._htmlattrs))
+        if attrs:
+            return '<html %s>' % attrs
+        return '<html>'
+
     def getvalue(self):
         """writes HTML headers, closes </head> tag and writes HTML body"""
         return u'%s\n%s\n%s\n%s\n%s\n</html>' % (self.xmldecl, self.doctype,
@@ -382,7 +408,6 @@
                                                  self.head.getvalue(),
                                                  self.body.getvalue())
 
-
 try:
     # may not be there if cubicweb-web not installed
     if sys.version_info < (2, 6):
--- a/view.py	Mon May 16 16:24:00 2011 +0200
+++ b/view.py	Mon May 16 16:25:33 2011 +0200
@@ -447,11 +447,14 @@
         rqlstdescr = self.cw_rset.syntax_tree().get_description(mainindex,
                                                                 translate)[0]
         labels = []
-        for colindex, label in enumerate(rqlstdescr):
-            # compute column header
-            if label == 'Any': # find a better label
-                label = ','.join(translate(et)
-                                 for et in self.cw_rset.column_types(colindex))
+        for colidx, label in enumerate(rqlstdescr):
+            try:
+                label = getattr(self, 'label_column_%s' % colidx)()
+            except AttributeError:
+                # compute column header
+                if label == 'Any': # find a better label
+                    label = ','.join(translate(et)
+                                     for et in self.cw_rset.column_types(colidx))
             labels.append(label)
         return labels
 
--- a/web/_exceptions.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/_exceptions.py	Mon May 16 16:25:33 2011 +0200
@@ -53,6 +53,9 @@
         self.status = int(status)
         self.content = content
 
+    def __repr__(self):
+        return '%s(%r, %r)' % (self.__class__.__name__, self.status, self.content)
+
 class InvalidSession(CubicWebException):
     """raised when a session id is found but associated session is not found or
     invalid
--- a/web/data/cubicweb.ajax.js	Mon May 16 16:24:00 2011 +0200
+++ b/web/data/cubicweb.ajax.js	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-/* copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+/* copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
  * contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
  *
  * This file is part of CubicWeb.
@@ -605,7 +605,7 @@
     var ajaxArgs = ['render', formparams, registry, compid];
     ajaxArgs = ajaxArgs.concat(cw.utils.sliceList(arguments, 4));
     var params = ajaxFuncArgs.apply(null, ajaxArgs);
-    $('#'+domid).loadxhtml('json', params, null, 'swap');
+    return $('#'+domid).loadxhtml('json', params, null, 'swap');
 }
 
 /* ajax tabs ******************************************************************/
--- a/web/data/cubicweb.css	Mon May 16 16:24:00 2011 +0200
+++ b/web/data/cubicweb.css	Mon May 16 16:25:33 2011 +0200
@@ -993,23 +993,49 @@
   background-image: none;
 }
 
-/* ui.tabs.css */
-ul.ui-tabs-nav,
-div.ui-tabs-panel {
-  font-family: %(defaultFontFamily)s;
-  font-size: %(defaultSize)s;
+/* jquery-ui tabs */
+
+div.ui-tabs.ui-widget-content {
+  background:none;
+  border:none;
+  color:inherit;
+}
+
+div.ui-tabs ul.ui-tabs-nav {
+  padding-left: 0.5em;
+}
+
+div.ui-tabs ul.ui-tabs-nav a {
+  color:#27537A;
+  padding: 0.3em 0.6em;
+}
+
+div.ui-tabs ul.ui-tabs-nav li.ui-tabs-selected a {
+  color:black;
 }
 
-div.ui-tabs-panel {
-  border-top:1px solid #b6b6b6;
+div.ui-tabs ul.ui-tabs-nav li.ui-state-hover {
+  background:none;
+}
+
+div.ui-tabs .ui-widget-header {
+  background:none;
+  border:none;
 }
 
-ul.ui-tabs-nav a {
-  color: #3d3d3d;
+div.ui-tabs .ui-widget-header li {
+  border-color:#333333;
 }
 
-ul.ui-tabs-nav a:hover {
-  color: #000;
+div.ui-tabs .ui-tabs-panel {
+  border-top:1px solid #97A5B0;
+  padding-left:0.5em;
+  color:inherit;
+}
+
+div.ui-tabs .ui-tabs-nav, div.ui-tabs .ui-tabs-panel {
+  font-family: %(defaultFontFamily)s;
+  font-size: %(defaultSize)s;
 }
 
 img.ui-datepicker-trigger {
--- a/web/data/cubicweb.lazy.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-
--- a/web/data/cubicweb.old.css	Mon May 16 16:24:00 2011 +0200
+++ b/web/data/cubicweb.old.css	Mon May 16 16:25:33 2011 +0200
@@ -976,3 +976,42 @@
   /* remove background image (orange bullet) for autocomplete suggestions */
   background-image: none;
 }
+
+div.ui-tabs.ui-widget-content {
+  background:none;
+  border:none;
+  color:inherit;
+}
+
+div.ui-tabs ul.ui-tabs-nav {
+  padding-left: 0.5em;
+}
+
+div.ui-tabs ul.ui-tabs-nav a {
+  color:#27537A;
+  padding: 0.3em 0.6em;
+  outline:0;
+}
+
+div.ui-tabs ul.ui-tabs-nav li.ui-tabs-selected a {
+  color:black;
+}
+
+div.ui-tabs ul.ui-tabs-nav li.ui-state-hover, div.ui-tabs ul.ui-tabs-nav li.ui-state-focus {
+  background:white;
+}
+
+div.ui-tabs .ui-widget-header {
+  background:none;
+  border:none;
+}
+
+div.ui-tabs .ui-widget-header li {
+  border-color:#333333;
+}
+
+div.ui-tabs .ui-tabs-panel {
+  border-top:1px solid #97A5B0;
+  padding-left:0.5em;
+  color:inherit;
+}
--- a/web/data/cubicweb.reledit.js	Mon May 16 16:24:00 2011 +0200
+++ b/web/data/cubicweb.reledit.js	Mon May 16 16:25:33 2011 +0200
@@ -18,6 +18,7 @@
     cleanupAfterCancel: function (divid) {
         jQuery('#appMsg').hide();
         jQuery('div.errorMessage').remove();
+        // plus re-set inline style ?
         jQuery('#' + divid).show();
         jQuery('#' + divid + '-value').show();
         jQuery('#' + divid + '-form').hide();
@@ -63,9 +64,9 @@
      * @param reload: boolean to reload page if true (when changing URL dependant data)
      * @param default_value : value if the field is empty
      */
-    loadInlineEditionForm: function(formid, eid, rtype, role, divid, reload, vid) {
+    loadInlineEditionForm: function(formid, eid, rtype, role, divid, reload, vid, action) {
         var args = {fname: 'reledit_form', rtype: rtype, role: role,
-                    pageid: pageid,
+                    pageid: pageid, action: action,
                     eid: eid, divid: divid, formid: formid,
                     reload: reload, vid: vid};
         var d = jQuery('#'+divid+'-reledit').loadxhtml(JSON_BASE_URL, args, 'post');
--- a/web/data/cubicweb.tabs.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-
--- a/web/data/jquery.corner.js	Mon May 16 16:24:00 2011 +0200
+++ b/web/data/jquery.corner.js	Mon May 16 16:25:33 2011 +0200
@@ -1,178 +1,247 @@
-/*
- * 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) && ($.browser.version < 8.0))
-                        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);
+/*!
+ * jQuery corner plugin: simple corner rounding
+ * Examples and documentation at: http://jquery.malsup.com/corner/
+ * version 2.11 (15-JUN-2010)
+ * Requires jQuery v1.3.2 or later
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ * Authors: Dave Methvin and Mike Alsup
+ */
+
+/**
+ *  corner() takes a single string argument:  $('#myDiv').corner("effect corners width")
+ *
+ *  effect:  name of the effect to apply, such as round, bevel, notch, bite, etc (default is round).
+ *  corners: one or more of: top, bottom, tr, tl, br, or bl.  (default is all corners)
+ *  width:   width of the effect; in the case of rounded corners this is the radius.
+ *           specify this value using the px suffix such as 10px (yes, it must be pixels).
+ */
+;(function($) {
+
+var style = document.createElement('div').style,
+    moz = style['MozBorderRadius'] !== undefined,
+    webkit = style['WebkitBorderRadius'] !== undefined,
+    radius = style['borderRadius'] !== undefined || style['BorderRadius'] !== undefined,
+    mode = document.documentMode || 0,
+    noBottomFold = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8),
+
+    expr = $.browser.msie && (function() {
+        var div = document.createElement('div');
+        try { div.style.setExpression('width','0+0'); div.style.removeExpression('width'); }
+        catch(e) { return false; }
+        return true;
+    })();
+
+$.support = $.support || {};
+$.support.borderRadius = moz || webkit || radius; // so you can do:  if (!$.support.borderRadius) $('#myDiv').corner();
+
+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) {
+    while(node) {
+        var v = $.css(node,'backgroundColor'), rgb;
+        if (v && v != 'transparent' && v != 'rgba(0, 0, 0, 0)') {
+            if (v.indexOf('rgb') >= 0) {
+                rgb = v.match(/\d+/g);
+                return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
+            }
+            return v;
+        }
+        if (node.nodeName.toLowerCase() == 'html')
+            break;
+        node = node.parentNode; // keep walking if transparent
+    }
+    return '#ffffff';
+};
+
+function getWidth(fx, i, width) {
+    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 'dogfold':
+    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 'bevelfold':
+    case 'bevel':  return i+1;
+    }
+};
+
+$.fn.corner = function(options) {
+    // in 1.3+ we can fix mistakes with the ready state
+    if (this.length == 0) {
+        if (!$.isReady && this.selector) {
+            var s = this.selector, c = this.context;
+            $(function() {
+                $(s,c).corner(options);
+            });
+        }
+        return this;
+    }
+
+    return this.each(function(index){
+        var $this = $(this),
+            // meta values override options
+            o = [$this.attr($.fn.corner.defaults.metaAttr) || '', options || ''].join(' ').toLowerCase(),
+            keep = /keep/.test(o),                       // keep borders?
+            cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]),  // corner color
+            sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]),  // strip color
+            width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10, // corner width
+            re = /round|bevelfold|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dogfold|dog/,
+            fx = ((o.match(re)||['round'])[0]),
+            fold = /dogfold|bevelfold/.test(o),
+            edges = { T:0, B:1 },
+            opts = {
+                TL:  /top|tl|left/.test(o),       TR:  /top|tr|right/.test(o),
+                BL:  /bottom|bl|left/.test(o),    BR:  /bottom|br|right/.test(o)
+            },
+            // vars used in func later
+            strip, pad, cssHeight, j, bot, d, ds, bw, i, w, e, c, common, $horz;
+
+        if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
+            opts = { TL:1, TR:1, BL:1, BR:1 };
+
+        // support native rounding
+        if ($.fn.corner.defaults.useNative && fx == 'round' && (radius || moz || webkit) && !cc && !sc) {
+            if (opts.TL)
+                $this.css(radius ? 'border-top-left-radius' : moz ? '-moz-border-radius-topleft' : '-webkit-border-top-left-radius', width + 'px');
+            if (opts.TR)
+                $this.css(radius ? 'border-top-right-radius' : moz ? '-moz-border-radius-topright' : '-webkit-border-top-right-radius', width + 'px');
+            if (opts.BL)
+                $this.css(radius ? 'border-bottom-left-radius' : moz ? '-moz-border-radius-bottomleft' : '-webkit-border-bottom-left-radius', width + 'px');
+            if (opts.BR)
+                $this.css(radius ? 'border-bottom-right-radius' : moz ? '-moz-border-radius-bottomright' : '-webkit-border-bottom-right-radius', width + 'px');
+            return;
+        }
+
+        strip = document.createElement('div');
+        $(strip).css({
+            overflow: 'hidden',
+            height: '1px',
+            minHeight: '1px',
+            fontSize: '1px',
+            backgroundColor: sc || 'transparent',
+            borderStyle: 'solid'
+        });
+
+        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 (typeof this.style.zoom != undefined) this.style.zoom = 1; // force 'hasLayout' in IE
+        if (!keep) this.style.border = 'none';
+        strip.style.borderColor = cc || gpc(this.parentNode);
+        cssHeight = $(this).outerHeight();
+
+        for (j in edges) {
+            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');
+                d = document.createElement('div');
+                $(d).addClass('jquery-corner');
+                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 (expr)
+                        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
+                    if (expr) {
+                        bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
+                        ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"');
+                    }
+                    else
+                        ds.width = '100%';
+                }
+                else {
+                    ds.position = 'relative';
+                    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 (i=0; i < width; i++) {
+                    w = Math.max(0,getWidth(fx,i, width));
+                    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);
+                }
+
+                if (fold && $.support.boxModel) {
+                    if (bot && noBottomFold) continue;
+                    for (c in opts) {
+                        if (!opts[c]) continue;
+                        if (bot && (c == 'TL' || c == 'TR')) continue;
+                        if (!bot && (c == 'BL' || c == 'BR')) continue;
+
+                        common = { position: 'absolute', border: 'none', margin: 0, padding: 0, overflow: 'hidden', backgroundColor: strip.style.borderColor };
+                        $horz = $('<div/>').css(common).css({ width: width + 'px', height: '1px' });
+                        switch(c) {
+                        case 'TL': $horz.css({ bottom: 0, left: 0 }); break;
+                        case 'TR': $horz.css({ bottom: 0, right: 0 }); break;
+                        case 'BL': $horz.css({ top: 0, left: 0 }); break;
+                        case 'BR': $horz.css({ top: 0, right: 0 }); break;
+                        }
+                        d.appendChild($horz[0]);
+
+                        var $vert = $('<div/>').css(common).css({ top: 0, bottom: 0, width: '1px', height: width + 'px' });
+                        switch(c) {
+                        case 'TL': $vert.css({ left: width }); break;
+                        case 'TR': $vert.css({ right: width }); break;
+                        case 'BL': $vert.css({ left: width }); break;
+                        case 'BR': $vert.css({ right: width }); break;
+                        }
+                        d.appendChild($vert[0]);
+                    }
+                }
+            }
+        }
+    });
+};
+
+$.fn.uncorner = function() {
+    if (radius || moz || webkit)
+        this.css(radius ? 'border-radius' : moz ? '-moz-border-radius' : '-webkit-border-radius', 0);
+    $('div.jquery-corner', this).remove();
+    return this;
+};
+
+// expose options
+$.fn.corner.defaults = {
+    useNative: true, // true if plugin should attempt to use native browser support for border radius rounding
+    metaAttr:  'data-corner' // name of meta attribute to use for options
+};
+
+})(jQuery);
--- a/web/data/jquery.js	Mon May 16 16:24:00 2011 +0200
+++ b/web/data/jquery.js	Mon May 16 16:25:33 2011 +0200
@@ -13,6228 +13,142 @@
  *
  * Date: Sat Feb 13 22:33:48 2010 -0500
  */
-(function( window, undefined ) {
-
-// Define a local copy of jQuery
-var jQuery = function( selector, context ) {
-		// The jQuery object is actually just the init constructor 'enhanced'
-		return new jQuery.fn.init( selector, context );
-	},
-
-	// Map over jQuery in case of overwrite
-	_jQuery = window.jQuery,
-
-	// Map over the $ in case of overwrite
-	_$ = window.$,
-
-	// Use the correct document accordingly with window argument (sandbox)
-	document = window.document,
-
-	// A central reference to the root jQuery(document)
-	rootjQuery,
-
-	// A simple way to check for HTML strings or ID strings
-	// (both of which we optimize for)
-	quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
-
-	// Is it a simple selector
-	isSimple = /^.[^:#\[\.,]*$/,
-
-	// Check if a string has a non-whitespace character in it
-	rnotwhite = /\S/,
-
-	// Used for trimming whitespace
-	rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,
-
-	// Match a standalone tag
-	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
-
-	// Keep a UserAgent string for use with jQuery.browser
-	userAgent = navigator.userAgent,
-
-	// For matching the engine and version of the browser
-	browserMatch,
-	
-	// Has the ready events already been bound?
-	readyBound = false,
-	
-	// The functions to execute on DOM ready
-	readyList = [],
-
-	// The ready event handler
-	DOMContentLoaded,
-
-	// Save a reference to some core methods
-	toString = Object.prototype.toString,
-	hasOwnProperty = Object.prototype.hasOwnProperty,
-	push = Array.prototype.push,
-	slice = Array.prototype.slice,
-	indexOf = Array.prototype.indexOf;
-
-jQuery.fn = jQuery.prototype = {
-	init: function( selector, context ) {
-		var match, elem, ret, doc;
-
-		// Handle $(""), $(null), or $(undefined)
-		if ( !selector ) {
-			return this;
-		}
-
-		// Handle $(DOMElement)
-		if ( selector.nodeType ) {
-			this.context = this[0] = selector;
-			this.length = 1;
-			return this;
-		}
-		
-		// The body element only exists once, optimize finding it
-		if ( selector === "body" && !context ) {
-			this.context = document;
-			this[0] = document.body;
-			this.selector = "body";
-			this.length = 1;
-			return this;
-		}
-
-		// Handle HTML strings
-		if ( typeof selector === "string" ) {
-			// Are we dealing with HTML string or an ID?
-			match = quickExpr.exec( selector );
-
-			// Verify a match, and that no context was specified for #id
-			if ( match && (match[1] || !context) ) {
-
-				// HANDLE: $(html) -> $(array)
-				if ( match[1] ) {
-					doc = (context ? context.ownerDocument || context : document);
-
-					// If a single string is passed in and it's a single tag
-					// just do a createElement and skip the rest
-					ret = rsingleTag.exec( selector );
-
-					if ( ret ) {
-						if ( jQuery.isPlainObject( context ) ) {
-							selector = [ document.createElement( ret[1] ) ];
-							jQuery.fn.attr.call( selector, context, true );
-
-						} else {
-							selector = [ doc.createElement( ret[1] ) ];
-						}
-
-					} else {
-						ret = buildFragment( [ match[1] ], [ doc ] );
-						selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
-					}
-					
-					return jQuery.merge( this, selector );
-					
-				// HANDLE: $("#id")
-				} else {
-					elem = document.getElementById( match[2] );
-
-					if ( elem ) {
-						// Handle the case where IE and Opera return items
-						// by name instead of ID
-						if ( elem.id !== match[2] ) {
-							return rootjQuery.find( selector );
-						}
-
-						// Otherwise, we inject the element directly into the jQuery object
-						this.length = 1;
-						this[0] = elem;
-					}
-
-					this.context = document;
-					this.selector = selector;
-					return this;
-				}
-
-			// HANDLE: $("TAG")
-			} else if ( !context && /^\w+$/.test( selector ) ) {
-				this.selector = selector;
-				this.context = document;
-				selector = document.getElementsByTagName( selector );
-				return jQuery.merge( this, selector );
-
-			// HANDLE: $(expr, $(...))
-			} else if ( !context || context.jquery ) {
-				return (context || rootjQuery).find( selector );
-
-			// HANDLE: $(expr, context)
-			// (which is just equivalent to: $(context).find(expr)
-			} else {
-				return jQuery( context ).find( selector );
-			}
-
-		// HANDLE: $(function)
-		// Shortcut for document ready
-		} else if ( jQuery.isFunction( selector ) ) {
-			return rootjQuery.ready( selector );
-		}
-
-		if (selector.selector !== undefined) {
-			this.selector = selector.selector;
-			this.context = selector.context;
-		}
-
-		return jQuery.makeArray( selector, this );
-	},
-
-	// Start with an empty selector
-	selector: "",
-
-	// The current version of jQuery being used
-	jquery: "1.4.2",
-
-	// The default length of a jQuery object is 0
-	length: 0,
-
-	// The number of elements contained in the matched element set
-	size: function() {
-		return this.length;
-	},
-
-	toArray: function() {
-		return slice.call( this, 0 );
-	},
-
-	// Get the Nth element in the matched element set OR
-	// Get the whole matched element set as a clean array
-	get: function( num ) {
-		return num == null ?
-
-			// Return a 'clean' array
-			this.toArray() :
-
-			// Return just the object
-			( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
-	},
-
-	// Take an array of elements and push it onto the stack
-	// (returning the new matched element set)
-	pushStack: function( elems, name, selector ) {
-		// Build a new jQuery matched element set
-		var ret = jQuery();
-
-		if ( jQuery.isArray( elems ) ) {
-			push.apply( ret, elems );
-		
-		} else {
-			jQuery.merge( ret, elems );
-		}
-
-		// Add the old object onto the stack (as a reference)
-		ret.prevObject = this;
-
-		ret.context = this.context;
-
-		if ( name === "find" ) {
-			ret.selector = this.selector + (this.selector ? " " : "") + selector;
-		} else if ( name ) {
-			ret.selector = this.selector + "." + name + "(" + selector + ")";
-		}
-
-		// Return the newly-formed element set
-		return ret;
-	},
-
-	// Execute a callback for every element in the matched set.
-	// (You can seed the arguments with an array of args, but this is
-	// only used internally.)
-	each: function( callback, args ) {
-		return jQuery.each( this, callback, args );
-	},
-	
-	ready: function( fn ) {
-		// Attach the listeners
-		jQuery.bindReady();
-
-		// If the DOM is already ready
-		if ( jQuery.isReady ) {
-			// Execute the function immediately
-			fn.call( document, jQuery );
-
-		// Otherwise, remember the function for later
-		} else if ( readyList ) {
-			// Add the function to the wait list
-			readyList.push( fn );
-		}
-
-		return this;
-	},
-	
-	eq: function( i ) {
-		return i === -1 ?
-			this.slice( i ) :
-			this.slice( i, +i + 1 );
-	},
-
-	first: function() {
-		return this.eq( 0 );
-	},
-
-	last: function() {
-		return this.eq( -1 );
-	},
-
-	slice: function() {
-		return this.pushStack( slice.apply( this, arguments ),
-			"slice", slice.call(arguments).join(",") );
-	},
-
-	map: function( callback ) {
-		return this.pushStack( jQuery.map(this, function( elem, i ) {
-			return callback.call( elem, i, elem );
-		}));
-	},
-	
-	end: function() {
-		return this.prevObject || jQuery(null);
-	},
-
-	// For internal use only.
-	// Behaves like an Array's method, not like a jQuery method.
-	push: push,
-	sort: [].sort,
-	splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
-	// copy reference to target object
-	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
-
-	// Handle a deep copy situation
-	if ( typeof target === "boolean" ) {
-		deep = target;
-		target = arguments[1] || {};
-		// skip the boolean and the target
-		i = 2;
-	}
-
-	// Handle case when target is a string or something (possible in deep copy)
-	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
-		target = {};
-	}
-
-	// extend jQuery itself if only one argument is passed
-	if ( length === i ) {
-		target = this;
-		--i;
-	}
-
-	for ( ; i < length; i++ ) {
-		// Only deal with non-null/undefined values
-		if ( (options = arguments[ i ]) != null ) {
-			// Extend the base object
-			for ( name in options ) {
-				src = target[ name ];
-				copy = options[ name ];
-
-				// Prevent never-ending loop
-				if ( target === copy ) {
-					continue;
-				}
-
-				// Recurse if we're merging object literal values or arrays
-				if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {
-					var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src
-						: jQuery.isArray(copy) ? [] : {};
-
-					// Never move original objects, clone them
-					target[ name ] = jQuery.extend( deep, clone, copy );
-
-				// Don't bring in undefined values
-				} else if ( copy !== undefined ) {
-					target[ name ] = copy;
-				}
-			}
-		}
-	}
-
-	// Return the modified object
-	return target;
-};
-
-jQuery.extend({
-	noConflict: function( deep ) {
-		window.$ = _$;
-
-		if ( deep ) {
-			window.jQuery = _jQuery;
-		}
-
-		return jQuery;
-	},
-	
-	// Is the DOM ready to be used? Set to true once it occurs.
-	isReady: false,
-	
-	// Handle when the DOM is ready
-	ready: function() {
-		// Make sure that the DOM is not already loaded
-		if ( !jQuery.isReady ) {
-			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-			if ( !document.body ) {
-				return setTimeout( jQuery.ready, 13 );
-			}
-
-			// Remember that the DOM is ready
-			jQuery.isReady = true;
-
-			// If there are functions bound, to execute
-			if ( readyList ) {
-				// Execute all of them
-				var fn, i = 0;
-				while ( (fn = readyList[ i++ ]) ) {
-					fn.call( document, jQuery );
-				}
-
-				// Reset the list of functions
-				readyList = null;
-			}
-
-			// Trigger any bound ready events
-			if ( jQuery.fn.triggerHandler ) {
-				jQuery( document ).triggerHandler( "ready" );
-			}
-		}
-	},
-	
-	bindReady: function() {
-		if ( readyBound ) {
-			return;
-		}
-
-		readyBound = true;
-
-		// Catch cases where $(document).ready() is called after the
-		// browser event has already occurred.
-		if ( document.readyState === "complete" ) {
-			return jQuery.ready();
-		}
-
-		// Mozilla, Opera and webkit nightlies currently support this event
-		if ( document.addEventListener ) {
-			// Use the handy event callback
-			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-			
-			// A fallback to window.onload, that will always work
-			window.addEventListener( "load", jQuery.ready, false );
-
-		// If IE event model is used
-		} else if ( document.attachEvent ) {
-			// ensure firing before onload,
-			// maybe late but safe also for iframes
-			document.attachEvent("onreadystatechange", DOMContentLoaded);
-			
-			// A fallback to window.onload, that will always work
-			window.attachEvent( "onload", jQuery.ready );
-
-			// If IE and not a frame
-			// continually check to see if the document is ready
-			var toplevel = false;
-
-			try {
-				toplevel = window.frameElement == null;
-			} catch(e) {}
-
-			if ( document.documentElement.doScroll && toplevel ) {
-				doScrollCheck();
-			}
-		}
-	},
-
-	// See test/unit/core.js for details concerning isFunction.
-	// Since version 1.3, DOM methods and functions like alert
-	// aren't supported. They return false on IE (#2968).
-	isFunction: function( obj ) {
-		return toString.call(obj) === "[object Function]";
-	},
-
-	isArray: function( obj ) {
-		return toString.call(obj) === "[object Array]";
-	},
-
-	isPlainObject: function( obj ) {
-		// Must be an Object.
-		// Because of IE, we also have to check the presence of the constructor property.
-		// Make sure that DOM nodes and window objects don't pass through, as well
-		if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
-			return false;
-		}
-		
-		// Not own constructor property must be Object
-		if ( obj.constructor
-			&& !hasOwnProperty.call(obj, "constructor")
-			&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
-			return false;
-		}
-		
-		// Own properties are enumerated firstly, so to speed up,
-		// if last one is own, then all properties are own.
-	
-		var key;
-		for ( key in obj ) {}
-		
-		return key === undefined || hasOwnProperty.call( obj, key );
-	},
-
-	isEmptyObject: function( obj ) {
-		for ( var name in obj ) {
-			return false;
-		}
-		return true;
-	},
-	
-	error: function( msg ) {
-		throw msg;
-	},
-	
-	parseJSON: function( data ) {
-		if ( typeof data !== "string" || !data ) {
-			return null;
-		}
-
-		// Make sure leading/trailing whitespace is removed (IE can't handle it)
-		data = jQuery.trim( data );
-		
-		// Make sure the incoming data is actual JSON
-		// Logic borrowed from http://json.org/json2.js
-		if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
-			.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
-			.replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) {
-
-			// Try to use the native JSON parser first
-			return window.JSON && window.JSON.parse ?
-				window.JSON.parse( data ) :
-				(new Function("return " + data))();
-
-		} else {
-			jQuery.error( "Invalid JSON: " + data );
-		}
-	},
-
-	noop: function() {},
-
-	// Evalulates a script in a global context
-	globalEval: function( data ) {
-		if ( data && rnotwhite.test(data) ) {
-			// Inspired by code by Andrea Giammarchi
-			// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
-			var head = document.getElementsByTagName("head")[0] || document.documentElement,
-				script = document.createElement("script");
-
-			script.type = "text/javascript";
-
-			if ( jQuery.support.scriptEval ) {
-				script.appendChild( document.createTextNode( data ) );
-			} else {
-				script.text = data;
-			}
-
-			// Use insertBefore instead of appendChild to circumvent an IE6 bug.
-			// This arises when a base node is used (#2709).
-			head.insertBefore( script, head.firstChild );
-			head.removeChild( script );
-		}
-	},
-
-	nodeName: function( elem, name ) {
-		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
-	},
-
-	// args is for internal usage only
-	each: function( object, callback, args ) {
-		var name, i = 0,
-			length = object.length,
-			isObj = length === undefined || jQuery.isFunction(object);
-
-		if ( args ) {
-			if ( isObj ) {
-				for ( name in object ) {
-					if ( callback.apply( object[ name ], args ) === false ) {
-						break;
-					}
-				}
-			} else {
-				for ( ; i < length; ) {
-					if ( callback.apply( object[ i++ ], args ) === false ) {
-						break;
-					}
-				}
-			}
-
-		// A special, fast, case for the most common use of each
-		} else {
-			if ( isObj ) {
-				for ( name in object ) {
-					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
-						break;
-					}
-				}
-			} else {
-				for ( var value = object[0];
-					i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
-			}
-		}
-
-		return object;
-	},
-
-	trim: function( text ) {
-		return (text || "").replace( rtrim, "" );
-	},
-
-	// results is for internal usage only
-	makeArray: function( array, results ) {
-		var ret = results || [];
-
-		if ( array != null ) {
-			// The window, strings (and functions) also have 'length'
-			// The extra typeof function check is to prevent crashes
-			// in Safari 2 (See: #3039)
-			if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {
-				push.call( ret, array );
-			} else {
-				jQuery.merge( ret, array );
-			}
-		}
-
-		return ret;
-	},
-
-	inArray: function( elem, array ) {
-		if ( array.indexOf ) {
-			return array.indexOf( elem );
-		}
-
-		for ( var i = 0, length = array.length; i < length; i++ ) {
-			if ( array[ i ] === elem ) {
-				return i;
-			}
-		}
-
-		return -1;
-	},
-
-	merge: function( first, second ) {
-		var i = first.length, j = 0;
-
-		if ( typeof second.length === "number" ) {
-			for ( var l = second.length; j < l; j++ ) {
-				first[ i++ ] = second[ j ];
-			}
-		
-		} else {
-			while ( second[j] !== undefined ) {
-				first[ i++ ] = second[ j++ ];
-			}
-		}
-
-		first.length = i;
-
-		return first;
-	},
-
-	grep: function( elems, callback, inv ) {
-		var ret = [];
-
-		// Go through the array, only saving the items
-		// that pass the validator function
-		for ( var i = 0, length = elems.length; i < length; i++ ) {
-			if ( !inv !== !callback( elems[ i ], i ) ) {
-				ret.push( elems[ i ] );
-			}
-		}
-
-		return ret;
-	},
-
-	// arg is for internal usage only
-	map: function( elems, callback, arg ) {
-		var ret = [], value;
-
-		// Go through the array, translating each of the items to their
-		// new value (or values).
-		for ( var i = 0, length = elems.length; i < length; i++ ) {
-			value = callback( elems[ i ], i, arg );
-
-			if ( value != null ) {
-				ret[ ret.length ] = value;
-			}
-		}
-
-		return ret.concat.apply( [], ret );
-	},
-
-	// A global GUID counter for objects
-	guid: 1,
-
-	proxy: function( fn, proxy, thisObject ) {
-		if ( arguments.length === 2 ) {
-			if ( typeof proxy === "string" ) {
-				thisObject = fn;
-				fn = thisObject[ proxy ];
-				proxy = undefined;
-
-			} else if ( proxy && !jQuery.isFunction( proxy ) ) {
-				thisObject = proxy;
-				proxy = undefined;
-			}
-		}
-
-		if ( !proxy && fn ) {
-			proxy = function() {
-				return fn.apply( thisObject || this, arguments );
-			};
-		}
-
-		// Set the guid of unique handler to the same of original handler, so it can be removed
-		if ( fn ) {
-			proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
-		}
-
-		// So proxy can be declared as an argument
-		return proxy;
-	},
-
-	// Use of jQuery.browser is frowned upon.
-	// More details: http://docs.jquery.com/Utilities/jQuery.browser
-	uaMatch: function( ua ) {
-		ua = ua.toLowerCase();
-
-		var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
-			/(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) ||
-			/(msie) ([\w.]+)/.exec( ua ) ||
-			!/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) ||
-		  	[];
-
-		return { browser: match[1] || "", version: match[2] || "0" };
-	},
-
-	browser: {}
-});
-
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
-	jQuery.browser[ browserMatch.browser ] = true;
-	jQuery.browser.version = browserMatch.version;
-}
-
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
-	jQuery.browser.safari = true;
-}
-
-if ( indexOf ) {
-	jQuery.inArray = function( elem, array ) {
-		return indexOf.call( array, elem );
-	};
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
-	DOMContentLoaded = function() {
-		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-		jQuery.ready();
-	};
-
-} else if ( document.attachEvent ) {
-	DOMContentLoaded = function() {
-		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-		if ( document.readyState === "complete" ) {
-			document.detachEvent( "onreadystatechange", DOMContentLoaded );
-			jQuery.ready();
-		}
-	};
-}
-
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
-	if ( jQuery.isReady ) {
-		return;
-	}
-
-	try {
-		// If IE is used, use the trick by Diego Perini
-		// http://javascript.nwbox.com/IEContentLoaded/
-		document.documentElement.doScroll("left");
-	} catch( error ) {
-		setTimeout( doScrollCheck, 1 );
-		return;
-	}
-
-	// and execute any waiting functions
-	jQuery.ready();
-}
-
-function evalScript( i, elem ) {
-	if ( elem.src ) {
-		jQuery.ajax({
-			url: elem.src,
-			async: false,
-			dataType: "script"
-		});
-	} else {
-		jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
-	}
-
-	if ( elem.parentNode ) {
-		elem.parentNode.removeChild( elem );
-	}
-}
-
-// Mutifunctional method to get and set values to a collection
-// The value/s can be optionally by executed if its a function
-function access( elems, key, value, exec, fn, pass ) {
-	var length = elems.length;
-	
-	// Setting many attributes
-	if ( typeof key === "object" ) {
-		for ( var k in key ) {
-			access( elems, k, key[k], exec, fn, value );
-		}
-		return elems;
-	}
-	
-	// Setting one attribute
-	if ( value !== undefined ) {
-		// Optionally, function values get executed if exec is true
-		exec = !pass && exec && jQuery.isFunction(value);
-		
-		for ( var i = 0; i < length; i++ ) {
-			fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
-		}
-		
-		return elems;
-	}
-	
-	// Getting an attribute
-	return length ? fn( elems[0], key ) : undefined;
-}
-
-function now() {
-	return (new Date).getTime();
-}
-(function() {
-
-	jQuery.support = {};
-
-	var root = document.documentElement,
-		script = document.createElement("script"),
-		div = document.createElement("div"),
-		id = "script" + now();
-
-	div.style.display = "none";
-	div.innerHTML = "   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-
-	var all = div.getElementsByTagName("*"),
-		a = div.getElementsByTagName("a")[0];
-
-	// Can't get basic test support
-	if ( !all || !all.length || !a ) {
-		return;
-	}
-
-	jQuery.support = {
-		// IE strips leading whitespace when .innerHTML is used
-		leadingWhitespace: div.firstChild.nodeType === 3,
-
-		// Make sure that tbody elements aren't automatically inserted
-		// IE will insert them into empty tables
-		tbody: !div.getElementsByTagName("tbody").length,
-
-		// Make sure that link elements get serialized correctly by innerHTML
-		// This requires a wrapper element in IE
-		htmlSerialize: !!div.getElementsByTagName("link").length,
-
-		// Get the style information from getAttribute
-		// (IE uses .cssText insted)
-		style: /red/.test( a.getAttribute("style") ),
-
-		// Make sure that URLs aren't manipulated
-		// (IE normalizes it by default)
-		hrefNormalized: a.getAttribute("href") === "/a",
-
-		// Make sure that element opacity exists
-		// (IE uses filter instead)
-		// Use a regex to work around a WebKit issue. See #5145
-		opacity: /^0.55$/.test( a.style.opacity ),
-
-		// Verify style float existence
-		// (IE uses styleFloat instead of cssFloat)
-		cssFloat: !!a.style.cssFloat,
-
-		// Make sure that if no value is specified for a checkbox
-		// that it defaults to "on".
-		// (WebKit defaults to "" instead)
-		checkOn: div.getElementsByTagName("input")[0].value === "on",
-
-		// Make sure that a selected-by-default option has a working selected property.
-		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
-		optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected,
-
-		parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null,
-
-		// Will be defined later
-		deleteExpando: true,
-		checkClone: false,
-		scriptEval: false,
-		noCloneEvent: true,
-		boxModel: null
-	};
-
-	script.type = "text/javascript";
-	try {
-		script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
-	} catch(e) {}
-
-	root.insertBefore( script, root.firstChild );
-
-	// Make sure that the execution of code works by injecting a script
-	// tag with appendChild/createTextNode
-	// (IE doesn't support this, fails, and uses .text instead)
-	if ( window[ id ] ) {
-		jQuery.support.scriptEval = true;
-		delete window[ id ];
-	}
-
-	// Test to see if it's possible to delete an expando from an element
-	// Fails in Internet Explorer
-	try {
-		delete script.test;
-	
-	} catch(e) {
-		jQuery.support.deleteExpando = false;
-	}
-
-	root.removeChild( script );
-
-	if ( div.attachEvent && div.fireEvent ) {
-		div.attachEvent("onclick", function click() {
-			// Cloning a node shouldn't copy over any
-			// bound event handlers (IE does this)
-			jQuery.support.noCloneEvent = false;
-			div.detachEvent("onclick", click);
-		});
-		div.cloneNode(true).fireEvent("onclick");
-	}
-
-	div = document.createElement("div");
-	div.innerHTML = "<input type='radio' name='radiotest' checked='checked'/>";
-
-	var fragment = document.createDocumentFragment();
-	fragment.appendChild( div.firstChild );
-
-	// WebKit doesn't clone checked state correctly in fragments
-	jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
-
-	// Figure out if the W3C box model works as expected
-	// document.body must exist before we can do this
-	jQuery(function() {
-		var div = document.createElement("div");
-		div.style.width = div.style.paddingLeft = "1px";
-
-		document.body.appendChild( div );
-		jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
-		document.body.removeChild( div ).style.display = 'none';
-
-		div = null;
-	});
-
-	// Technique from Juriy Zaytsev
-	// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
-	var eventSupported = function( eventName ) { 
-		var el = document.createElement("div"); 
-		eventName = "on" + eventName; 
-
-		var isSupported = (eventName in el); 
-		if ( !isSupported ) { 
-			el.setAttribute(eventName, "return;"); 
-			isSupported = typeof el[eventName] === "function"; 
-		} 
-		el = null; 
-
-		return isSupported; 
-	};
-	
-	jQuery.support.submitBubbles = eventSupported("submit");
-	jQuery.support.changeBubbles = eventSupported("change");
-
-	// release memory in IE
-	root = script = div = all = a = null;
-})();
-
-jQuery.props = {
-	"for": "htmlFor",
-	"class": "className",
-	readonly: "readOnly",
-	maxlength: "maxLength",
-	cellspacing: "cellSpacing",
-	rowspan: "rowSpan",
-	colspan: "colSpan",
-	tabindex: "tabIndex",
-	usemap: "useMap",
-	frameborder: "frameBorder"
-};
-var expando = "jQuery" + now(), uuid = 0, windowData = {};
-
-jQuery.extend({
-	cache: {},
-	
-	expando:expando,
-
-	// The following elements throw uncatchable exceptions if you
-	// attempt to add expando properties to them.
-	noData: {
-		"embed": true,
-		"object": true,
-		"applet": true
-	},
-
-	data: function( elem, name, data ) {
-		if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
-			return;
-		}
-
-		elem = elem == window ?
-			windowData :
-			elem;
-
-		var id = elem[ expando ], cache = jQuery.cache, thisCache;
-
-		if ( !id && typeof name === "string" && data === undefined ) {
-			return null;
-		}
-
-		// Compute a unique ID for the element
-		if ( !id ) { 
-			id = ++uuid;
-		}
-
-		// Avoid generating a new cache unless none exists and we
-		// want to manipulate it.
-		if ( typeof name === "object" ) {
-			elem[ expando ] = id;
-			thisCache = cache[ id ] = jQuery.extend(true, {}, name);
-
-		} else if ( !cache[ id ] ) {
-			elem[ expando ] = id;
-			cache[ id ] = {};
-		}
-
-		thisCache = cache[ id ];
-
-		// Prevent overriding the named cache with undefined values
-		if ( data !== undefined ) {
-			thisCache[ name ] = data;
-		}
-
-		return typeof name === "string" ? thisCache[ name ] : thisCache;
-	},
-
-	removeData: function( elem, name ) {
-		if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
-			return;
-		}
-
-		elem = elem == window ?
-			windowData :
-			elem;
-
-		var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];
-
-		// If we want to remove a specific section of the element's data
-		if ( name ) {
-			if ( thisCache ) {
-				// Remove the section of cache data
-				delete thisCache[ name ];
-
-				// If we've removed all the data, remove the element's cache
-				if ( jQuery.isEmptyObject(thisCache) ) {
-					jQuery.removeData( elem );
-				}
-			}
-
-		// Otherwise, we want to remove all of the element's data
-		} else {
-			if ( jQuery.support.deleteExpando ) {
-				delete elem[ jQuery.expando ];
-
-			} else if ( elem.removeAttribute ) {
-				elem.removeAttribute( jQuery.expando );
-			}
-
-			// Completely remove the data cache
-			delete cache[ id ];
-		}
-	}
-});
-
-jQuery.fn.extend({
-	data: function( key, value ) {
-		if ( typeof key === "undefined" && this.length ) {
-			return jQuery.data( this[0] );
-
-		} else if ( typeof key === "object" ) {
-			return this.each(function() {
-				jQuery.data( this, key );
-			});
-		}
-
-		var parts = key.split(".");
-		parts[1] = parts[1] ? "." + parts[1] : "";
-
-		if ( value === undefined ) {
-			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
-			if ( data === undefined && this.length ) {
-				data = jQuery.data( this[0], key );
-			}
-			return data === undefined && parts[1] ?
-				this.data( parts[0] ) :
-				data;
-		} else {
-			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {
-				jQuery.data( this, key, value );
-			});
-		}
-	},
-
-	removeData: function( key ) {
-		return this.each(function() {
-			jQuery.removeData( this, key );
-		});
-	}
-});
-jQuery.extend({
-	queue: function( elem, type, data ) {
-		if ( !elem ) {
-			return;
-		}
-
-		type = (type || "fx") + "queue";
-		var q = jQuery.data( elem, type );
-
-		// Speed up dequeue by getting out quickly if this is just a lookup
-		if ( !data ) {
-			return q || [];
-		}
-
-		if ( !q || jQuery.isArray(data) ) {
-			q = jQuery.data( elem, type, jQuery.makeArray(data) );
-
-		} else {
-			q.push( data );
-		}
-
-		return q;
-	},
-
-	dequeue: function( elem, type ) {
-		type = type || "fx";
-
-		var queue = jQuery.queue( elem, type ), fn = queue.shift();
-
-		// If the fx queue is dequeued, always remove the progress sentinel
-		if ( fn === "inprogress" ) {
-			fn = queue.shift();
-		}
-
-		if ( fn ) {
-			// Add a progress sentinel to prevent the fx queue from being
-			// automatically dequeued
-			if ( type === "fx" ) {
-				queue.unshift("inprogress");
-			}
-
-			fn.call(elem, function() {
-				jQuery.dequeue(elem, type);
-			});
-		}
-	}
-});
-
-jQuery.fn.extend({
-	queue: function( type, data ) {
-		if ( typeof type !== "string" ) {
-			data = type;
-			type = "fx";
-		}
-
-		if ( data === undefined ) {
-			return jQuery.queue( this[0], type );
-		}
-		return this.each(function( i, elem ) {
-			var queue = jQuery.queue( this, type, data );
-
-			if ( type === "fx" && queue[0] !== "inprogress" ) {
-				jQuery.dequeue( this, type );
-			}
-		});
-	},
-	dequeue: function( type ) {
-		return this.each(function() {
-			jQuery.dequeue( this, type );
-		});
-	},
-
-	// Based off of the plugin by Clint Helfers, with permission.
-	// http://blindsignals.com/index.php/2009/07/jquery-delay/
-	delay: function( time, type ) {
-		time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
-		type = type || "fx";
-
-		return this.queue( type, function() {
-			var elem = this;
-			setTimeout(function() {
-				jQuery.dequeue( elem, type );
-			}, time );
-		});
-	},
-
-	clearQueue: function( type ) {
-		return this.queue( type || "fx", [] );
-	}
-});
-var rclass = /[\n\t]/g,
-	rspace = /\s+/,
-	rreturn = /\r/g,
-	rspecialurl = /href|src|style/,
-	rtype = /(button|input)/i,
-	rfocusable = /(button|input|object|select|textarea)/i,
-	rclickable = /^(a|area)$/i,
-	rradiocheck = /radio|checkbox/;
-
-jQuery.fn.extend({
-	attr: function( name, value ) {
-		return access( this, name, value, true, jQuery.attr );
-	},
-
-	removeAttr: function( name, fn ) {
-		return this.each(function(){
-			jQuery.attr( this, name, "" );
-			if ( this.nodeType === 1 ) {
-				this.removeAttribute( name );
-			}
-		});
-	},
-
-	addClass: function( value ) {
-		if ( jQuery.isFunction(value) ) {
-			return this.each(function(i) {
-				var self = jQuery(this);
-				self.addClass( value.call(this, i, self.attr("class")) );
-			});
-		}
-
-		if ( value && typeof value === "string" ) {
-			var classNames = (value || "").split( rspace );
-
-			for ( var i = 0, l = this.length; i < l; i++ ) {
-				var elem = this[i];
-
-				if ( elem.nodeType === 1 ) {
-					if ( !elem.className ) {
-						elem.className = value;
-
-					} else {
-						var className = " " + elem.className + " ", setClass = elem.className;
-						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
-							if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
-								setClass += " " + classNames[c];
-							}
-						}
-						elem.className = jQuery.trim( setClass );
-					}
-				}
-			}
-		}
-
-		return this;
-	},
-
-	removeClass: function( value ) {
-		if ( jQuery.isFunction(value) ) {
-			return this.each(function(i) {
-				var self = jQuery(this);
-				self.removeClass( value.call(this, i, self.attr("class")) );
-			});
-		}
-
-		if ( (value && typeof value === "string") || value === undefined ) {
-			var classNames = (value || "").split(rspace);
-
-			for ( var i = 0, l = this.length; i < l; i++ ) {
-				var elem = this[i];
-
-				if ( elem.nodeType === 1 && elem.className ) {
-					if ( value ) {
-						var className = (" " + elem.className + " ").replace(rclass, " ");
-						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
-							className = className.replace(" " + classNames[c] + " ", " ");
-						}
-						elem.className = jQuery.trim( className );
-
-					} else {
-						elem.className = "";
-					}
-				}
-			}
-		}
-
-		return this;
-	},
-
-	toggleClass: function( value, stateVal ) {
-		var type = typeof value, isBool = typeof stateVal === "boolean";
-
-		if ( jQuery.isFunction( value ) ) {
-			return this.each(function(i) {
-				var self = jQuery(this);
-				self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
-			});
-		}
-
-		return this.each(function() {
-			if ( type === "string" ) {
-				// toggle individual class names
-				var className, i = 0, self = jQuery(this),
-					state = stateVal,
-					classNames = value.split( rspace );
-
-				while ( (className = classNames[ i++ ]) ) {
-					// check each className given, space seperated list
-					state = isBool ? state : !self.hasClass( className );
-					self[ state ? "addClass" : "removeClass" ]( className );
-				}
-
-			} else if ( type === "undefined" || type === "boolean" ) {
-				if ( this.className ) {
-					// store className if set
-					jQuery.data( this, "__className__", this.className );
-				}
-
-				// toggle whole className
-				this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";
-			}
-		});
-	},
-
-	hasClass: function( selector ) {
-		var className = " " + selector + " ";
-		for ( var i = 0, l = this.length; i < l; i++ ) {
-			if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
-				return true;
-			}
-		}
-
-		return false;
-	},
-
-	val: function( value ) {
-		if ( value === undefined ) {
-			var elem = this[0];
-
-			if ( elem ) {
-				if ( jQuery.nodeName( elem, "option" ) ) {
-					return (elem.attributes.value || {}).specified ? elem.value : elem.text;
-				}
-
-				// We need to handle select boxes special
-				if ( jQuery.nodeName( elem, "select" ) ) {
-					var index = elem.selectedIndex,
-						values = [],
-						options = elem.options,
-						one = elem.type === "select-one";
-
-					// Nothing was selected
-					if ( index < 0 ) {
-						return null;
-					}
-
-					// Loop through all the selected options
-					for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
-						var option = options[ i ];
-
-						if ( option.selected ) {
-							// Get the specifc value for the option
-							value = jQuery(option).val();
-
-							// We don't need an array for one selects
-							if ( one ) {
-								return value;
-							}
-
-							// Multi-Selects return an array
-							values.push( value );
-						}
-					}
-
-					return values;
-				}
-
-				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
-				if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
-					return elem.getAttribute("value") === null ? "on" : elem.value;
-				}
-				
-
-				// Everything else, we just grab the value
-				return (elem.value || "").replace(rreturn, "");
-
-			}
-
-			return undefined;
-		}
-
-		var isFunction = jQuery.isFunction(value);
-
-		return this.each(function(i) {
-			var self = jQuery(this), val = value;
-
-			if ( this.nodeType !== 1 ) {
-				return;
-			}
-
-			if ( isFunction ) {
-				val = value.call(this, i, self.val());
-			}
-
-			// Typecast each time if the value is a Function and the appended
-			// value is therefore different each time.
-			if ( typeof val === "number" ) {
-				val += "";
-			}
-
-			if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
-				this.checked = jQuery.inArray( self.val(), val ) >= 0;
-
-			} else if ( jQuery.nodeName( this, "select" ) ) {
-				var values = jQuery.makeArray(val);
-
-				jQuery( "option", this ).each(function() {
-					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
-				});
-
-				if ( !values.length ) {
-					this.selectedIndex = -1;
-				}
-
-			} else {
-				this.value = val;
-			}
-		});
-	}
-});
-
-jQuery.extend({
-	attrFn: {
-		val: true,
-		css: true,
-		html: true,
-		text: true,
-		data: true,
-		width: true,
-		height: true,
-		offset: true
-	},
-		
-	attr: function( elem, name, value, pass ) {
-		// don't set attributes on text and comment nodes
-		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
-			return undefined;
-		}
-
-		if ( pass && name in jQuery.attrFn ) {
-			return jQuery(elem)[name](value);
-		}
-
-		var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
-			// Whether we are setting (or getting)
-			set = value !== undefined;
-
-		// Try to normalize/fix the name
-		name = notxml && jQuery.props[ name ] || name;
-
-		// Only do all the following if this is a node (faster for style)
-		if ( elem.nodeType === 1 ) {
-			// These attributes require special treatment
-			var special = rspecialurl.test( name );
-
-			// Safari mis-reports the default selected property of an option
-			// Accessing the parent's selectedIndex property fixes it
-			if ( name === "selected" && !jQuery.support.optSelected ) {
-				var parent = elem.parentNode;
-				if ( parent ) {
-					parent.selectedIndex;
-	
-					// Make sure that it also works with optgroups, see #5701
-					if ( parent.parentNode ) {
-						parent.parentNode.selectedIndex;
-					}
-				}
-			}
-
-			// If applicable, access the attribute via the DOM 0 way
-			if ( name in elem && notxml && !special ) {
-				if ( set ) {
-					// We can't allow the type property to be changed (since it causes problems in IE)
-					if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
-						jQuery.error( "type property can't be changed" );
-					}
-
-					elem[ name ] = value;
-				}
-
-				// browsers index elements by id/name on forms, give priority to attributes.
-				if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
-					return elem.getAttributeNode( name ).nodeValue;
-				}
-
-				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
-				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
-				if ( name === "tabIndex" ) {
-					var attributeNode = elem.getAttributeNode( "tabIndex" );
-
-					return attributeNode && attributeNode.specified ?
-						attributeNode.value :
-						rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
-							0 :
-							undefined;
-				}
-
-				return elem[ name ];
-			}
-
-			if ( !jQuery.support.style && notxml && name === "style" ) {
-				if ( set ) {
-					elem.style.cssText = "" + value;
-				}
-
-				return elem.style.cssText;
-			}
-
-			if ( set ) {
-				// convert the value to a string (all browsers do this but IE) see #1070
-				elem.setAttribute( name, "" + value );
-			}
-
-			var attr = !jQuery.support.hrefNormalized && notxml && special ?
-					// Some attributes require a special call on IE
-					elem.getAttribute( name, 2 ) :
-					elem.getAttribute( name );
-
-			// Non-existent attributes return null, we normalize to undefined
-			return attr === null ? undefined : attr;
-		}
-
-		// elem is actually elem.style ... set the style
-		// Using attr for specific style information is now deprecated. Use style instead.
-		return jQuery.style( elem, name, value );
-	}
-});
-var rnamespaces = /\.(.*)$/,
-	fcleanup = function( nm ) {
-		return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
-			return "\\" + ch;
-		});
-	};
-
-/*
- * A number of helper functions used for managing events.
- * Many of the ideas behind this code originated from
- * Dean Edwards' addEvent library.
- */
-jQuery.event = {
-
-	// Bind an event to an element
-	// Original by Dean Edwards
-	add: function( elem, types, handler, data ) {
-		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
-			return;
-		}
-
-		// For whatever reason, IE has trouble passing the window object
-		// around, causing it to be cloned in the process
-		if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
-			elem = window;
-		}
-
-		var handleObjIn, handleObj;
-
-		if ( handler.handler ) {
-			handleObjIn = handler;
-			handler = handleObjIn.handler;
-		}
-
-		// Make sure that the function being executed has a unique ID
-		if ( !handler.guid ) {
-			handler.guid = jQuery.guid++;
-		}
-
-		// Init the element's event structure
-		var elemData = jQuery.data( elem );
-
-		// If no elemData is found then we must be trying to bind to one of the
-		// banned noData elements
-		if ( !elemData ) {
-			return;
-		}
-
-		var events = elemData.events = elemData.events || {},
-			eventHandle = elemData.handle, eventHandle;
-
-		if ( !eventHandle ) {
-			elemData.handle = eventHandle = function() {
-				// Handle the second event of a trigger and when
-				// an event is called after a page has unloaded
-				return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
-					jQuery.event.handle.apply( eventHandle.elem, arguments ) :
-					undefined;
-			};
-		}
-
-		// Add elem as a property of the handle function
-		// This is to prevent a memory leak with non-native events in IE.
-		eventHandle.elem = elem;
-
-		// Handle multiple events separated by a space
-		// jQuery(...).bind("mouseover mouseout", fn);
-		types = types.split(" ");
-
-		var type, i = 0, namespaces;
-
-		while ( (type = types[ i++ ]) ) {
-			handleObj = handleObjIn ?
-				jQuery.extend({}, handleObjIn) :
-				{ handler: handler, data: data };
-
-			// Namespaced event handlers
-			if ( type.indexOf(".") > -1 ) {
-				namespaces = type.split(".");
-				type = namespaces.shift();
-				handleObj.namespace = namespaces.slice(0).sort().join(".");
-
-			} else {
-				namespaces = [];
-				handleObj.namespace = "";
-			}
-
-			handleObj.type = type;
-			handleObj.guid = handler.guid;
-
-			// Get the current list of functions bound to this event
-			var handlers = events[ type ],
-				special = jQuery.event.special[ type ] || {};
-
-			// Init the event handler queue
-			if ( !handlers ) {
-				handlers = events[ type ] = [];
-
-				// Check for a special event handler
-				// Only use addEventListener/attachEvent if the special
-				// events handler returns false
-				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
-					// Bind the global event handler to the element
-					if ( elem.addEventListener ) {
-						elem.addEventListener( type, eventHandle, false );
-
-					} else if ( elem.attachEvent ) {
-						elem.attachEvent( "on" + type, eventHandle );
-					}
-				}
-			}
-			
-			if ( special.add ) { 
-				special.add.call( elem, handleObj ); 
-
-				if ( !handleObj.handler.guid ) {
-					handleObj.handler.guid = handler.guid;
-				}
-			}
-
-			// Add the function to the element's handler list
-			handlers.push( handleObj );
-
-			// Keep track of which events have been used, for global triggering
-			jQuery.event.global[ type ] = true;
-		}
-
-		// Nullify elem to prevent memory leaks in IE
-		elem = null;
-	},
-
-	global: {},
-
-	// Detach an event or set of events from an element
-	remove: function( elem, types, handler, pos ) {
-		// don't do events on text and comment nodes
-		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
-			return;
-		}
-
-		var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
-			elemData = jQuery.data( elem ),
-			events = elemData && elemData.events;
-
-		if ( !elemData || !events ) {
-			return;
-		}
-
-		// types is actually an event object here
-		if ( types && types.type ) {
-			handler = types.handler;
-			types = types.type;
-		}
-
-		// Unbind all events for the element
-		if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
-			types = types || "";
-
-			for ( type in events ) {
-				jQuery.event.remove( elem, type + types );
-			}
-
-			return;
-		}
-
-		// Handle multiple events separated by a space
-		// jQuery(...).unbind("mouseover mouseout", fn);
-		types = types.split(" ");
-
-		while ( (type = types[ i++ ]) ) {
-			origType = type;
-			handleObj = null;
-			all = type.indexOf(".") < 0;
-			namespaces = [];
-
-			if ( !all ) {
-				// Namespaced event handlers
-				namespaces = type.split(".");
-				type = namespaces.shift();
-
-				namespace = new RegExp("(^|\\.)" + 
-					jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
-			}
-
-			eventType = events[ type ];
-
-			if ( !eventType ) {
-				continue;
-			}
-
-			if ( !handler ) {
-				for ( var j = 0; j < eventType.length; j++ ) {
-					handleObj = eventType[ j ];
-
-					if ( all || namespace.test( handleObj.namespace ) ) {
-						jQuery.event.remove( elem, origType, handleObj.handler, j );
-						eventType.splice( j--, 1 );
-					}
-				}
-
-				continue;
-			}
-
-			special = jQuery.event.special[ type ] || {};
-
-			for ( var j = pos || 0; j < eventType.length; j++ ) {
-				handleObj = eventType[ j ];
-
-				if ( handler.guid === handleObj.guid ) {
-					// remove the given handler for the given type
-					if ( all || namespace.test( handleObj.namespace ) ) {
-						if ( pos == null ) {
-							eventType.splice( j--, 1 );
-						}
-
-						if ( special.remove ) {
-							special.remove.call( elem, handleObj );
-						}
-					}
-
-					if ( pos != null ) {
-						break;
-					}
-				}
-			}
-
-			// remove generic event handler if no more handlers exist
-			if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
-				if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
-					removeEvent( elem, type, elemData.handle );
-				}
-
-				ret = null;
-				delete events[ type ];
-			}
-		}
-
-		// Remove the expando if it's no longer used
-		if ( jQuery.isEmptyObject( events ) ) {
-			var handle = elemData.handle;
-			if ( handle ) {
-				handle.elem = null;
-			}
-
-			delete elemData.events;
-			delete elemData.handle;
-
-			if ( jQuery.isEmptyObject( elemData ) ) {
-				jQuery.removeData( elem );
-			}
-		}
-	},
-
-	// bubbling is internal
-	trigger: function( event, data, elem /*, bubbling */ ) {
-		// Event object or event type
-		var type = event.type || event,
-			bubbling = arguments[3];
-
-		if ( !bubbling ) {
-			event = typeof event === "object" ?
-				// jQuery.Event object
-				event[expando] ? event :
-				// Object literal
-				jQuery.extend( jQuery.Event(type), event ) :
-				// Just the event type (string)
-				jQuery.Event(type);
-
-			if ( type.indexOf("!") >= 0 ) {
-				event.type = type = type.slice(0, -1);
-				event.exclusive = true;
-			}
-
-			// Handle a global trigger
-			if ( !elem ) {
-				// Don't bubble custom events when global (to avoid too much overhead)
-				event.stopPropagation();
-
-				// Only trigger if we've ever bound an event for it
-				if ( jQuery.event.global[ type ] ) {
-					jQuery.each( jQuery.cache, function() {
-						if ( this.events && this.events[type] ) {
-							jQuery.event.trigger( event, data, this.handle.elem );
-						}
-					});
-				}
-			}
-
-			// Handle triggering a single element
-
-			// don't do events on text and comment nodes
-			if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
-				return undefined;
-			}
-
-			// Clean up in case it is reused
-			event.result = undefined;
-			event.target = elem;
-
-			// Clone the incoming data, if any
-			data = jQuery.makeArray( data );
-			data.unshift( event );
-		}
-
-		event.currentTarget = elem;
-
-		// Trigger the event, it is assumed that "handle" is a function
-		var handle = jQuery.data( elem, "handle" );
-		if ( handle ) {
-			handle.apply( elem, data );
-		}
-
-		var parent = elem.parentNode || elem.ownerDocument;
-
-		// Trigger an inline bound script
-		try {
-			if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
-				if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
-					event.result = false;
-				}
-			}
-
-		// prevent IE from throwing an error for some elements with some event types, see #3533
-		} catch (e) {}
-
-		if ( !event.isPropagationStopped() && parent ) {
-			jQuery.event.trigger( event, data, parent, true );
-
-		} else if ( !event.isDefaultPrevented() ) {
-			var target = event.target, old,
-				isClick = jQuery.nodeName(target, "a") && type === "click",
-				special = jQuery.event.special[ type ] || {};
-
-			if ( (!special._default || special._default.call( elem, event ) === false) && 
-				!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
-
-				try {
-					if ( target[ type ] ) {
-						// Make sure that we don't accidentally re-trigger the onFOO events
-						old = target[ "on" + type ];
-
-						if ( old ) {
-							target[ "on" + type ] = null;
-						}
-
-						jQuery.event.triggered = true;
-						target[ type ]();
-					}
-
-				// prevent IE from throwing an error for some elements with some event types, see #3533
-				} catch (e) {}
-
-				if ( old ) {
-					target[ "on" + type ] = old;
-				}
-
-				jQuery.event.triggered = false;
-			}
-		}
-	},
-
-	handle: function( event ) {
-		var all, handlers, namespaces, namespace, events;
-
-		event = arguments[0] = jQuery.event.fix( event || window.event );
-		event.currentTarget = this;
-
-		// Namespaced event handlers
-		all = event.type.indexOf(".") < 0 && !event.exclusive;
-
-		if ( !all ) {
-			namespaces = event.type.split(".");
-			event.type = namespaces.shift();
-			namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
-		}
-
-		var events = jQuery.data(this, "events"), handlers = events[ event.type ];
-
-		if ( events && handlers ) {
-			// Clone the handlers to prevent manipulation
-			handlers = handlers.slice(0);
-
-			for ( var j = 0, l = handlers.length; j < l; j++ ) {
-				var handleObj = handlers[ j ];
-
-				// Filter the functions by class
-				if ( all || namespace.test( handleObj.namespace ) ) {
-					// Pass in a reference to the handler function itself
-					// So that we can later remove it
-					event.handler = handleObj.handler;
-					event.data = handleObj.data;
-					event.handleObj = handleObj;
-	
-					var ret = handleObj.handler.apply( this, arguments );
-
-					if ( ret !== undefined ) {
-						event.result = ret;
-						if ( ret === false ) {
-							event.preventDefault();
-							event.stopPropagation();
-						}
-					}
-
-					if ( event.isImmediatePropagationStopped() ) {
-						break;
-					}
-				}
-			}
-		}
-
-		return event.result;
-	},
-
-	props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
-
-	fix: function( event ) {
-		if ( event[ expando ] ) {
-			return event;
-		}
-
-		// store a copy of the original event object
-		// and "clone" to set read-only properties
-		var originalEvent = event;
-		event = jQuery.Event( originalEvent );
-
-		for ( var i = this.props.length, prop; i; ) {
-			prop = this.props[ --i ];
-			event[ prop ] = originalEvent[ prop ];
-		}
-
-		// Fix target property, if necessary
-		if ( !event.target ) {
-			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
-		}
-
-		// check if target is a textnode (safari)
-		if ( event.target.nodeType === 3 ) {
-			event.target = event.target.parentNode;
-		}
-
-		// Add relatedTarget, if necessary
-		if ( !event.relatedTarget && event.fromElement ) {
-			event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
-		}
-
-		// Calculate pageX/Y if missing and clientX/Y available
-		if ( event.pageX == null && event.clientX != null ) {
-			var doc = document.documentElement, body = document.body;
-			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
-			event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
-		}
-
-		// Add which for key events
-		if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
-			event.which = event.charCode || event.keyCode;
-		}
-
-		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
-		if ( !event.metaKey && event.ctrlKey ) {
-			event.metaKey = event.ctrlKey;
-		}
-
-		// Add which for click: 1 === left; 2 === middle; 3 === right
-		// Note: button is not normalized, so don't use it
-		if ( !event.which && event.button !== undefined ) {
-			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
-		}
-
-		return event;
-	},
-
-	// Deprecated, use jQuery.guid instead
-	guid: 1E8,
-
-	// Deprecated, use jQuery.proxy instead
-	proxy: jQuery.proxy,
-
-	special: {
-		ready: {
-			// Make sure the ready event is setup
-			setup: jQuery.bindReady,
-			teardown: jQuery.noop
-		},
-
-		live: {
-			add: function( handleObj ) {
-				jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); 
-			},
-
-			remove: function( handleObj ) {
-				var remove = true,
-					type = handleObj.origType.replace(rnamespaces, "");
-				
-				jQuery.each( jQuery.data(this, "events").live || [], function() {
-					if ( type === this.origType.replace(rnamespaces, "") ) {
-						remove = false;
-						return false;
-					}
-				});
-
-				if ( remove ) {
-					jQuery.event.remove( this, handleObj.origType, liveHandler );
-				}
-			}
-
-		},
-
-		beforeunload: {
-			setup: function( data, namespaces, eventHandle ) {
-				// We only want to do this special case on windows
-				if ( this.setInterval ) {
-					this.onbeforeunload = eventHandle;
-				}
-
-				return false;
-			},
-			teardown: function( namespaces, eventHandle ) {
-				if ( this.onbeforeunload === eventHandle ) {
-					this.onbeforeunload = null;
-				}
-			}
-		}
-	}
-};
-
-var removeEvent = document.removeEventListener ?
-	function( elem, type, handle ) {
-	    elem.removeEventListener( type, handle, false );
-	} :
-	function( elem, type, handle ) {
-		elem.detachEvent( "on" + type, handle );
-	};
-
-jQuery.Event = function( src ) {
-	// Allow instantiation without the 'new' keyword
-	if ( !this.preventDefault ) {
-		return new jQuery.Event( src );
-	}
-
-	// Event object
-	if ( src && src.type ) {
-		this.originalEvent = src;
-		this.type = src.type;
-	// Event type
-	} else {
-		this.type = src;
-	}
-
-	// timeStamp is buggy for some events on Firefox(#3843)
-	// So we won't rely on the native value
-	this.timeStamp = now();
-
-	// Mark it as fixed
-	this[ expando ] = true;
-};
-
-function returnFalse() {
-	return false;
-}
-function returnTrue() {
-	return true;
-}
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
-	preventDefault: function() {
-		this.isDefaultPrevented = returnTrue;
-
-		var e = this.originalEvent;
-		if ( !e ) {
-			return;
-		}
-		
-		// if preventDefault exists run it on the original event
-		if ( e.preventDefault ) {
-			e.preventDefault();
-		}
-		// otherwise set the returnValue property of the original event to false (IE)
-		e.returnValue = false;
-	},
-	stopPropagation: function() {
-		this.isPropagationStopped = returnTrue;
-
-		var e = this.originalEvent;
-		if ( !e ) {
-			return;
-		}
-		// if stopPropagation exists run it on the original event
-		if ( e.stopPropagation ) {
-			e.stopPropagation();
-		}
-		// otherwise set the cancelBubble property of the original event to true (IE)
-		e.cancelBubble = true;
-	},
-	stopImmediatePropagation: function() {
-		this.isImmediatePropagationStopped = returnTrue;
-		this.stopPropagation();
-	},
-	isDefaultPrevented: returnFalse,
-	isPropagationStopped: returnFalse,
-	isImmediatePropagationStopped: returnFalse
-};
-
-// Checks if an event happened on an element within another element
-// Used in jQuery.event.special.mouseenter and mouseleave handlers
-var withinElement = function( event ) {
-	// Check if mouse(over|out) are still within the same parent element
-	var parent = event.relatedTarget;
-
-	// Firefox sometimes assigns relatedTarget a XUL element
-	// which we cannot access the parentNode property of
-	try {
-		// Traverse up the tree
-		while ( parent && parent !== this ) {
-			parent = parent.parentNode;
-		}
-
-		if ( parent !== this ) {
-			// set the correct event type
-			event.type = event.data;
-
-			// handle event if we actually just moused on to a non sub-element
-			jQuery.event.handle.apply( this, arguments );
-		}
-
-	// assuming we've left the element since we most likely mousedover a xul element
-	} catch(e) { }
-},
-
-// In case of event delegation, we only need to rename the event.type,
-// liveHandler will take care of the rest.
-delegate = function( event ) {
-	event.type = event.data;
-	jQuery.event.handle.apply( this, arguments );
-};
-
-// Create mouseenter and mouseleave events
-jQuery.each({
-	mouseenter: "mouseover",
-	mouseleave: "mouseout"
-}, function( orig, fix ) {
-	jQuery.event.special[ orig ] = {
-		setup: function( data ) {
-			jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
-		},
-		teardown: function( data ) {
-			jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
-		}
-	};
-});
-
-// submit delegation
-if ( !jQuery.support.submitBubbles ) {
-
-	jQuery.event.special.submit = {
-		setup: function( data, namespaces ) {
-			if ( this.nodeName.toLowerCase() !== "form" ) {
-				jQuery.event.add(this, "click.specialSubmit", function( e ) {
-					var elem = e.target, type = elem.type;
-
-					if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
-						return trigger( "submit", this, arguments );
-					}
-				});
-	 
-				jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
-					var elem = e.target, type = elem.type;
-
-					if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
-						return trigger( "submit", this, arguments );
-					}
-				});
-
-			} else {
-				return false;
-			}
-		},
-
-		teardown: function( namespaces ) {
-			jQuery.event.remove( this, ".specialSubmit" );
-		}
-	};
-
-}
-
-// change delegation, happens here so we have bind.
-if ( !jQuery.support.changeBubbles ) {
-
-	var formElems = /textarea|input|select/i,
-
-	changeFilters,
-
-	getVal = function( elem ) {
-		var type = elem.type, val = elem.value;
-
-		if ( type === "radio" || type === "checkbox" ) {
-			val = elem.checked;
-
-		} else if ( type === "select-multiple" ) {
-			val = elem.selectedIndex > -1 ?
-				jQuery.map( elem.options, function( elem ) {
-					return elem.selected;
-				}).join("-") :
-				"";
-
-		} else if ( elem.nodeName.toLowerCase() === "select" ) {
-			val = elem.selectedIndex;
-		}
-
-		return val;
-	},
-
-	testChange = function testChange( e ) {
-		var elem = e.target, data, val;
-
-		if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
-			return;
-		}
-
-		data = jQuery.data( elem, "_change_data" );
-		val = getVal(elem);
-
-		// the current data will be also retrieved by beforeactivate
-		if ( e.type !== "focusout" || elem.type !== "radio" ) {
-			jQuery.data( elem, "_change_data", val );
-		}
-		
-		if ( data === undefined || val === data ) {
-			return;
-		}
-
-		if ( data != null || val ) {
-			e.type = "change";
-			return jQuery.event.trigger( e, arguments[1], elem );
-		}
-	};
-
-	jQuery.event.special.change = {
-		filters: {
-			focusout: testChange, 
-
-			click: function( e ) {
-				var elem = e.target, type = elem.type;
-
-				if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
-					return testChange.call( this, e );
-				}
-			},
-
-			// Change has to be called before submit
-			// Keydown will be called before keypress, which is used in submit-event delegation
-			keydown: function( e ) {
-				var elem = e.target, type = elem.type;
-
-				if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
-					(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
-					type === "select-multiple" ) {
-					return testChange.call( this, e );
-				}
-			},
-
-			// Beforeactivate happens also before the previous element is blurred
-			// with this event you can't trigger a change event, but you can store
-			// information/focus[in] is not needed anymore
-			beforeactivate: function( e ) {
-				var elem = e.target;
-				jQuery.data( elem, "_change_data", getVal(elem) );
-			}
-		},
-
-		setup: function( data, namespaces ) {
-			if ( this.type === "file" ) {
-				return false;
-			}
-
-			for ( var type in changeFilters ) {
-				jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
-			}
-
-			return formElems.test( this.nodeName );
-		},
-
-		teardown: function( namespaces ) {
-			jQuery.event.remove( this, ".specialChange" );
-
-			return formElems.test( this.nodeName );
-		}
-	};
-
-	changeFilters = jQuery.event.special.change.filters;
-}
-
-function trigger( type, elem, args ) {
-	args[0].type = type;
-	return jQuery.event.handle.apply( elem, args );
-}
-
-// Create "bubbling" focus and blur events
-if ( document.addEventListener ) {
-	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-		jQuery.event.special[ fix ] = {
-			setup: function() {
-				this.addEventListener( orig, handler, true );
-			}, 
-			teardown: function() { 
-				this.removeEventListener( orig, handler, true );
-			}
-		};
-
-		function handler( e ) { 
-			e = jQuery.event.fix( e );
-			e.type = fix;
-			return jQuery.event.handle.call( this, e );
-		}
-	});
-}
-
-jQuery.each(["bind", "one"], function( i, name ) {
-	jQuery.fn[ name ] = function( type, data, fn ) {
-		// Handle object literals
-		if ( typeof type === "object" ) {
-			for ( var key in type ) {
-				this[ name ](key, data, type[key], fn);
-			}
-			return this;
-		}
-		
-		if ( jQuery.isFunction( data ) ) {
-			fn = data;
-			data = undefined;
-		}
-
-		var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
-			jQuery( this ).unbind( event, handler );
-			return fn.apply( this, arguments );
-		}) : fn;
-
-		if ( type === "unload" && name !== "one" ) {
-			this.one( type, data, fn );
-
-		} else {
-			for ( var i = 0, l = this.length; i < l; i++ ) {
-				jQuery.event.add( this[i], type, handler, data );
-			}
-		}
-
-		return this;
-	};
-});
-
-jQuery.fn.extend({
-	unbind: function( type, fn ) {
-		// Handle object literals
-		if ( typeof type === "object" && !type.preventDefault ) {
-			for ( var key in type ) {
-				this.unbind(key, type[key]);
-			}
-
-		} else {
-			for ( var i = 0, l = this.length; i < l; i++ ) {
-				jQuery.event.remove( this[i], type, fn );
-			}
-		}
-
-		return this;
-	},
-	
-	delegate: function( selector, types, data, fn ) {
-		return this.live( types, data, fn, selector );
-	},
-	
-	undelegate: function( selector, types, fn ) {
-		if ( arguments.length === 0 ) {
-				return this.unbind( "live" );
-		
-		} else {
-			return this.die( types, null, fn, selector );
-		}
-	},
-	
-	trigger: function( type, data ) {
-		return this.each(function() {
-			jQuery.event.trigger( type, data, this );
-		});
-	},
-
-	triggerHandler: function( type, data ) {
-		if ( this[0] ) {
-			var event = jQuery.Event( type );
-			event.preventDefault();
-			event.stopPropagation();
-			jQuery.event.trigger( event, data, this[0] );
-			return event.result;
-		}
-	},
-
-	toggle: function( fn ) {
-		// Save reference to arguments for access in closure
-		var args = arguments, i = 1;
-
-		// link all the functions, so any of them can unbind this click handler
-		while ( i < args.length ) {
-			jQuery.proxy( fn, args[ i++ ] );
-		}
-
-		return this.click( jQuery.proxy( fn, function( event ) {
-			// Figure out which function to execute
-			var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
-			jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
-			// Make sure that clicks stop
-			event.preventDefault();
-
-			// and execute the function
-			return args[ lastToggle ].apply( this, arguments ) || false;
-		}));
-	},
-
-	hover: function( fnOver, fnOut ) {
-		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
-	}
-});
-
-var liveMap = {
-	focus: "focusin",
-	blur: "focusout",
-	mouseenter: "mouseover",
-	mouseleave: "mouseout"
-};
-
-jQuery.each(["live", "die"], function( i, name ) {
-	jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
-		var type, i = 0, match, namespaces, preType,
-			selector = origSelector || this.selector,
-			context = origSelector ? this : jQuery( this.context );
-
-		if ( jQuery.isFunction( data ) ) {
-			fn = data;
-			data = undefined;
-		}
-
-		types = (types || "").split(" ");
-
-		while ( (type = types[ i++ ]) != null ) {
-			match = rnamespaces.exec( type );
-			namespaces = "";
-
-			if ( match )  {
-				namespaces = match[0];
-				type = type.replace( rnamespaces, "" );
-			}
-
-			if ( type === "hover" ) {
-				types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
-				continue;
-			}
-
-			preType = type;
-
-			if ( type === "focus" || type === "blur" ) {
-				types.push( liveMap[ type ] + namespaces );
-				type = type + namespaces;
-
-			} else {
-				type = (liveMap[ type ] || type) + namespaces;
-			}
-
-			if ( name === "live" ) {
-				// bind live handler
-				context.each(function(){
-					jQuery.event.add( this, liveConvert( type, selector ),
-						{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
-				});
-
-			} else {
-				// unbind live handler
-				context.unbind( liveConvert( type, selector ), fn );
-			}
-		}
-		
-		return this;
-	}
-});
-
-function liveHandler( event ) {
-	var stop, elems = [], selectors = [], args = arguments,
-		related, match, handleObj, elem, j, i, l, data,
-		events = jQuery.data( this, "events" );
-
-	// Make sure we avoid non-left-click bubbling in Firefox (#3861)
-	if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
-		return;
-	}
-
-	event.liveFired = this;
-
-	var live = events.live.slice(0);
-
-	for ( j = 0; j < live.length; j++ ) {
-		handleObj = live[j];
-
-		if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
-			selectors.push( handleObj.selector );
-
-		} else {
-			live.splice( j--, 1 );
-		}
-	}
-
-	match = jQuery( event.target ).closest( selectors, event.currentTarget );
-
-	for ( i = 0, l = match.length; i < l; i++ ) {
-		for ( j = 0; j < live.length; j++ ) {
-			handleObj = live[j];
-
-			if ( match[i].selector === handleObj.selector ) {
-				elem = match[i].elem;
-				related = null;
-
-				// Those two events require additional checking
-				if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
-					related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
-				}
-
-				if ( !related || related !== elem ) {
-					elems.push({ elem: elem, handleObj: handleObj });
-				}
-			}
-		}
-	}
-
-	for ( i = 0, l = elems.length; i < l; i++ ) {
-		match = elems[i];
-		event.currentTarget = match.elem;
-		event.data = match.handleObj.data;
-		event.handleObj = match.handleObj;
-
-		if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) {
-			stop = false;
-			break;
-		}
-	}
-
-	return stop;
-}
-
-function liveConvert( type, selector ) {
-	return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
-}
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
-	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
-	"change select submit keydown keypress keyup error").split(" "), function( i, name ) {
-
-	// Handle event binding
-	jQuery.fn[ name ] = function( fn ) {
-		return fn ? this.bind( name, fn ) : this.trigger( name );
-	};
-
-	if ( jQuery.attrFn ) {
-		jQuery.attrFn[ name ] = true;
-	}
-});
-
-// Prevent memory leaks in IE
-// Window isn't included so as not to unbind existing unload events
-// More info:
-//  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
-if ( window.attachEvent && !window.addEventListener ) {
-	window.attachEvent("onunload", function() {
-		for ( var id in jQuery.cache ) {
-			if ( jQuery.cache[ id ].handle ) {
-				// Try/Catch is to handle iframes being unloaded, see #4280
-				try {
-					jQuery.event.remove( jQuery.cache[ id ].handle.elem );
-				} catch(e) {}
-			}
-		}
-	});
-}
-/*!
- * Sizzle CSS Selector Engine - v1.0
- *  Copyright 2009, The Dojo Foundation
- *  Released under the MIT, BSD, and GPL Licenses.
- *  More information: http://sizzlejs.com/
- */
-(function(){
-
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
-	done = 0,
-	toString = Object.prototype.toString,
-	hasDuplicate = false,
-	baseHasDuplicate = true;
-
-// Here we check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
-// function. If that is the case, discard the hasDuplicate value.
-//   Thus far that includes Google Chrome.
-[0, 0].sort(function(){
-	baseHasDuplicate = false;
-	return 0;
-});
-
-var Sizzle = function(selector, context, results, seed) {
-	results = results || [];
-	var origContext = context = context || document;
-
-	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
-		return [];
-	}
-	
-	if ( !selector || typeof selector !== "string" ) {
-		return results;
-	}
-
-	var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
-		soFar = selector;
-	
-	// Reset the position of the chunker regexp (start from head)
-	while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
-		soFar = m[3];
-		
-		parts.push( m[1] );
-		
-		if ( m[2] ) {
-			extra = m[3];
-			break;
-		}
-	}
-
-	if ( parts.length > 1 && origPOS.exec( selector ) ) {
-		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
-			set = posProcess( parts[0] + parts[1], context );
-		} else {
-			set = Expr.relative[ parts[0] ] ?
-				[ context ] :
-				Sizzle( parts.shift(), context );
-
-			while ( parts.length ) {
-				selector = parts.shift();
-
-				if ( Expr.relative[ selector ] ) {
-					selector += parts.shift();
-				}
-				
-				set = posProcess( selector, set );
-			}
-		}
-	} else {
-		// Take a shortcut and set the context if the root selector is an ID
-		// (but not if it'll be faster if the inner selector is an ID)
-		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
-				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
-			var ret = Sizzle.find( parts.shift(), context, contextXML );
-			context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
-		}
-
-		if ( context ) {
-			var ret = seed ?
-				{ expr: parts.pop(), set: makeArray(seed) } :
-				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
-			set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
-
-			if ( parts.length > 0 ) {
-				checkSet = makeArray(set);
-			} else {
-				prune = false;
-			}
-
-			while ( parts.length ) {
-				var cur = parts.pop(), pop = cur;
-
-				if ( !Expr.relative[ cur ] ) {
-					cur = "";
-				} else {
-					pop = parts.pop();
-				}
-
-				if ( pop == null ) {
-					pop = context;
-				}
-
-				Expr.relative[ cur ]( checkSet, pop, contextXML );
-			}
-		} else {
-			checkSet = parts = [];
-		}
-	}
-
-	if ( !checkSet ) {
-		checkSet = set;
-	}
-
-	if ( !checkSet ) {
-		Sizzle.error( cur || selector );
-	}
-
-	if ( toString.call(checkSet) === "[object Array]" ) {
-		if ( !prune ) {
-			results.push.apply( results, checkSet );
-		} else if ( context && context.nodeType === 1 ) {
-			for ( var i = 0; checkSet[i] != null; i++ ) {
-				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
-					results.push( set[i] );
-				}
-			}
-		} else {
-			for ( var i = 0; checkSet[i] != null; i++ ) {
-				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
-					results.push( set[i] );
-				}
-			}
-		}
-	} else {
-		makeArray( checkSet, results );
-	}
-
-	if ( extra ) {
-		Sizzle( extra, origContext, results, seed );
-		Sizzle.uniqueSort( results );
-	}
-
-	return results;
-};
-
-Sizzle.uniqueSort = function(results){
-	if ( sortOrder ) {
-		hasDuplicate = baseHasDuplicate;
-		results.sort(sortOrder);
-
-		if ( hasDuplicate ) {
-			for ( var i = 1; i < results.length; i++ ) {
-				if ( results[i] === results[i-1] ) {
-					results.splice(i--, 1);
-				}
-			}
-		}
-	}
-
-	return results;
-};
-
-Sizzle.matches = function(expr, set){
-	return Sizzle(expr, null, null, set);
-};
-
-Sizzle.find = function(expr, context, isXML){
-	var set, match;
-
-	if ( !expr ) {
-		return [];
-	}
-
-	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
-		var type = Expr.order[i], match;
-		
-		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
-			var left = match[1];
-			match.splice(1,1);
-
-			if ( left.substr( left.length - 1 ) !== "\\" ) {
-				match[1] = (match[1] || "").replace(/\\/g, "");
-				set = Expr.find[ type ]( match, context, isXML );
-				if ( set != null ) {
-					expr = expr.replace( Expr.match[ type ], "" );
-					break;
-				}
-			}
-		}
-	}
-
-	if ( !set ) {
-		set = context.getElementsByTagName("*");
-	}
-
-	return {set: set, expr: expr};
-};
-
-Sizzle.filter = function(expr, set, inplace, not){
-	var old = expr, result = [], curLoop = set, match, anyFound,
-		isXMLFilter = set && set[0] && isXML(set[0]);
-
-	while ( expr && set.length ) {
-		for ( var type in Expr.filter ) {
-			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
-				var filter = Expr.filter[ type ], found, item, left = match[1];
-				anyFound = false;
-
-				match.splice(1,1);
-
-				if ( left.substr( left.length - 1 ) === "\\" ) {
-					continue;
-				}
-
-				if ( curLoop === result ) {
-					result = [];
-				}
-
-				if ( Expr.preFilter[ type ] ) {
-					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
-
-					if ( !match ) {
-						anyFound = found = true;
-					} else if ( match === true ) {
-						continue;
-					}
-				}
-
-				if ( match ) {
-					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
-						if ( item ) {
-							found = filter( item, match, i, curLoop );
-							var pass = not ^ !!found;
-
-							if ( inplace && found != null ) {
-								if ( pass ) {
-									anyFound = true;
-								} else {
-									curLoop[i] = false;
-								}
-							} else if ( pass ) {
-								result.push( item );
-								anyFound = true;
-							}
-						}
-					}
-				}
-
-				if ( found !== undefined ) {
-					if ( !inplace ) {
-						curLoop = result;
-					}
-
-					expr = expr.replace( Expr.match[ type ], "" );
-
-					if ( !anyFound ) {
-						return [];
-					}
-
-					break;
-				}
-			}
-		}
-
-		// Improper expression
-		if ( expr === old ) {
-			if ( anyFound == null ) {
-				Sizzle.error( expr );
-			} else {
-				break;
-			}
-		}
-
-		old = expr;
-	}
-
-	return curLoop;
-};
-
-Sizzle.error = function( msg ) {
-	throw "Syntax error, unrecognized expression: " + msg;
-};
-
-var Expr = Sizzle.selectors = {
-	order: [ "ID", "NAME", "TAG" ],
-	match: {
-		ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
-		CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
-		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
-		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
-		TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
-		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
-		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
-		PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
-	},
-	leftMatch: {},
-	attrMap: {
-		"class": "className",
-		"for": "htmlFor"
-	},
-	attrHandle: {
-		href: function(elem){
-			return elem.getAttribute("href");
-		}
-	},
-	relative: {
-		"+": function(checkSet, part){
-			var isPartStr = typeof part === "string",
-				isTag = isPartStr && !/\W/.test(part),
-				isPartStrNotTag = isPartStr && !isTag;
-
-			if ( isTag ) {
-				part = part.toLowerCase();
-			}
-
-			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
-				if ( (elem = checkSet[i]) ) {
-					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
-
-					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
-						elem || false :
-						elem === part;
-				}
-			}
-
-			if ( isPartStrNotTag ) {
-				Sizzle.filter( part, checkSet, true );
-			}
-		},
-		">": function(checkSet, part){
-			var isPartStr = typeof part === "string";
-
-			if ( isPartStr && !/\W/.test(part) ) {
-				part = part.toLowerCase();
-
-				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-					var elem = checkSet[i];
-					if ( elem ) {
-						var parent = elem.parentNode;
-						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
-					}
-				}
-			} else {
-				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-					var elem = checkSet[i];
-					if ( elem ) {
-						checkSet[i] = isPartStr ?
-							elem.parentNode :
-							elem.parentNode === part;
-					}
-				}
-
-				if ( isPartStr ) {
-					Sizzle.filter( part, checkSet, true );
-				}
-			}
-		},
-		"": function(checkSet, part, isXML){
-			var doneName = done++, checkFn = dirCheck;
-
-			if ( typeof part === "string" && !/\W/.test(part) ) {
-				var nodeCheck = part = part.toLowerCase();
-				checkFn = dirNodeCheck;
-			}
-
-			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
-		},
-		"~": function(checkSet, part, isXML){
-			var doneName = done++, checkFn = dirCheck;
-
-			if ( typeof part === "string" && !/\W/.test(part) ) {
-				var nodeCheck = part = part.toLowerCase();
-				checkFn = dirNodeCheck;
-			}
-
-			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
-		}
-	},
-	find: {
-		ID: function(match, context, isXML){
-			if ( typeof context.getElementById !== "undefined" && !isXML ) {
-				var m = context.getElementById(match[1]);
-				return m ? [m] : [];
-			}
-		},
-		NAME: function(match, context){
-			if ( typeof context.getElementsByName !== "undefined" ) {
-				var ret = [], results = context.getElementsByName(match[1]);
-
-				for ( var i = 0, l = results.length; i < l; i++ ) {
-					if ( results[i].getAttribute("name") === match[1] ) {
-						ret.push( results[i] );
-					}
-				}
-
-				return ret.length === 0 ? null : ret;
-			}
-		},
-		TAG: function(match, context){
-			return context.getElementsByTagName(match[1]);
-		}
-	},
-	preFilter: {
-		CLASS: function(match, curLoop, inplace, result, not, isXML){
-			match = " " + match[1].replace(/\\/g, "") + " ";
-
-			if ( isXML ) {
-				return match;
-			}
-
-			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
-				if ( elem ) {
-					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
-						if ( !inplace ) {
-							result.push( elem );
-						}
-					} else if ( inplace ) {
-						curLoop[i] = false;
-					}
-				}
-			}
-
-			return false;
-		},
-		ID: function(match){
-			return match[1].replace(/\\/g, "");
-		},
-		TAG: function(match, curLoop){
-			return match[1].toLowerCase();
-		},
-		CHILD: function(match){
-			if ( match[1] === "nth" ) {
-				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
-				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
-					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
-					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
-
-				// calculate the numbers (first)n+(last) including if they are negative
-				match[2] = (test[1] + (test[2] || 1)) - 0;
-				match[3] = test[3] - 0;
-			}
-
-			// TODO: Move to normal caching system
-			match[0] = done++;
-
-			return match;
-		},
-		ATTR: function(match, curLoop, inplace, result, not, isXML){
-			var name = match[1].replace(/\\/g, "");
-			
-			if ( !isXML && Expr.attrMap[name] ) {
-				match[1] = Expr.attrMap[name];
-			}
-
-			if ( match[2] === "~=" ) {
-				match[4] = " " + match[4] + " ";
-			}
-
-			return match;
-		},
-		PSEUDO: function(match, curLoop, inplace, result, not){
-			if ( match[1] === "not" ) {
-				// If we're dealing with a complex expression, or a simple one
-				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
-					match[3] = Sizzle(match[3], null, null, curLoop);
-				} else {
-					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
-					if ( !inplace ) {
-						result.push.apply( result, ret );
-					}
-					return false;
-				}
-			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
-				return true;
-			}
-			
-			return match;
-		},
-		POS: function(match){
-			match.unshift( true );
-			return match;
-		}
-	},
-	filters: {
-		enabled: function(elem){
-			return elem.disabled === false && elem.type !== "hidden";
-		},
-		disabled: function(elem){
-			return elem.disabled === true;
-		},
-		checked: function(elem){
-			return elem.checked === true;
-		},
-		selected: function(elem){
-			// Accessing this property makes selected-by-default
-			// options in Safari work properly
-			elem.parentNode.selectedIndex;
-			return elem.selected === true;
-		},
-		parent: function(elem){
-			return !!elem.firstChild;
-		},
-		empty: function(elem){
-			return !elem.firstChild;
-		},
-		has: function(elem, i, match){
-			return !!Sizzle( match[3], elem ).length;
-		},
-		header: function(elem){
-			return /h\d/i.test( elem.nodeName );
-		},
-		text: function(elem){
-			return "text" === elem.type;
-		},
-		radio: function(elem){
-			return "radio" === elem.type;
-		},
-		checkbox: function(elem){
-			return "checkbox" === elem.type;
-		},
-		file: function(elem){
-			return "file" === elem.type;
-		},
-		password: function(elem){
-			return "password" === elem.type;
-		},
-		submit: function(elem){
-			return "submit" === elem.type;
-		},
-		image: function(elem){
-			return "image" === elem.type;
-		},
-		reset: function(elem){
-			return "reset" === elem.type;
-		},
-		button: function(elem){
-			return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
-		},
-		input: function(elem){
-			return /input|select|textarea|button/i.test(elem.nodeName);
-		}
-	},
-	setFilters: {
-		first: function(elem, i){
-			return i === 0;
-		},
-		last: function(elem, i, match, array){
-			return i === array.length - 1;
-		},
-		even: function(elem, i){
-			return i % 2 === 0;
-		},
-		odd: function(elem, i){
-			return i % 2 === 1;
-		},
-		lt: function(elem, i, match){
-			return i < match[3] - 0;
-		},
-		gt: function(elem, i, match){
-			return i > match[3] - 0;
-		},
-		nth: function(elem, i, match){
-			return match[3] - 0 === i;
-		},
-		eq: function(elem, i, match){
-			return match[3] - 0 === i;
-		}
-	},
-	filter: {
-		PSEUDO: function(elem, match, i, array){
-			var name = match[1], filter = Expr.filters[ name ];
-
-			if ( filter ) {
-				return filter( elem, i, match, array );
-			} else if ( name === "contains" ) {
-				return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
-			} else if ( name === "not" ) {
-				var not = match[3];
-
-				for ( var i = 0, l = not.length; i < l; i++ ) {
-					if ( not[i] === elem ) {
-						return false;
-					}
-				}
-
-				return true;
-			} else {
-				Sizzle.error( "Syntax error, unrecognized expression: " + name );
-			}
-		},
-		CHILD: function(elem, match){
-			var type = match[1], node = elem;
-			switch (type) {
-				case 'only':
-				case 'first':
-					while ( (node = node.previousSibling) )	 {
-						if ( node.nodeType === 1 ) { 
-							return false; 
-						}
-					}
-					if ( type === "first" ) { 
-						return true; 
-					}
-					node = elem;
-				case 'last':
-					while ( (node = node.nextSibling) )	 {
-						if ( node.nodeType === 1 ) { 
-							return false; 
-						}
-					}
-					return true;
-				case 'nth':
-					var first = match[2], last = match[3];
-
-					if ( first === 1 && last === 0 ) {
-						return true;
-					}
-					
-					var doneName = match[0],
-						parent = elem.parentNode;
-	
-					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
-						var count = 0;
-						for ( node = parent.firstChild; node; node = node.nextSibling ) {
-							if ( node.nodeType === 1 ) {
-								node.nodeIndex = ++count;
-							}
-						} 
-						parent.sizcache = doneName;
-					}
-					
-					var diff = elem.nodeIndex - last;
-					if ( first === 0 ) {
-						return diff === 0;
-					} else {
-						return ( diff % first === 0 && diff / first >= 0 );
-					}
-			}
-		},
-		ID: function(elem, match){
-			return elem.nodeType === 1 && elem.getAttribute("id") === match;
-		},
-		TAG: function(elem, match){
-			return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
-		},
-		CLASS: function(elem, match){
-			return (" " + (elem.className || elem.getAttribute("class")) + " ")
-				.indexOf( match ) > -1;
-		},
-		ATTR: function(elem, match){
-			var name = match[1],
-				result = Expr.attrHandle[ name ] ?
-					Expr.attrHandle[ name ]( elem ) :
-					elem[ name ] != null ?
-						elem[ name ] :
-						elem.getAttribute( name ),
-				value = result + "",
-				type = match[2],
-				check = match[4];
-
-			return result == null ?
-				type === "!=" :
-				type === "=" ?
-				value === check :
-				type === "*=" ?
-				value.indexOf(check) >= 0 :
-				type === "~=" ?
-				(" " + value + " ").indexOf(check) >= 0 :
-				!check ?
-				value && result !== false :
-				type === "!=" ?
-				value !== check :
-				type === "^=" ?
-				value.indexOf(check) === 0 :
-				type === "$=" ?
-				value.substr(value.length - check.length) === check :
-				type === "|=" ?
-				value === check || value.substr(0, check.length + 1) === check + "-" :
-				false;
-		},
-		POS: function(elem, match, i, array){
-			var name = match[2], filter = Expr.setFilters[ name ];
-
-			if ( filter ) {
-				return filter( elem, i, match, array );
-			}
-		}
-	}
-};
-
-var origPOS = Expr.match.POS;
-
-for ( var type in Expr.match ) {
-	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
-	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
-		return "\\" + (num - 0 + 1);
-	}));
-}
-
-var makeArray = function(array, results) {
-	array = Array.prototype.slice.call( array, 0 );
-
-	if ( results ) {
-		results.push.apply( results, array );
-		return results;
-	}
-	
-	return array;
-};
-
-// Perform a simple check to determine if the browser is capable of
-// converting a NodeList to an array using builtin methods.
-// Also verifies that the returned array holds DOM nodes
-// (which is not the case in the Blackberry browser)
-try {
-	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
-
-// Provide a fallback method if it does not work
-} catch(e){
-	makeArray = function(array, results) {
-		var ret = results || [];
-
-		if ( toString.call(array) === "[object Array]" ) {
-			Array.prototype.push.apply( ret, array );
-		} else {
-			if ( typeof array.length === "number" ) {
-				for ( var i = 0, l = array.length; i < l; i++ ) {
-					ret.push( array[i] );
-				}
-			} else {
-				for ( var i = 0; array[i]; i++ ) {
-					ret.push( array[i] );
-				}
-			}
-		}
-
-		return ret;
-	};
-}
-
-var sortOrder;
-
-if ( document.documentElement.compareDocumentPosition ) {
-	sortOrder = function( a, b ) {
-		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
-			if ( a == b ) {
-				hasDuplicate = true;
-			}
-			return a.compareDocumentPosition ? -1 : 1;
-		}
-
-		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
-		if ( ret === 0 ) {
-			hasDuplicate = true;
-		}
-		return ret;
-	};
-} else if ( "sourceIndex" in document.documentElement ) {
-	sortOrder = function( a, b ) {
-		if ( !a.sourceIndex || !b.sourceIndex ) {
-			if ( a == b ) {
-				hasDuplicate = true;
-			}
-			return a.sourceIndex ? -1 : 1;
-		}
-
-		var ret = a.sourceIndex - b.sourceIndex;
-		if ( ret === 0 ) {
-			hasDuplicate = true;
-		}
-		return ret;
-	};
-} else if ( document.createRange ) {
-	sortOrder = function( a, b ) {
-		if ( !a.ownerDocument || !b.ownerDocument ) {
-			if ( a == b ) {
-				hasDuplicate = true;
-			}
-			return a.ownerDocument ? -1 : 1;
-		}
-
-		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
-		aRange.setStart(a, 0);
-		aRange.setEnd(a, 0);
-		bRange.setStart(b, 0);
-		bRange.setEnd(b, 0);
-		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
-		if ( ret === 0 ) {
-			hasDuplicate = true;
-		}
-		return ret;
-	};
-}
-
-// Utility function for retreiving the text value of an array of DOM nodes
-function getText( elems ) {
-	var ret = "", elem;
-
-	for ( var i = 0; elems[i]; i++ ) {
-		elem = elems[i];
-
-		// Get the text from text nodes and CDATA nodes
-		if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
-			ret += elem.nodeValue;
-
-		// Traverse everything else, except comment nodes
-		} else if ( elem.nodeType !== 8 ) {
-			ret += getText( elem.childNodes );
-		}
-	}
-
-	return ret;
-}
-
-// Check to see if the browser returns elements by name when
-// querying by getElementById (and provide a workaround)
-(function(){
-	// We're going to inject a fake input element with a specified name
-	var form = document.createElement("div"),
-		id = "script" + (new Date).getTime();
-	form.innerHTML = "<a name='" + id + "'/>";
-
-	// Inject it into the root element, check its status, and remove it quickly
-	var root = document.documentElement;
-	root.insertBefore( form, root.firstChild );
-
-	// The workaround has to do additional checks after a getElementById
-	// Which slows things down for other browsers (hence the branching)
-	if ( document.getElementById( id ) ) {
-		Expr.find.ID = function(match, context, isXML){
-			if ( typeof context.getElementById !== "undefined" && !isXML ) {
-				var m = context.getElementById(match[1]);
-				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
-			}
-		};
-
-		Expr.filter.ID = function(elem, match){
-			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
-			return elem.nodeType === 1 && node && node.nodeValue === match;
-		};
-	}
-
-	root.removeChild( form );
-	root = form = null; // release memory in IE
-})();
-
-(function(){
-	// Check to see if the browser returns only elements
-	// when doing getElementsByTagName("*")
-
-	// Create a fake element
-	var div = document.createElement("div");
-	div.appendChild( document.createComment("") );
-
-	// Make sure no comments are found
-	if ( div.getElementsByTagName("*").length > 0 ) {
-		Expr.find.TAG = function(match, context){
-			var results = context.getElementsByTagName(match[1]);
-
-			// Filter out possible comments
-			if ( match[1] === "*" ) {
-				var tmp = [];
-
-				for ( var i = 0; results[i]; i++ ) {
-					if ( results[i].nodeType === 1 ) {
-						tmp.push( results[i] );
-					}
-				}
-
-				results = tmp;
-			}
-
-			return results;
-		};
-	}
-
-	// Check to see if an attribute returns normalized href attributes
-	div.innerHTML = "<a href='#'></a>";
-	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
-			div.firstChild.getAttribute("href") !== "#" ) {
-		Expr.attrHandle.href = function(elem){
-			return elem.getAttribute("href", 2);
-		};
-	}
-
-	div = null; // release memory in IE
-})();
-
-if ( document.querySelectorAll ) {
-	(function(){
-		var oldSizzle = Sizzle, div = document.createElement("div");
-		div.innerHTML = "<p class='TEST'></p>";
-
-		// Safari can't handle uppercase or unicode characters when
-		// in quirks mode.
-		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
-			return;
-		}
-	
-		Sizzle = function(query, context, extra, seed){
-			context = context || document;
-
-			// Only use querySelectorAll on non-XML documents
-			// (ID selectors don't work in non-HTML documents)
-			if ( !seed && context.nodeType === 9 && !isXML(context) ) {
-				try {
-					return makeArray( context.querySelectorAll(query), extra );
-				} catch(e){}
-			}
-		
-			return oldSizzle(query, context, extra, seed);
-		};
-
-		for ( var prop in oldSizzle ) {
-			Sizzle[ prop ] = oldSizzle[ prop ];
-		}
-
-		div = null; // release memory in IE
-	})();
-}
-
-(function(){
-	var div = document.createElement("div");
-
-	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
-
-	// Opera can't find a second classname (in 9.6)
-	// Also, make sure that getElementsByClassName actually exists
-	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
-		return;
-	}
-
-	// Safari caches class attributes, doesn't catch changes (in 3.2)
-	div.lastChild.className = "e";
-
-	if ( div.getElementsByClassName("e").length === 1 ) {
-		return;
-	}
-	
-	Expr.order.splice(1, 0, "CLASS");
-	Expr.find.CLASS = function(match, context, isXML) {
-		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
-			return context.getElementsByClassName(match[1]);
-		}
-	};
-
-	div = null; // release memory in IE
-})();
-
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-		var elem = checkSet[i];
-		if ( elem ) {
-			elem = elem[dir];
-			var match = false;
-
-			while ( elem ) {
-				if ( elem.sizcache === doneName ) {
-					match = checkSet[elem.sizset];
-					break;
-				}
-
-				if ( elem.nodeType === 1 && !isXML ){
-					elem.sizcache = doneName;
-					elem.sizset = i;
-				}
-
-				if ( elem.nodeName.toLowerCase() === cur ) {
-					match = elem;
-					break;
-				}
-
-				elem = elem[dir];
-			}
-
-			checkSet[i] = match;
-		}
-	}
-}
-
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
-	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
-		var elem = checkSet[i];
-		if ( elem ) {
-			elem = elem[dir];
-			var match = false;
-
-			while ( elem ) {
-				if ( elem.sizcache === doneName ) {
-					match = checkSet[elem.sizset];
-					break;
-				}
-
-				if ( elem.nodeType === 1 ) {
-					if ( !isXML ) {
-						elem.sizcache = doneName;
-						elem.sizset = i;
-					}
-					if ( typeof cur !== "string" ) {
-						if ( elem === cur ) {
-							match = true;
-							break;
-						}
-
-					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
-						match = elem;
-						break;
-					}
-				}
-
-				elem = elem[dir];
-			}
-
-			checkSet[i] = match;
-		}
-	}
-}
-
-var contains = document.compareDocumentPosition ? function(a, b){
-	return !!(a.compareDocumentPosition(b) & 16);
-} : function(a, b){
-	return a !== b && (a.contains ? a.contains(b) : true);
-};
-
-var isXML = function(elem){
-	// documentElement is verified for cases where it doesn't yet exist
-	// (such as loading iframes in IE - #4833) 
-	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
-	return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-var posProcess = function(selector, context){
-	var tmpSet = [], later = "", match,
-		root = context.nodeType ? [context] : context;
-
-	// Position selectors must be done after the filter
-	// And so must :not(positional) so we move all PSEUDOs to the end
-	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
-		later += match[0];
-		selector = selector.replace( Expr.match.PSEUDO, "" );
-	}
-
-	selector = Expr.relative[selector] ? selector + "*" : selector;
-
-	for ( var i = 0, l = root.length; i < l; i++ ) {
-		Sizzle( selector, root[i], tmpSet );
-	}
-
-	return Sizzle.filter( later, tmpSet );
-};
-
-// EXPOSE
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.filters;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = getText;
-jQuery.isXMLDoc = isXML;
-jQuery.contains = contains;
-
-return;
-
-window.Sizzle = Sizzle;
-
-})();
-var runtil = /Until$/,
-	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
-	// Note: This RegExp should be improved, or likely pulled from Sizzle
-	rmultiselector = /,/,
-	slice = Array.prototype.slice;
-
-// Implement the identical functionality for filter and not
-var winnow = function( elements, qualifier, keep ) {
-	if ( jQuery.isFunction( qualifier ) ) {
-		return jQuery.grep(elements, function( elem, i ) {
-			return !!qualifier.call( elem, i, elem ) === keep;
-		});
-
-	} else if ( qualifier.nodeType ) {
-		return jQuery.grep(elements, function( elem, i ) {
-			return (elem === qualifier) === keep;
-		});
-
-	} else if ( typeof qualifier === "string" ) {
-		var filtered = jQuery.grep(elements, function( elem ) {
-			return elem.nodeType === 1;
-		});
-
-		if ( isSimple.test( qualifier ) ) {
-			return jQuery.filter(qualifier, filtered, !keep);
-		} else {
-			qualifier = jQuery.filter( qualifier, filtered );
-		}
-	}
-
-	return jQuery.grep(elements, function( elem, i ) {
-		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
-	});
-};
-
-jQuery.fn.extend({
-	find: function( selector ) {
-		var ret = this.pushStack( "", "find", selector ), length = 0;
-
-		for ( var i = 0, l = this.length; i < l; i++ ) {
-			length = ret.length;
-			jQuery.find( selector, this[i], ret );
-
-			if ( i > 0 ) {
-				// Make sure that the results are unique
-				for ( var n = length; n < ret.length; n++ ) {
-					for ( var r = 0; r < length; r++ ) {
-						if ( ret[r] === ret[n] ) {
-							ret.splice(n--, 1);
-							break;
-						}
-					}
-				}
-			}
-		}
-
-		return ret;
-	},
-
-	has: function( target ) {
-		var targets = jQuery( target );
-		return this.filter(function() {
-			for ( var i = 0, l = targets.length; i < l; i++ ) {
-				if ( jQuery.contains( this, targets[i] ) ) {
-					return true;
-				}
-			}
-		});
-	},
-
-	not: function( selector ) {
-		return this.pushStack( winnow(this, selector, false), "not", selector);
-	},
-
-	filter: function( selector ) {
-		return this.pushStack( winnow(this, selector, true), "filter", selector );
-	},
-	
-	is: function( selector ) {
-		return !!selector && jQuery.filter( selector, this ).length > 0;
-	},
-
-	closest: function( selectors, context ) {
-		if ( jQuery.isArray( selectors ) ) {
-			var ret = [], cur = this[0], match, matches = {}, selector;
-
-			if ( cur && selectors.length ) {
-				for ( var i = 0, l = selectors.length; i < l; i++ ) {
-					selector = selectors[i];
-
-					if ( !matches[selector] ) {
-						matches[selector] = jQuery.expr.match.POS.test( selector ) ? 
-							jQuery( selector, context || this.context ) :
-							selector;
-					}
-				}
-
-				while ( cur && cur.ownerDocument && cur !== context ) {
-					for ( selector in matches ) {
-						match = matches[selector];
-
-						if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
-							ret.push({ selector: selector, elem: cur });
-							delete matches[selector];
-						}
-					}
-					cur = cur.parentNode;
-				}
-			}
-
-			return ret;
-		}
-
-		var pos = jQuery.expr.match.POS.test( selectors ) ? 
-			jQuery( selectors, context || this.context ) : null;
-
-		return this.map(function( i, cur ) {
-			while ( cur && cur.ownerDocument && cur !== context ) {
-				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
-					return cur;
-				}
-				cur = cur.parentNode;
-			}
-			return null;
-		});
-	},
-	
-	// Determine the position of an element within
-	// the matched set of elements
-	index: function( elem ) {
-		if ( !elem || typeof elem === "string" ) {
-			return jQuery.inArray( this[0],
-				// If it receives a string, the selector is used
-				// If it receives nothing, the siblings are used
-				elem ? jQuery( elem ) : this.parent().children() );
-		}
-		// Locate the position of the desired element
-		return jQuery.inArray(
-			// If it receives a jQuery object, the first element is used
-			elem.jquery ? elem[0] : elem, this );
-	},
-
-	add: function( selector, context ) {
-		var set = typeof selector === "string" ?
-				jQuery( selector, context || this.context ) :
-				jQuery.makeArray( selector ),
-			all = jQuery.merge( this.get(), set );
-
-		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
-			all :
-			jQuery.unique( all ) );
-	},
-
-	andSelf: function() {
-		return this.add( this.prevObject );
-	}
-});
-
-// A painfully simple check to see if an element is disconnected
-// from a document (should be improved, where feasible).
-function isDisconnected( node ) {
-	return !node || !node.parentNode || node.parentNode.nodeType === 11;
-}
-
-jQuery.each({
-	parent: function( elem ) {
-		var parent = elem.parentNode;
-		return parent && parent.nodeType !== 11 ? parent : null;
-	},
-	parents: function( elem ) {
-		return jQuery.dir( elem, "parentNode" );
-	},
-	parentsUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "parentNode", until );
-	},
-	next: function( elem ) {
-		return jQuery.nth( elem, 2, "nextSibling" );
-	},
-	prev: function( elem ) {
-		return jQuery.nth( elem, 2, "previousSibling" );
-	},
-	nextAll: function( elem ) {
-		return jQuery.dir( elem, "nextSibling" );
-	},
-	prevAll: function( elem ) {
-		return jQuery.dir( elem, "previousSibling" );
-	},
-	nextUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "nextSibling", until );
-	},
-	prevUntil: function( elem, i, until ) {
-		return jQuery.dir( elem, "previousSibling", until );
-	},
-	siblings: function( elem ) {
-		return jQuery.sibling( elem.parentNode.firstChild, elem );
-	},
-	children: function( elem ) {
-		return jQuery.sibling( elem.firstChild );
-	},
-	contents: function( elem ) {
-		return jQuery.nodeName( elem, "iframe" ) ?
-			elem.contentDocument || elem.contentWindow.document :
-			jQuery.makeArray( elem.childNodes );
-	}
-}, function( name, fn ) {
-	jQuery.fn[ name ] = function( until, selector ) {
-		var ret = jQuery.map( this, fn, until );
-		
-		if ( !runtil.test( name ) ) {
-			selector = until;
-		}
-
-		if ( selector && typeof selector === "string" ) {
-			ret = jQuery.filter( selector, ret );
-		}
-
-		ret = this.length > 1 ? jQuery.unique( ret ) : ret;
-
-		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
-			ret = ret.reverse();
-		}
-
-		return this.pushStack( ret, name, slice.call(arguments).join(",") );
-	};
-});
-
-jQuery.extend({
-	filter: function( expr, elems, not ) {
-		if ( not ) {
-			expr = ":not(" + expr + ")";
-		}
-
-		return jQuery.find.matches(expr, elems);
-	},
-	
-	dir: function( elem, dir, until ) {
-		var matched = [], cur = elem[dir];
-		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
-			if ( cur.nodeType === 1 ) {
-				matched.push( cur );
-			}
-			cur = cur[dir];
-		}
-		return matched;
-	},
-
-	nth: function( cur, result, dir, elem ) {
-		result = result || 1;
-		var num = 0;
-
-		for ( ; cur; cur = cur[dir] ) {
-			if ( cur.nodeType === 1 && ++num === result ) {
-				break;
-			}
-		}
-
-		return cur;
-	},
-
-	sibling: function( n, elem ) {
-		var r = [];
-
-		for ( ; n; n = n.nextSibling ) {
-			if ( n.nodeType === 1 && n !== elem ) {
-				r.push( n );
-			}
-		}
-
-		return r;
-	}
-});
-var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
-	rleadingWhitespace = /^\s+/,
-	rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
-	rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,
-	rtagName = /<([\w:]+)/,
-	rtbody = /<tbody/i,
-	rhtml = /<|&#?\w+;/,
-	rnocache = /<script|<object|<embed|<option|<style/i,
-	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,  // checked="checked" or checked (html5)
-	fcloseTag = function( all, front, tag ) {
-		return rselfClosing.test( tag ) ?
-			all :
-			front + "></" + tag + ">";
-	},
-	wrapMap = {
-		option: [ 1, "<select multiple='multiple'>", "</select>" ],
-		legend: [ 1, "<fieldset>", "</fieldset>" ],
-		thead: [ 1, "<table>", "</table>" ],
-		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
-		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
-		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
-		area: [ 1, "<map>", "</map>" ],
-		_default: [ 0, "", "" ]
-	};
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-// IE can't serialize <link> and <script> tags normally
-if ( !jQuery.support.htmlSerialize ) {
-	wrapMap._default = [ 1, "div<div>", "</div>" ];
-}
-
-jQuery.fn.extend({
-	text: function( text ) {
-		if ( jQuery.isFunction(text) ) {
-			return this.each(function(i) {
-				var self = jQuery(this);
-				self.text( text.call(this, i, self.text()) );
-			});
-		}
-
-		if ( typeof text !== "object" && text !== undefined ) {
-			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
-		}
-
-		return jQuery.text( this );
-	},
-
-	wrapAll: function( html ) {
-		if ( jQuery.isFunction( html ) ) {
-			return this.each(function(i) {
-				jQuery(this).wrapAll( html.call(this, i) );
-			});
-		}
-
-		if ( this[0] ) {
-			// The elements to wrap the target around
-			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
-
-			if ( this[0].parentNode ) {
-				wrap.insertBefore( this[0] );
-			}
-
-			wrap.map(function() {
-				var elem = this;
-
-				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
-					elem = elem.firstChild;
-				}
-
-				return elem;
-			}).append(this);
-		}
-
-		return this;
-	},
-
-	wrapInner: function( html ) {
-		if ( jQuery.isFunction( html ) ) {
-			return this.each(function(i) {
-				jQuery(this).wrapInner( html.call(this, i) );
-			});
-		}
-
-		return this.each(function() {
-			var self = jQuery( this ), contents = self.contents();
-
-			if ( contents.length ) {
-				contents.wrapAll( html );
-
-			} else {
-				self.append( html );
-			}
-		});
-	},
-
-	wrap: function( html ) {
-		return this.each(function() {
-			jQuery( this ).wrapAll( html );
-		});
-	},
-
-	unwrap: function() {
-		return this.parent().each(function() {
-			if ( !jQuery.nodeName( this, "body" ) ) {
-				jQuery( this ).replaceWith( this.childNodes );
-			}
-		}).end();
-	},
-
-	append: function() {
-		return this.domManip(arguments, true, function( elem ) {
-			if ( this.nodeType === 1 ) {
-				this.appendChild( elem );
-			}
-		});
-	},
-
-	prepend: function() {
-		return this.domManip(arguments, true, function( elem ) {
-			if ( this.nodeType === 1 ) {
-				this.insertBefore( elem, this.firstChild );
-			}
-		});
-	},
-
-	before: function() {
-		if ( this[0] && this[0].parentNode ) {
-			return this.domManip(arguments, false, function( elem ) {
-				this.parentNode.insertBefore( elem, this );
-			});
-		} else if ( arguments.length ) {
-			var set = jQuery(arguments[0]);
-			set.push.apply( set, this.toArray() );
-			return this.pushStack( set, "before", arguments );
-		}
-	},
-
-	after: function() {
-		if ( this[0] && this[0].parentNode ) {
-			return this.domManip(arguments, false, function( elem ) {
-				this.parentNode.insertBefore( elem, this.nextSibling );
-			});
-		} else if ( arguments.length ) {
-			var set = this.pushStack( this, "after", arguments );
-			set.push.apply( set, jQuery(arguments[0]).toArray() );
-			return set;
-		}
-	},
-	
-	// keepData is for internal use only--do not document
-	remove: function( selector, keepData ) {
-		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
-				if ( !keepData && elem.nodeType === 1 ) {
-					jQuery.cleanData( elem.getElementsByTagName("*") );
-					jQuery.cleanData( [ elem ] );
-				}
-
-				if ( elem.parentNode ) {
-					 elem.parentNode.removeChild( elem );
-				}
-			}
-		}
-		
-		return this;
-	},
-
-	empty: function() {
-		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
-			// Remove element nodes and prevent memory leaks
-			if ( elem.nodeType === 1 ) {
-				jQuery.cleanData( elem.getElementsByTagName("*") );
-			}
-
-			// Remove any remaining nodes
-			while ( elem.firstChild ) {
-				elem.removeChild( elem.firstChild );
-			}
-		}
-		
-		return this;
-	},
-
-	clone: function( events ) {
-		// Do the clone
-		var ret = this.map(function() {
-			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
-				// IE copies events bound via attachEvent when
-				// using cloneNode. Calling detachEvent on the
-				// clone will also remove the events from the orignal
-				// In order to get around this, we use innerHTML.
-				// Unfortunately, this means some modifications to
-				// attributes in IE that are actually only stored
-				// as properties will not be copied (such as the
-				// the name attribute on an input).
-				var html = this.outerHTML, ownerDocument = this.ownerDocument;
-				if ( !html ) {
-					var div = ownerDocument.createElement("div");
-					div.appendChild( this.cloneNode(true) );
-					html = div.innerHTML;
-				}
-
-				return jQuery.clean([html.replace(rinlinejQuery, "")
-					// Handle the case in IE 8 where action=/test/> self-closes a tag
-					.replace(/=([^="'>\s]+\/)>/g, '="$1">')
-					.replace(rleadingWhitespace, "")], ownerDocument)[0];
-			} else {
-				return this.cloneNode(true);
-			}
-		});
-
-		// Copy the events from the original to the clone
-		if ( events === true ) {
-			cloneCopyEvent( this, ret );
-			cloneCopyEvent( this.find("*"), ret.find("*") );
-		}
-
-		// Return the cloned set
-		return ret;
-	},
-
-	html: function( value ) {
-		if ( value === undefined ) {
-			return this[0] && this[0].nodeType === 1 ?
-				this[0].innerHTML.replace(rinlinejQuery, "") :
-				null;
-
-		// See if we can take a shortcut and just use innerHTML
-		} else if ( typeof value === "string" && !rnocache.test( value ) &&
-			(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
-			!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
-
-			value = value.replace(rxhtmlTag, fcloseTag);
-
-			try {
-				for ( var i = 0, l = this.length; i < l; i++ ) {
-					// Remove element nodes and prevent memory leaks
-					if ( this[i].nodeType === 1 ) {
-						jQuery.cleanData( this[i].getElementsByTagName("*") );
-						this[i].innerHTML = value;
-					}
-				}
-
-			// If using innerHTML throws an exception, use the fallback method
-			} catch(e) {
-				this.empty().append( value );
-			}
-
-		} else if ( jQuery.isFunction( value ) ) {
-			this.each(function(i){
-				var self = jQuery(this), old = self.html();
-				self.empty().append(function(){
-					return value.call( this, i, old );
-				});
-			});
-
-		} else {
-			this.empty().append( value );
-		}
-
-		return this;
-	},
-
-	replaceWith: function( value ) {
-		if ( this[0] && this[0].parentNode ) {
-			// Make sure that the elements are removed from the DOM before they are inserted
-			// this can help fix replacing a parent with child elements
-			if ( jQuery.isFunction( value ) ) {
-				return this.each(function(i) {
-					var self = jQuery(this), old = self.html();
-					self.replaceWith( value.call( this, i, old ) );
-				});
-			}
-
-			if ( typeof value !== "string" ) {
-				value = jQuery(value).detach();
-			}
-
-			return this.each(function() {
-				var next = this.nextSibling, parent = this.parentNode;
-
-				jQuery(this).remove();
-
-				if ( next ) {
-					jQuery(next).before( value );
-				} else {
-					jQuery(parent).append( value );
-				}
-			});
-		} else {
-			return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
-		}
-	},
-
-	detach: function( selector ) {
-		return this.remove( selector, true );
-	},
-
-	domManip: function( args, table, callback ) {
-		var results, first, value = args[0], scripts = [], fragment, parent;
-
-		// We can't cloneNode fragments that contain checked, in WebKit
-		if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
-			return this.each(function() {
-				jQuery(this).domManip( args, table, callback, true );
-			});
-		}
-
-		if ( jQuery.isFunction(value) ) {
-			return this.each(function(i) {
-				var self = jQuery(this);
-				args[0] = value.call(this, i, table ? self.html() : undefined);
-				self.domManip( args, table, callback );
-			});
-		}
-
-		if ( this[0] ) {
-			parent = value && value.parentNode;
-
-			// If we're in a fragment, just use that instead of building a new one
-			if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
-				results = { fragment: parent };
-
-			} else {
-				results = buildFragment( args, this, scripts );
-			}
-			
-			fragment = results.fragment;
-			
-			if ( fragment.childNodes.length === 1 ) {
-				first = fragment = fragment.firstChild;
-			} else {
-				first = fragment.firstChild;
-			}
-
-			if ( first ) {
-				table = table && jQuery.nodeName( first, "tr" );
-
-				for ( var i = 0, l = this.length; i < l; i++ ) {
-					callback.call(
-						table ?
-							root(this[i], first) :
-							this[i],
-						i > 0 || results.cacheable || this.length > 1  ?
-							fragment.cloneNode(true) :
-							fragment
-					);
-				}
-			}
-
-			if ( scripts.length ) {
-				jQuery.each( scripts, evalScript );
-			}
-		}
-
-		return this;
-
-		function root( elem, cur ) {
-			return jQuery.nodeName(elem, "table") ?
-				(elem.getElementsByTagName("tbody")[0] ||
-				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
-				elem;
-		}
-	}
-});
-
-function cloneCopyEvent(orig, ret) {
-	var i = 0;
-
-	ret.each(function() {
-		if ( this.nodeName !== (orig[i] && orig[i].nodeName) ) {
-			return;
-		}
-
-		var oldData = jQuery.data( orig[i++] ), curData = jQuery.data( this, oldData ), events = oldData && oldData.events;
-
-		if ( events ) {
-			delete curData.handle;
-			curData.events = {};
-
-			for ( var type in events ) {
-				for ( var handler in events[ type ] ) {
-					jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
-				}
-			}
-		}
-	});
-}
-
-function buildFragment( args, nodes, scripts ) {
-	var fragment, cacheable, cacheresults,
-		doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
-
-	// Only cache "small" (1/2 KB) strings that are associated with the main document
-	// Cloning options loses the selected state, so don't cache them
-	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
-	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
-	if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
-		!rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
-
-		cacheable = true;
-		cacheresults = jQuery.fragments[ args[0] ];
-		if ( cacheresults ) {
-			if ( cacheresults !== 1 ) {
-				fragment = cacheresults;
-			}
-		}
-	}
-
-	if ( !fragment ) {
-		fragment = doc.createDocumentFragment();
-		jQuery.clean( args, doc, fragment, scripts );
-	}
-
-	if ( cacheable ) {
-		jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
-	}
-
-	return { fragment: fragment, cacheable: cacheable };
-}
-
-jQuery.fragments = {};
-
-jQuery.each({
-	appendTo: "append",
-	prependTo: "prepend",
-	insertBefore: "before",
-	insertAfter: "after",
-	replaceAll: "replaceWith"
-}, function( name, original ) {
-	jQuery.fn[ name ] = function( selector ) {
-		var ret = [], insert = jQuery( selector ),
-			parent = this.length === 1 && this[0].parentNode;
-		
-		if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
-			insert[ original ]( this[0] );
-			return this;
-			
-		} else {
-			for ( var i = 0, l = insert.length; i < l; i++ ) {
-				var elems = (i > 0 ? this.clone(true) : this).get();
-				jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
-				ret = ret.concat( elems );
-			}
-		
-			return this.pushStack( ret, name, insert.selector );
-		}
-	};
-});
-
-jQuery.extend({
-	clean: function( elems, context, fragment, scripts ) {
-		context = context || document;
-
-		// !context.createElement fails in IE with an error but returns typeof 'object'
-		if ( typeof context.createElement === "undefined" ) {
-			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
-		}
-
-		var ret = [];
-
-		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-			if ( typeof elem === "number" ) {
-				elem += "";
-			}
-
-			if ( !elem ) {
-				continue;
-			}
-
-			// Convert html string into DOM nodes
-			if ( typeof elem === "string" && !rhtml.test( elem ) ) {
-				elem = context.createTextNode( elem );
-
-			} else if ( typeof elem === "string" ) {
-				// Fix "XHTML"-style tags in all browsers
-				elem = elem.replace(rxhtmlTag, fcloseTag);
-
-				// Trim whitespace, otherwise indexOf won't work as expected
-				var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
-					wrap = wrapMap[ tag ] || wrapMap._default,
-					depth = wrap[0],
-					div = context.createElement("div");
-
-				// Go to html and back, then peel off extra wrappers
-				div.innerHTML = wrap[1] + elem + wrap[2];
-
-				// Move to the right depth
-				while ( depth-- ) {
-					div = div.lastChild;
-				}
-
-				// Remove IE's autoinserted <tbody> from table fragments
-				if ( !jQuery.support.tbody ) {
-
-					// String was a <table>, *may* have spurious <tbody>
-					var hasBody = rtbody.test(elem),
-						tbody = tag === "table" && !hasBody ?
-							div.firstChild && div.firstChild.childNodes :
-
-							// String was a bare <thead> or <tfoot>
-							wrap[1] === "<table>" && !hasBody ?
-								div.childNodes :
-								[];
-
-					for ( var j = tbody.length - 1; j >= 0 ; --j ) {
-						if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
-							tbody[ j ].parentNode.removeChild( tbody[ j ] );
-						}
-					}
-
-				}
-
-				// IE completely kills leading whitespace when innerHTML is used
-				if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
-					div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
-				}
-
-				elem = div.childNodes;
-			}
-
-			if ( elem.nodeType ) {
-				ret.push( elem );
-			} else {
-				ret = jQuery.merge( ret, elem );
-			}
-		}
-
-		if ( fragment ) {
-			for ( var i = 0; ret[i]; i++ ) {
-				if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
-					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
-				
-				} else {
-					if ( ret[i].nodeType === 1 ) {
-						ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
-					}
-					fragment.appendChild( ret[i] );
-				}
-			}
-		}
-
-		return ret;
-	},
-	
-	cleanData: function( elems ) {
-		var data, id, cache = jQuery.cache,
-			special = jQuery.event.special,
-			deleteExpando = jQuery.support.deleteExpando;
-		
-		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
-			id = elem[ jQuery.expando ];
-			
-			if ( id ) {
-				data = cache[ id ];
-				
-				if ( data.events ) {
-					for ( var type in data.events ) {
-						if ( special[ type ] ) {
-							jQuery.event.remove( elem, type );
-
-						} else {
-							removeEvent( elem, type, data.handle );
-						}
-					}
-				}
-				
-				if ( deleteExpando ) {
-					delete elem[ jQuery.expando ];
-
-				} else if ( elem.removeAttribute ) {
-					elem.removeAttribute( jQuery.expando );
-				}
-				
-				delete cache[ id ];
-			}
-		}
-	}
-});
-// exclude the following css properties to add px
-var rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
-	ralpha = /alpha\([^)]*\)/,
-	ropacity = /opacity=([^)]*)/,
-	rfloat = /float/i,
-	rdashAlpha = /-([a-z])/ig,
-	rupper = /([A-Z])/g,
-	rnumpx = /^-?\d+(?:px)?$/i,
-	rnum = /^-?\d/,
-
-	cssShow = { position: "absolute", visibility: "hidden", display:"block" },
-	cssWidth = [ "Left", "Right" ],
-	cssHeight = [ "Top", "Bottom" ],
-
-	// cache check for defaultView.getComputedStyle
-	getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
-	// normalize float css property
-	styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat",
-	fcamelCase = function( all, letter ) {
-		return letter.toUpperCase();
-	};
-
-jQuery.fn.css = function( name, value ) {
-	return access( this, name, value, true, function( elem, name, value ) {
-		if ( value === undefined ) {
-			return jQuery.curCSS( elem, name );
-		}
-		
-		if ( typeof value === "number" && !rexclude.test(name) ) {
-			value += "px";
-		}
-
-		jQuery.style( elem, name, value );
-	});
-};
-
-jQuery.extend({
-	style: function( elem, name, value ) {
-		// don't set styles on text and comment nodes
-		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
-			return undefined;
-		}
-
-		// ignore negative width and height values #1599
-		if ( (name === "width" || name === "height") && parseFloat(value) < 0 ) {
-			value = undefined;
-		}
-
-		var style = elem.style || elem, set = value !== undefined;
-
-		// IE uses filters for opacity
-		if ( !jQuery.support.opacity && name === "opacity" ) {
-			if ( set ) {
-				// IE has trouble with opacity if it does not have layout
-				// Force it by setting the zoom level
-				style.zoom = 1;
-
-				// Set the alpha filter to set the opacity
-				var opacity = parseInt( value, 10 ) + "" === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";
-				var filter = style.filter || jQuery.curCSS( elem, "filter" ) || "";
-				style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;
-			}
-
-			return style.filter && style.filter.indexOf("opacity=") >= 0 ?
-				(parseFloat( ropacity.exec(style.filter)[1] ) / 100) + "":
-				"";
-		}
-
-		// Make sure we're using the right name for getting the float value
-		if ( rfloat.test( name ) ) {
-			name = styleFloat;
-		}
-
-		name = name.replace(rdashAlpha, fcamelCase);
-
-		if ( set ) {
-			style[ name ] = value;
-		}
-
-		return style[ name ];
-	},
-
-	css: function( elem, name, force, extra ) {
-		if ( name === "width" || name === "height" ) {
-			var val, props = cssShow, which = name === "width" ? cssWidth : cssHeight;
-
-			function getWH() {
-				val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
-
-				if ( extra === "border" ) {
-					return;
-				}
-
-				jQuery.each( which, function() {
-					if ( !extra ) {
-						val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
-					}
-
-					if ( extra === "margin" ) {
-						val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
-					} else {
-						val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
-					}
-				});
-			}
-
-			if ( elem.offsetWidth !== 0 ) {
-				getWH();
-			} else {
-				jQuery.swap( elem, props, getWH );
-			}
-
-			return Math.max(0, Math.round(val));
-		}
-
-		return jQuery.curCSS( elem, name, force );
-	},
-
-	curCSS: function( elem, name, force ) {
-		var ret, style = elem.style, filter;
-
-		// IE uses filters for opacity
-		if ( !jQuery.support.opacity && name === "opacity" && elem.currentStyle ) {
-			ret = ropacity.test(elem.currentStyle.filter || "") ?
-				(parseFloat(RegExp.$1) / 100) + "" :
-				"";
-
-			return ret === "" ?
-				"1" :
-				ret;
-		}
-
-		// Make sure we're using the right name for getting the float value
-		if ( rfloat.test( name ) ) {
-			name = styleFloat;
-		}
-
-		if ( !force && style && style[ name ] ) {
-			ret = style[ name ];
-
-		} else if ( getComputedStyle ) {
-
-			// Only "float" is needed here
-			if ( rfloat.test( name ) ) {
-				name = "float";
-			}
-
-			name = name.replace( rupper, "-$1" ).toLowerCase();
-
-			var defaultView = elem.ownerDocument.defaultView;
-
-			if ( !defaultView ) {
-				return null;
-			}
-
-			var computedStyle = defaultView.getComputedStyle( elem, null );
-
-			if ( computedStyle ) {
-				ret = computedStyle.getPropertyValue( name );
-			}
-
-			// We should always get a number back from opacity
-			if ( name === "opacity" && ret === "" ) {
-				ret = "1";
-			}
-
-		} else if ( elem.currentStyle ) {
-			var camelCase = name.replace(rdashAlpha, fcamelCase);
-
-			ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
-
-			// From the awesome hack by Dean Edwards
-			// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
-			// If we're not dealing with a regular pixel number
-			// but a number that has a weird ending, we need to convert it to pixels
-			if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
-				// Remember the original values
-				var left = style.left, rsLeft = elem.runtimeStyle.left;
-
-				// Put in the new values to get a computed value out
-				elem.runtimeStyle.left = elem.currentStyle.left;
-				style.left = camelCase === "fontSize" ? "1em" : (ret || 0);
-				ret = style.pixelLeft + "px";
-
-				// Revert the changed values
-				style.left = left;
-				elem.runtimeStyle.left = rsLeft;
-			}
-		}
-
-		return ret;
-	},
-
-	// A method for quickly swapping in/out CSS properties to get correct calculations
-	swap: function( elem, options, callback ) {
-		var old = {};
-
-		// Remember the old values, and insert the new ones
-		for ( var name in options ) {
-			old[ name ] = elem.style[ name ];
-			elem.style[ name ] = options[ name ];
-		}
-
-		callback.call( elem );
-
-		// Revert the old values
-		for ( var name in options ) {
-			elem.style[ name ] = old[ name ];
-		}
-	}
-});
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-	jQuery.expr.filters.hidden = function( elem ) {
-		var width = elem.offsetWidth, height = elem.offsetHeight,
-			skip = elem.nodeName.toLowerCase() === "tr";
-
-		return width === 0 && height === 0 && !skip ?
-			true :
-			width > 0 && height > 0 && !skip ?
-				false :
-				jQuery.curCSS(elem, "display") === "none";
-	};
-
-	jQuery.expr.filters.visible = function( elem ) {
-		return !jQuery.expr.filters.hidden( elem );
-	};
-}
-var jsc = now(),
-	rscript = /<script(.|\s)*?\/script>/gi,
-	rselectTextarea = /select|textarea/i,
-	rinput = /color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,
-	jsre = /=\?(&|$)/,
-	rquery = /\?/,
-	rts = /(\?|&)_=.*?(&|$)/,
-	rurl = /^(\w+:)?\/\/([^\/?#]+)/,
-	r20 = /%20/g,
-
-	// Keep a copy of the old load method
-	_load = jQuery.fn.load;
-
-jQuery.fn.extend({
-	load: function( url, params, callback ) {
-		if ( typeof url !== "string" ) {
-			return _load.call( this, url );
-
-		// Don't do a request if no elements are being requested
-		} else if ( !this.length ) {
-			return this;
-		}
-
-		var off = url.indexOf(" ");
-		if ( off >= 0 ) {
-			var selector = url.slice(off, url.length);
-			url = url.slice(0, off);
-		}
-
-		// Default to a GET request
-		var type = "GET";
-
-		// If the second parameter was provided
-		if ( params ) {
-			// If it's a function
-			if ( jQuery.isFunction( params ) ) {
-				// We assume that it's the callback
-				callback = params;
-				params = null;
-
-			// Otherwise, build a param string
-			} else if ( typeof params === "object" ) {
-				params = jQuery.param( params, jQuery.ajaxSettings.traditional );
-				type = "POST";
-			}
-		}
-
-		var self = this;
-
-		// Request the remote document
-		jQuery.ajax({
-			url: url,
-			type: type,
-			dataType: "html",
-			data: params,
-			complete: function( res, status ) {
-				// If successful, inject the HTML into all the matched elements
-				if ( status === "success" || status === "notmodified" ) {
-					// See if a selector was specified
-					self.html( selector ?
-						// Create a dummy div to hold the results
-						jQuery("<div />")
-							// inject the contents of the document in, removing the scripts
-							// to avoid any 'Permission Denied' errors in IE
-							.append(res.responseText.replace(rscript, ""))
-
-							// Locate the specified elements
-							.find(selector) :
-
-						// If not, just inject the full result
-						res.responseText );
-				}
-
-				if ( callback ) {
-					self.each( callback, [res.responseText, status, res] );
-				}
-			}
-		});
-
-		return this;
-	},
-
-	serialize: function() {
-		return jQuery.param(this.serializeArray());
-	},
-	serializeArray: function() {
-		return this.map(function() {
-			return this.elements ? jQuery.makeArray(this.elements) : this;
-		})
-		.filter(function() {
-			return this.name && !this.disabled &&
-				(this.checked || rselectTextarea.test(this.nodeName) ||
-					rinput.test(this.type));
-		})
-		.map(function( i, elem ) {
-			var val = jQuery(this).val();
-
-			return val == null ?
-				null :
-				jQuery.isArray(val) ?
-					jQuery.map( val, function( val, i ) {
-						return { name: elem.name, value: val };
-					}) :
-					{ name: elem.name, value: val };
-		}).get();
-	}
-});
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function( i, o ) {
-	jQuery.fn[o] = function( f ) {
-		return this.bind(o, f);
-	};
-});
-
-jQuery.extend({
-
-	get: function( url, data, callback, type ) {
-		// shift arguments if data argument was omited
-		if ( jQuery.isFunction( data ) ) {
-			type = type || callback;
-			callback = data;
-			data = null;
-		}
-
-		return jQuery.ajax({
-			type: "GET",
-			url: url,
-			data: data,
-			success: callback,
-			dataType: type
-		});
-	},
-
-	getScript: function( url, callback ) {
-		return jQuery.get(url, null, callback, "script");
-	},
-
-	getJSON: function( url, data, callback ) {
-		return jQuery.get(url, data, callback, "json");
-	},
-
-	post: function( url, data, callback, type ) {
-		// shift arguments if data argument was omited
-		if ( jQuery.isFunction( data ) ) {
-			type = type || callback;
-			callback = data;
-			data = {};
-		}
-
-		return jQuery.ajax({
-			type: "POST",
-			url: url,
-			data: data,
-			success: callback,
-			dataType: type
-		});
-	},
-
-	ajaxSetup: function( settings ) {
-		jQuery.extend( jQuery.ajaxSettings, settings );
-	},
-
-	ajaxSettings: {
-		url: location.href,
-		global: true,
-		type: "GET",
-		contentType: "application/x-www-form-urlencoded",
-		processData: true,
-		async: true,
-		/*
-		timeout: 0,
-		data: null,
-		username: null,
-		password: null,
-		traditional: false,
-		*/
-		// Create the request object; Microsoft failed to properly
-		// implement the XMLHttpRequest in IE7 (can't request local files),
-		// so we use the ActiveXObject when it is available
-		// This function can be overriden by calling jQuery.ajaxSetup
-		xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?
-			function() {
-				return new window.XMLHttpRequest();
-			} :
-			function() {
-				try {
-					return new window.ActiveXObject("Microsoft.XMLHTTP");
-				} catch(e) {}
-			},
-		accepts: {
-			xml: "application/xml, text/xml",
-			html: "text/html",
-			script: "text/javascript, application/javascript",
-			json: "application/json, text/javascript",
-			text: "text/plain",
-			_default: "*/*"
-		}
-	},
-
-	// Last-Modified header cache for next request
-	lastModified: {},
-	etag: {},
-
-	ajax: function( origSettings ) {
-		var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
-		
-		var jsonp, status, data,
-			callbackContext = origSettings && origSettings.context || s,
-			type = s.type.toUpperCase();
-
-		// convert data if not already a string
-		if ( s.data && s.processData && typeof s.data !== "string" ) {
-			s.data = jQuery.param( s.data, s.traditional );
-		}
-
-		// Handle JSONP Parameter Callbacks
-		if ( s.dataType === "jsonp" ) {
-			if ( type === "GET" ) {
-				if ( !jsre.test( s.url ) ) {
-					s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
-				}
-			} else if ( !s.data || !jsre.test(s.data) ) {
-				s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
-			}
-			s.dataType = "json";
-		}
-
-		// Build temporary JSONP function
-		if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
-			jsonp = s.jsonpCallback || ("jsonp" + jsc++);
-
-			// Replace the =? sequence both in the query string and the data
-			if ( s.data ) {
-				s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
-			}
-
-			s.url = s.url.replace(jsre, "=" + jsonp + "$1");
-
-			// We need to make sure
-			// that a JSONP style response is executed properly
-			s.dataType = "script";
-
-			// Handle JSONP-style loading
-			window[ jsonp ] = window[ jsonp ] || function( tmp ) {
-				data = tmp;
-				success();
-				complete();
-				// Garbage collect
-				window[ jsonp ] = undefined;
-
-				try {
-					delete window[ jsonp ];
-				} catch(e) {}
-
-				if ( head ) {
-					head.removeChild( script );
-				}
-			};
-		}
-
-		if ( s.dataType === "script" && s.cache === null ) {
-			s.cache = false;
-		}
-
-		if ( s.cache === false && type === "GET" ) {
-			var ts = now();
-
-			// try replacing _= if it is there
-			var ret = s.url.replace(rts, "$1_=" + ts + "$2");
-
-			// if nothing was replaced, add timestamp to the end
-			s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
-		}
-
-		// If data is available, append data to url for get requests
-		if ( s.data && type === "GET" ) {
-			s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
-		}
-
-		// Watch for a new set of requests
-		if ( s.global && ! jQuery.active++ ) {
-			jQuery.event.trigger( "ajaxStart" );
-		}
-
-		// Matches an absolute URL, and saves the domain
-		var parts = rurl.exec( s.url ),
-			remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
-
-		// If we're requesting a remote document
-		// and trying to load JSON or Script with a GET
-		if ( s.dataType === "script" && type === "GET" && remote ) {
-			var head = document.getElementsByTagName("head")[0] || document.documentElement;
-			var script = document.createElement("script");
-			script.src = s.url;
-			if ( s.scriptCharset ) {
-				script.charset = s.scriptCharset;
-			}
-
-			// Handle Script loading
-			if ( !jsonp ) {
-				var done = false;
-
-				// Attach handlers for all browsers
-				script.onload = script.onreadystatechange = function() {
-					if ( !done && (!this.readyState ||
-							this.readyState === "loaded" || this.readyState === "complete") ) {
-						done = true;
-						success();
-						complete();
-
-						// Handle memory leak in IE
-						script.onload = script.onreadystatechange = null;
-						if ( head && script.parentNode ) {
-							head.removeChild( script );
-						}
-					}
-				};
-			}
-
-			// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
-			// This arises when a base node is used (#2709 and #4378).
-			head.insertBefore( script, head.firstChild );
-
-			// We handle everything using the script element injection
-			return undefined;
-		}
-
-		var requestDone = false;
-
-		// Create the request object
-		var xhr = s.xhr();
-
-		if ( !xhr ) {
-			return;
-		}
-
-		// Open the socket
-		// Passing null username, generates a login popup on Opera (#2865)
-		if ( s.username ) {
-			xhr.open(type, s.url, s.async, s.username, s.password);
-		} else {
-			xhr.open(type, s.url, s.async);
-		}
-
-		// Need an extra try/catch for cross domain requests in Firefox 3
-		try {
-			// Set the correct header, if data is being sent
-			if ( s.data || origSettings && origSettings.contentType ) {
-				xhr.setRequestHeader("Content-Type", s.contentType);
-			}
-
-			// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-			if ( s.ifModified ) {
-				if ( jQuery.lastModified[s.url] ) {
-					xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
-				}
-
-				if ( jQuery.etag[s.url] ) {
-					xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
-				}
-			}
-
-			// Set header so the called script knows that it's an XMLHttpRequest
-			// Only send the header if it's not a remote XHR
-			if ( !remote ) {
-				xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
-			}
-
-			// Set the Accepts header for the server, depending on the dataType
-			xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
-				s.accepts[ s.dataType ] + ", */*" :
-				s.accepts._default );
-		} catch(e) {}
-
-		// Allow custom headers/mimetypes and early abort
-		if ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {
-			// Handle the global AJAX counter
-			if ( s.global && ! --jQuery.active ) {
-				jQuery.event.trigger( "ajaxStop" );
-			}
-
-			// close opended socket
-			xhr.abort();
-			return false;
-		}
-
-		if ( s.global ) {
-			trigger("ajaxSend", [xhr, s]);
-		}
-
-		// Wait for a response to come back
-		var onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {
-			// The request was aborted
-			if ( !xhr || xhr.readyState === 0 || isTimeout === "abort" ) {
-				// Opera doesn't call onreadystatechange before this point
-				// so we simulate the call
-				if ( !requestDone ) {
-					complete();
-				}
-
-				requestDone = true;
-				if ( xhr ) {
-					xhr.onreadystatechange = jQuery.noop;
-				}
-
-			// The transfer is complete and the data is available, or the request timed out
-			} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
-				requestDone = true;
-				xhr.onreadystatechange = jQuery.noop;
-
-				status = isTimeout === "timeout" ?
-					"timeout" :
-					!jQuery.httpSuccess( xhr ) ?
-						"error" :
-						s.ifModified && jQuery.httpNotModified( xhr, s.url ) ?
-							"notmodified" :
-							"success";
-
-				var errMsg;
-
-				if ( status === "success" ) {
-					// Watch for, and catch, XML document parse errors
-					try {
-						// process the data (runs the xml through httpData regardless of callback)
-						data = jQuery.httpData( xhr, s.dataType, s );
-					} catch(err) {
-						status = "parsererror";
-						errMsg = err;
-					}
-				}
-
-				// Make sure that the request was successful or notmodified
-				if ( status === "success" || status === "notmodified" ) {
-					// JSONP handles its own success callback
-					if ( !jsonp ) {
-						success();
-					}
-				} else {
-					jQuery.handleError(s, xhr, status, errMsg);
-				}
-
-				// Fire the complete handlers
-				complete();
-
-				if ( isTimeout === "timeout" ) {
-					xhr.abort();
-				}
-
-				// Stop memory leaks
-				if ( s.async ) {
-					xhr = null;
-				}
-			}
-		};
-
-		// Override the abort handler, if we can (IE doesn't allow it, but that's OK)
-		// Opera doesn't fire onreadystatechange at all on abort
-		try {
-			var oldAbort = xhr.abort;
-			xhr.abort = function() {
-				if ( xhr ) {
-					oldAbort.call( xhr );
-				}
-
-				onreadystatechange( "abort" );
-			};
-		} catch(e) { }
-
-		// Timeout checker
-		if ( s.async && s.timeout > 0 ) {
-			setTimeout(function() {
-				// Check to see if the request is still happening
-				if ( xhr && !requestDone ) {
-					onreadystatechange( "timeout" );
-				}
-			}, s.timeout);
-		}
-
-		// Send the data
-		try {
-			xhr.send( type === "POST" || type === "PUT" || type === "DELETE" ? s.data : null );
-		} catch(e) {
-			jQuery.handleError(s, xhr, null, e);
-			// Fire the complete handlers
-			complete();
-		}
-
-		// firefox 1.5 doesn't fire statechange for sync requests
-		if ( !s.async ) {
-			onreadystatechange();
-		}
-
-		function success() {
-			// If a local callback was specified, fire it and pass it the data
-			if ( s.success ) {
-				s.success.call( callbackContext, data, status, xhr );
-			}
-
-			// Fire the global callback
-			if ( s.global ) {
-				trigger( "ajaxSuccess", [xhr, s] );
-			}
-		}
-
-		function complete() {
-			// Process result
-			if ( s.complete ) {
-				s.complete.call( callbackContext, xhr, status);
-			}
-
-			// The request was completed
-			if ( s.global ) {
-				trigger( "ajaxComplete", [xhr, s] );
-			}
-
-			// Handle the global AJAX counter
-			if ( s.global && ! --jQuery.active ) {
-				jQuery.event.trigger( "ajaxStop" );
-			}
-		}
-		
-		function trigger(type, args) {
-			(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
-		}
-
-		// return XMLHttpRequest to allow aborting the request etc.
-		return xhr;
-	},
-
-	handleError: function( s, xhr, status, e ) {
-		// If a local callback was specified, fire it
-		if ( s.error ) {
-			s.error.call( s.context || s, xhr, status, e );
-		}
-
-		// Fire the global callback
-		if ( s.global ) {
-			(s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );
-		}
-	},
-
-	// Counter for holding the number of active queries
-	active: 0,
-
-	// Determines if an XMLHttpRequest was successful or not
-	httpSuccess: function( xhr ) {
-		try {
-			// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
-			return !xhr.status && location.protocol === "file:" ||
-				// Opera returns 0 when status is 304
-				( xhr.status >= 200 && xhr.status < 300 ) ||
-				xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
-		} catch(e) {}
-
-		return false;
-	},
-
-	// Determines if an XMLHttpRequest returns NotModified
-	httpNotModified: function( xhr, url ) {
-		var lastModified = xhr.getResponseHeader("Last-Modified"),
-			etag = xhr.getResponseHeader("Etag");
-
-		if ( lastModified ) {
-			jQuery.lastModified[url] = lastModified;
-		}
-
-		if ( etag ) {
-			jQuery.etag[url] = etag;
-		}
-
-		// Opera returns 0 when status is 304
-		return xhr.status === 304 || xhr.status === 0;
-	},
-
-	httpData: function( xhr, type, s ) {
-		var ct = xhr.getResponseHeader("content-type") || "",
-			xml = type === "xml" || !type && ct.indexOf("xml") >= 0,
-			data = xml ? xhr.responseXML : xhr.responseText;
-
-		if ( xml && data.documentElement.nodeName === "parsererror" ) {
-			jQuery.error( "parsererror" );
-		}
-
-		// Allow a pre-filtering function to sanitize the response
-		// s is checked to keep backwards compatibility
-		if ( s && s.dataFilter ) {
-			data = s.dataFilter( data, type );
-		}
-
-		// The filter can actually parse the response
-		if ( typeof data === "string" ) {
-			// Get the JavaScript object, if JSON is used.
-			if ( type === "json" || !type && ct.indexOf("json") >= 0 ) {
-				data = jQuery.parseJSON( data );
-
-			// If the type is "script", eval it in global context
-			} else if ( type === "script" || !type && ct.indexOf("javascript") >= 0 ) {
-				jQuery.globalEval( data );
-			}
-		}
-
-		return data;
-	},
-
-	// Serialize an array of form elements or a set of
-	// key/values into a query string
-	param: function( a, traditional ) {
-		var s = [];
-		
-		// Set traditional to true for jQuery <= 1.3.2 behavior.
-		if ( traditional === undefined ) {
-			traditional = jQuery.ajaxSettings.traditional;
-		}
-		
-		// If an array was passed in, assume that it is an array of form elements.
-		if ( jQuery.isArray(a) || a.jquery ) {
-			// Serialize the form elements
-			jQuery.each( a, function() {
-				add( this.name, this.value );
-			});
-			
-		} else {
-			// If traditional, encode the "old" way (the way 1.3.2 or older
-			// did it), otherwise encode params recursively.
-			for ( var prefix in a ) {
-				buildParams( prefix, a[prefix] );
-			}
-		}
-
-		// Return the resulting serialization
-		return s.join("&").replace(r20, "+");
-
-		function buildParams( prefix, obj ) {
-			if ( jQuery.isArray(obj) ) {
-				// Serialize array item.
-				jQuery.each( obj, function( i, v ) {
-					if ( traditional || /\[\]$/.test( prefix ) ) {
-						// Treat each array item as a scalar.
-						add( prefix, v );
-					} else {
-						// If array item is non-scalar (array or object), encode its
-						// numeric index to resolve deserialization ambiguity issues.
-						// Note that rack (as of 1.0.0) can't currently deserialize
-						// nested arrays properly, and attempting to do so may cause
-						// a server error. Possible fixes are to modify rack's
-						// deserialization algorithm or to provide an option or flag
-						// to force array serialization to be shallow.
-						buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v );
-					}
-				});
-					
-			} else if ( !traditional && obj != null && typeof obj === "object" ) {
-				// Serialize object item.
-				jQuery.each( obj, function( k, v ) {
-					buildParams( prefix + "[" + k + "]", v );
-				});
-					
-			} else {
-				// Serialize scalar item.
-				add( prefix, obj );
-			}
-		}
-
-		function add( key, value ) {
-			// If value is a function, invoke it and return its value
-			value = jQuery.isFunction(value) ? value() : value;
-			s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
-		}
-	}
-});
-var elemdisplay = {},
-	rfxtypes = /toggle|show|hide/,
-	rfxnum = /^([+-]=)?([\d+-.]+)(.*)$/,
-	timerId,
-	fxAttrs = [
-		// height animations
-		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
-		// width animations
-		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
-		// opacity animations
-		[ "opacity" ]
-	];
-
-jQuery.fn.extend({
-	show: function( speed, callback ) {
-		if ( speed || speed === 0) {
-			return this.animate( genFx("show", 3), speed, callback);
-
-		} else {
-			for ( var i = 0, l = this.length; i < l; i++ ) {
-				var old = jQuery.data(this[i], "olddisplay");
-
-				this[i].style.display = old || "";
-
-				if ( jQuery.css(this[i], "display") === "none" ) {
-					var nodeName = this[i].nodeName, display;
-
-					if ( elemdisplay[ nodeName ] ) {
-						display = elemdisplay[ nodeName ];
-
-					} else {
-						var elem = jQuery("<" + nodeName + " />").appendTo("body");
-
-						display = elem.css("display");
-
-						if ( display === "none" ) {
-							display = "block";
-						}
-
-						elem.remove();
-
-						elemdisplay[ nodeName ] = display;
-					}
-
-					jQuery.data(this[i], "olddisplay", display);
-				}
-			}
-
-			// Set the display of the elements in a second loop
-			// to avoid the constant reflow
-			for ( var j = 0, k = this.length; j < k; j++ ) {
-				this[j].style.display = jQuery.data(this[j], "olddisplay") || "";
-			}
-
-			return this;
-		}
-	},
-
-	hide: function( speed, callback ) {
-		if ( speed || speed === 0 ) {
-			return this.animate( genFx("hide", 3), speed, callback);
-
-		} else {
-			for ( var i = 0, l = this.length; i < l; i++ ) {
-				var old = jQuery.data(this[i], "olddisplay");
-				if ( !old && old !== "none" ) {
-					jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
-				}
-			}
-
-			// Set the display of the elements in a second loop
-			// to avoid the constant reflow
-			for ( var j = 0, k = this.length; j < k; j++ ) {
-				this[j].style.display = "none";
-			}
-
-			return this;
-		}
-	},
-
-	// Save the old toggle function
-	_toggle: jQuery.fn.toggle,
-
-	toggle: function( fn, fn2 ) {
-		var bool = typeof fn === "boolean";
-
-		if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
-			this._toggle.apply( this, arguments );
-
-		} else if ( fn == null || bool ) {
-			this.each(function() {
-				var state = bool ? fn : jQuery(this).is(":hidden");
-				jQuery(this)[ state ? "show" : "hide" ]();
-			});
-
-		} else {
-			this.animate(genFx("toggle", 3), fn, fn2);
-		}
-
-		return this;
-	},
-
-	fadeTo: function( speed, to, callback ) {
-		return this.filter(":hidden").css("opacity", 0).show().end()
-					.animate({opacity: to}, speed, callback);
-	},
-
-	animate: function( prop, speed, easing, callback ) {
-		var optall = jQuery.speed(speed, easing, callback);
-
-		if ( jQuery.isEmptyObject( prop ) ) {
-			return this.each( optall.complete );
-		}
-
-		return this[ optall.queue === false ? "each" : "queue" ](function() {
-			var opt = jQuery.extend({}, optall), p,
-				hidden = this.nodeType === 1 && jQuery(this).is(":hidden"),
-				self = this;
-
-			for ( p in prop ) {
-				var name = p.replace(rdashAlpha, fcamelCase);
-
-				if ( p !== name ) {
-					prop[ name ] = prop[ p ];
-					delete prop[ p ];
-					p = name;
-				}
-
-				if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) {
-					return opt.complete.call(this);
-				}
-
-				if ( ( p === "height" || p === "width" ) && this.style ) {
-					// Store display property
-					opt.display = jQuery.css(this, "display");
-
-					// Make sure that nothing sneaks out
-					opt.overflow = this.style.overflow;
-				}
-
-				if ( jQuery.isArray( prop[p] ) ) {
-					// Create (if needed) and add to specialEasing
-					(opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];
-					prop[p] = prop[p][0];
-				}
-			}
-
-			if ( opt.overflow != null ) {
-				this.style.overflow = "hidden";
-			}
-
-			opt.curAnim = jQuery.extend({}, prop);
-
-			jQuery.each( prop, function( name, val ) {
-				var e = new jQuery.fx( self, opt, name );
-
-				if ( rfxtypes.test(val) ) {
-					e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop );
-
-				} else {
-					var parts = rfxnum.exec(val),
-						start = e.cur(true) || 0;
-
-					if ( parts ) {
-						var end = parseFloat( parts[2] ),
-							unit = parts[3] || "px";
-
-						// We need to compute starting value
-						if ( unit !== "px" ) {
-							self.style[ name ] = (end || 1) + unit;
-							start = ((end || 1) / e.cur(true)) * start;
-							self.style[ name ] = start + unit;
-						}
-
-						// If a +=/-= token was provided, we're doing a relative animation
-						if ( parts[1] ) {
-							end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
-						}
-
-						e.custom( start, end, unit );
-
-					} else {
-						e.custom( start, val, "" );
-					}
-				}
-			});
-
-			// For JS strict compliance
-			return true;
-		});
-	},
-
-	stop: function( clearQueue, gotoEnd ) {
-		var timers = jQuery.timers;
-
-		if ( clearQueue ) {
-			this.queue([]);
-		}
-
-		this.each(function() {
-			// go in reverse order so anything added to the queue during the loop is ignored
-			for ( var i = timers.length - 1; i >= 0; i-- ) {
-				if ( timers[i].elem === this ) {
-					if (gotoEnd) {
-						// force the next step to be the last
-						timers[i](true);
-					}
-
-					timers.splice(i, 1);
-				}
-			}
-		});
-
-		// start the next in the queue if the last step wasn't forced
-		if ( !gotoEnd ) {
-			this.dequeue();
-		}
-
-		return this;
-	}
-
-});
-
-// Generate shortcuts for custom animations
-jQuery.each({
-	slideDown: genFx("show", 1),
-	slideUp: genFx("hide", 1),
-	slideToggle: genFx("toggle", 1),
-	fadeIn: { opacity: "show" },
-	fadeOut: { opacity: "hide" }
-}, function( name, props ) {
-	jQuery.fn[ name ] = function( speed, callback ) {
-		return this.animate( props, speed, callback );
-	};
-});
-
-jQuery.extend({
-	speed: function( speed, easing, fn ) {
-		var opt = speed && typeof speed === "object" ? speed : {
-			complete: fn || !fn && easing ||
-				jQuery.isFunction( speed ) && speed,
-			duration: speed,
-			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
-		};
-
-		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
-			jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
-
-		// Queueing
-		opt.old = opt.complete;
-		opt.complete = function() {
-			if ( opt.queue !== false ) {
-				jQuery(this).dequeue();
-			}
-			if ( jQuery.isFunction( opt.old ) ) {
-				opt.old.call( this );
-			}
-		};
-
-		return opt;
-	},
-
-	easing: {
-		linear: function( p, n, firstNum, diff ) {
-			return firstNum + diff * p;
-		},
-		swing: function( p, n, firstNum, diff ) {
-			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
-		}
-	},
-
-	timers: [],
-
-	fx: function( elem, options, prop ) {
-		this.options = options;
-		this.elem = elem;
-		this.prop = prop;
-
-		if ( !options.orig ) {
-			options.orig = {};
-		}
-	}
-
-});
-
-jQuery.fx.prototype = {
-	// Simple function for setting a style value
-	update: function() {
-		if ( this.options.step ) {
-			this.options.step.call( this.elem, this.now, this );
-		}
-
-		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
-
-		// Set display property to block for height/width animations
-		if ( ( this.prop === "height" || this.prop === "width" ) && this.elem.style ) {
-			this.elem.style.display = "block";
-		}
-	},
-
-	// Get the current size
-	cur: function( force ) {
-		if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
-			return this.elem[ this.prop ];
-		}
-
-		var r = parseFloat(jQuery.css(this.elem, this.prop, force));
-		return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
-	},
-
-	// Start an animation from one number to another
-	custom: function( from, to, unit ) {
-		this.startTime = now();
-		this.start = from;
-		this.end = to;
-		this.unit = unit || this.unit || "px";
-		this.now = this.start;
-		this.pos = this.state = 0;
-
-		var self = this;
-		function t( gotoEnd ) {
-			return self.step(gotoEnd);
-		}
-
-		t.elem = this.elem;
-
-		if ( t() && jQuery.timers.push(t) && !timerId ) {
-			timerId = setInterval(jQuery.fx.tick, 13);
-		}
-	},
-
-	// Simple 'show' function
-	show: function() {
-		// Remember where we started, so that we can go back to it later
-		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
-		this.options.show = true;
-
-		// Begin the animation
-		// Make sure that we start at a small width/height to avoid any
-		// flash of content
-		this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
-
-		// Start by showing the element
-		jQuery( this.elem ).show();
-	},
-
-	// Simple 'hide' function
-	hide: function() {
-		// Remember where we started, so that we can go back to it later
-		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
-		this.options.hide = true;
-
-		// Begin the animation
-		this.custom(this.cur(), 0);
-	},
-
-	// Each step of an animation
-	step: function( gotoEnd ) {
-		var t = now(), done = true;
-
-		if ( gotoEnd || t >= this.options.duration + this.startTime ) {
-			this.now = this.end;
-			this.pos = this.state = 1;
-			this.update();
-
-			this.options.curAnim[ this.prop ] = true;
-
-			for ( var i in this.options.curAnim ) {
-				if ( this.options.curAnim[i] !== true ) {
-					done = false;
-				}
-			}
-
-			if ( done ) {
-				if ( this.options.display != null ) {
-					// Reset the overflow
-					this.elem.style.overflow = this.options.overflow;
-
-					// Reset the display
-					var old = jQuery.data(this.elem, "olddisplay");
-					this.elem.style.display = old ? old : this.options.display;
-
-					if ( jQuery.css(this.elem, "display") === "none" ) {
-						this.elem.style.display = "block";
-					}
-				}
-
-				// Hide the element if the "hide" operation was done
-				if ( this.options.hide ) {
-					jQuery(this.elem).hide();
-				}
-
-				// Reset the properties, if the item has been hidden or shown
-				if ( this.options.hide || this.options.show ) {
-					for ( var p in this.options.curAnim ) {
-						jQuery.style(this.elem, p, this.options.orig[p]);
-					}
-				}
-
-				// Execute the complete function
-				this.options.complete.call( this.elem );
-			}
-
-			return false;
-
-		} else {
-			var n = t - this.startTime;
-			this.state = n / this.options.duration;
-
-			// Perform the easing function, defaults to swing
-			var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];
-			var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear");
-			this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);
-			this.now = this.start + ((this.end - this.start) * this.pos);
-
-			// Perform the next step of the animation
-			this.update();
-		}
-
-		return true;
-	}
-};
-
-jQuery.extend( jQuery.fx, {
-	tick: function() {
-		var timers = jQuery.timers;
-
-		for ( var i = 0; i < timers.length; i++ ) {
-			if ( !timers[i]() ) {
-				timers.splice(i--, 1);
-			}
-		}
-
-		if ( !timers.length ) {
-			jQuery.fx.stop();
-		}
-	},
-		
-	stop: function() {
-		clearInterval( timerId );
-		timerId = null;
-	},
-	
-	speeds: {
-		slow: 600,
- 		fast: 200,
- 		// Default speed
- 		_default: 400
-	},
-
-	step: {
-		opacity: function( fx ) {
-			jQuery.style(fx.elem, "opacity", fx.now);
-		},
-
-		_default: function( fx ) {
-			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
-				fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
-			} else {
-				fx.elem[ fx.prop ] = fx.now;
-			}
-		}
-	}
-});
-
-if ( jQuery.expr && jQuery.expr.filters ) {
-	jQuery.expr.filters.animated = function( elem ) {
-		return jQuery.grep(jQuery.timers, function( fn ) {
-			return elem === fn.elem;
-		}).length;
-	};
-}
-
-function genFx( type, num ) {
-	var obj = {};
-
-	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
-		obj[ this ] = type;
-	});
-
-	return obj;
-}
-if ( "getBoundingClientRect" in document.documentElement ) {
-	jQuery.fn.offset = function( options ) {
-		var elem = this[0];
-
-		if ( options ) { 
-			return this.each(function( i ) {
-				jQuery.offset.setOffset( this, options, i );
-			});
-		}
-
-		if ( !elem || !elem.ownerDocument ) {
-			return null;
-		}
-
-		if ( elem === elem.ownerDocument.body ) {
-			return jQuery.offset.bodyOffset( elem );
-		}
-
-		var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
-			clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
-			top  = box.top  + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
-			left = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
-
-		return { top: top, left: left };
-	};
-
-} else {
-	jQuery.fn.offset = function( options ) {
-		var elem = this[0];
-
-		if ( options ) { 
-			return this.each(function( i ) {
-				jQuery.offset.setOffset( this, options, i );
-			});
-		}
-
-		if ( !elem || !elem.ownerDocument ) {
-			return null;
-		}
-
-		if ( elem === elem.ownerDocument.body ) {
-			return jQuery.offset.bodyOffset( elem );
-		}
-
-		jQuery.offset.initialize();
-
-		var offsetParent = elem.offsetParent, prevOffsetParent = elem,
-			doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
-			body = doc.body, defaultView = doc.defaultView,
-			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
-			top = elem.offsetTop, left = elem.offsetLeft;
-
-		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
-			if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
-				break;
-			}
-
-			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
-			top  -= elem.scrollTop;
-			left -= elem.scrollLeft;
-
-			if ( elem === offsetParent ) {
-				top  += elem.offsetTop;
-				left += elem.offsetLeft;
-
-				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {
-					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-				}
-
-				prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
-			}
-
-			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
-				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-			}
-
-			prevComputedStyle = computedStyle;
-		}
-
-		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
-			top  += body.offsetTop;
-			left += body.offsetLeft;
-		}
-
-		if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
-			top  += Math.max( docElem.scrollTop, body.scrollTop );
-			left += Math.max( docElem.scrollLeft, body.scrollLeft );
-		}
-
-		return { top: top, left: left };
-	};
-}
-
-jQuery.offset = {
-	initialize: function() {
-		var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0,
-			html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
-
-		jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
-
-		container.innerHTML = html;
-		body.insertBefore( container, body.firstChild );
-		innerDiv = container.firstChild;
-		checkDiv = innerDiv.firstChild;
-		td = innerDiv.nextSibling.firstChild.firstChild;
-
-		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
-		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
-
-		checkDiv.style.position = "fixed", checkDiv.style.top = "20px";
-		// safari subtracts parent border width here which is 5px
-		this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
-		checkDiv.style.position = checkDiv.style.top = "";
-
-		innerDiv.style.overflow = "hidden", innerDiv.style.position = "relative";
-		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
-
-		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
-
-		body.removeChild( container );
-		body = container = innerDiv = checkDiv = table = td = null;
-		jQuery.offset.initialize = jQuery.noop;
-	},
-
-	bodyOffset: function( body ) {
-		var top = body.offsetTop, left = body.offsetLeft;
-
-		jQuery.offset.initialize();
-
-		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
-			top  += parseFloat( jQuery.curCSS(body, "marginTop",  true) ) || 0;
-			left += parseFloat( jQuery.curCSS(body, "marginLeft", true) ) || 0;
-		}
-
-		return { top: top, left: left };
-	},
-	
-	setOffset: function( elem, options, i ) {
-		// set position first, in-case top/left are set even on static elem
-		if ( /static/.test( jQuery.curCSS( elem, "position" ) ) ) {
-			elem.style.position = "relative";
-		}
-		var curElem   = jQuery( elem ),
-			curOffset = curElem.offset(),
-			curTop    = parseInt( jQuery.curCSS( elem, "top",  true ), 10 ) || 0,
-			curLeft   = parseInt( jQuery.curCSS( elem, "left", true ), 10 ) || 0;
-
-		if ( jQuery.isFunction( options ) ) {
-			options = options.call( elem, i, curOffset );
-		}
-
-		var props = {
-			top:  (options.top  - curOffset.top)  + curTop,
-			left: (options.left - curOffset.left) + curLeft
-		};
-		
-		if ( "using" in options ) {
-			options.using.call( elem, props );
-		} else {
-			curElem.css( props );
-		}
-	}
-};
-
-
-jQuery.fn.extend({
-	position: function() {
-		if ( !this[0] ) {
-			return null;
-		}
-
-		var elem = this[0],
-
-		// Get *real* offsetParent
-		offsetParent = this.offsetParent(),
-
-		// Get correct offsets
-		offset       = this.offset(),
-		parentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
-
-		// Subtract element margins
-		// note: when an element has margin: auto the offsetLeft and marginLeft
-		// are the same in Safari causing offset.left to incorrectly be 0
-		offset.top  -= parseFloat( jQuery.curCSS(elem, "marginTop",  true) ) || 0;
-		offset.left -= parseFloat( jQuery.curCSS(elem, "marginLeft", true) ) || 0;
-
-		// Add offsetParent borders
-		parentOffset.top  += parseFloat( jQuery.curCSS(offsetParent[0], "borderTopWidth",  true) ) || 0;
-		parentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], "borderLeftWidth", true) ) || 0;
-
-		// Subtract the two offsets
-		return {
-			top:  offset.top  - parentOffset.top,
-			left: offset.left - parentOffset.left
-		};
-	},
-
-	offsetParent: function() {
-		return this.map(function() {
-			var offsetParent = this.offsetParent || document.body;
-			while ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
-				offsetParent = offsetParent.offsetParent;
-			}
-			return offsetParent;
-		});
-	}
-});
-
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( ["Left", "Top"], function( i, name ) {
-	var method = "scroll" + name;
-
-	jQuery.fn[ method ] = function(val) {
-		var elem = this[0], win;
-		
-		if ( !elem ) {
-			return null;
-		}
-
-		if ( val !== undefined ) {
-			// Set the scroll offset
-			return this.each(function() {
-				win = getWindow( this );
-
-				if ( win ) {
-					win.scrollTo(
-						!i ? val : jQuery(win).scrollLeft(),
-						 i ? val : jQuery(win).scrollTop()
-					);
-
-				} else {
-					this[ method ] = val;
-				}
-			});
-		} else {
-			win = getWindow( elem );
-
-			// Return the scroll offset
-			return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
-				jQuery.support.boxModel && win.document.documentElement[ method ] ||
-					win.document.body[ method ] :
-				elem[ method ];
-		}
-	};
-});
-
-function getWindow( elem ) {
-	return ("scrollTo" in elem && elem.document) ?
-		elem :
-		elem.nodeType === 9 ?
-			elem.defaultView || elem.parentWindow :
-			false;
-}
-// Create innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each([ "Height", "Width" ], function( i, name ) {
-
-	var type = name.toLowerCase();
-
-	// innerHeight and innerWidth
-	jQuery.fn["inner" + name] = function() {
-		return this[0] ?
-			jQuery.css( this[0], type, false, "padding" ) :
-			null;
-	};
-
-	// outerHeight and outerWidth
-	jQuery.fn["outer" + name] = function( margin ) {
-		return this[0] ?
-			jQuery.css( this[0], type, false, margin ? "margin" : "border" ) :
-			null;
-	};
-
-	jQuery.fn[ type ] = function( size ) {
-		// Get window width or height
-		var elem = this[0];
-		if ( !elem ) {
-			return size == null ? null : this;
-		}
-		
-		if ( jQuery.isFunction( size ) ) {
-			return this.each(function( i ) {
-				var self = jQuery( this );
-				self[ type ]( size.call( this, i, self[ type ]() ) );
-			});
-		}
-
-		return ("scrollTo" in elem && elem.document) ? // does it walk and quack like a window?
-			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
-			elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||
-			elem.document.body[ "client" + name ] :
-
-			// Get document width or height
-			(elem.nodeType === 9) ? // is it a document
-				// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
-				Math.max(
-					elem.documentElement["client" + name],
-					elem.body["scroll" + name], elem.documentElement["scroll" + name],
-					elem.body["offset" + name], elem.documentElement["offset" + name]
-				) :
-
-				// Get or set width or height on the element
-				size === undefined ?
-					// Get width or height on the element
-					jQuery.css( elem, type ) :
-
-					// Set the width or height on the element (default to pixels if value is unitless)
-					this.css( type, typeof size === "string" ? size : size + "px" );
-	};
-
-});
-// Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
-
-})(window);
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
Binary file web/data/tab.png has changed
--- a/web/data/ui.core.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,431 +0,0 @@
-/*
- * jQuery UI @VERSION
- *
- * Copyright (c) 2010 Paul Bakaus (ui.jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI
- */
-;(function($) {
-
-/** jQuery core modifications and additions **/
-
-var _remove = $.fn.remove;
-$.fn.remove = function() {
-	$("*", this).add(this).triggerHandler("remove");
-	return _remove.apply(this, arguments );
-};
-
-function isVisible(element) {
-	function checkStyles(element) {
-		var style = element.style;
-		return (style.display != 'none' && style.visibility != 'hidden');
-	}
-	
-	var visible = checkStyles(element);
-	
-	(visible && $.each($.dir(element, 'parentNode'), function() {
-		return (visible = checkStyles(this));
-	}));
-	
-	return visible;
-}
-
-$.extend($.expr[':'], {
-	data: function(a, i, m) {
-		return $.data(a, m[3]);
-	},
-	
-	// TODO: add support for object, area
-	tabbable: function(a, i, m) {
-		var nodeName = a.nodeName.toLowerCase();
-		
-		return (
-			// in tab order
-			a.tabIndex >= 0 &&
-			
-			( // filter node types that participate in the tab order
-				
-				// anchor tag
-				('a' == nodeName && a.href) ||
-				
-				// enabled form element
-				(/input|select|textarea|button/.test(nodeName) &&
-					'hidden' != a.type && !a.disabled)
-			) &&
-			
-			// visible on page
-			isVisible(a)
-		);
-	}
-});
-
-$.keyCode = {
-	BACKSPACE: 8,
-	CAPS_LOCK: 20,
-	COMMA: 188,
-	CONTROL: 17,
-	DELETE: 46,
-	DOWN: 40,
-	END: 35,
-	ENTER: 13,
-	ESCAPE: 27,
-	HOME: 36,
-	INSERT: 45,
-	LEFT: 37,
-	NUMPAD_ADD: 107,
-	NUMPAD_DECIMAL: 110,
-	NUMPAD_DIVIDE: 111,
-	NUMPAD_ENTER: 108,
-	NUMPAD_MULTIPLY: 106,
-	NUMPAD_SUBTRACT: 109,
-	PAGE_DOWN: 34,
-	PAGE_UP: 33,
-	PERIOD: 190,
-	RIGHT: 39,
-	SHIFT: 16,
-	SPACE: 32,
-	TAB: 9,
-	UP: 38
-};
-
-// $.widget is a factory to create jQuery plugins
-// taking some boilerplate code out of the plugin code
-// created by Scott González and Jörn Zaefferer
-function getter(namespace, plugin, method, args) {
-	function getMethods(type) {
-		var methods = $[namespace][plugin][type] || [];
-		return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
-	}
-	
-	var methods = getMethods('getter');
-	if (args.length == 1 && typeof args[0] == 'string') {
-		methods = methods.concat(getMethods('getterSetter'));
-	}
-	return ($.inArray(method, methods) != -1);
-}
-
-$.widget = function(name, prototype) {
-	var namespace = name.split(".")[0];
-	name = name.split(".")[1];
-	
-	// create plugin method
-	$.fn[name] = function(options) {
-		var isMethodCall = (typeof options == 'string'),
-			args = Array.prototype.slice.call(arguments, 1);
-		
-		// prevent calls to internal methods
-		if (isMethodCall && options.substring(0, 1) == '_') {
-			return this;
-		}
-		
-		// handle getter methods
-		if (isMethodCall && getter(namespace, name, options, args)) {
-			var instance = $.data(this[0], name);
-			return (instance ? instance[options].apply(instance, args)
-				: undefined);
-		}
-		
-		// handle initialization and non-getter methods
-		return this.each(function() {
-			var instance = $.data(this, name);
-			
-			// constructor
-			(!instance && !isMethodCall &&
-				$.data(this, name, new $[namespace][name](this, options)));
-			
-			// method call
-			(instance && isMethodCall && $.isFunction(instance[options]) &&
-				instance[options].apply(instance, args));
-		});
-	};
-	
-	// create widget constructor
-	$[namespace][name] = function(element, options) {
-		var self = this;
-		
-		this.widgetName = name;
-		this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
-		this.widgetBaseClass = namespace + '-' + name;
-		
-		this.options = $.extend({},
-			$.widget.defaults,
-			$[namespace][name].defaults,
-			$.metadata && $.metadata.get(element)[name],
-			options);
-		
-		this.element = $(element)
-			.bind('setData.' + name, function(e, key, value) {
-				return self._setData(key, value);
-			})
-			.bind('getData.' + name, function(e, key) {
-				return self._getData(key);
-			})
-			.bind('remove', function() {
-				return self.destroy();
-			});
-		
-		this._init();
-	};
-	
-	// add widget prototype
-	$[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
-	
-	// TODO: merge getter and getterSetter properties from widget prototype
-	// and plugin prototype
-	$[namespace][name].getterSetter = 'option';
-};
-
-$.widget.prototype = {
-	_init: function() {},
-	destroy: function() {
-		this.element.removeData(this.widgetName);
-	},
-	
-	option: function(key, value) {
-		var options = key,
-			self = this;
-		
-		if (typeof key == "string") {
-			if (value === undefined) {
-				return this._getData(key);
-			}
-			options = {};
-			options[key] = value;
-		}
-		
-		$.each(options, function(key, value) {
-			self._setData(key, value);
-		});
-	},
-	_getData: function(key) {
-		return this.options[key];
-	},
-	_setData: function(key, value) {
-		this.options[key] = value;
-		
-		if (key == 'disabled') {
-			this.element[value ? 'addClass' : 'removeClass'](
-				this.widgetBaseClass + '-disabled');
-		}
-	},
-	
-	enable: function() {
-		this._setData('disabled', false);
-	},
-	disable: function() {
-		this._setData('disabled', true);
-	},
-	
-	_trigger: function(type, e, data) {
-		var eventName = (type == this.widgetEventPrefix
-			? type : this.widgetEventPrefix + type);
-		e = e  || $.event.fix({ type: eventName, target: this.element[0] });
-		return this.element.triggerHandler(eventName, [e, data], this.options[type]);
-	}
-};
-
-$.widget.defaults = {
-	disabled: false
-};
-
-
-/** jQuery UI core **/
-
-$.ui = {
-	plugin: {
-		add: function(module, option, set) {
-			var proto = $.ui[module].prototype;
-			for(var i in set) {
-				proto.plugins[i] = proto.plugins[i] || [];
-				proto.plugins[i].push([option, set[i]]);
-			}
-		},
-		call: function(instance, name, args) {
-			var set = instance.plugins[name];
-			if(!set) { return; }
-			
-			for (var i = 0; i < set.length; i++) {
-				if (instance.options[set[i][0]]) {
-					set[i][1].apply(instance.element, args);
-				}
-			}
-		}	
-	},
-	cssCache: {},
-	css: function(name) {
-		if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
-		var tmp = $('<div class="ui-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
-		
-		//if (!$.browser.safari)
-			//tmp.appendTo('body'); 
-		
-		//Opera and Safari set width and height to 0px instead of auto
-		//Safari returns rgba(0,0,0,0) when bgcolor is not set
-		$.ui.cssCache[name] = !!(
-			(!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 
-			!(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
-		);
-		try { $('body').get(0).removeChild(tmp.get(0));	} catch(e){}
-		return $.ui.cssCache[name];
-	},
-	disableSelection: function(el) {
-		$(el)
-			.attr('unselectable', 'on')
-			.css('MozUserSelect', 'none')
-			.bind('selectstart.ui', function() { return false; });
-	},
-	enableSelection: function(el) {
-		$(el)
-			.attr('unselectable', 'off')
-			.css('MozUserSelect', '')
-			.unbind('selectstart.ui');
-	},
-	hasScroll: function(e, a) {
-		var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
-			has = false;
-		
-		if (e[scroll] > 0) { return true; }
-		
-		// TODO: determine which cases actually cause this to happen
-		// if the element doesn't have the scroll set, see if it's possible to
-		// set the scroll
-		e[scroll] = 1;
-		has = (e[scroll] > 0);
-		e[scroll] = 0;
-		return has;
-	}
-};
-
-
-/** Mouse Interaction Plugin **/
-
-$.ui.mouse = {
-	_mouseInit: function() {
-		var self = this;
-	
-		this.element.bind('mousedown.'+this.widgetName, function(e) {
-			return self._mouseDown(e);
-		});
-		
-		// Prevent text selection in IE
-		if ($.browser.msie) {
-			this._mouseUnselectable = this.element.attr('unselectable');
-			this.element.attr('unselectable', 'on');
-		}
-		
-		this.started = false;
-	},
-	
-	// TODO: make sure destroying one instance of mouse doesn't mess with
-	// other instances of mouse
-	_mouseDestroy: function() {
-		this.element.unbind('.'+this.widgetName);
-		
-		// Restore text selection in IE
-		($.browser.msie
-			&& this.element.attr('unselectable', this._mouseUnselectable));
-	},
-	
-	_mouseDown: function(e) {
-		// we may have missed mouseup (out of window)
-		(this._mouseStarted && this._mouseUp(e));
-		
-		this._mouseDownEvent = e;
-		
-		var self = this,
-			btnIsLeft = (e.which == 1),
-			elIsCancel = (typeof this.options.cancel == "string" ? $(e.target).parents().add(e.target).filter(this.options.cancel).length : false);
-		if (!btnIsLeft || elIsCancel || !this._mouseCapture(e)) {
-			return true;
-		}
-		
-		this.mouseDelayMet = !this.options.delay;
-		if (!this.mouseDelayMet) {
-			this._mouseDelayTimer = setTimeout(function() {
-				self.mouseDelayMet = true;
-			}, this.options.delay);
-		}
-		
-		if (this._mouseDistanceMet(e) && this._mouseDelayMet(e)) {
-			this._mouseStarted = (this._mouseStart(e) !== false);
-			if (!this._mouseStarted) {
-				e.preventDefault();
-				return true;
-			}
-		}
-		
-		// these delegates are required to keep context
-		this._mouseMoveDelegate = function(e) {
-			return self._mouseMove(e);
-		};
-		this._mouseUpDelegate = function(e) {
-			return self._mouseUp(e);
-		};
-		$(document)
-			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
-			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
-		
-		return false;
-	},
-	
-	_mouseMove: function(e) {
-		// IE mouseup check - mouseup happened when mouse was out of window
-		if ($.browser.msie && !e.button) {
-			return this._mouseUp(e);
-		}
-		
-		if (this._mouseStarted) {
-			this._mouseDrag(e);
-			return false;
-		}
-		
-		if (this._mouseDistanceMet(e) && this._mouseDelayMet(e)) {
-			this._mouseStarted =
-				(this._mouseStart(this._mouseDownEvent, e) !== false);
-			(this._mouseStarted ? this._mouseDrag(e) : this._mouseUp(e));
-		}
-		
-		return !this._mouseStarted;
-	},
-	
-	_mouseUp: function(e) {
-		$(document)
-			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
-			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
-		
-		if (this._mouseStarted) {
-			this._mouseStarted = false;
-			this._mouseStop(e);
-		}
-		
-		return false;
-	},
-	
-	_mouseDistanceMet: function(e) {
-		return (Math.max(
-				Math.abs(this._mouseDownEvent.pageX - e.pageX),
-				Math.abs(this._mouseDownEvent.pageY - e.pageY)
-			) >= this.options.distance
-		);
-	},
-	
-	_mouseDelayMet: function(e) {
-		return this.mouseDelayMet;
-	},
-	
-	// These are placeholder methods, to be overriden by extending plugin
-	_mouseStart: function(e) {},
-	_mouseDrag: function(e) {},
-	_mouseStop: function(e) {},
-	_mouseCapture: function(e) { return true; }
-};
-
-$.ui.mouse.defaults = {
-	cancel: null,
-	distance: 1,
-	delay: 0
-};
-
-})(jQuery);
--- a/web/data/ui.slider.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * jQuery UI 1.7.1
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI
- */
jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.1",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/*
- * jQuery UI Draggable 1.7.1
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Draggables
- *
- * Depends:
- *	ui.core.js
- */
(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger("start",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass("ui-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();this._trigger("drag",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger("stop",c);b._clear()})}else{this._trigger("stop",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");if(this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval){this.helper.remove()}this.helper=null;this.cancelHelperRemoval=false},_trigger:function(b,c,d){d=d||this._uiHash();a.ui.plugin.call(this,b,[c,d]);if(b=="drag"){this.positionAbs=this._convertPositionTo("absolute")}return a.widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(b){return{helper:this.helper,position:this.position,absolutePosition:this.positionAbs,offset:this.positionAbs}}}));a.extend(a.ui.draggable,{version:"1.7.1",eventPrefix:"drag",defaults:{addClasses:true,appendTo:"parent",axis:false,cancel:":input,option",connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false}});a.ui.plugin.add("draggable","connectToSortable",{start:function(c,e){var d=a(this).data("draggable"),f=d.options,b=a.extend({},e,{item:d.element});d.sortables=[];a(f.connectToSortable).each(function(){var g=a.data(this,"sortable");if(g&&!g.options.disabled){d.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",c,b)}})},stop:function(c,e){var d=a(this).data("draggable"),b=a.extend({},e,{item:d.element});a.each(d.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;d.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert){this.instance.options.revert=true}this.instance._mouseStop(c);this.instance.options.helper=this.instance.options._helper;if(d.options.helper=="original"){this.instance.currentItem.css({top:"auto",left:"auto"})}}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",c,b)}})},drag:function(c,f){var e=a(this).data("draggable"),b=this;var d=function(i){var n=this.offset.click.top,m=this.offset.click.left;var g=this.positionAbs.top,k=this.positionAbs.left;var j=i.height,l=i.width;var p=i.top,h=i.left;return a.ui.isOver(g+n,k+m,p,h,j,l)};a.each(e.sortables,function(g){this.instance.positionAbs=e.positionAbs;this.instance.helperProportions=e.helperProportions;this.instance.offset.click=e.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=a(b).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return f.helper[0]};c.target=this.instance.currentItem[0];this.instance._mouseCapture(c,true);this.instance._mouseStart(c,true,true);this.instance.offset.click.top=e.offset.click.top;this.instance.offset.click.left=e.offset.click.left;this.instance.offset.parent.left-=e.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=e.offset.parent.top-this.instance.offset.parent.top;e._trigger("toSortable",c);e.dropped=this.instance.element;e.currentItem=e.element;this.instance.fromOutside=e}if(this.instance.currentItem){this.instance._mouseDrag(c)}}else{if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",c,this.instance._uiHash(this.instance));this.instance._mouseStop(c,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();if(this.instance.placeholder){this.instance.placeholder.remove()}e._trigger("fromSortable",c);e.dropped=false}}})}});a.ui.plugin.add("draggable","cursor",{start:function(c,d){var b=a("body"),e=a(this).data("draggable").options;if(b.css("cursor")){e._cursor=b.css("cursor")}b.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._cursor){a("body").css("cursor",d._cursor)}}});a.ui.plugin.add("draggable","iframeFix",{start:function(b,c){var d=a(this).data("draggable").options;a(d.iframeFix===true?"iframe":d.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop+f.scrollSpeed}else{if(d.pageY-c.overflowOffset.top<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop-f.scrollSpeed}}}if(!f.axis||f.axis!="y"){if((c.overflowOffset.left+c.scrollParent[0].offsetWidth)-d.pageX<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft+f.scrollSpeed}else{if(d.pageX-c.overflowOffset.left<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft-f.scrollSpeed}}}}else{if(!f.axis||f.axis!="x"){if(d.pageY-a(document).scrollTop()<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-f.scrollSpeed)}else{if(a(window).height()-(d.pageY-a(document).scrollTop())<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+f.scrollSpeed)}}}if(!f.axis||f.axis!="y"){if(d.pageX-a(document).scrollLeft()<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-f.scrollSpeed)}else{if(a(window).width()-(d.pageX-a(document).scrollLeft())<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+f.scrollSpeed)}}}}if(b!==false&&a.ui.ddmanager&&!f.dropBehaviour){a.ui.ddmanager.prepareOffsets(c,d)}}});a.ui.plugin.add("draggable","snap",{start:function(c,d){var b=a(this).data("draggable"),e=b.options;b.snapElements=[];a(e.snap.constructor!=String?(e.snap.items||":data(draggable)"):e.snap).each(function(){var g=a(this);var f=g.offset();if(this!=b.element[0]){b.snapElements.push({item:this,width:g.outerWidth(),height:g.outerHeight(),top:f.top,left:f.left})}})},drag:function(u,p){var g=a(this).data("draggable"),q=g.options;var y=q.snapTolerance;var x=p.offset.left,w=x+g.helperProportions.width,f=p.offset.top,e=f+g.helperProportions.height;for(var v=g.snapElements.length-1;v>=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y<x&&x<n+y&&m-y<f&&f<A+y)||(s-y<x&&x<n+y&&m-y<e&&e<A+y)||(s-y<w&&w<n+y&&m-y<f&&f<A+y)||(s-y<w&&w<n+y&&m-y<e&&e<A+y))){if(g.snapElements[v].snapping){(g.options.snap.release&&g.options.snap.release.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=false;continue}if(q.snapMode!="inner"){var c=Math.abs(m-e)<=y;var z=Math.abs(A-f)<=y;var j=Math.abs(s-w)<=y;var k=Math.abs(n-x)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m-g.helperProportions.height,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s-g.helperProportions.width}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n}).left-g.margins.left}}var h=(c||z||j||k);if(q.snapMode!="outer"){var c=Math.abs(m-f)<=y;var z=Math.abs(A-e)<=y;var j=Math.abs(s-x)<=y;var k=Math.abs(n-w)<=y;if(c){p.position.top=g._convertPositionTo("relative",{top:m,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo("relative",{top:A-g.helperProportions.height,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo("relative",{top:0,left:s}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo("relative",{top:0,left:n-g.helperProportions.width}).left-g.margins.left}}if(!g.snapElements[v].snapping&&(c||z||j||k||h)){(g.options.snap.snap&&g.options.snap.snap.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=(c||z||j||k||h)}}});a.ui.plugin.add("draggable","stack",{start:function(b,c){var e=a(this).data("draggable").options;var d=a.makeArray(a(e.stack.group)).sort(function(g,f){return(parseInt(a(g).css("zIndex"),10)||e.stack.min)-(parseInt(a(f).css("zIndex"),10)||e.stack.min)});a(d).each(function(f){this.style.zIndex=e.stack.min+f});this[0].style.zIndex=e.stack.min+d.length}});a.ui.plugin.add("draggable","zIndex",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("zIndex")){e._zIndex=b.css("zIndex")}b.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._zIndex){a(c.helper).css("zIndex",d._zIndex)}}})})(jQuery);;/*
- * jQuery UI Droppable 1.7.1
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Droppables
- *
- * Depends:
- *	ui.core.js
- *	ui.draggable.js
- */
(function(a){a.widget("ui.droppable",{_init:function(){var c=this.options,b=c.accept;this.isover=0;this.isout=1;this.options.accept=this.options.accept&&a.isFunction(this.options.accept)?this.options.accept:function(e){return e.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};a.ui.ddmanager.droppables[this.options.scope]=a.ui.ddmanager.droppables[this.options.scope]||[];a.ui.ddmanager.droppables[this.options.scope].push(this);(this.options.addClasses&&this.element.addClass("ui-droppable"))},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++){if(b[c]==this){b.splice(c,1)}}this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable")},_setData:function(b,c){if(b=="accept"){this.options.accept=c&&a.isFunction(c)?c:function(e){return e.is(c)}}else{a.widget.prototype._setData.apply(this,arguments)}},_activate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.addClass(this.options.activeClass)}(b&&this._trigger("activate",c,this.ui(b)))},_deactivate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}(b&&this._trigger("deactivate",c,this.ui(b)))},_over:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.addClass(this.options.hoverClass)}this._trigger("over",c,this.ui(b))}},_out:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("out",c,this.ui(b))}},_drop:function(c,d){var b=d||a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return false}var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var f=a.data(this,"droppable");if(f.options.greedy&&a.ui.intersect(b,a.extend(f,{offset:f.element.offset()}),f.options.tolerance)){e=true;return false}});if(e){return false}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger("drop",c,this.ui(b));return this.element}return false},ui:function(b){return{draggable:(b.currentItem||b.element),helper:b.helper,position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs}}});a.extend(a.ui.droppable,{version:"1.7.1",eventPrefix:"drop",defaults:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"}});a.ui.intersect=function(q,j,o){if(!j.offset){return false}var e=(q.positionAbs||q.position.absolute).left,d=e+q.helperProportions.width,n=(q.positionAbs||q.position.absolute).top,m=n+q.helperProportions.height;var g=j.offset.left,c=g+j.proportions.width,p=j.offset.top,k=p+j.proportions.height;switch(o){case"fit":return(g<e&&d<c&&p<n&&m<k);break;case"intersect":return(g<e+(q.helperProportions.width/2)&&d-(q.helperProportions.width/2)<c&&p<n+(q.helperProportions.height/2)&&m-(q.helperProportions.height/2)<k);break;case"pointer":var h=((q.positionAbs||q.position.absolute).left+(q.clickOffset||q.offset.click).left),i=((q.positionAbs||q.position.absolute).top+(q.clickOffset||q.offset.click).top),f=a.ui.isOver(i,h,p,g,j.proportions.height,j.proportions.width);return f;break;case"touch":return((n>=p&&n<=k)||(m>=p&&m<=k)||(n<p&&m>k))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(e<g&&d>c));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d<b.length;d++){if(b[d].options.disabled||(e&&!b[d].options.accept.call(b[d].element[0],(e.currentItem||e.element)))){continue}for(var c=0;c<h.length;c++){if(h[c]==b[d].element[0]){b[d].proportions.height=0;continue droppablesLoop}}b[d].visible=b[d].element.css("display")!="none";if(!b[d].visible){continue}b[d].offset=b[d].element.offset();b[d].proportions={width:b[d].element[0].offsetWidth,height:b[d].element[0].offsetHeight};if(f=="mousedown"){b[d]._activate.call(b[d],g)}}},drop:function(b,c){var d=false;a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(!this.options){return}if(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)){d=this._drop.call(this,c)}if(!this.options.disabled&&this.visible&&this.options.accept.call(this.element[0],(b.currentItem||b.element))){this.isout=1;this.isover=0;this._deactivate.call(this,c)}});return d},drag:function(b,c){if(b.options.refreshPositions){a.ui.ddmanager.prepareOffsets(b,c)}a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(this.options.disabled||this.greedyChild||!this.visible){return}var e=a.ui.intersect(b,this,this.options.tolerance);var g=!e&&this.isover==1?"isout":(e&&this.isover==0?"isover":null);if(!g){return}var f;if(this.options.greedy){var d=this.element.parents(":data(droppable):eq(0)");if(d.length){f=a.data(d[0],"droppable");f.greedyChild=(g=="isover"?1:0)}}if(f&&g=="isover"){f.isover=0;f.isout=1;f._out.call(f,c)}this[g]=1;this[g=="isout"?"isover":"isout"]=0;this[g=="isover"?"_over":"_out"].call(this,c);if(f&&g=="isout"){f.isout=0;f.isover=1;f._over.call(f,c)}})}}})(jQuery);;/*
- * jQuery UI Slider 1.7.1
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Slider
- *
- * Depends:
- *	ui.core.js
- */
(function(a){a.widget("ui.slider",a.extend({},a.ui.mouse,{_init:function(){var b=this,c=this.options;this._keySliding=false;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");this.range=a([]);if(c.range){if(c.range===true){this.range=a("<div></div>");if(!c.values){c.values=[this._valueMin(),this._valueMin()]}if(c.values.length&&c.values.length!=2){c.values=[c.values[0],c.values[0]]}}else{this.range=a("<div></div>")}this.range.appendTo(this.element).addClass("ui-slider-range");if(c.range=="min"||c.range=="max"){this.range.addClass("ui-slider-range-"+c.range)}this.range.addClass("ui-widget-header")}if(a(".ui-slider-handle",this.element).length==0){a('<a href="#"></a>').appendTo(this.element).addClass("ui-slider-handle")}if(c.values&&c.values.length){while(a(".ui-slider-handle",this.element).length<c.values.length){a('<a href="#"></a>').appendTo(this.element).addClass("ui-slider-handle")}}this.handles=a(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(d){d.preventDefault()}).hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){a(".ui-slider .ui-state-focus").removeClass("ui-state-focus");a(this).addClass("ui-state-focus")}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(d){a(this).data("index.ui-slider-handle",d)});this.handles.keydown(function(i){var f=true;var e=a(this).data("index.ui-slider-handle");if(b.options.disabled){return}switch(i.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:f=false;if(!b._keySliding){b._keySliding=true;a(this).addClass("ui-state-active");b._start(i,e)}break}var g,d,h=b._step();if(b.options.values&&b.options.values.length){g=d=b.values(e)}else{g=d=b.value()}switch(i.keyCode){case a.ui.keyCode.HOME:d=b._valueMin();break;case a.ui.keyCode.END:d=b._valueMax();break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g==b._valueMax()){return}d=g+h;break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g==b._valueMin()){return}d=g-h;break}b._slide(i,e,d);return f}).keyup(function(e){var d=a(this).data("index.ui-slider-handle");if(b._keySliding){b._stop(e,d);b._change(e,d);b._keySliding=false;a(this).removeClass("ui-state-active")}});this._refreshValue()},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy()},_mouseCapture:function(d){var e=this.options;if(e.disabled){return false}this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();var h={x:d.pageX,y:d.pageY};var j=this._normValueFromMouse(h);var c=this._valueMax()-this._valueMin()+1,f;var k=this,i;this.handles.each(function(l){var m=Math.abs(j-k.values(l));if(c>m){c=m;f=a(this);i=l}});if(e.range==true&&this.values(1)==e.min){f=a(this.handles[++i])}this._start(d,i);k._handleIndex=i;f.addClass("ui-state-active").focus();var g=f.offset();var b=!a(d.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=b?{left:0,top:0}:{left:d.pageX-g.left-(f.width()/2),top:d.pageY-g.top-(f.height()/2)-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};j=this._normValueFromMouse(h);this._slide(d,i,j);return true},_mouseStart:function(b){return true},_mouseDrag:function(d){var b={x:d.pageX,y:d.pageY};var c=this._normValueFromMouse(b);this._slide(d,this._handleIndex,c);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._handleIndex=null;this._clickOffset=null;return false},_detectOrientation:function(){this.orientation=this.options.orientation=="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(d){var c,h;if("horizontal"==this.orientation){c=this.elementSize.width;h=d.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{c=this.elementSize.height;h=d.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}var f=(h/c);if(f>1){f=1}if(f<0){f=0}if("vertical"==this.orientation){f=1-f}var e=this._valueMax()-this._valueMin(),i=f*e,b=i%this.options.step,g=this._valueMin()+i-b;if(b>(this.options.step/2)){g+=this.options.step}return parseFloat(g.toFixed(5))},_start:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("start",d,b)},_slide:function(f,e,d){var g=this.handles[e];if(this.options.values&&this.options.values.length){var b=this.values(e?0:1);if((e==0&&d>=b)||(e==1&&d<=b)){d=b}if(d!=this.values(e)){var c=this.values();c[e]=d;var h=this._trigger("slide",f,{handle:this.handles[e],value:d,values:c});var b=this.values(e?0:1);if(h!==false){this.values(e,d,(f.type=="mousedown"&&this.options.animate),true)}}}else{if(d!=this.value()){var h=this._trigger("slide",f,{handle:this.handles[e],value:d});if(h!==false){this._setData("value",d,(f.type=="mousedown"&&this.options.animate))}}}},_stop:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("stop",d,b)},_change:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("change",d,b)},value:function(b){if(arguments.length){this._setData("value",b);this._change(null,0)}return this._value()},values:function(b,e,c,d){if(arguments.length>1){this.options.values[b]=e;this._refreshValue(c);if(!d){this._change(null,b)}}if(arguments.length){if(this.options.values&&this.options.values.length){return this._values(b)}else{return this.value()}}else{return this._values()}},_setData:function(b,d,c){a.widget.prototype._setData.apply(this,arguments);switch(b){case"orientation":this._detectOrientation();this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue(c);break;case"value":this._refreshValue(c);break}},_step:function(){var b=this.options.step;return b},_value:function(){var b=this.options.value;if(b<this._valueMin()){b=this._valueMin()}if(b>this._valueMax()){b=this._valueMax()}return b},_values:function(b){if(arguments.length){var c=this.options.values[b];if(c<this._valueMin()){c=this._valueMin()}if(c>this._valueMax()){c=this._valueMax()}return c}else{return this.options.values}},_valueMin:function(){var b=this.options.min;return b},_valueMax:function(){var b=this.options.max;return b},_refreshValue:function(c){var f=this.options.range,d=this.options,l=this;if(this.options.values&&this.options.values.length){var i,h;this.handles.each(function(p,n){var o=(l.values(p)-l._valueMin())/(l._valueMax()-l._valueMin())*100;var m={};m[l.orientation=="horizontal"?"left":"bottom"]=o+"%";a(this).stop(1,1)[c?"animate":"css"](m,d.animate);if(l.options.range===true){if(l.orientation=="horizontal"){(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({left:o+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({width:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}else{(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({bottom:(o)+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({height:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}}lastValPercent=o})}else{var j=this.value(),g=this._valueMin(),k=this._valueMax(),e=k!=g?(j-g)/(k-g)*100:0;var b={};b[l.orientation=="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[c?"animate":"css"](b,d.animate);(f=="min")&&(this.orientation=="horizontal")&&this.range.stop(1,1)[c?"animate":"css"]({width:e+"%"},d.animate);(f=="max")&&(this.orientation=="horizontal")&&this.range[c?"animate":"css"]({width:(100-e)+"%"},{queue:false,duration:d.animate});(f=="min")&&(this.orientation=="vertical")&&this.range.stop(1,1)[c?"animate":"css"]({height:e+"%"},d.animate);(f=="max")&&(this.orientation=="vertical")&&this.range[c?"animate":"css"]({height:(100-e)+"%"},{queue:false,duration:d.animate})}}}));a.extend(a.ui.slider,{getter:"value values",version:"1.7.1",eventPrefix:"slide",defaults:{animate:false,delay:0,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null}})})(jQuery);;
\ No newline at end of file
--- a/web/data/ui.tabs.css	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/* Caution! Ensure accessibility in print and other media types... */
-@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
-    .ui-tabs-hide {
-        display: none;
-    }
-}
-
-/* Hide useless elements in print layouts... */
-@media print {
-    .ui-tabs-nav {
-        display: none;
-    }
-}
-
-/* Skin */
-.ui-tabs-nav, .ui-tabs-panel {
-    font-family: "Trebuchet MS", Trebuchet, Verdana, Helvetica, Arial, sans-serif;
-    font-size: 12px;
-
-}
-.ui-tabs-nav {
-    list-style: none;
-    margin: 0px;
-    padding: 0px 0px 0px 4px; 
-
-}
-.ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */
-    display: block;
-    clear: both;
-    content: " ";
-}
-.ui-tabs-nav li {
-    float: left;
-    margin: 0 0 0 1px;
-    min-width: 84px; /* be nice to Opera */
-    list-style: none;
-    background: none;
-    padding: 0px 0px 1px 1px;
-}
-.ui-tabs-nav a, .ui-tabs-nav a span {
-    display: block;
-    padding: 0 10px;
-    background: url(tab.png) no-repeat;
-}
-.ui-tabs-nav a {
-    margin: 1px 0 0; /* position: relative makes opacity fail for disabled tab in IE */
-    padding-left: 0;
-    color: #27537a;
-    font-weight: bold;
-    line-height: 1.2;
-    text-align: center;
-    text-decoration: none;
-    white-space: nowrap; /* required in IE 6 */    
-    outline: 0; /* prevent dotted border in Firefox */
-}
-.ui-tabs-nav .ui-tabs-selected a {
-    position: relative;
-    top: 1px;
-    z-index: 2;
-    margin-top: 0;
-    color: #000;
-}
-.ui-tabs-nav a span {
-    width: 64px; /* IE 6 treats width as min-width */
-    min-width: 64px;
-    height: 18px; /* IE 6 treats height as min-height */
-    min-height: 18px;
-    padding-top: 6px;
-    padding-right: 0;
-}
-*>.ui-tabs-nav a span { /* hide from IE 6 */
-    width: auto;
-    height: auto;
-}
-.ui-tabs-nav .ui-tabs-selected a span {
-    padding-bottom: 1px;
-}
-.ui-tabs-nav .ui-tabs-selected a, .ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active {
-    background-position: 100% -150px;
-}
-.ui-tabs-nav a, .ui-tabs-nav .ui-tabs-disabled a:hover, .ui-tabs-nav .ui-tabs-disabled a:focus, .ui-tabs-nav .ui-tabs-disabled a:active {
-    background-position: 100% -100px;
-}
-.ui-tabs-nav .ui-tabs-selected a span, .ui-tabs-nav a:hover span, .ui-tabs-nav a:focus span, .ui-tabs-nav a:active span {
-    background-position: 0 -50px;
-}
-.ui-tabs-nav a span, .ui-tabs-nav .ui-tabs-disabled a:hover span, .ui-tabs-nav .ui-tabs-disabled a:focus span, .ui-tabs-nav .ui-tabs-disabled a:active span {
-    background-position: 0 0;
-}
-.ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited, .ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */
-    cursor: text;
-}
-.ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active,
-.ui-tabs-nav .ui-tabs-unselect a:hover, .ui-tabs-nav .ui-tabs-unselect a:focus, .ui-tabs-nav .ui-tabs-unselect a:active { /* @ Opera, we need to be explicit again here now... */
-    cursor: pointer;
-}
-.ui-tabs-disabled {
-    opacity: .4;
-    filter: alpha(opacity=40);
-}
-.ui-tabs-panel {
-    border-top: 1px solid #97a5b0;
-    padding: 1em 8px;
-    margin-top:-1px;  /* Logilab style */
-    background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */
-}
-.ui-tabs-loading em {
-    padding: 0 0 0 20px;
-    background: url(loading.gif) no-repeat 0 50%;
-}
-
-/* Additional IE specific bug fixes... */
-* html .ui-tabs-nav { /* auto clear, @ IE 6 & IE 7 Quirks Mode */
-    display: inline-block;
-}
-*:first-child+html .ui-tabs-nav  { /* @ IE 7 Standards Mode - do not group selectors, otherwise IE 6 will ignore complete rule (because of the unknown + combinator)... */
-    display: inline-block;
-}
-
-/* ========= Lobilab styles =========== */
-
-/* added by katia */
-* html .ui-tabs-panel{  
-    width:100%;
-}
\ No newline at end of file
--- a/web/data/ui.tabs.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,587 +0,0 @@
-/*
- * jQuery UI Tabs @VERSION
- *
- * Copyright (c) 2007, 2010 Klaus Hartl (stilbuero.de)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Tabs
- *
- * Depends:
- *	ui.core.js
- */
-(function($) {
-
-$.widget("ui.tabs", {
-	_init: function() {
-		this.options.event += '.tabs'; // namespace event
-		
-		// create tabs
-		this._tabify(true);
-	},
-	_setData: function(key, value) {
-		if ((/^selected/).test(key))
-			this.select(value);
-		else {
-			this.options[key] = value;
-			this._tabify();
-		}
-	},
-	length: function() {
-		return this.$tabs.length;
-	},
-	_tabId: function(a) {
-		return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
-			|| this.options.idPrefix + $.data(a);
-	},
-	ui: function(tab, panel) {
-		return {
-			options: this.options,
-			tab: tab,
-			panel: panel,
-			index: this.$tabs.index(tab)
-		};
-	},
-	_tabify: function(init) {
-
-		this.$lis = $('li:has(a[href])', this.element);
-		this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
-		this.$panels = $([]);
-
-		var self = this, o = this.options;
-
-		this.$tabs.each(function(i, a) {
-			// inline tab
-			if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
-				self.$panels = self.$panels.add(a.hash);
-			// remote tab
-			else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
-				$.data(a, 'href.tabs', a.href); // required for restore on destroy
-				$.data(a, 'load.tabs', a.href); // mutable
-				var id = self._tabId(a);
-				a.href = '#' + id;
-				var $panel = $('#' + id);
-				if (!$panel.length) {
-					$panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
-						.insertAfter( self.$panels[i - 1] || self.element );
-					$panel.data('destroy.tabs', true);
-				}
-				self.$panels = self.$panels.add( $panel );
-			}
-			// invalid tab href
-			else
-				o.disabled.push(i + 1);
-		});
-
-		// initialization from scratch
-		if (init) {
-
-			// attach necessary classes for styling if not present
-			this.element.addClass(o.navClass);
-			this.$panels.each(function() {
-				var $this = $(this);
-				$this.addClass(o.panelClass);
-			});
-
-			// Selected tab
-			// use "selected" option or try to retrieve:
-			// 1. from fragment identifier in url
-			// 2. from cookie
-			// 3. from selected class attribute on <li>
-			if (o.selected === undefined) {
-				if (location.hash) {
-					this.$tabs.each(function(i, a) {
-						if (a.hash == location.hash) {
-							o.selected = i;
-							// prevent page scroll to fragment
-							if ($.browser.msie || $.browser.opera) { // && !o.remote
-								var $toShow = $(location.hash), toShowId = $toShow.attr('id');
-								$toShow.attr('id', '');
-								setTimeout(function() {
-									$toShow.attr('id', toShowId); // restore id
-								}, 500);
-							}
-							scrollTo(0, 0);
-							return false; // break
-						}
-					});
-				}
-				else if (o.cookie) {
-					var index = parseInt($.cookie('ui-tabs-' + $.data(self.element[0])), 10);
-					if (index && self.$tabs[index])
-						o.selected = index;
-				}
-				else if (self.$lis.filter('.' + o.selectedClass).length)
-					o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] );
-			}
-			o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default
-
-			// Take disabling tabs via class attribute from HTML
-			// into account and update option properly.
-			// A selected tab cannot become disabled.
-			o.disabled = $.unique(o.disabled.concat(
-				$.map(this.$lis.filter('.' + o.disabledClass),
-					function(n, i) { return self.$lis.index(n); } )
-			)).sort();
-			if ($.inArray(o.selected, o.disabled) != -1)
-				o.disabled.splice($.inArray(o.selected, o.disabled), 1);
-			
-			// highlight selected tab
-			this.$panels.addClass(o.hideClass);
-			this.$lis.removeClass(o.selectedClass);
-			if (o.selected !== null) {
-				this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
-				this.$lis.eq(o.selected).addClass(o.selectedClass);
-				
-				// seems to be expected behavior that the show callback is fired
-				var onShow = function() {
-					self._trigger('show', null,
-						self.ui(self.$tabs[o.selected], self.$panels[o.selected]));
-				};
-
-				// load if remote tab
-				if ($.data(this.$tabs[o.selected], 'load.tabs'))
-					this.load(o.selected, onShow);
-				// just trigger show event
-				else
-					onShow();
-			}
-			
-			// clean up to avoid memory leaks in certain versions of IE 6
-			$(window).bind('unload', function() {
-				self.$tabs.unbind('.tabs');
-				self.$lis = self.$tabs = self.$panels = null;
-			});
-
-		}
-		// update selected after add/remove
-		else
-			o.selected = this.$lis.index( this.$lis.filter('.' + o.selectedClass)[0] );
-
-		// set or update cookie after init and add/remove respectively
-		if (o.cookie)
-			$.cookie('ui-tabs-' + $.data(self.element[0]), o.selected, o.cookie);
-		
-		// disable tabs
-		for (var i = 0, li; li = this.$lis[i]; i++)
-			$(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
-
-		// reset cache if switching from cached to not cached
-		if (o.cache === false)
-			this.$tabs.removeData('cache.tabs');
-		
-		// set up animations
-		var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
-		if (o.fx && o.fx.constructor == Array)
-			hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
-		else
-			hideFx = showFx = o.fx || baseFx;
-
-		// reset some styles to maintain print style sheets etc.
-		var resetCSS = { display: '', overflow: '', height: '' };
-		if (!$.browser.msie) // not in IE to prevent ClearType font issue
-			resetCSS.opacity = '';
-
-		// Hide a tab, animation prevents browser scrolling to fragment,
-		// $show is optional.
-		function hideTab(clicked, $hide, $show) {
-			$hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
-				$hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
-				if ($.browser.msie && hideFx.opacity)
-					$hide[0].style.filter = '';
-				if ($show)
-					showTab(clicked, $show, $hide);
-			});
-		}
-
-		// Show a tab, animation prevents browser scrolling to fragment,
-		// $hide is optional.
-		function showTab(clicked, $show, $hide) {
-			if (showFx === baseFx)
-				$show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
-			$show.animate(showFx, showFx.duration || baseDuration, function() {
-				$show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
-				if ($.browser.msie && showFx.opacity)
-					$show[0].style.filter = '';
-
-				// callback
-				self._trigger('show', null, self.ui(clicked, $show[0]));
-			});
-		}
-
-		// switch a tab
-		function switchTab(clicked, $li, $hide, $show) {
-			/*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
-				$.ajaxHistory.update(clicked.hash);
-			}*/
-			$li.addClass(o.selectedClass)
-				.siblings().removeClass(o.selectedClass);
-			hideTab(clicked, $hide, $show);
-		}
-
-		// attach tab event handler, unbind to avoid duplicates from former tabifying...
-		this.$tabs.unbind('.tabs').bind(o.event, function() {
-
-			//var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
-			var $li = $(this).parents('li:eq(0)'),
-				$hide = self.$panels.filter(':visible'),
-				$show = $(this.hash);
-
-			// If tab is already selected and not unselectable or tab disabled or 
-			// or is already loading or click callback returns false stop here.
-			// Check if click handler returns false last so that it is not executed
-			// for a disabled or loading tab!
-			if (($li.hasClass(o.selectedClass) && !o.unselect)
-				|| $li.hasClass(o.disabledClass) 
-				|| $(this).hasClass(o.loadingClass)
-				|| self._trigger('select', null, self.ui(this, $show[0])) === false
-				) {
-				this.blur();
-				return false;
-			}
-
-			self.options.selected = self.$tabs.index(this);
-
-			// if tab may be closed
-			if (o.unselect) {
-				if ($li.hasClass(o.selectedClass)) {
-					self.options.selected = null;
-					$li.removeClass(o.selectedClass);
-					self.$panels.stop();
-					hideTab(this, $hide);
-					this.blur();
-					return false;
-				} else if (!$hide.length) {
-					self.$panels.stop();
-					var a = this;
-					self.load(self.$tabs.index(this), function() {
-						$li.addClass(o.selectedClass).addClass(o.unselectClass);
-						showTab(a, $show);
-					});
-					this.blur();
-					return false;
-				}
-			}
-
-			if (o.cookie)
-				$.cookie('ui-tabs-' + $.data(self.element[0]), self.options.selected, o.cookie);
-
-			// stop possibly running animations
-			self.$panels.stop();
-
-			// show new tab
-			if ($show.length) {
-
-				// prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
-				/*if ($.browser.msie && o.bookmarkable) {
-					var showId = this.hash.replace('#', '');
-					$show.attr('id', '');
-					setTimeout(function() {
-						$show.attr('id', showId); // restore id
-					}, 0);
-				}*/
-
-				var a = this;
-				self.load(self.$tabs.index(this), $hide.length ? 
-					function() {
-						switchTab(a, $li, $hide, $show);
-					} :
-					function() {
-						$li.addClass(o.selectedClass);
-						showTab(a, $show);
-					}
-				);
-
-				// Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
-				/*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
-				var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
-				setTimeout(function() {
-					scrollTo(scrollX, scrollY);
-				}, 0);*/
-
-			} else
-				throw 'jQuery UI Tabs: Mismatching fragment identifier.';
-
-			// Prevent IE from keeping other link focussed when using the back button
-			// and remove dotted border from clicked link. This is controlled in modern
-			// browsers via CSS, also blur removes focus from address bar in Firefox
-			// which can become a usability and annoying problem with tabsRotate.
-			if ($.browser.msie)
-				this.blur();
-
-			//return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
-			return false;
-
-		});
-
-		// disable click if event is configured to something else
-		if (!(/^click/).test(o.event))
-			this.$tabs.bind('click.tabs', function() { return false; });
-
-	},
-	add: function(url, label, index) {
-		if (index == undefined) 
-			index = this.$tabs.length; // append by default
-
-		var o = this.options;
-		var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label));
-		$li.data('destroy.tabs', true);
-
-		var id = url.indexOf('#') == 0 ? url.replace('#', '') : this._tabId( $('a:first-child', $li)[0] );
-
-		// try to find an existing element before creating a new one
-		var $panel = $('#' + id);
-		if (!$panel.length) {
-			$panel = $(o.panelTemplate).attr('id', id)
-				.addClass(o.hideClass)
-				.data('destroy.tabs', true);
-		}
-		$panel.addClass(o.panelClass);
-		if (index >= this.$lis.length) {
-			$li.appendTo(this.element);
-			$panel.appendTo(this.element[0].parentNode);
-		} else {
-			$li.insertBefore(this.$lis[index]);
-			$panel.insertBefore(this.$panels[index]);
-		}
-		
-		o.disabled = $.map(o.disabled,
-			function(n, i) { return n >= index ? ++n : n });
-			
-		this._tabify();
-
-		if (this.$tabs.length == 1) {
-			$li.addClass(o.selectedClass);
-			$panel.removeClass(o.hideClass);
-			var href = $.data(this.$tabs[0], 'load.tabs');
-			if (href)
-				this.load(index, href);
-		}
-
-		// callback
-		this._trigger('add', null, this.ui(this.$tabs[index], this.$panels[index]));
-	},
-	remove: function(index) {
-		var o = this.options, $li = this.$lis.eq(index).remove(),
-			$panel = this.$panels.eq(index).remove();
-
-		// If selected tab was removed focus tab to the right or
-		// in case the last tab was removed the tab to the left.
-		if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
-			this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));
-
-		o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
-			function(n, i) { return n >= index ? --n : n });
-
-		this._tabify();
-
-		// callback
-		this._trigger('remove', null, this.ui($li.find('a')[0], $panel[0]));
-	},
-	enable: function(index) {
-		var o = this.options;
-		if ($.inArray(index, o.disabled) == -1)
-			return;
-			
-		var $li = this.$lis.eq(index).removeClass(o.disabledClass);
-		if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
-			$li.css('display', 'inline-block');
-			setTimeout(function() {
-				$li.css('display', 'block');
-			}, 0);
-		}
-
-		o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
-
-		// callback
-		this._trigger('enable', null, this.ui(this.$tabs[index], this.$panels[index]));
-	},
-	disable: function(index) {
-		var self = this, o = this.options;
-		if (index != o.selected) { // cannot disable already selected tab
-			this.$lis.eq(index).addClass(o.disabledClass);
-
-			o.disabled.push(index);
-			o.disabled.sort();
-
-			// callback
-			this._trigger('disable', null, this.ui(this.$tabs[index], this.$panels[index]));
-		}
-	},
-	select: function(index) {
-		if (typeof index == 'string')
-			index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
-		this.$tabs.eq(index).trigger(this.options.event);
-	},
-	load: function(index, callback) { // callback is for internal usage only
-		
-		var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
-				bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');
-
-		callback = callback || function() {};
-		
-		// no remote or from cache - just finish with callback
-		if (!url || !bypassCache && $.data(a, 'cache.tabs')) {
-			callback();
-			return;
-		}
-
-		// load remote from here on
-		
-		var inner = function(parent) {
-			var $parent = $(parent), $inner = $parent.find('*:last');
-			return $inner.length && $inner.is(':not(img)') && $inner || $parent;
-		};
-		var cleanup = function() {
-			self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass)
-						.each(function() {
-							if (o.spinner)
-								inner(this).parent().html(inner(this).data('label.tabs'));
-						});
-			self.xhr = null;
-		};
-		
-		if (o.spinner) {
-			var label = inner(a).html();
-			inner(a).wrapInner('<em></em>')
-				.find('em').data('label.tabs', label).html(o.spinner);
-		}
-
-		var ajaxOptions = $.extend({}, o.ajaxOptions, {
-			url: url,
-			success: function(r, s) {
-				$(a.hash).html(r);
-				cleanup();
-				
-				if (o.cache)
-					$.data(a, 'cache.tabs', true); // if loaded once do not load them again
-
-				// callbacks
-				self._trigger('load', null, self.ui(self.$tabs[index], self.$panels[index]));
-				o.ajaxOptions.success && o.ajaxOptions.success(r, s);
-				
-				// This callback is required because the switch has to take
-				// place after loading has completed. Call last in order to 
-				// fire load before show callback...
-				callback();
-			}
-		});
-		if (this.xhr) {
-			// terminate pending requests from other tabs and restore tab label
-			this.xhr.abort();
-			cleanup();
-		}
-		$a.addClass(o.loadingClass);
-		setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
-			self.xhr = $.ajax(ajaxOptions);
-		}, 0);
-
-	},
-	url: function(index, url) {
-		this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
-	},
-	destroy: function() {
-		var o = this.options;
-		this.element.unbind('.tabs')
-			.removeClass(o.navClass).removeData('tabs');
-		this.$tabs.each(function() {
-			var href = $.data(this, 'href.tabs');
-			if (href)
-				this.href = href;
-			var $this = $(this).unbind('.tabs');
-			$.each(['href', 'load', 'cache'], function(i, prefix) {
-				$this.removeData(prefix + '.tabs');
-			});
-		});
-		this.$lis.add(this.$panels).each(function() {
-			if ($.data(this, 'destroy.tabs'))
-				$(this).remove();
-			else
-				$(this).removeClass([o.selectedClass, o.unselectClass,
-					o.disabledClass, o.panelClass, o.hideClass].join(' '));
-		});
-	}
-});
-
-$.ui.tabs.defaults = {
-	// basic setup
-	unselect: false,
-	event: 'click',
-	disabled: [],
-	cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
-	// TODO history: false,
-
-	// Ajax
-	spinner: 'Loading&#8230;',
-	cache: false,
-	idPrefix: 'ui-tabs-',
-	ajaxOptions: {},
-
-	// animations
-	fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
-
-	// templates
-	tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
-	panelTemplate: '<div></div>',
-
-	// CSS classes
-	navClass: 'ui-tabs-nav',
-	selectedClass: 'ui-tabs-selected',
-	unselectClass: 'ui-tabs-unselect',
-	disabledClass: 'ui-tabs-disabled',
-	panelClass: 'ui-tabs-panel',
-	hideClass: 'ui-tabs-hide',
-	loadingClass: 'ui-tabs-loading'
-};
-
-$.ui.tabs.getter = "length";
-
-/*
- * Tabs Extensions
- */
-
-/*
- * Rotate
- */
-$.extend($.ui.tabs.prototype, {
-	rotation: null,
-	rotate: function(ms, continuing) {
-		
-		continuing = continuing || false;
-		
-		var self = this, t = this.options.selected;
-		
-		function start() {
-			self.rotation = setInterval(function() {
-				t = ++t < self.$tabs.length ? t : 0;
-				self.select(t);
-			}, ms); 
-		}
-		
-		function stop(e) {
-			if (!e || e.clientX) { // only in case of a true click
-				clearInterval(self.rotation);
-			}
-		}
-		
-		// start interval
-		if (ms) {
-			start();
-			if (!continuing)
-				this.$tabs.bind(this.options.event, stop);
-			else
-				this.$tabs.bind(this.options.event, function() {
-					stop();
-					t = self.options.selected;
-					start();
-				});
-		}
-		// stop interval
-		else {
-			stop();
-			this.$tabs.unbind(this.options.event, stop);
-		}
-	}
-});
-
-})(jQuery);
--- a/web/facet.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/facet.py	Mon May 16 16:25:33 2011 +0200
@@ -605,7 +605,7 @@
                 insert_attr_select_relation(
                     rqlst, self.filtered_variable, self.rtype, self.role, self.target_attr,
                     select_target_entity=False)
-            values = [str(x) for x, in self.rqlexec(rqlst.as_string())]
+            values = [unicode(x) for x, in self.rqlexec(rqlst.as_string())]
         except:
             self.exception('while computing values for %s', self)
             return []
@@ -936,7 +936,7 @@
         """return the widget instance to use to display this facet"""
         values = set(value for _, value in self.vocabulary() if value is not None)
         # Rset with entities (the facet is selected) but without values
-        if len(values) == 0:
+        if len(values) < 2:
             return None
         return self.wdgclass(self, min(values), max(values))
 
@@ -1016,6 +1016,7 @@
           rtype = 'has_image'
           role = 'subject'
     """
+    __select__ = partial_relation_possible() & match_context_prop()
     rtype = None # override me in subclass
     role = 'subject' # role of filtered entity in the relation
 
@@ -1125,8 +1126,8 @@
 
     def _render(self):
         facet = self.facet
-        facet._cw.add_js('ui.slider.js')
-        facet._cw.add_css('ui.all.css')
+        facet._cw.add_js('jquery.ui.js')
+        facet._cw.add_css('jquery.ui.css')
         sliderid = make_uid('theslider')
         facetid = xml_escape(self.facet.__regid__)
         facet._cw.html_headers.add_onload(self.onload % {
--- a/web/formfields.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/formfields.py	Mon May 16 16:25:33 2011 +0200
@@ -875,7 +875,9 @@
         if self.choices:
             return super(BooleanField, self).vocabulary(form)
         if self.allow_none:
-            return [('', ''), (form._cw._('yes'), '1'), (form._cw._('no'), '0')]
+            return [(form._cw._('indifferent'), ''),
+                    (form._cw._('yes'), '1'),
+                    (form._cw._('no'), '0')]
         # XXX empty string for 'no' in that case for bw compat
         return [(form._cw._('yes'), '1'), (form._cw._('no'), '')]
 
@@ -1200,14 +1202,19 @@
 
 
 FIELDS = {
-    'Boolean':  BooleanField,
+    'String' :  StringField,
     'Bytes':    FileField,
-    'Date':     DateField,
-    'Datetime': DateTimeField,
+    'Password': PasswordField,
+
+    'Boolean':  BooleanField,
     'Int':      IntField,
     'Float':    FloatField,
     'Decimal':  StringField,
-    'Password': PasswordField,
-    'String' :  StringField,
-    'Time':     TimeField,
+
+    'Date':       DateField,
+    'Datetime':   DateTimeField,
+    'TZDatetime': DateTimeField,
+    'Time':       TimeField,
+    'TZTime':     TimeField,
+    # XXX implement 'Interval': TimeIntervalField,
     }
--- a/web/formwidgets.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/formwidgets.py	Mon May 16 16:25:33 2011 +0200
@@ -478,11 +478,12 @@
     default <br/> is used.
     """
     type = 'checkbox'
+    default_separator = u'<br/>\n'
     vocabulary_widget = True
 
-    def __init__(self, attrs=None, separator=u'<br/>\n', **kwargs):
+    def __init__(self, attrs=None, separator=None, **kwargs):
         super(CheckBox, self).__init__(attrs, **kwargs)
-        self.separator = separator
+        self.separator = separator or self.default_separator
 
     def _render(self, form, field, renderer):
         curvalues, attrs = self.values_and_attributes(form, field)
--- a/web/request.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/request.py	Mon May 16 16:25:33 2011 +0200
@@ -116,8 +116,8 @@
         pid = self.form.get('pageid')
         if pid is None:
             pid = make_uid(id(self))
+            self.html_headers.define_var('pageid', pid, override=False)
         self.pageid = pid
-        self.html_headers.define_var('pageid', pid, override=False)
 
     @property
     def authmode(self):
@@ -732,26 +732,14 @@
         return None, None
 
     def parse_accept_header(self, header):
-        """returns an ordered list of preferred languages"""
+        """returns an ordered list of accepted values"""
+        try:
+            value_parser, value_sort_key = ACCEPT_HEADER_PARSER[header.lower()]
+        except KeyError:
+            value_parser = value_sort_key = None
         accepteds = self.get_header(header, '')
-        values = []
-        for info in accepteds.split(','):
-            try:
-                value, scores = info.split(';', 1)
-            except ValueError:
-                value = info
-                score = 1.0
-            else:
-                for score in scores.split(';'):
-                    try:
-                        scorekey, scoreval = score.split('=')
-                        if scorekey == 'q': # XXX 'level'
-                            score = float(scoreval)
-                    except ValueError:
-                        continue
-            values.append((score, value))
-        values.sort(reverse=True)
-        return (value for (score, value) in values)
+        values = _parse_accept_header(accepteds, value_parser, value_sort_key)
+        return (raw_value for (raw_value, parsed_value, score) in values)
 
     def header_if_modified_since(self):
         """If the HTTP header If-modified-since is set, return the equivalent
@@ -766,8 +754,16 @@
         will display '<[' at the beginning of the page
         """
         self.set_content_type('text/html')
-        self.main_stream.doctype = TRANSITIONAL_DOCTYPE_NOEXT
-        self.main_stream.xmldecl = u''
+        self.main_stream.set_doctype(TRANSITIONAL_DOCTYPE_NOEXT)
+
+    def set_doctype(self, doctype, reset_xmldecl=True):
+        """helper method to dynamically change page doctype
+
+        :param doctype: the new doctype, e.g. '<!DOCTYPE html>'
+        :param reset_xmldecl: if True, remove the '<?xml version="1.0"?>'
+                              declaration from the page
+        """
+        self.main_stream.set_doctype(doctype, reset_xmldecl)
 
     # page data management ####################################################
 
@@ -856,5 +852,91 @@
                 self.parse_accept_header('Accept-Language')]
 
 
+
+## HTTP-accept parsers / utilies ##############################################
+def _mimetype_sort_key(accept_info):
+    """accepted mimetypes must be sorted by :
+
+    1/ highest score first
+    2/ most specific mimetype first, e.g. :
+       - 'text/html level=1' is more specific 'text/html'
+       - 'text/html' is more specific than 'text/*'
+       - 'text/*' itself more specific than '*/*'
+
+    """
+    raw_value, (media_type, media_subtype, media_type_params), score = accept_info
+    # FIXME: handle '+' in media_subtype ? (should xhtml+xml have a
+    # higher precedence than xml ?)
+    if media_subtype == '*':
+        score -= 0.0001
+    if media_type == '*':
+        score -= 0.0001
+    return 1./score, media_type, media_subtype, 1./(1+len(media_type_params))
+
+def _charset_sort_key(accept_info):
+    """accepted mimetypes must be sorted by :
+
+    1/ highest score first
+    2/ most specific charset first, e.g. :
+       - 'utf-8' is more specific than '*'
+    """
+    raw_value, value, score = accept_info
+    if value == '*':
+        score -= 0.0001
+    return 1./score, value
+
+def _parse_accept_header(raw_header, value_parser=None, value_sort_key=None):
+    """returns an ordered list accepted types
+
+    returned value is a list of 2-tuple (value, score), ordered
+    by score. Exact type of `value` will depend on what `value_parser`
+    will reutrn. if `value_parser` is None, then the raw value, as found
+    in the http header, is used.
+    """
+    if value_sort_key is None:
+        value_sort_key = lambda infos: 1./infos[-1]
+    values = []
+    for info in raw_header.split(','):
+        score = 1.0
+        other_params = {}
+        try:
+            value, infodef = info.split(';', 1)
+        except ValueError:
+            value = info
+        else:
+            for info in infodef.split(';'):
+                try:
+                    infokey, infoval = info.split('=')
+                    if infokey == 'q': # XXX 'level'
+                        score = float(infoval)
+                        continue
+                except ValueError:
+                    continue
+                other_params[infokey] = infoval
+        parsed_value = value_parser(value, other_params) if value_parser else value
+        values.append( (value.strip(), parsed_value, score) )
+    values.sort(key=value_sort_key)
+    return values
+
+
+def _mimetype_parser(value, other_params):
+    """return a 3-tuple
+    (type, subtype, type_params) corresponding to the mimetype definition
+    e.g. : for 'text/*', `mimetypeinfo` will be ('text', '*', {}), for
+    'text/html;level=1', `mimetypeinfo` will be ('text', '*', {'level': '1'})
+    """
+    try:
+        media_type, media_subtype = value.strip().split('/')
+    except ValueError: # safety belt : '/' should always be present
+        media_type = value.strip()
+        media_subtype = '*'
+    return (media_type, media_subtype, other_params)
+
+
+ACCEPT_HEADER_PARSER = {
+    'accept': (_mimetype_parser, _mimetype_sort_key),
+    'accept-charset': (None, _charset_sort_key),
+    }
+
 from cubicweb import set_log_methods
 set_log_methods(CubicWebRequestBase, LOGGER)
--- a/web/schemaviewer.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/schemaviewer.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -15,9 +15,8 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""an helper class to display CubicWeb schema using ureports
+"""an helper class to display CubicWeb schema using ureports"""
 
-"""
 __docformat__ = "restructuredtext en"
 _ = unicode
 
@@ -217,7 +216,7 @@
                     if val is None:
                         val = ''
                     elif prop == 'constraints':
-                        val = ', '.join([c.restriction for c in val])
+                        val = ', '.join([c.expression for c in val])
                     elif isinstance(val, dict):
                         for key, value in val.iteritems():
                             if isinstance(value, (list, tuple)):
--- a/web/test/jstests/ajax_url0.html	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-<div id="ajaxroot">
-  <h1>Hello</h1>
-</div>
--- a/web/test/jstests/ajax_url1.html	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<div id="ajaxroot">
-  <div class="ajaxHtmlHead">
-    <script src="http://foo.js" type="text/javascript"> </script>
-  </div>
-  <h1>Hello</h1>
-</div>
--- a/web/test/jstests/ajax_url2.html	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<div id="ajaxroot">
-  <div class="ajaxHtmlHead">
-    <script src="http://foo.js" type="text/javascript"> </script>
-    <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
-  </div>
-  <h1>Hello</h1>
-</div>
--- a/web/test/jstests/ajaxresult.json	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-['foo', 'bar']
--- a/web/test/jstests/test_ajax.html	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-<html>
-  <head>
-    <!-- dependencies -->
-    <script type="text/javascript" src="../../data/jquery.js"></script>
-    <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.dom.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.ajax.js" type="text/javascript"></script>
-    <!-- qunit files -->
-    <script type="text/javascript" src="../../../devtools/data/qunit.js"></script>
-    <link rel="stylesheet" type="text/css" media="all" href="../../../devtools/data/qunit.css" />
-    <!-- test suite -->
-    <script src="cwmock.js" type="text/javascript"></script>
-    <script src="test_ajax.js" type="text/javascript"></script>
-  </head>
-  <body>
-    <div id="main"> </div>
-    <h1 id="qunit-header">cubicweb.ajax.js functions tests</h1>
-    <h2 id="qunit-banner"></h2>
-    <ol id="qunit-tests">
-  </body>
-</html>
--- a/web/test/jstests/test_ajax.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,244 +0,0 @@
-$(document).ready(function() {
-
-    module("ajax", {
-        setup: function() {
-          this.scriptsLength = $('head script[src]').length-1;
-          this.cssLength = $('head link[rel=stylesheet]').length-1;
-          // re-initialize cw loaded cache so that each tests run in a
-          // clean environment, have a lookt at _loadAjaxHtmlHead implementation
-          // in cubicweb.ajax.js for more information.
-          cw.loaded_src = [];
-          cw.loaded_href = [];
-        },
-        teardown: function() {
-          $('head script[src]:gt(' + this.scriptsLength + ')').remove();
-          $('head link[rel=stylesheet]:gt(' + this.cssLength + ')').remove();
-        }
-      });
-
-    function jsSources() {
-        return $.map($('head script[src]'), function(script) {
-            return script.getAttribute('src');
-        });
-    }
-
-    test('test simple h1 inclusion (ajax_url0.html)', function() {
-        expect(3);
-        equals(jQuery('#main').children().length, 0);
-        stop();
-        jQuery('#main').loadxhtml('/../ajax_url0.html', {
-            callback: function() {
-                equals(jQuery('#main').children().length, 1);
-                equals(jQuery('#main h1').html(), 'Hello');
-                start();
-            }
-        });
-    });
-
-    test('test simple html head inclusion (ajax_url1.html)', function() {
-        expect(6);
-        var scriptsIncluded = jsSources();
-        equals(jQuery.inArray('http://foo.js', scriptsIncluded), - 1);
-        stop();
-        jQuery('#main').loadxhtml('/../ajax_url1.html', {
-            callback: function() {
-                var origLength = scriptsIncluded.length;
-                scriptsIncluded = jsSources();
-                // check that foo.js has been *appended* to <head>
-                equals(scriptsIncluded.length, origLength + 1);
-                equals(scriptsIncluded[origLength].indexOf('http://foo.js'), 0);
-                // check that <div class="ajaxHtmlHead"> has been removed
-                equals(jQuery('#main').children().length, 1);
-                equals(jQuery('div.ajaxHtmlHead').length, 0);
-                equals(jQuery('#main h1').html(), 'Hello');
-                start();
-            }
-        });
-    });
-
-    test('test addCallback', function() {
-        expect(3);
-        equals(jQuery('#main').children().length, 0);
-        stop();
-        var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
-        d.addCallback(function() {
-            equals(jQuery('#main').children().length, 1);
-            equals(jQuery('#main h1').html(), 'Hello');
-            start();
-        });
-    });
-
-    test('test callback after synchronous request', function() {
-        expect(1);
-        var deferred = new Deferred();
-        var result = jQuery.ajax({
-            url: './ajax_url0.html',
-            async: false,
-            beforeSend: function(xhr) {
-                deferred._req = xhr;
-            },
-            success: function(data, status) {
-                deferred.success(data);
-            }
-        });
-        stop();
-        deferred.addCallback(function() {
-            // add an assertion to ensure the callback is executed
-            ok(true, "callback is executed");
-            start();
-        });
-    });
-
-    test('test addCallback with parameters', function() {
-        expect(3);
-        equals(jQuery('#main').children().length, 0);
-        stop();
-        var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
-        d.addCallback(function(data, req, arg1, arg2) {
-            equals(arg1, 'Hello');
-            equals(arg2, 'world');
-            start();
-        },
-        'Hello', 'world');
-    });
-
-    test('test callback after synchronous request with parameters', function() {
-        var deferred = new Deferred();
-        var result = jQuery.ajax({
-            url: '/../ajax_url0.html',
-            async: false,
-            beforeSend: function(xhr) {
-                deferred._req = xhr;
-            },
-            success: function(data, status) {
-                deferred.success(data);
-            }
-        });
-        deferred.addCallback(function(data, req, arg1, arg2) {
-            // add an assertion to ensure the callback is executed
-            ok(true, "callback is executed");
-            equals(arg1, 'Hello');
-            equals(arg2, 'world');
-        },
-        'Hello', 'world');
-    });
-
-  test('test addErrback', function() {
-        expect(1);
-        stop();
-        var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
-        d.addCallback(function() {
-            // throw an exception to start errback chain
-            throw new Error();
-        });
-        d.addErrback(function() {
-            ok(true, "errback is executed");
-            start();
-        });
-    });
-
-    test('test callback / errback execution order', function() {
-        expect(4);
-        var counter = 0;
-        stop();
-        var d = jQuery('#main').loadxhtml('/../ajax_url0.html', {
-            callback: function() {
-                equals(++counter, 1); // should be executed first
-                start();
-            }
-        });
-        d.addCallback(function() {
-            equals(++counter, 2); // should be executed and break callback chain
-            throw new Error();
-        });
-        d.addCallback(function() {
-            // should not be executed since second callback raised an error
-            ok(false, "callback is executed");
-        });
-        d.addErrback(function() {
-            // should be executed after the second callback
-            equals(++counter, 3);
-        });
-        d.addErrback(function() {
-            // should be executed after the first errback
-            equals(++counter, 4);
-        });
-    });
-
-    test('test already included resources are ignored (ajax_url1.html)', function() {
-        expect(10);
-        var scriptsIncluded = jsSources();
-        // NOTE:
-        equals(jQuery.inArray('http://foo.js', scriptsIncluded), -1);
-        equals(jQuery('head link').length, 1);
-        /* use endswith because in pytest context we have an absolute path */
-        ok(jQuery('head link').attr('href').endswith('/qunit.css'));
-        stop();
-        jQuery('#main').loadxhtml('/../ajax_url1.html', {
-            callback: function() {
-                var origLength = scriptsIncluded.length;
-                scriptsIncluded = jsSources();
-                try {
-                    // check that foo.js has been inserted in <head>
-                    equals(scriptsIncluded.length, origLength + 1);
-                    equals(scriptsIncluded[origLength].indexOf('http://foo.js'), 0);
-                    // check that <div class="ajaxHtmlHead"> has been removed
-                    equals(jQuery('#main').children().length, 1);
-                    equals(jQuery('div.ajaxHtmlHead').length, 0);
-                    equals(jQuery('#main h1').html(), 'Hello');
-                    // qunit.css is not added twice
-                    equals(jQuery('head link').length, 1);
-                    /* use endswith because in pytest context we have an absolute path */
-                    ok(jQuery('head link').attr('href').endswith('/qunit.css'));
-                } finally {
-                    start();
-                }
-            }
-        });
-    });
-
-    test('test synchronous request loadRemote', function() {
-        var res = loadRemote('/../ajaxresult.json', {},
-        'GET', true);
-        same(res, ['foo', 'bar']);
-    });
-
-    test('test event on CubicWeb', function() {
-        expect(1);
-        stop();
-        var events = null;
-        jQuery(CubicWeb).bind('server-response', function() {
-            // check that server-response event on CubicWeb is triggered
-            events = 'CubicWeb';
-        });
-        jQuery('#main').loadxhtml('/../ajax_url0.html', {
-            callback: function() {
-                equals(events, 'CubicWeb');
-                start();
-            }
-        });
-    });
-
-    test('test event on node', function() {
-        expect(3);
-        stop();
-        var nodes = [];
-        jQuery('#main').bind('server-response', function() {
-            nodes.push('node');
-        });
-        jQuery(CubicWeb).bind('server-response', function() {
-            nodes.push('CubicWeb');
-        });
-        jQuery('#main').loadxhtml('/../ajax_url0.html', {
-            callback: function() {
-                equals(nodes.length, 2);
-                // check that server-response event on CubicWeb is triggered
-                // only once and event server-response on node is triggered
-                equals(nodes[0], 'CubicWeb');
-                equals(nodes[1], 'node');
-                start();
-            }
-        });
-    });
-});
-
--- a/web/test/jstests/test_htmlhelpers.html	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-<html>
-  <head>
-    <script type="text/javascript" src="../../data/jquery.js"></script>
-    <script src="../../data/cubicweb.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
-    <script type="text/javascript" src="qunit.js"></script>
-    <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
-    <script src="cwmock.js" type="text/javascript"></script>
-    <script src="test_htmlhelpers.js" type="text/javascript"></script>
-  </head>
-  <body>
-    <div id="main">
-    </div>
-    <h1 id="qunit-header">cubicweb.htmlhelpers.js functions tests</h1>
-    <h2 id="qunit-banner"></h2>
-    <h2 id="qunit-userAgent"></h2>
-    <ol id="qunit-tests">
-  </body>
-</html>
--- a/web/test/jstests/test_htmlhelpers.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-$(document).ready(function() {
-
-    module("module2", {
-      setup: function() {
-        $('#main').append('<select id="theselect" multiple="multiple" size="2">' +
-    			'</select>');
-      }
-    });
-
-    test("test first selected", function() {
-        $('#theselect').append('<option value="foo">foo</option>' +
-    			     '<option selected="selected" value="bar">bar</option>' +
-    			     '<option value="baz">baz</option>' +
-    			     '<option selected="selecetd"value="spam">spam</option>');
-        var selected = firstSelected(document.getElementById("theselect"));
-        equals(selected.value, 'bar');
-    });
-
-    test("test first selected 2", function() {
-        $('#theselect').append('<option value="foo">foo</option>' +
-    			     '<option value="bar">bar</option>' +
-    			     '<option value="baz">baz</option>' +
-    			     '<option value="spam">spam</option>');
-        var selected = firstSelected(document.getElementById("theselect"));
-        equals(selected, null);
-    });
-
-    module("visibilty");
-    test('toggleVisibility', function() {
-        $('#main').append('<div id="foo"></div>');
-        toggleVisibility('foo');
-        ok($('#foo').hasClass('hidden'), 'check hidden class is set');
-    });
-
-});
-
--- a/web/test/jstests/test_utils.html	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-<html>
-  <head>
-    <script type="text/javascript" src="../../data/jquery.js"></script>
-    <script src="../../data/jquery.corner.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
-    <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
-    <script src="utils.js" type="text/javascript"></script>
-    <script type="text/javascript" src="qunit.js"></script>
-    <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
-    <script src="cwmock.js" type="text/javascript"></script>
-    <script src="test_utils.js" type="text/javascript"></script>
-  </head>
-  <body>
-    <div id="main">
-    </div>
-    <h1 id="qunit-header">cw.utils functions tests</h1>
-    <h2 id="qunit-banner"></h2>
-    <h2 id="qunit-userAgent"></h2>
-    <ol id="qunit-tests">
-  </body>
-</html>
--- a/web/test/jstests/test_utils.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-$(document).ready(function() {
-
-  module("datetime");
-
-  test("test full datetime", function() {
-      equals(cw.utils.toISOTimestamp(new Date(1986, 3, 18, 10, 30, 0, 0)),
-	     '1986-04-18 10:30:00');
-  });
-
-  test("test only date", function() {
-      equals(cw.utils.toISOTimestamp(new Date(1986, 3, 18)), '1986-04-18 00:00:00');
-  });
-
-  test("test null", function() {
-      equals(cw.utils.toISOTimestamp(null), null);
-  });
-
-  module("parsing");
-  test("test basic number parsing", function() {
-      var d = strptime('2008/08/08', '%Y/%m/%d');
-      same(datetuple(d), [2008, 8, 8, 0, 0]);
-      d = strptime('2008/8/8', '%Y/%m/%d');
-      same(datetuple(d), [2008, 8, 8, 0, 0]);
-      d = strptime('8/8/8', '%Y/%m/%d');
-      same(datetuple(d), [8, 8, 8, 0, 0]);
-      d = strptime('0/8/8', '%Y/%m/%d');
-      same(datetuple(d), [0, 8, 8, 0, 0]);
-      d = strptime('-10/8/8', '%Y/%m/%d');
-      same(datetuple(d), [-10, 8, 8, 0, 0]);
-      d = strptime('-35000', '%Y');
-      same(datetuple(d), [-35000, 1, 1, 0, 0]);
-  });
-
-  test("test custom format parsing", function() {
-      var d = strptime('2008-08-08', '%Y-%m-%d');
-      same(datetuple(d), [2008, 8, 8, 0, 0]);
-      d = strptime('2008 - !  08: 08', '%Y - !  %m: %d');
-      same(datetuple(d), [2008, 8, 8, 0, 0]);
-      d = strptime('2008-08-08 12:14', '%Y-%m-%d %H:%M');
-      same(datetuple(d), [2008, 8, 8, 12, 14]);
-      d = strptime('2008-08-08 1:14', '%Y-%m-%d %H:%M');
-      same(datetuple(d), [2008, 8, 8, 1, 14]);
-      d = strptime('2008-08-08 01:14', '%Y-%m-%d %H:%M');
-      same(datetuple(d), [2008, 8, 8, 1, 14]);
-  });
-
-  module("sliceList");
-  test("test slicelist", function() {
-      var list = ['a', 'b', 'c', 'd', 'e', 'f'];
-      same(sliceList(list, 2),  ['c', 'd', 'e', 'f']);
-      same(sliceList(list, 2, -2), ['c', 'd']);
-      same(sliceList(list, -3), ['d', 'e', 'f']);
-      same(sliceList(list, 0, -2), ['a', 'b', 'c', 'd']);
-      same(sliceList(list),  list);
-  });
-
-  module("formContents", {
-    setup: function() {
-      $('#main').append('<form id="test-form"></form>');
-    }
-  });
-  // XXX test fckeditor
-  test("test formContents", function() {
-      $('#test-form').append('<input name="input-text" ' +
-			     'type="text" value="toto" />');
-      $('#test-form').append('<textarea rows="10" cols="30" '+
-			     'name="mytextarea">Hello World!</textarea> ');
-      $('#test-form').append('<input name="choice" type="radio" ' +
-			     'value="yes" />');
-      $('#test-form').append('<input name="choice" type="radio" ' +
-			     'value="no" checked="checked"/>');
-      $('#test-form').append('<input name="check" type="checkbox" ' +
-			     'value="yes" />');
-      $('#test-form').append('<input name="check" type="checkbox" ' +
-			     'value="no" checked="checked"/>');
-      $('#test-form').append('<select id="theselect" name="theselect" ' +
-			     'multiple="multiple" size="2"></select>');
-      $('#theselect').append('<option selected="selected" ' +
-			     'value="foo">foo</option>' +
-  			     '<option value="bar">bar</option>');
-      //Append an unchecked radio input : should not be in formContents list
-      $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
-			     'value="one" />');
-      $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
-			     'value="two"/>');
-      same(formContents($('#test-form')[0]), [
-	['input-text', 'mytextarea', 'choice', 'check', 'theselect'],
-	['toto', 'Hello World!', 'no', 'no', 'foo']
-      ]);
-  });
-});
-
--- a/web/test/jstests/utils.js	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-function datetuple(d) {
-    return [d.getFullYear(), d.getMonth()+1, d.getDate(),
-	    d.getHours(), d.getMinutes()];
-}
-
-function pprint(obj) {
-    print('{');
-    for(k in obj) {
-	print('  ' + k + ' = ' + obj[k]);
-    }
-    print('}');
-}
-
-function arrayrepr(array) {
-    return '[' + array.join(', ') + ']';
-}
-
-function assertArrayEquals(array1, array2) {
-    if (array1.length != array2.length) {
-	throw new crosscheck.AssertionFailure(array1.join(', ') + ' != ' + array2.join(', '));
-    }
-    for (var i=0; i<array1.length; i++) {
-	if (array1[i] != array2[i]) {
-
-	    throw new crosscheck.AssertionFailure(arrayrepr(array1) + ' and ' + arrayrepr(array2)
-						 + ' differs at index ' + i);
-	}
-    }
-}
--- a/web/test/test_jscript.py	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-from cubicweb.devtools.qunit import QUnitTestCase, unittest_main
-
-from os import path as osp
-
-
-class JScript(QUnitTestCase):
-
-    all_js_tests = (
-        ("jstests/test_utils.js", (
-            "../data/cubicweb.js",
-            "../data/cubicweb.compat.js",
-            "../data/cubicweb.python.js",
-            "jstests/utils.js",
-            ),
-         ),
-
-        ("jstests/test_htmlhelpers.js", (
-            "../data/cubicweb.js",
-            "../data/cubicweb.compat.js",
-            "../data/cubicweb.python.js",
-            "../data/cubicweb.htmlhelpers.js",
-            ),
-         ),
-
-        ("jstests/test_ajax.js", (
-            "../data/cubicweb.python.js",
-            "../data/cubicweb.js",
-            "../data/cubicweb.compat.js",
-            "../data/cubicweb.htmlhelpers.js",
-            "../data/cubicweb.ajax.js",
-            ), (
-            "jstests/ajax_url0.html",
-            "jstests/ajax_url1.html",
-            "jstests/ajax_url2.html",
-            "jstests/ajaxresult.json",
-            ),
-         ),
-    )
-
-
-if __name__ == '__main__':
-    unittest_main()
--- a/web/test/test_windmill.py	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-# Run all scenarii found in windmill directory
-from os.path import join, dirname
-from cubicweb.devtools.cwwindmill import (CubicWebWindmillUseCase,
-                                          unittest_main)
-
-class CubicWebWindmillUseCase(CubicWebWindmillUseCase):
-    #test_dir = join(dirname(__file__), "windmill/test_edit_relation.py")
-    pass
-
-
-if __name__ == '__main__':
-    unittest_main()
--- a/web/test/unittest_application.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_application.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
--- a/web/test/unittest_form.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_form.py	Mon May 16 16:25:33 2011 +0200
@@ -104,9 +104,9 @@
 
     def test_reledit_composite_field(self):
         rset = self.execute('INSERT BlogEntry X: X title "cubicweb.org", X content "hop"')
-        form = self.vreg['views'].select('doreledit', self.request(),
+        form = self.vreg['views'].select('reledit', self.request(),
                                          rset=rset, row=0, rtype='content')
-        data = form.render(row=0, rtype='content', formid='base')
+        data = form.render(row=0, rtype='content', formid='base', action='edit_rtype')
         self.failUnless('content_format' in data)
 
     # form view tests #########################################################
--- a/web/test/unittest_reledit.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_reledit.py	Mon May 16 16:25:33 2011 +0200
@@ -16,7 +16,7 @@
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 """
-mainly regression-preventing tests for reledit/doreledit views
+mainly regression-preventing tests for reledit views
 """
 
 from cubicweb.devtools.testlib import CubicWebTC
@@ -33,9 +33,9 @@
 class ClickAndEditFormTC(ReleditMixinTC, CubicWebTC):
 
     def test_default_config(self):
-        reledit = {'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField hidden"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, false, &#39;&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
-                   'long_desc': """<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField hidden"><div id="long_desc-subject-%(eid)s-add" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to add a value"><img title="click to add a value" src="http://testing.fr/cubicweb/data/plus.png" alt="click to add a value"/></div></div></div>""",
-                   'manager': """<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="manager-subject-%(eid)s" class="editableField hidden"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
+        reledit = {'title': '''<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField hidden"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, false, &#39;&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>''',
+                   'long_desc': '''<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField hidden"><div id="long_desc-subject-%(eid)s-add" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;add&#39;);" title="click to add a value"><img title="click to add a value" src="http://testing.fr/cubicweb/data/plus.png" alt="click to add a value"/></div></div></div>''',
+                   'manager': '''<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue">&lt;not specified&gt;</div><div id="manager-subject-%(eid)s" class="editableField hidden"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>''',
                    'composite_card11_2ttypes': """&lt;not specified&gt;""",
                    'concerns': """&lt;not specified&gt;"""}
 
@@ -44,9 +44,11 @@
                 continue
             rtype = rschema.type
             self.assertMultiLineEqual(reledit[rtype] % {'eid': self.proj.eid},
-                                      self.proj.view('reledit', rtype=rtype, role=role), rtype)
+                                      self.proj.view('reledit', rtype=rtype, role=role),
+                                      rtype)
 
     def test_default_forms(self):
+        self.skip('Need to check if this test should still run post reledit/doreledit merge')
         doreledit = {'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><form action="http://testing.fr/cubicweb/validateform?__onsuccess=window.parent.cw.reledit.onSuccess" method="post" enctype="application/x-www-form-urlencoded" id="title-subject-%(eid)s-form" onsubmit="return freezeFormButtons(&#39;title-subject-%(eid)s-form&#39;);" class="releditForm" cubicweb:target="eformframe">
 <fieldset>
 <input name="__form_id" type="hidden" value="base" />
@@ -190,11 +192,11 @@
         reledit_ctrl.tag_object_of(('Ticket', 'concerns', 'Project'),
                                    {'edit_target': 'rtype'})
         reledit = {
-            'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField hidden"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, true, &#39;&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
-            'long_desc': """<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;long_desc is required&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField hidden"><div id="long_desc-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, true, &#39;autolimited&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
-            'manager': """<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/personne/%(toto)s" title="">Toto</a></div><div id="manager-subject-%(eid)s" class="editableField hidden"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div><div id="manager-subject-%(eid)s-delete" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;deleteconf&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to delete this value"><img title="click to delete this value" src="http://testing.fr/cubicweb/data/cancel.png" alt="click to delete this value"/></div></div></div>""",
+            'title': """<div id="title-subject-%(eid)s-reledit" onmouseout="jQuery('#title-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#title-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="title-subject-%(eid)s-value" class="editableFieldValue">cubicweb-world-domination</div><div id="title-subject-%(eid)s" class="editableField hidden"><div id="title-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;title&#39;, &#39;subject&#39;, &#39;title-subject-%(eid)s&#39;, true, &#39;&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
+            'long_desc': """<div id="long_desc-subject-%(eid)s-reledit" onmouseout="jQuery('#long_desc-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#long_desc-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="long_desc-subject-%(eid)s-value" class="editableFieldValue">&lt;long_desc is required&gt;</div><div id="long_desc-subject-%(eid)s" class="editableField hidden"><div id="long_desc-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;long_desc&#39;, &#39;subject&#39;, &#39;long_desc-subject-%(eid)s&#39;, true, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>""",
+            'manager': """<div id="manager-subject-%(eid)s-reledit" onmouseout="jQuery('#manager-subject-%(eid)s').addClass('hidden')" onmouseover="jQuery('#manager-subject-%(eid)s').removeClass('hidden')" class="releditField"><div id="manager-subject-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/personne/%(toto)s" title="">Toto</a></div><div id="manager-subject-%(eid)s" class="editableField hidden"><div id="manager-subject-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;edition&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_related&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div><div id="manager-subject-%(eid)s-delete" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;deleteconf&#39;, %(eid)s, &#39;manager&#39;, &#39;subject&#39;, &#39;manager-subject-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;delete&#39;);" title="click to delete this value"><img title="click to delete this value" src="http://testing.fr/cubicweb/data/cancel.png" alt="click to delete this value"/></div></div></div>""",
             'composite_card11_2ttypes': """&lt;not specified&gt;""",
-            'concerns': """<div id="concerns-object-%(eid)s-reledit" onmouseout="jQuery('#concerns-object-%(eid)s').addClass('hidden')" onmouseover="jQuery('#concerns-object-%(eid)s').removeClass('hidden')" class="releditField"><div id="concerns-object-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/ticket/%(tick)s" title="">write the code</a></div><div id="concerns-object-%(eid)s" class="editableField hidden"><div id="concerns-object-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;concerns&#39;, &#39;object&#39;, &#39;concerns-object-%(eid)s&#39;, false, &#39;autolimited&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>"""
+            'concerns': """<div id="concerns-object-%(eid)s-reledit" onmouseout="jQuery('#concerns-object-%(eid)s').addClass('hidden')" onmouseover="jQuery('#concerns-object-%(eid)s').removeClass('hidden')" class="releditField"><div id="concerns-object-%(eid)s-value" class="editableFieldValue"><a href="http://testing.fr/cubicweb/ticket/%(tick)s" title="">write the code</a></div><div id="concerns-object-%(eid)s" class="editableField hidden"><div id="concerns-object-%(eid)s-update" class="editableField" onclick="cw.reledit.loadInlineEditionForm(&#39;base&#39;, %(eid)s, &#39;concerns&#39;, &#39;object&#39;, &#39;concerns-object-%(eid)s&#39;, false, &#39;autolimited&#39;, &#39;edit_rtype&#39;);" title="click to edit this field"><img title="click to edit this field" src="http://testing.fr/cubicweb/data/pen_icon.png" alt="click to edit this field"/></div></div></div>"""
             }
         for rschema, ttypes, role in self.proj.e_schema.relation_definitions(includefinal=True):
             if rschema not in reledit:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/unittest_request.py	Mon May 16 16:25:33 2011 +0200
@@ -0,0 +1,69 @@
+"""misc. unittests for utility functions
+"""
+
+from logilab.common.testlib import TestCase, unittest_main
+
+from functools import partial
+
+from cubicweb.web.request import (_parse_accept_header,
+                                  _mimetype_sort_key, _mimetype_parser, _charset_sort_key)
+
+
+
+class AcceptParserTC(TestCase):
+
+    def test_parse_accept(self):
+        parse_accept_header = partial(_parse_accept_header,
+                                      value_parser=_mimetype_parser,
+                                      value_sort_key=_mimetype_sort_key)
+        # compare scores
+        self.assertEqual(parse_accept_header("audio/*;q=0.2, audio/basic"),
+                         [( ('audio/basic', ('audio', 'basic', {}), 1.0 ) ),
+                          ( ('audio/*', ('audio', '*', {}), 0.2 ) )])
+        self.assertEqual(parse_accept_header("text/plain;q=0.5, text/html, text/x-dvi;q=0.8, text/x-c"),
+                         [( ('text/html', ('text', 'html', {}), 1.0 ) ),
+                          ( ('text/x-c', ('text', 'x-c', {}), 1.0 ) ),
+                          ( ('text/x-dvi', ('text', 'x-dvi', {}), 0.8 ) ),
+                          ( ('text/plain', ('text', 'plain', {}), 0.5 ) )])
+        # compare mimetype precedence for a same given score
+        self.assertEqual(parse_accept_header("audio/*, audio/basic"),
+                         [( ('audio/basic', ('audio', 'basic', {}), 1.0 ) ),
+                          ( ('audio/*', ('audio', '*', {}), 1.0 ) )])
+        self.assertEqual(parse_accept_header("text/*, text/html, text/html;level=1, */*"),
+                         [( ('text/html', ('text', 'html', {'level': '1'}), 1.0 ) ),
+                          ( ('text/html', ('text', 'html', {}), 1.0 ) ),
+                          ( ('text/*', ('text', '*', {}), 1.0 ) ),
+                          ( ('*/*', ('*', '*', {}), 1.0 ) )])
+        # free party
+        self.assertEqual(parse_accept_header("text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5"),
+                         [( ('text/html', ('text', 'html', {'level': '1'}), 1.0 ) ),
+                          ( ('text/html', ('text', 'html', {}), 0.7 ) ),
+                          ( ('*/*', ('*', '*', {}), 0.5 ) ),
+                          ( ('text/html', ('text', 'html', {'level': '2'}), 0.4 ) ),
+                          ( ('text/*', ('text', '*', {}), 0.3 ) )
+                          ])
+        # chrome sample header
+        self.assertEqual(parse_accept_header("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"),
+                         [( ('application/xhtml+xml', ('application', 'xhtml+xml', {}), 1.0 ) ),
+                          ( ('application/xml', ('application', 'xml', {}), 1.0 ) ),
+                          ( ('image/png', ('image', 'png', {}), 1.0 ) ),
+                          ( ('text/html', ('text', 'html', {}), 0.9 ) ),
+                          ( ('text/plain', ('text', 'plain', {}), 0.8 ) ),
+                          ( ('*/*', ('*', '*', {}), 0.5 ) ),
+                          ])
+
+    def test_parse_accept_language(self):
+        self.assertEqual(_parse_accept_header('fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'),
+                         [('fr', 'fr', 1.0), ('fr-fr', 'fr-fr', 0.8),
+                          ('en-us', 'en-us', 0.5), ('en', 'en', 0.3)])
+
+    def test_parse_accept_charset(self):
+        parse_accept_header = partial(_parse_accept_header,
+                                      value_sort_key=_charset_sort_key)
+        self.assertEqual(parse_accept_header('ISO-8859-1,utf-8;q=0.7,*;q=0.7'),
+                         [('ISO-8859-1', 'ISO-8859-1', 1.0),
+                          ('utf-8', 'utf-8', 0.7),
+                          ('*', '*', 0.7)])
+
+if __name__ == '__main__':
+    unittest_main()
--- a/web/test/unittest_urlpublisher.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_urlpublisher.py	Mon May 16 16:25:33 2011 +0200
@@ -33,8 +33,8 @@
     """test suite for QSPreProcessor"""
 
     def setup_database(self):
-        self.create_user(u'ÿsaÿe')
         req = self.request()
+        self.create_user(req, u'ÿsaÿe')
         b = req.create_entity('BlogEntry', title=u'hell\'o', content=u'blabla')
         c = req.create_entity('Tag', name=u'yo') # take care: Tag's name normalized to lower case
         self.execute('SET C tags B WHERE C eid %(c)s, B eid %(b)s', {'c':c.eid, 'b':b.eid})
--- a/web/test/unittest_urlrewrite.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_urlrewrite.py	Mon May 16 16:25:33 2011 +0200
@@ -103,9 +103,10 @@
 class RgxActionRewriteTC(CubicWebTC):
 
     def setup_database(self):
-        self.p1 = self.create_user(u'user1')
+        req = self.request()
+        self.p1 = self.create_user(req, u'user1')
         self.p1.set_attributes(firstname=u'joe', surname=u'Dalton')
-        self.p2 = self.create_user(u'user2')
+        self.p2 = self.create_user(req, u'user2')
         self.p2.set_attributes(firstname=u'jack', surname=u'Dalton')
 
     def test_rgx_action_with_transforms(self):
--- a/web/test/unittest_views_basecontrollers.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_views_basecontrollers.py	Mon May 16 16:25:33 2011 +0200
@@ -93,9 +93,9 @@
         self.assertEqual([g.eid for g in e.in_group], groupeids)
 
     def test_user_can_change_its_password(self):
-        user = self.create_user('user')
+        req = self.request()
+        user = self.create_user(req, 'user')
         cnx = self.login('user')
-        req = self.request()
         eid = u(user.eid)
         req.form = {
             'eid': eid, '__maineid' : eid,
@@ -160,8 +160,8 @@
         self.assertEqual(email.address, 'dima@logilab.fr')
 
     def test_edit_multiple_linked(self):
-        peid = u(self.create_user('adim').eid)
         req = self.request()
+        peid = u(self.create_user(req, 'adim').eid)
         req.form = {'eid': [peid, 'Y'], '__maineid': peid,
 
                     '__type:'+peid: u'CWUser',
@@ -450,7 +450,8 @@
 
 
     def test_nonregr_rollback_on_validation_error(self):
-        p = self.create_user("doe")
+        req = self.request()
+        p = self.create_user(req, "doe")
         # do not try to skip 'primary_email' for this test
         old_skips = p.__class__.skip_copy_for
         p.__class__.skip_copy_for = ()
@@ -497,7 +498,7 @@
 
 class ReportBugControllerTC(CubicWebTC):
 
-    def test_usable_by_guets(self):
+    def test_usable_by_guest(self):
         self.login('anon')
         self.assertRaises(NoSelectableObject,
                           self.vreg['controllers'].select, 'reportbug', self.request())
@@ -506,7 +507,7 @@
 
 class SendMailControllerTC(CubicWebTC):
 
-    def test_not_usable_by_guets(self):
+    def test_not_usable_by_guest(self):
         self.assertRaises(NoSelectableObject,
                           self.vreg['controllers'].select, 'sendmail', self.request())
         self.vreg['controllers'].select('sendmail',
@@ -529,7 +530,7 @@
         req = self.request()
         self.pytag = req.create_entity('Tag', name=u'python')
         self.cubicwebtag = req.create_entity('Tag', name=u'cubicweb')
-        self.john = self.create_user(u'John')
+        self.john = self.create_user(req, u'John')
 
 
     ## tests ##################################################################
--- a/web/test/unittest_views_baseviews.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_views_baseviews.py	Mon May 16 16:25:33 2011 +0200
@@ -16,11 +16,14 @@
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 
+from __future__ import with_statement
+
 from logilab.common.testlib import unittest_main
 from logilab.mtconverter import html_unescape
 
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.utils import json
+from cubicweb.view import StartupView, TRANSITIONAL_DOCTYPE_NOEXT
 from cubicweb.web.htmlwidgets import TableWidget
 from cubicweb.web.views import vid_from_rset
 
@@ -125,5 +128,47 @@
         self.assertListEqual(got, expected)
 
 
+class HTMLStreamTests(CubicWebTC):
+
+    def test_set_doctype_reset_xmldecl(self):
+        """
+        tests `cubicweb.web.request.CubicWebRequestBase.set_doctype`
+        with xmldecl reset
+        """
+        class MyView(StartupView):
+            __regid__ = 'my-view'
+            def call(self):
+                self._cw.set_doctype('<!DOCTYPE html>')
+
+        with self.temporary_appobjects(MyView):
+            html_source = self.view('my-view').source
+            source_lines = [line.strip() for line in html_source.splitlines(False)
+                            if line.strip()]
+            self.assertListEqual(source_lines[:2],
+                                 ['<!DOCTYPE html>',
+                                  '<html xmlns="http://www.w3.org/1999/xhtml" xmlns:cubicweb="http://www.logilab.org/2008/cubicweb" xml:lang="en" lang="en">'])
+
+    def test_set_doctype_no_reset_xmldecl(self):
+        """
+        tests `cubicweb.web.request.CubicWebRequestBase.set_doctype`
+        with no xmldecl reset
+        """
+        html_doctype = TRANSITIONAL_DOCTYPE_NOEXT.strip()
+        class MyView(StartupView):
+            __regid__ = 'my-view'
+            def call(self):
+                self._cw.set_doctype(html_doctype, reset_xmldecl=False)
+                self._cw.main_stream.set_namespaces([('xmlns', 'http://www.w3.org/1999/xhtml')])
+                self._cw.main_stream.set_htmlattrs([('lang', 'cz')])
+
+        with self.temporary_appobjects(MyView):
+            html_source = self.view('my-view').source
+            source_lines = [line.strip() for line in html_source.splitlines(False)
+                            if line.strip()]
+            self.assertListEqual(source_lines[:3],
+                                 ['<?xml version="1.0" encoding="UTF-8"?>',
+                                  html_doctype,
+                                  '<html xmlns="http://www.w3.org/1999/xhtml" lang="cz">'])
+
 if __name__ == '__main__':
     unittest_main()
--- a/web/test/unittest_viewselector.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/test/unittest_viewselector.py	Mon May 16 16:25:33 2011 +0200
@@ -180,7 +180,7 @@
         self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'propertiesform', req1, rset=rset2)
 
     def test_propertiesform_jdoe(self):
-        self.create_user('jdoe')
+        self.create_user(self.request(), 'jdoe')
         self.login('jdoe')
         req1 = self.request()
         req2 = self.request()
--- a/web/test/windmill/test_connexion.py	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-from cubicweb.devtools import DEFAULT_SOURCES
-LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
-
-# Generated by the windmill services transformer
-from windmill.authoring import WindmillTestClient
-
-def test_connect():
-    client = WindmillTestClient(__name__)
-
-    client.open(url=u'/')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
-    client.type(text=LOGIN, id=u'__login')
-    client.type(text=PASSWORD, id=u'__password')
-
-    client.execJS(js=u"$('#loginForm').submit()")
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.sleep(milliseconds=u'5000')
-    client.asserts.assertJS(js=u'$(\'.message\').text() == "welcome %s !"' % LOGIN)
-    client.open(url=u'/logout')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.open(url=u'/')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
-
-
-def test_wrong_connect():
-    client = WindmillTestClient(__name__)
-
-    client.open(url=u'/')
-    # XXX windmill wants to use its proxy internally on 403 :-(
-    #client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
-    #client.type(text=LOGIN, id=u'__login')
-    #client.type(text=u'novalidpassword', id=u'__password')
-    #client.click(value=u'log in')
-    client.open(url=u'/?__login=user&__password=nopassword')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.asserts.assertTextIn(validator=u'authentication failure', id=u'loginBox')
-    client.open(url=u'/')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
--- a/web/test/windmill/test_creation.py	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-from cubicweb.devtools import DEFAULT_SOURCES
-LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
-
-# Generated by the windmill services transformer
-from windmill.authoring import WindmillTestClient
-
-def test_creation():
-    client = WindmillTestClient(__name__)
-
-    client.open(url=u'/')
-    client.waits.forPageLoad(timeout=u'8000')
-    client.type(text=LOGIN, id=u'__login')
-    client.type(text=PASSWORD, id=u'__password')
-    client.click(value=u'log in')
-    client.waits.forPageLoad(timeout=u'20000')
-
-    # pre-condition
-    client.open(url=u'/cwuser/myuser')
-    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "this resource does not exist"')
-    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
-    client.asserts.assertJS(js=u'$(\'.searchMessage strong\').text() == "No result matching query"')
-
-    client.open(url=u'/manage')
-    client.open(url=u'/add/CWUser')
-    client.type(text=u'myuser', id=u'login-subject:A')
-    client.type(text=u'myuser', id=u'upassword-subject:A')
-    client.type(text=u'myuser', name=u'upassword-subject-confirm:A')
-    client.type(text=u'myuser', id=u'firstname-subject:A')
-    client.select(option=u'managers', id=u'from_in_group-subject:A')
-    client.click(id=u'cwinoutadd')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.click(id=u'adduse_email:Alink')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.type(text=u'myuser@logilab.fr', id=u'address-subject:B')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.click(value=u'button_ok')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.sleep(milliseconds=u'5000')
-    client.asserts.assertJS(js=u'$(\'.message\').text() == "entity created"')
-    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "myuser"')
-    client.waits.forPageLoad(timeout=u'8000')
-    client.open(url=u'/cwuser/myuser?vid=sameetypelist')
-    client.waits.forPageLoad(timeout=u'8000')
-    client.asserts.assertJS(js=u'$(\'#contentmain a\').text() == "myuser"')
-    client.open(url=u'/cwuser/myuser?vid=text')
-    client.waits.forPageLoad(timeout=u'8000')
-    client.asserts.assertJS(js=u'$(\'#contentmain\').text() == "\\nmyuser"')
-    client.open(url=u'/cwuser/myuser?vid=deleteconf')
-    client.waits.forElement(timeout=u'8000', value=u'button_delete')
-    client.click(value=u'button_delete')
-    client.waits.forPageLoad(timeout=u'8000')
-    client.open(url=u'/cwuser/myuser')
-    client.asserts.assertJS(js=u'$(\'#contentmain h1\').text() == "this resource does not exist"')
-    client.open(url=u'/?rql=Any U WHERE U is CWUser, U login "myuser"')
-    client.asserts.assertJS(js=u'$(\'.searchMessage strong\').text() == "No result matching query"')
-
--- a/web/test/windmill/test_edit_relation.py	Mon May 16 16:24:00 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-from cubicweb.devtools import DEFAULT_SOURCES
-LOGIN, PASSWORD = DEFAULT_SOURCES['admin'].values()
-
-# Generated by the windmill services transformer
-from windmill.authoring import WindmillTestClient
-
-
-def test_edit_relation():
-    client = WindmillTestClient(__name__)
-
-    client.open(url=u'/logout')
-    client.open(url=u'/')
-    client.asserts.assertJS(js=u"$('#loginForm').is(':visible')")
-    client.type(text=LOGIN, id=u'__login')
-    client.type(text=PASSWORD, id=u'__password')
-    client.execJS(js=u"$('#loginForm').submit()")
-    client.waits.forPageLoad(timeout=u'20000')
-    client.open(url=u'/add/Folder')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(timeout=u'8000', id=u'name-subject:A')
-    client.click(id=u'name-subject:A')
-    client.type(text=u'folder1', id=u'name-subject:A')
-    client.click(value=u'button_ok')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(link=u'add add Folder filed_under Folder object', timeout=u'8000')
-    client.click(link=u'add add Folder filed_under Folder object')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(timeout=u'8000', id=u'name-subject:A')
-    client.click(id=u'name-subject:A')
-    client.type(text=u'subfolder1', id=u'name-subject:A')
-    client.click(value=u'button_ok')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(link=u'more actions', timeout=u'8000')
-    client.click(link=u'more actions')
-    client.click(link=u'copy')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.type(text=u'folder2', id=u'name-subject:A')
-    client.click(value=u'button_ok')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(link=u'modify', timeout=u'8000')
-    client.click(link=u'modify')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(timeout=u'8000', id=u'footer')
-    client.click(link=u'x')
-    client.click(value=u'button_ok')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(link=u'add add Folder filed_under Folder object', timeout=u'8000')
-    client.click(link=u'add add Folder filed_under Folder object')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.type(text=u'subfolder2', id=u'name-subject:A')
-    client.click(value=u'button_ok')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(link=u'subfolder2', timeout=u'8000')
-    client.click(link=u'subfolder2')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(link=u'modify', timeout=u'8000')
-    client.click(link=u'modify')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(timeout=u'8000', id=u'footer')
-    client.click(link=u'x')
-    client.select(xpath=u'//select', index=u'1')
-    #client.execJQuery(jquery=u'("select").trigger(\'change\')') # BUGGY freeze UI..
-    client.execJS(js=u'$("select").trigger(\'change\')')
-    client.waits.sleep(milliseconds=u'2000')
-    client.select(jquery=u'(\'select:contains("Search")\')[0]', option=u'Search for folder')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.click(link=u'folder1')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.waits.forElement(timeout=u'8000', value=u'button_ok')
-    client.click(value=u'button_ok')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.asserts.assertText(xpath=u'//h1', validator=u'subfolder2')
-    client.waits.forElement(link=u'folder_plural', timeout=u'8000')
-    client.click(link=u'folder_plural')
-    client.waits.forPageLoad(timeout=u'20000')
-    client.asserts.assertText(jquery=u"('#contentmain div a')[0]", validator=u'folder1')
-    client.asserts.assertText(jquery=u"('#contentmain div a')[1]", validator=u'folder2')
-    client.asserts.assertText(jquery=u"('#contentmain div a')[2]", validator=u'subfolder1')
-    client.asserts.assertText(jquery=u"('#contentmain div a')[3]", validator=u'subfolder2')
-    client.click(link=u'subfolder2')
-    client.click(link=u'modify')
-    client.click(link=u'folder1')
--- a/web/views/basecontrollers.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/basecontrollers.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -455,13 +455,13 @@
     def js_reledit_form(self):
         req = self._cw
         args = dict((x, req.form[x])
-                    for x in ('formid', 'rtype', 'role', 'reload'))
+                    for x in ('formid', 'rtype', 'role', 'reload', 'action'))
         rset = req.eid_rset(typed_eid(self._cw.form['eid']))
         try:
             args['reload'] = json.loads(args['reload'])
         except ValueError: # not true/false, an absolute url
             assert args['reload'].startswith('http')
-        view = req.vreg['views'].select('doreledit', req, rset=rset, rtype=args['rtype'])
+        view = req.vreg['views'].select('reledit', req, rset=rset, rtype=args['rtype'])
         return self._call_view(view, **args)
 
     @jsonize
--- a/web/views/baseviews.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/baseviews.py	Mon May 16 16:25:33 2011 +0200
@@ -201,8 +201,15 @@
             self.w(u'<span class="value">%s</span>'
                    % self._cw.format_date(entity.creation_date))
         if entity.creator:
-            self.w(u' <span>%s</span> ' % _('by'))
+            if entity.creation_date:
+                self.w(u' <span>%s</span> ' % _('by'))
+            else:
+                self.w(u' <span>%s</span> ' % _('created_by'))
             self.w(u'<span class="value">%s</span>' % entity.creator.name())
+        meta = entity.cw_metainformation()
+        if meta['source']['uri'] != 'system':
+            self.w(u' (<span>%s</span>' % _('cw_source'))
+            self.w(u' <span class="value">%s</span>)' % meta['source']['uri'])
         self.w(u'</div>')
 
 
--- a/web/views/cwsources.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/cwsources.py	Mon May 16 16:25:33 2011 +0200
@@ -126,6 +126,8 @@
         else: # CWAttribute/CWRelation
             self.srelations.setdefault(cwerschema.rtype.name, []).append(
                 (cwerschema.stype.name, cwerschema.otype.name) )
+            self.sentities.add(cwerschema.stype.name)
+            self.sentities.add(cwerschema.otype.name)
 
     def check(self):
         self.init()
@@ -154,14 +156,15 @@
                     warning(_('relation %(rtype)s with %(etype)s as %(role)s is '
                               'supported but no target type supported') %
                             {'rtype': rschema, 'role': role, 'etype': etype})
-        for rtype in self.srelations:
-            rschema = self.schema[rtype]
-            for subj, obj in rschema.rdefs:
-                if subj in self.sentities and obj in self.sentities:
-                    break
-            else:
-                error(_('relation %s is supported but none if its definitions '
-                        'matches supported entities') % rtype)
+        for rtype, rdefs in self.srelations.iteritems():
+            if rdefs is None:
+                rschema = self.schema[rtype]
+                for subj, obj in rschema.rdefs:
+                    if subj in self.sentities and obj in self.sentities:
+                        break
+                else:
+                    error(_('relation %s is supported but none of its definitions '
+                            'matches supported entities') % rtype)
         self.custom_check()
 
     def custom_check(self):
--- a/web/views/cwuser.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/cwuser.py	Mon May 16 16:25:33 2011 +0200
@@ -24,6 +24,7 @@
 
 from logilab.mtconverter import xml_escape
 
+from cubicweb import tags
 from cubicweb.schema import display_name
 from cubicweb.selectors import one_line_rset, is_instance, match_user_groups
 from cubicweb.view import EntityView, StartupView
@@ -32,16 +33,8 @@
 
 _pvs = uicfg.primaryview_section
 _pvs.tag_attribute(('CWUser', 'login'), 'hidden')
-_pvs.tag_attribute(('CWGroup', 'name'), 'hidden')
-_pvs.tag_subject_of(('CWGroup', 'read_permission', '*'), 'relations')
-_pvs.tag_subject_of(('CWGroup', 'add_permission', '*'), 'relations')
-_pvs.tag_subject_of(('CWGroup', 'delete_permission', '*'), 'relations')
-_pvs.tag_subject_of(('CWGroup', 'update_permission', '*'), 'relations')
-_pvs.tag_object_of(('*', 'in_group', 'CWGroup'), 'relations')
-_pvs.tag_object_of(('*', 'require_group', 'CWGroup'), 'relations')
 
 _affk = uicfg.autoform_field_kwargs
-
 _affk.tag_subject_of(('CWUser', 'in_group', 'CWGroup'),
                     {'widget': formwidgets.InOutWidget})
 
@@ -99,6 +92,11 @@
 
 # group views ##################################################################
 
+_pvs.tag_attribute(('CWGroup', 'name'), 'hidden')
+_pvs.tag_subject_of(('CWGroup', 'read_permission', '*'), 'relations')
+_pvs.tag_subject_of(('CWGroup', 'add_permission', '*'), 'relations')
+_pvs.tag_subject_of(('CWGroup', 'delete_permission', '*'), 'relations')
+_pvs.tag_subject_of(('CWGroup', 'update_permission', '*'), 'relations')
 _pvs.tag_object_of(('CWUser', 'in_group', 'CWGroup'), 'hidden')
 _pvs.tag_object_of(('*', 'require_group', 'CWGroup'), 'hidden')
 
@@ -170,7 +168,11 @@
 
 class CWUserManagementView(StartupView):
     __regid__ = 'cw.user-management'
-    rql = ('Any U, F, S, U, L ORDERBY L WHERE U is CWUser, U login L, U firstname F, U surname S')
+    rql = ('Any U,USN,F,S,U,UAA,UDS, L,UAA,UDSN ORDERBY L WHERE U is CWUser, '
+           'U login L, U firstname F, U surname S, '
+           'U in_state US, US name USN, '
+           'U primary_email UA?, UA address UAA, '
+           'U cw_source UDS, US name UDSN')
     title = _('users and groups management')
 
     def call(self, **kwargs):
@@ -180,7 +182,7 @@
             if eschema.has_perm(self._cw, 'add'):
                 self.w(u'<a href="%s" class="addButton right">%s</a>' % (
                     self._cw.build_url('add/%s' % eschema),
-                    self._cw._('add a %s' % etype).capitalize()))
+                    self._cw.__('New %s' % etype).capitalize()))
         self.w(u'<div class="clear"></div>')
         self.wview('cw.user-table', self._cw.execute(self.rql))
 
@@ -191,10 +193,15 @@
 
     def call(self, **kwargs):
         headers = (display_name(self._cw, 'CWUser', 'plural'),
+                   display_name(self._cw, 'in_state'),
                    self._cw._('firstname'), self._cw._('surname'),
-                   display_name(self._cw, 'CWGroup', 'plural'))
+                   display_name(self._cw, 'CWGroup', 'plural'),
+                   display_name(self._cw, 'primary_email'),
+                   display_name(self._cw, 'CWSource'))
         super(CWUserTable, self).call(
-            paginate=True, cellvids={3: 'cw.user-table.group-cell'},
+            paginate=True, displayfilter=True,
+            cellvids={0: 'cw.user.login',
+                      4: 'cw.user-table.group-cell'},
             headers=headers, **kwargs)
 
 
@@ -205,3 +212,11 @@
     def cell_call(self, row, col, **kwargs):
         entity = self.cw_rset.get_entity(row, col)
         self.w(entity.view('reledit', rtype='in_group', role='subject'))
+
+class CWUserLoginCell(EntityView):
+    __regid__ = 'cw.user.login'
+    __select__ = is_instance('CWUser')
+
+    def cell_call(self, row, col, **kwargs):
+        entity = self.cw_rset.get_entity(row, col)
+        self.w(tags.a(entity.login, href=entity.absolute_url()))
--- a/web/views/owl.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/owl.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -35,15 +35,19 @@
                 }
 
 OWL_TYPE_MAP = {'String': 'xsd:string',
-                'Datetime': 'xsd:dateTime',
                 'Bytes': 'xsd:byte',
-                'Float': 'xsd:float',
+                'Password': 'xsd:byte',
+
                 'Boolean': 'xsd:boolean',
                 'Int': 'xsd:int',
+                'Float': 'xsd:float',
+                'Decimal' : 'xsd:decimal',
+
                 'Date':'xsd:date',
+                'Datetime': 'xsd:dateTime',
+                'TZDatetime': 'xsd:dateTime',
                 'Time': 'xsd:time',
-                'Password': 'xsd:byte',
-                'Decimal' : 'xsd:decimal',
+                'TZTime': 'xsd:time',
                 'Interval': 'xsd:duration'
                 }
 
--- a/web/views/plots.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/plots.py	Mon May 16 16:25:33 2011 +0200
@@ -47,7 +47,7 @@
 @objectify_selector
 def columns_are_date_then_numbers(cls, req, rset=None, *args, **kwargs):
     etypes = rset.description[0]
-    if etypes[0] not in ('Date', 'Datetime'):
+    if etypes[0] not in ('Date', 'Datetime', 'TZDatetime'):
         return 0
     for etype in etypes[1:]:
         if etype not in ('Int', 'Float'):
--- a/web/views/reledit.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/reledit.py	Mon May 16 16:25:33 2011 +0200
@@ -15,7 +15,9 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""the 'reledit' feature (eg edit attribute/relation from primary view)"""
+"""edit entity attributes/relations from any view, without going to the entity
+form
+"""
 
 __docformat__ = "restructuredtext en"
 _ = unicode
@@ -24,7 +26,8 @@
 from warnings import warn
 
 from logilab.mtconverter import xml_escape
-from logilab.common.deprecation import deprecated
+from logilab.common.deprecation import deprecated, class_renamed
+from logilab.common.decorators import cached
 
 from cubicweb import neg_role
 from cubicweb.schema import display_name
@@ -43,16 +46,18 @@
         return u''
     def append_field(self, *args):
         pass
+    def add_hidden(self, *args):
+        pass
 
 rctrl = uicfg.reledit_ctrl
 
-class ClickAndEditFormView(EntityView):
-    __regid__ = 'doreledit'
+class AutoClickAndEditFormView(EntityView):
+    __regid__ = 'reledit'
     __select__ = non_final_entity() & match_kwargs('rtype')
 
     # ui side continuations
     _onclick = (u"cw.reledit.loadInlineEditionForm('%(formid)s', %(eid)s, '%(rtype)s', '%(role)s', "
-                "'%(divid)s', %(reload)s, '%(vid)s');")
+                "'%(divid)s', %(reload)s, '%(vid)s', '%(action)s');")
     _cancelclick = "cw.reledit.cleanupAfterCancel('%s')"
 
     # ui side actions/buttons
@@ -75,93 +80,84 @@
                                 # function taking the subject entity & returning a boolean or an eid
                   rvid=None,    # vid to be applied to other side of rtype (non final relations only)
                   default_value=None,
-                  formid='base'
+                  formid='base',
+                  action=None
                   ):
         """display field to edit entity's `rtype` relation on click"""
         assert rtype
-        assert role in ('subject', 'object'), '%s is not an acceptable role value' % role
         self._cw.add_css('cubicweb.form.css')
         self._cw.add_js(('cubicweb.reledit.js', 'cubicweb.edition.js', 'cubicweb.ajax.js'))
-        entity = self.cw_rset.get_entity(row, col)
+        self.entity = self.cw_rset.get_entity(row, col)
         rschema = self._cw.vreg.schema[rtype]
-        self._rules = rctrl.etype_get(entity.e_schema.type, rschema.type, role, '*')
+        self._rules = rctrl.etype_get(self.entity.e_schema.type, rschema.type, role, '*')
         if rvid is not None or default_value is not None:
             warn('[3.9] specifying rvid/default_value on select is deprecated, '
                  'reledit_ctrl rtag to control this' % self, DeprecationWarning)
-        reload = self._compute_reload(entity, rschema, role, reload)
-        divid = self._build_divid(rtype, role, entity.eid)
+        reload = self._compute_reload(rschema, role, reload)
+        divid = self._build_divid(rtype, role, self.entity.eid)
         if rschema.final:
-            self._handle_attribute(entity, rschema, role, divid, reload)
+            self._handle_attribute(rschema, role, divid, reload, action)
         else:
             if self._is_composite():
-                self._handle_composite(entity, rschema, role, divid, reload, formid)
+                self._handle_composite(rschema, role, divid, reload, formid, action)
             else:
-                self._handle_relation(entity, rschema, role, divid, reload, formid)
+                self._handle_relation(rschema, role, divid, reload, formid, action)
 
-    def _handle_attribute(self, entity, rschema, role, divid, reload):
-        rtype = rschema.type
-        value = entity.printable_value(rtype)
-        if not self._should_edit_attribute(entity, rschema):
+    def _handle_attribute(self, rschema, role, divid, reload, action):
+        value = self.entity.printable_value(rschema.type)
+        if not self._should_edit_attribute(rschema):
             self.w(value)
             return
-        display_label, related_entity = self._prepare_form(entity, rtype, role)
-        form, renderer = self._build_form(entity, rtype, role, divid, 'base',
-                                          reload, display_label, related_entity)
+        form, renderer = self._build_form(self.entity, rschema, role, divid, 'base', reload, action)
         value = value or self._compute_default_value(rschema, role)
         self.view_form(divid, value, form, renderer)
 
-    def _compute_formid_value(self, entity, rschema, role, rvid, formid):
-        related_rset = entity.related(rschema.type, role)
+    def _compute_formid_value(self, rschema, role, rvid, formid):
+        related_rset = self.entity.related(rschema.type, role)
         if related_rset:
             value = self._cw.view(rvid, related_rset)
         else:
             value = self._compute_default_value(rschema, role)
-        if not self._should_edit_relation(entity, rschema, role):
+        if not self._should_edit_relation(rschema, role):
             return None, value
         return formid, value
 
-    def _handle_relation(self, entity, rschema, role, divid, reload, formid):
+    def _handle_relation(self, rschema, role, divid, reload, formid, action):
         rvid = self._rules.get('rvid', 'autolimited')
-        formid, value = self._compute_formid_value(entity, rschema, role, rvid, formid)
+        formid, value = self._compute_formid_value(rschema, role, rvid, formid)
         if formid is None:
             return self.w(value)
-        rtype = rschema.type
-        display_label, related_entity = self._prepare_form(entity, rtype, role)
-        form, renderer = self._build_form(entity, rtype, role, divid, formid, reload,
-                                          display_label, related_entity, dict(vid=rvid))
+        form, renderer = self._build_form(self.entity,  rschema, role, divid, formid,
+                                          reload, action, dict(vid=rvid))
         self.view_form(divid, value, form, renderer)
 
-    def _handle_composite(self, entity, rschema, role, divid, reload, formid):
+    def _handle_composite(self, rschema, role, divid, reload, formid, action):
         # this is for attribute-like composites (1 target type, 1 related entity at most, for now)
-        ttypes = self._compute_ttypes(rschema, role)
+        entity = self.entity
         related_rset = entity.related(rschema.type, role)
-        add_related = self._may_add_related(related_rset, entity, rschema, role, ttypes)
-        edit_related = self._may_edit_related_entity(related_rset, entity, rschema, role, ttypes)
-        delete_related = edit_related and self._may_delete_related(related_rset, entity, rschema, role)
+        add_related = self._may_add_related(related_rset, rschema, role)
+        edit_related = self._may_edit_related_entity(related_rset, rschema, role)
+        delete_related = edit_related and self._may_delete_related(related_rset, rschema, role)
         rvid = self._rules.get('rvid', 'autolimited')
-        formid, value = self._compute_formid_value(entity, rschema, role, rvid, formid)
+        formid, value = self._compute_formid_value(rschema, role, rvid, formid)
         if formid is None or not (edit_related or add_related):
             # till we learn to handle cases where not (edit_related or add_related)
             self.w(value)
             return
-        rtype = rschema.type
-        ttype = ttypes[0]
-        _fdata = self._prepare_composite_form(entity, rtype, role, edit_related,
-                                              add_related and ttype)
-        display_label, related_entity = _fdata
-        form, renderer = self._build_form(entity, rtype, role, divid, formid, reload,
-                                          display_label, related_entity, dict(vid=rvid))
+        form, renderer = self._build_form(entity, rschema, role, divid, formid,
+                                          reload, action, dict(vid=rvid))
         self.view_form(divid, value, form, renderer,
                        edit_related, add_related, delete_related)
 
+    @cached
     def _compute_ttypes(self, rschema, role):
         dual_role = neg_role(role)
         return getattr(rschema, '%ss' % dual_role)()
 
-    def _compute_reload(self, entity, rschema, role, reload):
+    def _compute_reload(self, rschema, role, reload):
         ctrl_reload = self._rules.get('reload', reload)
         if callable(ctrl_reload):
-            ctrl_reload = ctrl_reload(entity)
+            ctrl_reload = ctrl_reload(self.entity)
         if isinstance(ctrl_reload, int) and ctrl_reload > 1: # not True/False
             ctrl_reload = self._cw.build_url(ctrl_reload)
         return ctrl_reload
@@ -179,33 +175,36 @@
     def _is_composite(self):
         return self._rules.get('edit_target') == 'related'
 
-    def _may_add_related(self, related_rset, entity, rschema, role, ttypes):
+    def _may_add_related(self, related_rset, rschema, role):
         """ ok for attribute-like composite entities """
+        ttypes = self._compute_ttypes(rschema, role)
         if len(ttypes) > 1: # many etypes: learn how to do it
             return False
-        rdef = rschema.role_rdef(entity.e_schema, ttypes[0], role)
+        rdef = rschema.role_rdef(self.entity.e_schema, ttypes[0], role)
         card = rdef.role_cardinality(role)
         if related_rset or card not in '?1':
             return False
         if role == 'subject':
-            kwargs = {'fromeid': entity.eid}
+            kwargs = {'fromeid': self.entity.eid}
         else:
-            kwargs = {'toeid': entity.eid}
+            kwargs = {'toeid': self.entity.eid}
         return rdef.has_perm(self._cw, 'add', **kwargs)
 
-    def _may_edit_related_entity(self, related_rset, entity, rschema, role, ttypes):
+    def _may_edit_related_entity(self, related_rset, rschema, role):
         """ controls the edition of the related entity """
+        ttypes = self._compute_ttypes(rschema, role)
         if len(ttypes) > 1 or len(related_rset.rows) != 1:
             return False
-        if entity.e_schema.rdef(rschema, role).role_cardinality(role) not in '?1':
+        if self.entity.e_schema.rdef(rschema, role).role_cardinality(role) not in '?1':
             return False
         return related_rset.get_entity(0, 0).cw_has_perm('update')
 
-    def _may_delete_related(self, related_rset, entity, rschema, role):
+    def _may_delete_related(self, related_rset, rschema, role):
         # we assume may_edit_related, only 1 related entity
         if not related_rset:
             return False
         rentity = related_rset.get_entity(0, 0)
+        entity = self.entity
         if role == 'subject':
             kwargs = {'fromeid': entity.eid, 'toeid': rentity.eid}
         else:
@@ -230,33 +229,33 @@
         """ builds an id for the root div of a reledit widget """
         return '%s-%s-%s' % (rtype, role, entity_eid)
 
-    def _build_args(self, entity, rtype, role, formid, reload,
+    def _build_args(self, entity, rtype, role, formid, reload, action,
                     extradata=None):
         divid = self._build_divid(rtype, role, entity.eid)
         event_args = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype, 'formid': formid,
-                      'reload' : json_dumps(reload),
+                      'reload' : json_dumps(reload), 'action': action,
                       'role' : role, 'vid' : u''}
         if extradata:
             event_args.update(extradata)
         return event_args
 
-    def _prepare_form(self, entity, _rtype, role):
-        display_label = False
-        related_entity = entity
-        return display_label, related_entity
-
-    def _prepare_composite_form(self, entity, rtype, role, edit_related, add_related):
-        display_label = True
-        if edit_related and not add_related:
-            related_entity = entity.related(rtype, role).get_entity(0, 0)
-        elif add_related:
-            _new_entity = self._cw.vreg['etypes'].etype_class(add_related)(self._cw)
+    def _prepare_form(self, entity, rschema, role, action):
+        assert action in ('edit_rtype', 'edit_related', 'add', 'delete'), action
+        if action == 'edit_rtype':
+            return False, entity
+        label = True
+        if action in ('edit_related', 'delete'):
+            edit_entity = entity.related(rschema, role).get_entity(0, 0)
+        elif action == 'add':
+            add_etype = self._compute_ttypes(rschema, role)[0]
+            _new_entity = self._cw.vreg['etypes'].etype_class(add_etype)(self._cw)
             _new_entity.eid = self._cw.varmaker.next()
-            related_entity = _new_entity
+            edit_entity = _new_entity
             # XXX see forms.py ~ 276 and entities.linked_to method
             #     is there another way ?
-            self._cw.form['__linkto'] = '%s:%s:%s' % (rtype, entity.eid, neg_role(role))
-        return display_label, related_entity
+            self._cw.form['__linkto'] = '%s:%s:%s' % (rschema, entity.eid, neg_role(role))
+        assert edit_entity
+        return label, edit_entity
 
     def _build_renderer(self, related_entity, display_label):
         return self._cw.vreg['formrenderers'].select(
@@ -266,13 +265,18 @@
             display_help=False, button_bar_class='buttonbar',
             display_progress_div=False)
 
-    def _build_form(self, entity, rtype, role, divid, formid, reload,
-                    display_label, related_entity, extradata=None, **formargs):
-        event_args = self._build_args(entity, rtype, role, formid,
-                                      reload, extradata)
+    def _build_form(self, entity, rschema, role, divid, formid, reload, action,
+                    extradata=None, **formargs):
+        rtype = rschema.type
+        event_args = self._build_args(entity, rtype, role, formid, reload, action, extradata)
+        if not action:
+            form = _DummyForm()
+            form.event_args = event_args
+            return form, None
+        label, edit_entity = self._prepare_form(entity, rschema, role, action)
         cancelclick = self._cancelclick % divid
         form = self._cw.vreg['forms'].select(
-            formid, self._cw, rset=related_entity.as_rset(), entity=related_entity,
+            formid, self._cw, rset=edit_entity.as_rset(), entity=edit_entity,
             domid='%s-form' % divid, formtype='inlined',
             action=self._cw.build_url('validateform', __onsuccess='window.parent.cw.reledit.onSuccess'),
             cwtarget='eformframe', cssclass='releditForm',
@@ -298,9 +302,10 @@
         if formid == 'base':
             field = form.field_by_name(rtype, role, entity.e_schema)
             form.append_field(field)
-        return form, self._build_renderer(related_entity, display_label)
+        return form, self._build_renderer(edit_entity, label)
 
-    def _should_edit_attribute(self, entity, rschema):
+    def _should_edit_attribute(self, rschema):
+        entity = self.entity
         rdef = entity.e_schema.rdef(rschema)
         # check permissions
         if not entity.cw_has_perm('update'):
@@ -312,8 +317,8 @@
                                         ' use _should_edit_attribute instead',
                                         _should_edit_attribute)
 
-    def _should_edit_relation(self, entity, rschema, role):
-        eeid = entity.eid
+    def _should_edit_relation(self, rschema, role):
+        eeid = self.entity.eid
         perm_args = {'fromeid': eeid} if role == 'subject' else {'toeid': eeid}
         return rschema.has_perm(self._cw, 'add', **perm_args)
 
@@ -335,9 +340,11 @@
         w(u'<div id="%s" class="editableField hidden">' % divid)
 
     def _edit_action(self, divid, args, edit_related, add_related, _delete_related):
+        # XXX disambiguate wrt edit_related
         if not add_related: # currently, excludes edition
             w = self.w
             args['formid'] = 'edition' if edit_related else 'base'
+            args['action'] = 'edit_related' if edit_related else 'edit_rtype'
             w(u'<div id="%s-update" class="editableField" onclick="%s" title="%s">' %
               (divid, xml_escape(self._onclick % args), self._cw._(self._editzonemsg)))
             w(self._build_edit_zone())
@@ -346,7 +353,8 @@
     def _add_action(self, divid, args, _edit_related, add_related, _delete_related):
         if add_related:
             w = self.w
-            args['formid'] = 'edition' if add_related else 'base'
+            args['formid'] = 'edition'
+            args['action'] = 'add'
             w(u'<div id="%s-add" class="editableField" onclick="%s" title="%s">' %
               (divid, xml_escape(self._onclick % args), self._cw._(self._addmsg)))
             w(self._build_add_zone())
@@ -356,6 +364,7 @@
         if delete_related:
             w = self.w
             args['formid'] = 'deleteconf'
+            args['action'] = 'delete'
             w(u'<div id="%s-delete" class="editableField" onclick="%s" title="%s">' %
               (divid, xml_escape(self._onclick % args), self._cw._(self._deletemsg)))
             w(self._build_delete_zone())
@@ -376,13 +385,4 @@
         self._close_form_wrapper()
 
 
-class AutoClickAndEditFormView(ClickAndEditFormView):
-    __regid__ = 'reledit'
-
-    def _build_form(self, entity, rtype, role, divid, formid, reload,
-                    display_label, related_entity, extradata=None, **formargs):
-        event_args = self._build_args(entity, rtype, role, 'base',
-                                      reload, extradata)
-        form = _DummyForm()
-        form.event_args = event_args
-        return form, None
+ClickAndEditFormView = class_renamed('ClickAndEditFormView', AutoClickAndEditFormView)
--- a/web/views/sparql.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/sparql.py	Mon May 16 16:25:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -77,17 +77,22 @@
 
 YAMS_XMLSCHEMA_MAPPING = {
     'String': 'string',
+
+    'Boolean': 'boolean',
     'Int': 'integer',
     'Float': 'float',
-    'Boolean': 'boolean',
+
     'Datetime': 'dateTime',
+    'TZDatetime': 'dateTime',
     'Date': 'date',
     'Time': 'time',
+    'TZTime': 'time',
+
     # XXX the following types don't have direct mapping
     'Decimal': 'string',
     'Interval': 'duration',
+    'Bytes': 'base64Binary',
     'Password': 'string',
-    'Bytes': 'base64Binary',
     }
 
 def xmlschema(yamstype):
--- a/web/views/tabs.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/tabs.py	Mon May 16 16:25:33 2011 +0200
@@ -46,7 +46,7 @@
                  reloadable=False, show_spinbox=True, w=None):
         """a lazy version of wview"""
         w = w or self.w
-        self._cw.add_js('cubicweb.lazy.js')
+        self._cw.add_js('cubicweb.ajax.js')
         urlparams = self._cw.form.copy()
         urlparams.update({'vid' : vid, 'fname' : 'view'})
         if rql:
@@ -127,8 +127,8 @@
         if entity and len(self.cw_rset) > 1:
             entity.view(default, w=self.w)
             return
-        self._cw.add_css('ui.tabs.css')
-        self._cw.add_js(('ui.core.js', 'ui.tabs.js', 'cubicweb.ajax.js'))
+        self._cw.add_css('jquery.ui.css')
+        self._cw.add_js(('jquery.ui.js', 'cubicweb.ajax.js'))
         # prune tabs : not all are to be shown
         tabs, active_tab = self.prune_tabs(tabs, default)
         # build the html structure
@@ -148,7 +148,6 @@
             if domid == active_tab:
                 active_tab_idx = i
         w(u'</ul>')
-        w(u'</div>')
         for tabid, domid, tabkwargs in tabs:
             w(u'<div id="%s">' % domid)
             tabkwargs.setdefault('tabid', domid)
@@ -156,11 +155,12 @@
             tabkwargs.setdefault('rset', self.cw_rset)
             self.lazyview(**tabkwargs)
             w(u'</div>')
+        w(u'</div>')
         # call the setTab() JS function *after* each tab is generated
         # because the callback binding needs to be done before
         # XXX make work history: true
         self._cw.add_onload(u"""
-  jQuery('#entity-tabs-%(eeid)s > ul').tabs( { selected: %(tabindex)s });
+  jQuery('#entity-tabs-%(eeid)s').tabs( { selected: %(tabindex)s });
   setTab('%(domid)s', '%(cookiename)s');
 """ % {'tabindex'   : active_tab_idx,
        'domid'        : active_tab,
--- a/web/views/xmlrss.py	Mon May 16 16:24:00 2011 +0200
+++ b/web/views/xmlrss.py	Mon May 16 16:25:33 2011 +0200
@@ -42,6 +42,8 @@
     'Date': lambda x: x.strftime('%Y-%m-%d'),
     'Datetime': lambda x: x.strftime('%Y-%m-%d %H:%M:%S'),
     'Time': lambda x: x.strftime('%H:%M:%S'),
+    'TZDatetime': lambda x: x.strftime('%Y-%m-%d %H:%M:%S'), # XXX TZ
+    'TZTime': lambda x: x.strftime('%H:%M:%S'),
     'Interval': lambda x: x.days * 60*60*24 + x.seconds,
     }