merge
authorAlexandre Fayolle <alexandre.fayolle@logilab.fr>
Fri, 22 Apr 2011 12:20:48 +0200
changeset 7247 0d2ad493735b
parent 7245 2f72b958ae22 (diff)
parent 7246 ecae5b526437 (current diff)
child 7248 f20fc41e3f7d
merge
--- a/dataimport.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/dataimport.py	Fri Apr 22 12:20:48 2011 +0200
@@ -133,7 +133,7 @@
     """
     for idx, item in enumerate(iterable):
         yield item
-        if idx % number:
+        if not idx % number:
             func()
     func()
 
--- a/devtools/__init__.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/devtools/__init__.py	Fri Apr 22 12:20:48 2011 +0200
@@ -129,7 +129,7 @@
     mode = 'test'
     read_instance_schema = False
     init_repository = True
-
+    skip_db_create_and_restore = False
     def __init__(self, appid='data', apphome=None, log_threshold=logging.CRITICAL+10):
         # must be set before calling parent __init__
         if apphome is None:
@@ -415,9 +415,9 @@
     def dbname(self):
         return self.system_source['db-name']
 
-    def init_test_database():
+    def init_test_database(self):
         """actual initialisation of the database"""
-        raise ValueError('no initialization function for driver %r' % driver)
+        raise ValueError('no initialization function for driver %r' % self.DRIVER)
 
     def has_cache(self, db_id):
         """Check if a given database id exist in cb cache for the current config"""
@@ -636,7 +636,7 @@
         """initialize a fresh sqlserver databse used for testing purpose"""
         if self.config.init_repository:
             from cubicweb.server import init_repository
-            init_repository(config, interactive=False, drop=True)
+            init_repository(self.config, interactive=False, drop=True)
 
 ### sqlite test database handling ##############################################
 
--- a/devtools/fake.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/devtools/fake.py	Fri Apr 22 12:20:48 2011 +0200
@@ -25,6 +25,8 @@
 from cubicweb.req import RequestSessionBase
 from cubicweb.cwvreg import CubicWebVRegistry
 from cubicweb.web.request import CubicWebRequestBase
+from cubicweb.web.http_headers import Headers
+
 from cubicweb.devtools import BASE_URL, BaseApptestConfiguration
 
 
@@ -59,8 +61,14 @@
         self._url = kwargs.pop('url', 'view?rql=Blop&vid=blop')
         super(FakeRequest, self).__init__(*args, **kwargs)
         self._session_data = {}
-        self._headers = {}
+        self._headers_in = Headers()
 
+    def set_cookie(self, cookie, key, maxage=300, expires=None):
+        super(FakeRequest, self).set_cookie(cookie, key, maxage=300, expires=None)
+        cookie = self.get_response_header('Set-Cookie')
+        self._headers_in.setHeader('Cookie', cookie)
+
+    ## Implement request abstract API
     def header_accept_language(self):
         """returns an ordered list of preferred languages"""
         return ('en',)
@@ -81,48 +89,32 @@
             return url
         return url.split('?', 1)[0]
 
-    def set_content_type(self, content_type, filename=None, encoding=None):
-        """set output content type for this request. An optional filename
-        may be given
+    def get_header(self, header, default=None, raw=True):
+        """return the value associated with the given input header, raise
+        KeyError if the header is not set
         """
-        pass
-
-    def set_header(self, header, value, raw=True):
-        """set an output HTTP header"""
-        self._headers[header] = value
+        if raw:
+            return self._headers_in.getRawHeaders(header, [default])[0]
+        return self._headers_in.getHeader(header, default)
 
-    def add_header(self, header, value):
-        """set an output HTTP header"""
-        self._headers[header] = value # XXX
+    ## extend request API to control headers in / out values
+    def set_request_header(self, header, value, raw=False):
+        """set an input HTTP header"""
+        if isinstance(value, basestring):
+            value = [value]
+        if raw:
+            self._headers_in.setRawHeaders(header, value)
+        else:
+            self._headers_in.setHeader(header, value)
 
-    def remove_header(self, header):
-        """remove an output HTTP header"""
-        self._headers.pop(header, None)
-
-    def get_header(self, header, default=None):
+    def get_response_header(self, header, default=None, raw=False):
         """return the value associated with the given input header,
         raise KeyError if the header is not set
         """
-        return self._headers.get(header, default)
-
-    def set_cookie(self, cookie, key, maxage=300, expires=None):
-        """set / update a cookie key
-
-        by default, cookie will be available for the next 5 minutes
-        """
-        morsel = cookie[key]
-        if maxage is not None:
-            morsel['Max-Age'] = maxage
-        if expires:
-            morsel['expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S %z')
-        # make sure cookie is set on the correct path
-        morsel['path'] = self.base_url_path()
-        self.add_header('Set-Cookie', morsel.OutputString())
-        self.add_header('Cookie', morsel.OutputString())
-
-    def remove_cookie(self, cookie, key):
-        self.remove_header('Set-Cookie')
-        self.remove_header('Cookie')
+        if raw:
+            return self.headers_out.getRawHeaders(header, default)[0]
+        else:
+            return self.headers_out.getHeader(header, default)
 
     def validate_cache(self):
         pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/admin/config.rst	Fri Apr 22 12:20:48 2011 +0200
@@ -0,0 +1,224 @@
+.. -*- coding: utf-8 -*-
+
+.. _ConfigEnv:
+
+Set-up of a *CubicWeb* environment
+==================================
+
+You can `configure the database`_ system of your choice:
+
+  - `PostgreSQL configuration`_
+  - `MySql configuration`_
+  - `SQLServer configuration`_
+  - `SQLite configuration`_
+
+For advanced features, have a look to:
+
+  - `Pyro configuration`_
+  - `Cubicweb resources configuration`_
+
+.. _`configure the database`: DatabaseInstallation_
+.. _`PostgreSQL configuration`: PostgresqlConfiguration_
+.. _`MySql configuration`: MySqlConfiguration_
+.. _`SQLServer configuration`: SQLServerConfiguration_
+.. _`SQLite configuration`: SQLiteConfiguration_
+.. _`Pyro configuration`: PyroConfiguration_
+.. _`Cubicweb resources configuration`: RessourcesConfiguration_
+
+
+
+.. _RessourcesConfiguration:
+
+Cubicweb resources configuration
+--------------------------------
+
+.. autodocstring:: cubicweb.cwconfig
+
+
+.. _DatabaseInstallation:
+
+Databases configuration
+-----------------------
+
+Each instance can be configured with its own database connection information,
+that will be stored in the instance's :file:`sources` file. The database to use
+will be chosen when creating the instance. CubicWeb is known to run with
+Postgresql (recommended), MySQL, SQLServer and SQLite.
+
+Other possible sources of data include CubicWeb, Subversion, LDAP and Mercurial,
+but at least one relational database is required for CubicWeb to work. You do
+not need to install a backend that you do not intend to use for one of your
+instances. SQLite is not fit for production use, but it works well for testing
+and ships with Python, which saves installation time when you want to get
+started quickly.
+
+.. _PostgresqlConfiguration:
+
+PostgreSQL
+~~~~~~~~~~
+
+For installation, please refer to the `PostgreSQL project online documentation`_.
+
+.. _`PostgreSQL project online documentation`: http://www.postgresql.org/
+
+You need to install the three following packages: `postgresql-8.X`,
+`postgresql-client-8.X`, and `postgresql-plpython-8.X`. If you run postgres
+version prior to 8.3, you'll also need the `postgresql-contrib-8.X` package for
+full-text search extension.
+
+If you run postgres on another host than the |cubicweb| repository, you should
+install the `postgresql-client` package on the |cubicweb| host, and others on the
+database host.
+
+.. Note::
+
+    If you already have an existing cluster and PostgreSQL server running, you do
+    not need to execute the initilization step of your PostgreSQL database unless
+    you want a specific cluster for |cubicweb| databases or if your existing
+    cluster doesn't use the UTF8 encoding (see note below).
+
+* First, initialize a PostgreSQL cluster with the command ``initdb``::
+
+    $ initdb -E UTF8 -D /path/to/pgsql
+
+  Notice the encoding specification. This is necessary since |cubicweb| usually
+  want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll
+  get error like::
+
+    new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII)
+    HINT:  Use the same encoding as in the template database, or use template0 as template.
+
+
+  Once initialized, start the database server PostgreSQL with the command::
+
+    $ postgres -D /path/to/psql
+
+  If you cannot execute this command due to permission issues, please make sure
+  that your username has write access on the database.  ::
+
+    $ chown username /path/to/pgsql
+
+* The database authentication can be either set to `ident sameuser` or `md5`.  If
+  set to `md5`, make sure to use an existing user of your database.  If set to
+  `ident sameuser`, make sure that your client's operating system user name has a
+  matching user in the database. If not, please do as follow to create a user::
+
+    $ su
+    $ su - postgres
+    $ createuser -s -P username
+
+  The option `-P` (for password prompt), will encrypt the password with the
+  method set in the configuration file :file:`pg_hba.conf`.  If you do not use this
+  option `-P`, then the default value will be null and you will need to set it
+  with::
+
+    $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql"
+
+.. Note::
+    The authentication method can be configured in file:`pg_hba.conf`.
+
+
+The above login/password will be requested when you will create an instance with
+`cubicweb-ctl create` to initialize the database of your instance.
+
+Notice that the `cubicweb-ctl db-create` does database initialization that
+may requires a postgres superuser. That's why a login/password is explicitly asked
+at this step, so you can use there a superuser without using this user when running
+the instance. Things that require special privileges at this step:
+
+* database creation, require the 'create database' permission
+* install the plpython extension language (require superuser)
+* install the tsearch extension for postgres version prior to 8.3 (require superuser)
+
+To avoid using a super user each time you create an install, a nice trick is to
+install plpython (and tsearch when needed) on the special `template1` database,
+so they will be installed automatically when cubicweb databases are created
+without even with needs for special access rights. To do so, run ::
+
+  # Installation of plpythonu language by default ::
+  $ createlang -U pgadmin plpythonu template1
+  $ psql -U pgadmin template1
+  template1=# update pg_language set lanpltrusted=TRUE where lanname='plpythonu';
+
+Where `pgadmin` is a postgres superuser. The last command is necessary since by
+default plpython is an 'untrusted' language and as such can't be used by non
+superuser. This update fix that problem by making it trusted.
+
+To install the tsearch plain-text index extension on postgres prior to 8.3, run::
+
+    cat /usr/share/postgresql/8.X/contrib/tsearch2.sql | psql -U username template1
+
+
+
+.. _MySqlConfiguration:
+
+MySql
+~~~~~
+
+You must add the following lines in ``/etc/mysql/my.cnf`` file::
+
+    transaction-isolation=READ-COMMITTED
+    default-storage-engine=INNODB
+    default-character-set=utf8
+    max_allowed_packet = 128M
+
+.. Note::
+    It is unclear whether mysql supports indexed string of arbitrary length or
+    not.
+
+
+.. _SQLServerConfiguration:
+
+SQLServer
+~~~~~~~~~
+
+As of this writing, support for SQLServer 2005 is functional but incomplete. You
+should be able to connect, create a database and go quite far, but some of the
+SQL generated from RQL queries is still currently not accepted by the
+backend. Porting to SQLServer 2008 is also an item on the backlog.
+
+The `source` configuration file may look like this (specific parts only are
+shown)::
+
+  [system]
+  db-driver=sqlserver2005
+  db-user=someuser
+  # database password not needed
+  #db-password=toto123
+  #db-create/init may ask for a pwd: just say anything
+  db-extra-arguments=Trusted_Connection
+  db-encoding=utf8
+
+
+
+.. _SQLiteConfiguration:
+
+SQLite
+~~~~~~
+SQLite has the great advantage of requiring almost no configuration. Simply
+use 'sqlite' as db-driver, and set path to the dabase as db-name. Don't specify
+anything for db-user and db-password, they will be ignore anyway.
+
+.. Note::
+  SQLite is great for testing and to play with cubicweb but is not suited for
+  production environments.
+
+
+.. _PyroConfiguration:
+
+Pyro configuration
+------------------
+
+If you want to use Pyro to access your instance remotely, or to have multi-source
+or distributed configuration, it is required to have a Pyro name server running
+on your network. By default it is detected by a broadcast request, but you can
+specify a location in the instance's configuration file.
+
+To do so, you need to :
+
+* launch the pyro name server with `pyro-nsd start` before starting cubicweb
+
+* under debian, edit the file :file:`/etc/default/pyro-nsd` so that the name
+  server pyro will be launched automatically when the machine fire up
+
+
--- a/doc/book/en/admin/instance-config.rst	Fri Apr 22 12:17:51 2011 +0200
+++ b/doc/book/en/admin/instance-config.rst	Fri Apr 22 12:20:48 2011 +0200
@@ -4,11 +4,6 @@
 Configure an instance
 =====================
 
-On a Unix system, the instances are usually stored in the directory
-:file:`/etc/cubicweb.d/`. During development, the
-:file:`~/etc/cubicweb.d/` directory is looked up, as well as the paths
-in :envvar:`CW_INSTANCES_DIR` environment variable.
-
 While creating an instance, a configuration file is generated in::
 
     $ (CW_INSTANCES_DIR) / <instance> / <configuration name>.conf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/admin/setup-windows.rst	Fri Apr 22 12:20:48 2011 +0200
@@ -0,0 +1,156 @@
+.. -*- coding: utf-8 -*-
+
+.. _SetUpWindowsEnv:
+
+Installing a development environement on Windows
+================================================
+
+Setting up a Windows development environment is not too complicated
+but it requires a series of small steps.
+
+We proposed an example of a typical |cubicweb| installation on Windows
+from sources. We assume everything goes into ``C:\\`` and for any
+package, without version specification, "the latest is
+the greatest".
+
+Take into the mind that adjusting the installation drive should be
+straightforward.
+
+
+
+Install the required elements
+-----------------------------
+
+|cubicweb| requires some base elements that must be installed to run
+correctly. So, first of all, you must install them :
+
+* python >= 2.5 and < 3 
+  (`Download Python <http://www.python.org/download/>`_). 
+  You can also consider the Python(x,y) distribution 
+  (`Download Python(x,y) <http://code.google.com/p/pythonxy/wiki/Downloads>`_)
+  as it makes things easier for Windows user by wrapping in a single installer
+  python 2.5 plus numerous useful third-party modules and
+  applications (including Eclipse + pydev, which is an arguably good
+  IDE for Python under Windows).
+
+* `Twisted <http://twistedmatrix.com/trac/>`_ is an event-driven
+  networking engine 
+  (`Download Twisted <http://twistedmatrix.com/trac/>`_)
+
+* `lxml <http://codespeak.net/lxml/>`_ library
+  (version >=2.2.1) allows working with XML and HTML 
+  (`Download lxml <http://pypi.python.org/pypi/lxml/2.2.1>`_)
+
+* `Postgresql 8.4 <http://www.postgresql.org/>`_, 
+  an object-relational database system 
+  (`Download Postgresql <http://www.enterprisedb.com/products/pgdownload.do#windows>`_) 
+  and its python drivers 
+  (`Download psycopg <http://www.stickpeople.com/projects/python/win-psycopg/#Version2>`_)
+
+* A recent version of `gettext` 
+  (`Download gettext <http://download.logilab.org/pub/gettext/gettext-0.17-win32-setup.exe>`_).
+
+* `rql <http://www.logilab.org/project/rql>`_, 
+  the recent version of the Relationship Query Language parser 
+  (`Download rql <http://download.logilab.org/pub/rql/rql-0.26.3.win32-py2.5.exe>`_).
+
+Install optional elements
+-------------------------
+
+We recommend you to install the following elements. They are not
+mandatory but they activate very interesting features in |cubicweb|:
+
+* `Simplejson <http://pypi.python.org/pypi/simplejson/>`_ 
+  must be installed if you have python <= 2.5 
+  (`Download simplejson <http://www.osuch.org/python-simplejson%3Awin32>`_).
+  It is included in the Standard library from Python >= 2.6.
+
+* `Pyro <http://www.xs4all.nl/~irmen/pyro3/>`_ 
+  enables remote access to cubicweb repository instances.
+  It also allows the client and the server not running on the same machine
+  (`Download Pyro <http://www.xs4all.nl/~irmen/pyro3/download/>`_).
+
+* `python-ldap <http://pypi.python.org/pypi/python-ldap>`_ 
+  provides access to LDAP/Active directory directories
+  (`Download python-ldap <http://www.osuch.org/python-ldap>`_).
+
+* `graphviz <http://www.graphviz.org/>`_ 
+  which allow schema drawings.  
+  (`Download graphviz <http://www.graphviz.org/Download_windows.php>`_).
+  It is quite recommended (albeit not mandatory).
+
+Other elements will activate more features once installed. Take a look
+at :ref:`InstallDependencies`.
+
+Useful tools
+------------
+
+Some additional tools could be useful to develop :ref:`cubes <AvailableCubes>`
+with the framework.
+
+* `mercurial <http://mercurial.selenic.com/>`_ and its standard
+  windows GUI (`TortoiseHG <http://tortoisehg.bitbucket.org/>`_) 
+  allow you to get the source code of |cubicweb| from control version
+  repositories. So you will be able to get the latest development
+  version in an easy way 
+  (`Download mercurial <http://bitbucket.org/tortoisehg/stable/wiki/download>`_).
+
+* You can also consider the ssh client `Putty` in order to peruse
+  mercurial over ssh (`Download <http://www.putty.org/>`_).
+
+* If you are an Eclipse user, mercurial can be integrated using the
+  `MercurialEclipse` plugin 
+  (`Home page <http://www.vectrace.com/mercurialeclipse/>`_).
+
+Getting the sources
+-------------------
+
+There are tow ways to get the sources of |cubicweb| and its
+:ref:`cubes <AvailableCubes>`:
+
+* download the latest release (:ref:`SourceInstallation`) 
+* get the development version using Mercurial 
+  (:ref:`MercurialInstallation`)
+
+Environment variables
+---------------------
+
+You will need some convenience environment variables once all is set up. These
+variables are settable through the GUI by getting at the `System properties`
+window (by righ-clicking on `My Computer` -> `properties`).
+
+In the `advanced` tab, there is an `Environment variables` button. Click on
+it. That opens a small window allowing edition of user-related and system-wide
+variables.
+
+We will consider only user variables. First, the ``PATH`` variable. Assuming 
+you are logged as user *Jane*, add the following paths, separated by 
+semi-colons::
+
+  C:\Documents and Settings\Jane\My Documents\Python\cubicweb\cubicweb\bin
+  C:\Program Files\Graphviz2.24\bin
+
+The ``PYTHONPATH`` variable should also contain::
+
+  C:\Documents and Settings\Jane\My Documents\Python\cubicweb\
+
+From now, on a fresh `cmd` shell, you should be able to type::
+
+  cubicweb-ctl list
+
+... and get a meaningful output.
+
+Running an instance as a service
+--------------------------------
+
+This currently assumes that the instances configurations is located at
+``C:\\etc\\cubicweb.d``. For a cube 'my_instance', you will find
+``C:\\etc\\cubicweb.d\\my_instance\\win32svc.py``.
+
+Now, register your instance as a windows service with::
+
+  win32svc install
+
+Then start the service with::
+
+  net start cubicweb-my_instance
--- a/doc/book/en/admin/setup.rst	Fri Apr 22 12:17:51 2011 +0200
+++ b/doc/book/en/admin/setup.rst	Fri Apr 22 12:20:48 2011 +0200
@@ -2,39 +2,54 @@
 
 .. _SetUpEnv:
 
-Installation and set-up of a |cubicweb| environment
-===================================================
+Installation of a *CubicWeb* environment
+========================================
 
-Installation of `Cubicweb` and its dependencies
------------------------------------------------
+Official releases are available from the `CubicWeb.org forge`_ and from
+`PyPI`_. Since CubicWeb is developed using `Agile software development
+<http://en.wikipedia.org/wiki/Agile_software_development>`_ techniques, releases
+happen frequently. In a version numbered X.Y.Z, X changes after a few years when
+the API breaks, Y changes after a few weeks when features are added and Z
+changes after a few days when bugs are fixed.
 
-|cubicweb| is packaged for `Debian and Ubuntu`_, is `pip installable`_ and
-`easy_install installable`_. It can be installed from source using a tarball_
-or the `Mercurial version control system`_ . Windows user may want to check the
-`Windows Installation`_ section.
+Depending on your needs, you will chose a different way to install CubicWeb on
+your system:
 
-Also, since version 3.9, can be safely installed, used and contained inside a
-`virtualenv`_.
+- `Installation on Debian/Ubuntu`_
+- `Installation on Windows`_
+- `Installation in a virtualenv`_
+- `Installation with pip`_
+- `Installation with easy_install`_
+- `Installation from tarball`_
 
+If you are a power-user and need the very latest features, you will
+
+- `Install from version control`_
 
-.. _`Debian and Ubuntu` : DebianInstallation_
-.. _`pip installable`: PipInstallation_
-.. _`easy_install installable`: EasyInstallInstallation_
-.. _tarball: TarballInstallation_
-.. _`Mercurial version control system`: MercurialInstallation_
-.. _`Windows Installation`: WindowsInstallation_
-.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
+Once the software is installed, move on to :ref:`ConfigEnv` for better control
+and advanced features of |cubicweb|.
 
+.. _`Installation on Debian/Ubuntu`: DebianInstallation_
+.. _`Installation on Windows`: WindowsInstallation_
+.. _`Installation in a virtualenv`: VirtualenvInstallation_
+.. _`Installation with pip`: PipInstallation_
+.. _`Installation with easy_install`: EasyInstallInstallation_
+.. _`Installation from tarball`: TarballInstallation_
+.. _`Install from version control`: MercurialInstallation_
 
-.. file:///home/pyves/tmp/cwdoc/html/admin/setup.html#pipinstallation
 
 .. _DebianInstallation:
 
-Debian and Ubuntu packages
-```````````````````````````
+Debian/Ubuntu install
+---------------------
+
+|cubicweb| is packaged for Debian/Ubuntu (and derived
+distributions). Their integrated package-management system make
+installation and upgrade much easier for users since
+dependencies (like databases) are automatically installed.
 
 Depending on the distribution you are using, add the appropriate line to your
-list of sources (for example by editing ``/etc/apt/sources.list``).
+`list of sources` (for example by editing ``/etc/apt/sources.list``).
 
 For Debian Squeeze (stable)::
 
@@ -44,533 +59,198 @@
 
   deb http://download.logilab.org/production/ sid/
 
-For Ubuntu Lucid (Long Term Support)::
+For Ubuntu Lucid (Long Term Support) and newer::
 
   deb http://download.logilab.org/production/ lucid/
 
+  Note that for Ubuntu Maverick and newer, you shall use the `lucid`
+  repository and install the ``libgecode19`` package from `lucid
+  universe <http://packages.ubuntu.com/lucid/libgecode19>`_.
 
-You can now install the required packages with the following command::
+The repositories are signed with the `Logilab's gnupg key`_. You can download
+and register the key to avoid warnings::
+
+  wget -q http://download.logilab.org/logilab-dists-key.asc -O- | sudo apt-key add -
+
+Update your list of packages and perform the installation::
 
   apt-get update
   apt-get install cubicweb cubicweb-dev
 
-
-`cubicweb` installs the framework itself, allowing you to create new instances.
-
-`cubicweb-dev` installs the development environment allowing you to develop new
-cubes.
-
-.. note::
-
-   `cubicweb-dev` will install basic sqlite support. You can easily setup
-   `cubicweb with other database`_ using the following virtual packages :
-   `cubicweb-postgresql-support` contains necessary dependency for using
-   `cubicweb with postgresql datatabase`_ and `cubicweb-mysql-support` contains
-   necessary dependency for using `cubicweb with mysql database`_ .
-
-There is also a wide variety of :ref:`cubes <AvailableCubes>` listed on the
-`CubicWeb.org Forge`_ available as debian packages and tarball.
-
-The repositories are signed with `Logilab's gnupg key`_. To avoid warning on
-"apt-get update":
+``cubicweb`` installs the framework itself, allowing you to create new
+instances. ``cubicweb-dev`` installs the development environment
+allowing you to develop new cubes.
 
-1. become root using sudo
-2. download http://download.logilab.org/logilab-dists-key.asc using e.g. wget
-3. run "apt-key add logilab-dists-key.asc"
-4. re-run apt-get update (manually or through the package manager, whichever you prefer)
-
-.. _`Logilab's gnupg key`: http://download.logilab.org/logilab-dists-key.asc
-.. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/
-.. _`cubicweb with other database`: DatabaseInstallation_
-.. _`cubicweb with postgresql datatabase` : PostgresqlConfiguration_
-.. _`cubicweb with mysql database` : MySqlConfiguration_
-
-
-.. _PipInstallation:
-
-Installation with pip
-`````````````````````
-
-pip_ is a smart python utility that lets you automatically download, build,
-install, and manage python packages and their dependencies.
-
-|cubicweb| and its cubes have been pip_ installable since version 3.9. Search
-for them on pypi_::
-
-  pip install cubicweb
-  pip install cubicweb-blog
+There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
+list of available cubes using ``apt-cache search cubicweb`` or at the
+`CubicWeb.org forge`_.
 
 .. note::
 
-    Pip is the recommended way to install |cubicweb| if there is no binary
-    package available on your system or you want to install it inside a
-    `virtualenv`_. However pip doesn't install binary package and may require
-    several compilation steps while installing |cubicweb| dependencies. If you
-    don't have a compilation environment you should use  `easy_install
-    installation`_ to install |cubicweb|.
+  `cubicweb-dev` will install basic sqlite support. You can easily setup
+  :ref:`cubicweb with other database <DatabaseInstallation>` using the following
+  virtual packages :
+
+  * `cubicweb-postgresql-support` contains the necessary dependency for
+    using :ref:`cubicweb with postgresql datatabase <PostgresqlConfiguration>`
+
+  * `cubicweb-mysql-support` contains the necessary dependency for using
+    :ref:`cubicweb with mysql database <MySqlConfiguration>`.
+
+.. _`list of sources`: http://wiki.debian.org/SourcesList
+.. _`Logilab's gnupg key`: http://download.logilab.org/logilab-dists-key.asc
+.. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/
+
+.. _WindowsInstallation:
+
+Windows Install
+---------------
 
-    Once, |cubicweb| is installed, this limitation doesn't apply when installing
-    cubes.
+You need to have `python`_ version >= 2.5 and < 3 installed.
+
+If you want an automated install, your best option is probably the
+:ref:`EasyInstallInstallation`. EasyInstall is a tool that helps users to
+install python packages along with their dependencies, searching for suitable
+pre-compiled binaries on the `The Python Package Index`_.
 
+If you want better control over the process as well as a suitable development
+environment or if you are having problems with `easy_install`, read on to
+:ref:`SetUpWindowsEnv`.
+
+.. _python:  http://www.python.org/
+.. _`The Python Package Index`: http://pypi.python.org
+
+.. _VirtualenvInstallation:
+
+`Virtualenv` install
+--------------------
 
-.. _pip: http://pypi.python.org/pypi/pip
-.. _pypi: http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb
-.. _`easy_install installation`: EasyInstallInstallation_
+Since version 3.9, |cubicweb| can be safely installed, used and contained inside
+a `virtualenv`_. You can use either :ref:`pip <PipInstallation>` or
+:ref:`easy_install <EasyInstallInstallation>` to install |cubicweb| inside an
+activated virtual environment.
+
+.. _PipInstallation:
 
+`pip` install
+-------------
+
+pip_ is a python utility that helps downloading, building, installing, and
+managing python packages and their dependencies. It is fully compatible with
+`virtualenv`_ and installs the packages from sources published on the
+`The Python Package Index`_.
+
+.. _`pip`: http://pip.openplans.org/
+.. _`virtualenv`: http://virtualenv.openplans.org/
 
-.. warning::
+A working compilation chain is needed to build the modules that include C
+extensions. If you definitively wont, installing `Lxml
+<http://codespeak.net/lxml/>`_, `Twisted <http://twistedmatrix.com/trac/>`_ and
+`libgecode <http://www.gecode.org/>`_ will help.
+
+To install |cubicweb| and its dependencies, just run::
+
+  pip install cubicweb
 
-  |cubicweb| depends upon the `lxml` python module. This module contains ``C``
-  code that must be compiled.  To successfully install |cubicweb| with pip, you
-  must either have an environment ables to compile Python ``C`` extensions or
-  preinstall lxml from a binary package.
+There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
+list of available cubes on
+`PyPI <http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb&submit=search>`_
+or at the `CubicWeb.org forge`_.
+
+For example, installing the *blog cube* is achieved by::
+
+  pip install cubicweb-blog
+
+.. _EasyInstallInstallation:
+
+`easy_install` install
+----------------------
 
 .. note::
 
-  For better performance the setup processor will compile a ``C`` extension for
-  the :ref:`RQL <RQL>` language if you have an environment ables to compile
-  Python ``C`` extensions and the `gecode library`_.  Otherwise, a pure python
-  alternative will be used for degraded performance.
+   If you are not a Windows user and you have a compilation environment, we
+   recommend you to use the PipInstallation_.
+
+`easy_install`_ is a python utility that helps downloading, installing, and
+managing python packages and their dependencies.
+
+Install |cubicweb| and its dependencies, run::
 
-.. _`gecode library`: http://www.gecode.org/
-.. _`easy_install`:   http://packages.python.org/distribute/easy_install.html
-
+  easy_install cubicweb
 
-.. _EasyInstallInstallation:
+There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
+list of available cubes on `PyPI
+<http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb&submit=search>`_
+or at the `CubicWeb.org Forge`_.
 
-Installation with EasyInstall
-``````````````````````````````
+For example, installing the *blog cube* is achieved by::
+
+  easy_install cubicweb-blog
 
 .. note::
 
-    We don't recommend the use of `easy_install` and setuptools in the generic
-    case. However as easy_install is currently the sole pure python package
-    system that support binary installation. Using `easy_install` is currently
-    the easiest way to install |cubicweb| when you don't have a compilation
-    environment set-up or Debian based distribution.
-
-
-|cubicweb| is easy_install_ installable for version 3.9::
+  If you encounter problem with :ref:`cubes <AvailableCubes>` installation,
+  consider using :ref:`PipInstallation` which is more stable
+  but can not installed pre-compiled binaries.
 
-  easy_install cubicweb
-
-.. warning::
-
-    Cubes are **not** is easy_install_ installable. But they are
-    `pip installable`_
-
-
+.. _`easy_install`: http://packages.python.org/distribute/easy_install.html
 
 
 .. _SourceInstallation:
 
 Install from source
-```````````````````
+-------------------
 
 .. _TarballInstallation:
 
-You can download the archive containing the sources from our `download site`_ at::
-
-  http://download.logilab.org/pub/cubicweb/
-
-.. _`download site`: http://download.logilab.org/pub/cubicweb/
+You can download the archive containing the sources from
+`http://download.logilab.org/pub/cubicweb/ <http://download.logilab.org/pub/cubicweb/>`_.
 
 Make sure you also have all the :ref:`InstallDependencies`.
 
+Once uncompressed, you can install the framework from inside the uncompressed
+folder with::
+
+  python setup.py install
+
+Or you can run |cubicweb| directly from the source directory by
+setting the :ref:`resource mode <RessourcesConfiguration>` to `user`. This will
+ease the development with the framework.
+
+There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
+list of availble cubes at the `CubicWeb.org Forge`_.
+
+
 .. _MercurialInstallation:
 
 Install from version control system
-```````````````````````````````````
+-----------------------------------
 
-You can keep up to date with on-going development by using Mercurial::
-
-  hg clone http://hg.logilab.org/cubicweb
+To keep-up with on-going development, clone the :ref:`Mercurial
+<MercurialPresentation>` repository::
 
-See :ref:`MercurialPresentation` for more details about Mercurial.
+  hg clone -u stable http://hg.logilab.org/cubicweb # stable branch
+  hg clone http://hg.logilab.org/cubicweb # development branch
 
-A practical way to get many of CubicWeb's dependencies and a nice set
-of base cubes is to run the `clone_deps.py` script located in
-`cubicweb/bin/`::
+To get many of CubicWeb's dependencies and a nice set of base cubes, run the
+`clone_deps.py` script located in `cubicweb/bin/`::
 
   python cubicweb/bin/clone_deps.py
 
 (Windows users should replace slashes with antislashes).
 
-This script will clone a set of mercurial repositories into in the
-directory containing the CubicWeb repository, and update them to the
+This script will clone a set of mercurial repositories into the
+directory containing the ``cubicweb`` repository, and update them to the
 latest published version tag (if any).
 
-When cloning a repository, you might be set in a development branch
-(the 'default' branch). You should check that the branches of the
-repositories are set to 'stable' (using `hg up stable` for each one)
-if you do not intend to develop the framework itself.
+.. note::
 
-Even better, `hg tags` will display a list of tags in reverse
-chronological order. One reasonnable way to get to a working version
-is to pick the latest published version (as done by the `clone_deps`
-script). These look like `cubicweb-debian-version-3.9.7-1`. Typing::
+  In every cloned repositories, a `hg tags` will display a list of
+  tags in reverse chronological order. One reasonnable option is to go to a
+  tagged version: the latest published version or example, as done by
+  the `clone_deps` script)::
 
- hg update cubicweb-debian-version-3.9.7-1
-
-will update the repository files to this version.
+   hg update cubicweb-version-3.12.2
 
 Make sure you also have all the :ref:`InstallDependencies`.
 
-
-.. _WindowsInstallation:
-
-Windows installation
-````````````````````
-
-Your best option is probably the :ref:`PipInstallation`. If it does not work or
-if you want more control over the process, continue with the following
-instructions.
-
-Base elements
-~~~~~~~~~~~~~
-
-Setting up a windows development environment is not too complicated but requires
-a series of small steps. What is proposed there is only an example of what can be
-done. We assume everything goes into `C:\\` in this document. Adjusting the
-installation drive should be straightforward.
-
-You should start by downloading and installing Python version >= 2.5 and < 3.
-
-An alternative option would be installing the Python(x,y)
-distribution. Python(x,y) is not a requirement, but it makes things easier for
-Windows user by wrapping in a single installer python 2.5 plus numerous useful
-third-party modules and applications (including Eclipse + pydev, which is an
-arguably good IDE for Python under Windows). Download it from this page::
-
-  http://code.google.com/p/pythonxy/wiki/Downloads
-
-Then you must grab Twisted. There is a windows installer directly available from
-this page::
-
-  http://twistedmatrix.com/trac/
-
-A windows installer for lxml will be found there::
-
-  http://pypi.python.org/pypi/lxml/2.2.1
-
-Check out the lxml-2.2.1-win32-py2.5.exe file. More recent bugfix
-releases should probably work, too.
-
-You should find postgresql 8.4 there::
-
-  http://www.enterprisedb.com/products/pgdownload.do#windows
-
-The python drivers for posgtresql are to be found there::
-
-  http://www.stickpeople.com/projects/python/win-psycopg/#Version2
-
-Please be careful to select the right python (2.5) and postgres (8.4) versions.
-
-A windows compiled recent version of gettext::
-
-  http://download.logilab.org/pub/gettext/gettext-0.17-win32-setup.exe
-
-A pre-compiled version of rql for windows (take care of retrieving the
-most recent version available there)::
-
-  http://download.logilab.org/pub/rql/rql-0.23.0.win32-py2.5.exe
-
-Pyro enables remote access to cubicweb repository instances. Get it there::
-
-  http://sourceforge.net/projects/pyro/files/
-
-To access LDAP/Active directory directories, we need the python-ldap
-package. Windows binaries are available from::
-
-  http://www.osuch.org/python-ldap
-
-Check out the latest release.
-
-Having graphviz will allow schema drawings, which is quite recommended (albeit
-not mandatory). You should get an msi installer there::
-
-  http://www.graphviz.org/Download_windows.php
-
-Simplejson is needed when installing with Python 2.5, but included in the
-standard library for Python >= 2.6. Get it from there::
-
-  http://www.osuch.org/python-simplejson%3Awin32
-
-Make sure you also have all the :ref:`InstallDependencies` that are not specific
-to Windows.
-
-Tools
-~~~~~
-
-Get mercurial + its standard windows GUI (TortoiseHG) there (the latest is the
-greatest)::
-
-  http://bitbucket.org/tortoisehg/stable/wiki/download
-
-If you need to peruse mercurial over ssh, it can be helpful to get an ssh client
-like Putty::
-
-  http://www.putty.org/
-
-Integration of mercurial and Eclipse is convenient enough that we want
-it. Instructions are set there, in the `Download & Install` section::
-
-  http://www.vectrace.com/mercurialeclipse/
-
-Getting the sources
-~~~~~~~~~~~~~~~~~~~
-
-You can either download the latest release (see
-:ref:`SourceInstallation`) or get the development version using
-Mercurial (see :ref:`MercurialInstallation` and below), which is more
-convenient.
-
-Environment variables
-~~~~~~~~~~~~~~~~~~~~~
-
-You will need some convenience environment variables once all is set up. These
-variables are settable through the GUI by getting at the 'System properties'
-window (by righ-clicking on 'My Computer' -> properties).
-
-In the 'advanced' tab, there is an 'Environment variables' button. Click on
-it. That opens a small window allowing edition of user-related and system-wide
-variables.
-
-We will consider only user variables. First, the PATH variable. You should ensure
-it contains, separated by semi-colons, and assuming you are logged in as user
-Jane::
-
-  C:\Documents and Settings\Jane\My Documents\Python\cubicweb\cubicweb\bin
-  C:\Program Files\Graphviz2.24\bin
-
-The PYTHONPATH variable should also contain::
-
-  C:\Documents and Settings\Jane\My Documents\Python\cubicweb\
-
-From now, on a fresh `cmd` shell, you should be able to type::
-
-  cubicweb-ctl list
-
-... and get a meaningful output.
-
-Running an instance as a service
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This currently assumes that the instances configurations is located at
-C:\\etc\\cubicweb.d.
-
-For a cube 'my_instance', you will then find
-C:\\etc\\cubicweb.d\\my_instance\\win32svc.py that has to be used as follows::
-
-  win32svc install
-
-This should just register your instance as a windows service. A simple::
-
-  net start cubicweb-my_instance
-
-should start the service.
-
-
-Other dependencies
-``````````````````
-
-You can also install:
-
-* `pyro` if you wish the repository to be accessible through Pyro
-  or if the client and the server are not running on the same machine
-  (in which case the packages will have to be installed on both
-  machines)
-
-* `python-ldap` if you plan to use a LDAP source on the server
-
-
-.. _DatabaseInstallation:
-
-Databases configuration
------------------------
-
-Each instance can be configured with its own database connection information,
-that will be stored in the instance's :file:`sources` file. The database to use
-will be chosen when creating the instance. Currently cubicweb has been tested
-using Postgresql (recommended), MySQL, SQLServer and SQLite.
-
-Other possible sources of data include CubicWeb, Subversion, LDAP and Mercurial,
-but at least one relational database is required for CubicWeb to work. You do
-not need to install a backend that you do not intend to use for one of your
-instances. SQLite is not fit for production use, but it works well for testing
-and ships with Python, which saves installation time when you want to get
-started quickly.
-
-.. _PostgresqlConfiguration:
-
-PostgreSQL configuration
-````````````````````````
-
-For installation, please refer to the `PostgreSQL project online documentation`_.
-
-.. _`PostgreSQL project online documentation`: http://www.postgresql.org/
-
-You need to install the three following packages: `postgresql-8.X`,
-`postgresql-client-8.X`, and `postgresql-plpython-8.X`. If you run postgres
-version prior to 8.3, you'll also need the `postgresql-contrib-8.X` package for
-full-text search extension.
-
-If you run postgres on another host than the |cubicweb| repository, you should
-install the `postgresql-client` package on the |cubicweb| host, and others on the
-database host.
-
-.. Note::
-
-    If you already have an existing cluster and PostgreSQL server running, you do
-    not need to execute the initilization step of your PostgreSQL database unless
-    you want a specific cluster for |cubicweb| databases or if your existing
-    cluster doesn't use the UTF8 encoding (see note below).
-
-* First, initialize a PostgreSQL cluster with the command ``initdb``.
-  ::
-
-    $ initdb -E UTF8 -D /path/to/pgsql
-
-  Notice the encoding specification. This is necessary since |cubicweb| usually
-  want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll
-  get error like::
-
-    new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII)
-    HINT:  Use the same encoding as in the template database, or use template0 as template.
-
-
-  Once initialized, start the database server PostgreSQL with the command::
-
-    $ postgres -D /path/to/psql
-
-  If you cannot execute this command due to permission issues, please make sure
-  that your username has write access on the database.  ::
-
-    $ chown username /path/to/pgsql
-
-* The database authentication can be either set to `ident sameuser` or `md5`.  If
-  set to `md5`, make sure to use an existing user of your database.  If set to
-  `ident sameuser`, make sure that your client's operating system user name has a
-  matching user in the database. If not, please do as follow to create a user::
-
-    $ su
-    $ su - postgres
-    $ createuser -s -P username
-
-  The option `-P` (for password prompt), will encrypt the password with the
-  method set in the configuration file :file:`pg_hba.conf`.  If you do not use this
-  option `-P`, then the default value will be null and you will need to set it
-  with::
-
-    $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql"
-
-.. Note::
-    The authentication method can be configured in file:`pg_hba.conf`.
-
-
-The above login/password will be requested when you will create an instance with
-`cubicweb-ctl create` to initialize the database of your instance.
-
-Notice that the `cubicweb-ctl db-create` does database initialization that
-may requires a postgres superuser. That's why a login/password is explicitly asked
-at this step, so you can use there a superuser without using this user when running
-the instance. Things that require special privileges at this step:
-
-* database creation, require the 'create database' permission
-* install the plpython extension language (require superuser)
-* install the tsearch extension for postgres version prior to 8.3 (require superuser)
-
-To avoid using a super user each time you create an install, a nice trick is to
-install plpython (and tsearch when needed) on the special `template1` database,
-so they will be installed automatically when cubicweb databases are created
-without even with needs for special access rights. To do so, run ::
-
-  # Installation of plpythonu language by default ::
-  $ createlang -U pgadmin plpythonu template1
-  $ psql -U pgadmin template1
-  template1=# update pg_language set lanpltrusted=TRUE where lanname='plpythonu';
-
-Where `pgadmin` is a postgres superuser. The last command is necessary since by
-default plpython is an 'untrusted' language and as such can't be used by non
-superuser. This update fix that problem by making it trusted.
-
-To install the tsearch plain-text index extension on postgres prior to 8.3, run::
-
-    cat /usr/share/postgresql/8.X/contrib/tsearch2.sql | psql -U username template1
-
-
-.. _MySqlConfiguration:
-
-MySql configuration
-```````````````````
-You must add the following lines in ``/etc/mysql/my.cnf`` file::
-
-    transaction-isolation=READ-COMMITTED
-    default-storage-engine=INNODB
-    default-character-set=utf8
-    max_allowed_packet = 128M
-
-.. Note::
-    It is unclear whether mysql supports indexed string of arbitrary length or
-    not.
-
-
-.. _SQLServerConfiguration:
-
-SQLServer configuration
-```````````````````````
-
-As of this writing, support for SQLServer 2005 is functional but incomplete. You
-should be able to connect, create a database and go quite far, but some of the
-SQL generated from RQL queries is still currently not accepted by the
-backend. Porting to SQLServer 2008 is also an item on the backlog.
-
-The `source` configuration file may look like this (specific parts only are
-shown)::
-
-  [system]
-  db-driver=sqlserver2005
-  db-user=someuser
-  # database password not needed
-  #db-password=toto123
-  #db-create/init may ask for a pwd: just say anything
-  db-extra-arguments=Trusted_Connection
-  db-encoding=utf8
-
-
-
-.. _SQLiteConfiguration:
-
-SQLite configuration
-````````````````````
-SQLite has the great advantage of requiring almost no configuration. Simply
-use 'sqlite' as db-driver, and set path to the dabase as db-name. Don't specify
-anything for db-user and db-password, they will be ignore anyway.
-
-.. Note::
-  SQLite is great for testing and to play with cubicweb but is not suited for
-  production environments.
-
-
-.. _PyroConfiguration:
-
-Pyro configuration
-------------------
-
-If you want to use Pyro to access your instance remotely, or to have multi-source
-or distributed configuration, it is required to have a Pyro name server running
-on your network. By default it is detected by a broadcast request, but you can
-specify a location in the instance's configuration file.
-
-To do so, you need to :
-
-* launch the pyro name server with `pyro-nsd start` before starting cubicweb
-
-* under debian, edit the file :file:`/etc/default/pyro-nsd` so that the name
-  server pyro will be launched automatically when the machine fire up
-
-
-Cubicweb resources configuration
---------------------------------
-
-.. autodocstring:: cubicweb.cwconfig
--- a/doc/book/en/index.rst	Fri Apr 22 12:17:51 2011 +0200
+++ b/doc/book/en/index.rst	Fri Apr 22 12:20:48 2011 +0200
@@ -38,7 +38,7 @@
 
 The hacker will join development at the forge_.
 
-The impatient developer will move right away to :ref:`SetUpEnv`.
+The impatient developer will move right away to :ref:`SetUpEnv` then to :ref:`ConfigEnv`.
 
 The chatter lover will join the `jabber forum`_, the `mailing-list`_ and the blog_.
 
--- a/doc/tools/pyjsrest.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/doc/tools/pyjsrest.py	Fri Apr 22 12:20:48 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/test/unittest_base.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/entities/test/unittest_base.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/entities/test/unittest_wfobjs.py	Fri Apr 22 12:20:48 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/hooks/metadata.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/hooks/metadata.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/hooks/test/unittest_hooks.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/hooks/test/unittest_syncschema.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/i18n/de.po	Fri Apr 22 12:20:48 2011 +0200
@@ -2755,6 +2755,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	Fri Apr 22 12:17:51 2011 +0200
+++ b/i18n/en.po	Fri Apr 22 12:20:48 2011 +0200
@@ -2680,6 +2680,9 @@
 "is created"
 msgstr ""
 
+msgid "indifferent"
+msgstr "indifferent"
+
 msgid "info"
 msgstr ""
 
--- a/i18n/es.po	Fri Apr 22 12:17:51 2011 +0200
+++ b/i18n/es.po	Fri Apr 22 12:20:48 2011 +0200
@@ -2785,6 +2785,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"
 
--- a/i18n/fr.po	Fri Apr 22 12:17:51 2011 +0200
+++ b/i18n/fr.po	Fri Apr 22 12:20:48 2011 +0200
@@ -2795,6 +2795,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"
 
--- a/server/hook.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/hook.py	Fri Apr 22 12:20:48 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/querier.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/querier.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/repository.py	Fri Apr 22 12:20:48 2011 +0200
@@ -1375,19 +1375,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/schemaserial.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/schemaserial.py	Fri Apr 22 12:20:48 2011 +0200
@@ -557,6 +557,8 @@
                     yield ('SET X %s_permission Y WHERE Y eid %%(g)s, X eid %%(x)s' % action,
                            {'g': groupmap[group_or_rqlexpr]})
                 except KeyError:
+                    print ("WARNING: group %s used in permissions for %s was ignored because it doesn't exist."
+                           " You may want to add it into a precreate.py file" % (group_or_rqlexpr, erschema))
                     continue
             else:
                 # rqlexpr
--- a/server/session.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/session.py	Fri Apr 22 12:20:48 2011 +0200
@@ -213,14 +213,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.
--- a/server/sources/__init__.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/sources/__init__.py	Fri Apr 22 12:20:48 2011 +0200
@@ -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/native.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/sources/native.py	Fri Apr 22 12:20:48 2011 +0200
@@ -628,22 +628,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 +1252,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,
--- a/server/sqlutils.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/sqlutils.py	Fri Apr 22 12:20:48 2011 +0200
@@ -335,6 +335,9 @@
 
 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/ssplanner.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/test/data/schema.py	Fri Apr 22 12:20:48 2011 +0200
@@ -220,3 +220,20 @@
 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 = '??'
--- a/server/test/unittest_ldapuser.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/test/unittest_ldapuser.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/test/unittest_migractions.py	Fri Apr 22 12:20:48 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_postgres.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/test/unittest_postgres.py	Fri Apr 22 12:20:48 2011 +0200
@@ -15,12 +15,12 @@
 from unittest_querier import FixedOffset
 
 class PostgresFTITC(CubicWebTC):
-    config = ApptestConfiguration('data', sourcefile='sources_postgres')
-
     @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()
@@ -71,7 +71,12 @@
         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
--- a/server/test/unittest_repository.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/test/unittest_repository.py	Fri Apr 22 12:20:48 2011 +0200
@@ -685,5 +685,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_security.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/test/unittest_security.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/server/test/unittest_undo.py	Fri Apr 22 12:20:48 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/test/unittest_email.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/sobjects/test/unittest_email.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/sobjects/test/unittest_notification.py	Fri Apr 22 12:20:48 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/test/unittest_entity.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/test/unittest_entity.py	Fri Apr 22 12:20:48 2011 +0200
@@ -245,9 +245,10 @@
                          '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 EXISTS(ZZ use_email O), S eid %(x)s, '
@@ -353,7 +354,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')
--- a/test/unittest_selectors.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/test/unittest_selectors.py	Fri Apr 22 12:20:48 2011 +0200
@@ -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()
--- a/web/data/cubicweb.css	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/data/cubicweb.css	Fri Apr 22 12:20:48 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.old.css	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/data/cubicweb.old.css	Fri Apr 22 12:20:48 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/jquery.corner.js	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/data/jquery.corner.js	Fri Apr 22 12:20:48 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);
Binary file web/data/tab.png has changed
--- a/web/data/ui.core.js	Fri Apr 22 12:17:51 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	Fri Apr 22 12:17:51 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	Fri Apr 22 12:17:51 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	Fri Apr 22 12:17:51 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/facet.py	Fri Apr 22 12:20:48 2011 +0200
@@ -1066,12 +1066,12 @@
   <option value="AND">%s</option>
 </select>''' % (facetid + '_andor', _('and/or between different values'),
                 _('OR'), _('AND')))
-        cssclass = ''
+        cssclass = 'facetBody'
         if not self.facet.start_unfolded:
             cssclass += ' hidden'
         if len(self.items) > 6:
             cssclass += ' overflowed'
-        self.w(u'<div class="facetBody%s">\n' % cssclass)
+        self.w(u'<div class="%s">\n' % cssclass)
         for item in self.items:
             item.render(w=self.w)
         self.w(u'</div>\n')
@@ -1125,8 +1125,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 % {
@@ -1140,6 +1140,10 @@
         self.w(u'<div id="%s" class="facet">\n' % facetid)
         self.w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
                (facetid, title))
+        cssclass = 'facetBody'
+        if not self.facet.start_unfolded:
+            cssclass += ' hidden'
+        self.w(u'<div class="%s">\n' % cssclass)
         self.w(u'<span id="%s_inf"></span> - <span id="%s_sup"></span>'
                % (sliderid, sliderid))
         self.w(u'<input type="hidden" name="%s_inf" value="%s" />'
@@ -1152,6 +1156,7 @@
                % (facetid, self.maxvalue))
         self.w(u'<div id="%s"></div>' % sliderid)
         self.w(u'</div>\n')
+        self.w(u'</div>\n')
 
 
 class DateFacetRangeWidget(FacetRangeWidget):
@@ -1183,15 +1188,15 @@
         self.selected = selected
 
     def _render(self):
+        cssclass = 'facetValue facetCheckBox'
         if self.selected:
-            cssclass = ' facetValueSelected'
+            cssclass += ' facetValueSelected'
             imgsrc = self._cw.data_url(self.selected_img)
             imgalt = self._cw._('selected')
         else:
-            cssclass = ''
             imgsrc = self._cw.data_url(self.unselected_img)
             imgalt = self._cw._('not selected')
-        self.w(u'<div class="facetValue facetCheckBox%s" cubicweb:value="%s">\n'
+        self.w(u'<div class="%s" cubicweb:value="%s">\n'
                % (cssclass, xml_escape(unicode(self.value))))
         self.w(u'<img src="%s" alt="%s"/>&#160;' % (imgsrc, imgalt))
         self.w(u'<a href="javascript: {}">%s</a>' % xml_escape(self.label))
@@ -1212,15 +1217,15 @@
         title = xml_escape(self.facet.title)
         facetid = xml_escape(self.facet.__regid__)
         self.w(u'<div id="%s" class="facet">\n' % facetid)
+        cssclass = 'facetValue facetCheckBox'
         if self.selected:
-            cssclass = ' facetValueSelected'
+            cssclass += ' facetValueSelected'
             imgsrc = self._cw.data_url(self.selected_img)
             imgalt = self._cw._('selected')
         else:
-            cssclass = ''
             imgsrc = self._cw.data_url(self.unselected_img)
             imgalt = self._cw._('not selected')
-        self.w(u'<div class="facetValue facetCheckBox%s" cubicweb:value="%s">\n'
+        self.w(u'<div class="%s" cubicweb:value="%s">\n'
                % (cssclass, xml_escape(unicode(self.value))))
         self.w(u'<div class="facetCheckBoxWidget">')
         self.w(u'<img src="%s" alt="%s" cubicweb:unselimg="true" />&#160;' % (imgsrc, imgalt))
--- a/web/formfields.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/formfields.py	Fri Apr 22 12:20:48 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'), '')]
 
--- a/web/formwidgets.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/formwidgets.py	Fri Apr 22 12:20:48 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/test/unittest_application.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/test/unittest_application.py	Fri Apr 22 12:20:48 2011 +0200
@@ -334,7 +334,7 @@
         self.assertRaises(AuthenticationError, self.app_publish, req, 'login')
         self.assertEqual(req.cnx, None)
         authstr = base64.encodestring('%s:%s' % (self.admlogin, self.admpassword))
-        req._headers['Authorization'] = 'basic %s' % authstr
+        req.set_request_header('Authorization', 'basic %s' % authstr)
         self.assertAuthSuccess(req, origsession)
         self.assertRaises(LogOut, self.app_publish, req, 'logout')
         self.assertEqual(len(self.open_sessions), 0)
@@ -378,7 +378,8 @@
         cookie = Cookie.SimpleCookie()
         sessioncookie = self.app.session_handler.session_cookie(req)
         cookie[sessioncookie] = req.session.sessionid
-        req._headers['Cookie'] = cookie[sessioncookie].OutputString()
+        req.set_request_header('Cookie', cookie[sessioncookie].OutputString(),
+                               raw=True)
         clear_cache(req, 'get_authorization')
         # reset session as if it was a new incoming request
         req.session = req.cnx = None
@@ -403,10 +404,10 @@
         req, origsession = self.init_authentication('http', 'anon')
         self._test_auth_anon(req)
         authstr = base64.encodestring('toto:pouet')
-        req._headers['Authorization'] = 'basic %s' % authstr
+        req.set_request_header('Authorization', 'basic %s' % authstr)
         self._test_anon_auth_fail(req)
         authstr = base64.encodestring('%s:%s' % (self.admlogin, self.admpassword))
-        req._headers['Authorization'] = 'basic %s' % authstr
+        req.set_request_header('Authorization', 'basic %s' % authstr)
         self.assertAuthSuccess(req, origsession)
         self.assertRaises(LogOut, self.app_publish, req, 'logout')
         self.assertEqual(len(self.open_sessions), 0)
--- a/web/test/unittest_urlpublisher.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/test/unittest_urlpublisher.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/test/unittest_urlrewrite.py	Fri Apr 22 12:20:48 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	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/test/unittest_views_basecontrollers.py	Fri Apr 22 12:20:48 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_viewselector.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/test/unittest_viewselector.py	Fri Apr 22 12:20:48 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/views/tabs.py	Fri Apr 22 12:17:51 2011 +0200
+++ b/web/views/tabs.py	Fri Apr 22 12:20:48 2011 +0200
@@ -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,