backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 12 Mar 2010 16:11:56 +0100
changeset 4899 c666d265fb95
parent 4897 e402e0b32075 (current diff)
parent 4898 5dec0d400d08 (diff)
child 4902 4e67a538e476
backport stable
__pkginfo__.py
cwconfig.py
debian/control
req.py
server/migractions.py
server/repository.py
server/serverctl.py
server/session.py
server/sources/extlite.py
server/sources/native.py
server/sqlutils.py
utils.py
web/request.py
--- a/.hgtags	Fri Mar 12 15:05:33 2010 +0100
+++ b/.hgtags	Fri Mar 12 16:11:56 2010 +0100
@@ -105,3 +105,5 @@
 4ae30c9ca11b1edad67d25b76fce672171d02023 cubicweb-version-3.6.1
 b9cdfe3341d1228687515d9af8686971ad5e6f5c cubicweb-debian-version-3.6.1-1
 0a16f07112b90fb61d2e905855fece77e5a7e39c cubicweb-debian-version-3.6.1-2
+bfebe3d14d5390492925fc294dfdafad890a7104 cubicweb-version-3.6.2
+f3b4bb9121a0e7ee5961310ff79e61c890948a77 cubicweb-debian-version-3.6.2-1
--- a/__pkginfo__.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/__pkginfo__.py	Fri Mar 12 16:11:56 2010 +0100
@@ -7,7 +7,7 @@
 distname = "cubicweb"
 modname = "cubicweb"
 
-numversion = (3, 6, 1)
+numversion = (3, 6, 2)
 version = '.'.join(str(num) for num in numversion)
 
 license = 'LGPL'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_gcdebug.py	Fri Mar 12 16:11:56 2010 +0100
@@ -0,0 +1,87 @@
+
+import gc, types, weakref
+
+from cubicweb.schema import CubicWebRelationSchema, CubicWebEntitySchema
+
+listiterator = type(iter([]))
+
+IGNORE_CLASSES = (
+    type, tuple, dict, list, set, frozenset, type(len),
+    weakref.ref, weakref.WeakKeyDictionary,
+    listiterator,
+    property, classmethod,
+    types.ModuleType, types.FunctionType, types.MethodType,
+    types.MemberDescriptorType, types.GetSetDescriptorType,
+    )
+
+def _get_counted_class(obj, classes):
+    for cls in classes:
+        if isinstance(obj, cls):
+            return cls
+    raise AssertionError()
+
+def gc_info(countclasses,
+            ignoreclasses=IGNORE_CLASSES,
+            viewreferrersclasses=(), showobjs=False, maxlevel=1):
+    gc.collect()
+    gc.collect()
+    counters = {}
+    ocounters = {}
+    for obj in gc.get_objects():
+        if isinstance(obj, countclasses):
+            cls = _get_counted_class(obj, countclasses)
+            try:
+                counters[cls.__name__] += 1
+            except KeyError:
+                counters[cls.__name__] = 1
+        elif not isinstance(obj, ignoreclasses):
+            try:
+                key = '%s.%s' % (obj.__class__.__module__,
+                                 obj.__class__.__name__)
+            except AttributeError:
+                key = str(obj)
+            try:
+                ocounters[key] += 1
+            except KeyError:
+                ocounters[key] = 1
+        if isinstance(obj, viewreferrersclasses):
+            print '   ', obj, referrers(obj, showobjs, maxlevel)
+    return counters, ocounters, gc.garbage
+
+
+def referrers(obj, showobj=False, maxlevel=1):
+    objreferrers = _referrers(obj, maxlevel)
+    try:
+        return sorted(set((type(x), showobj and x or getattr(x, '__name__', '%#x' % id(x)))
+                          for x in objreferrers))
+    except TypeError:
+        s = set()
+        unhashable = []
+        for x in objreferrers:
+            try:
+                s.add(x)
+            except TypeError:
+                unhashable.append(x)
+        return sorted(s) + unhashable
+
+def _referrers(obj, maxlevel, _seen=None, _level=0):
+    interesting = []
+    if _seen is None:
+        _seen = set()
+    for x in gc.get_referrers(obj):
+        if id(x) in _seen:
+            continue
+        _seen.add(id(x))
+        if isinstance(x, types.FrameType):
+            continue
+        if isinstance(x, (CubicWebRelationSchema, CubicWebEntitySchema)):
+            continue
+        if isinstance(x, (list, tuple, set, dict, listiterator)):
+            if _level >= maxlevel:
+                pass
+                #interesting.append(x)
+            else:
+                interesting += _referrers(x, maxlevel, _seen, _level+1)
+        else:
+            interesting.append(x)
+    return interesting
--- a/cwconfig.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/cwconfig.py	Fri Mar 12 16:11:56 2010 +0100
@@ -217,7 +217,9 @@
 
     if os.environ.get('APYCOT_ROOT'):
         mode = 'test'
-        if CWDEV:
+        # allow to test cubes within apycot using cubicweb not installed by
+        # apycot
+        if __file__.startswith(os.environ['APYCOT_ROOT']):
             CUBES_DIR = '%(APYCOT_ROOT)s/local/share/cubicweb/cubes/' % os.environ
             # create __init__ file
             file(join(CUBES_DIR, '__init__.py'), 'w').close()
@@ -638,16 +640,18 @@
     """base class for cubicweb server and web configurations"""
 
     INSTANCES_DATA_DIR = None
-    if CubicWebNoAppConfiguration.mode == 'test':
+    if os.environ.get('APYCOT_ROOT'):
         root = os.environ['APYCOT_ROOT']
         REGISTRY_DIR = '%s/etc/cubicweb.d/' % root
+        if not exists(REGISTRY_DIR):
+            os.makedirs(REGISTRY_DIR)
         RUNTIME_DIR = tempfile.gettempdir()
-        if CWDEV:
+        # allow to test cubes within apycot using cubicweb not installed by
+        # apycot
+        if __file__.startswith(os.environ['APYCOT_ROOT']):
             MIGRATION_DIR = '%s/local/share/cubicweb/migration/' % root
         else:
             MIGRATION_DIR = '/usr/share/cubicweb/migration/'
-        if not exists(REGISTRY_DIR):
-            os.makedirs(REGISTRY_DIR)
     else:
         if CubicWebNoAppConfiguration.mode == 'user':
             REGISTRY_DIR = expanduser('~/etc/cubicweb.d/')
--- a/debian/changelog	Fri Mar 12 15:05:33 2010 +0100
+++ b/debian/changelog	Fri Mar 12 16:11:56 2010 +0100
@@ -1,3 +1,18 @@
+cubicweb (3.6.2-2) unstable; urgency=low
+
+  * remove postgresql-contrib from cubicweb dependency (using tsearch
+    which is included with postgres >= 8.3)
+  * add postgresql-client | mysql-client to cubicweb-server dependencies, necessary
+    for dump/restore of database
+
+ --
+
+cubicweb (3.6.2-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Thu, 11 Mar 2010 19:49:04 +0100
+
 cubicweb (3.6.1-2) unstable; urgency=low
 
   * remove depends to python-elementtree (included in python>=2.5)
--- a/debian/control	Fri Mar 12 15:05:33 2010 +0100
+++ b/debian/control	Fri Mar 12 16:11:56 2010 +0100
@@ -16,7 +16,7 @@
 Architecture: all
 XB-Python-Version: ${python:Versions}
 Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-twisted (= ${source:Version})
-XB-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3
+XB-Recommends: (postgresql, postgresql-plpython) | mysql | sqlite3
 Recommends: postgresql | mysql | sqlite3
 Description: the complete CubicWeb framework
  CubicWeb is a semantic web application framework.
@@ -33,7 +33,8 @@
 Conflicts: cubicweb-multisources
 Replaces: cubicweb-multisources
 Provides: cubicweb-multisources
-Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database, python-psycopg2 | python-mysqldb | python-pysqlite2
+# postgresql/mysql -client packages for backup/restore of non local database
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database, (python-psycopg2, postgresql-client) | (python-mysqldb, mysql-client) | python-pysqlite2
 Recommends: pyro, cubicweb-documentation (= ${source:Version})
 Description: server part of the CubicWeb framework
  CubicWeb is a semantic web application framework.
--- a/doc/book/en/admin/instance-config.rst	Fri Mar 12 15:05:33 2010 +0100
+++ b/doc/book/en/admin/instance-config.rst	Fri Mar 12 16:11:56 2010 +0100
@@ -49,13 +49,13 @@
    and `https://localhost/demo` and actually running on port 8080, it
    takes to the http:::
 
-     RewriteCond %(REQUEST_URI) ^/demo
+     RewriteCond %{REQUEST_URI} ^/demo
      RewriteRule ^/demo$ /demo/
      RewriteRule ^/demo/(.*) http://127.0.0.1:8080/$1 [L,P]
 
    and for the https:::
 
-     RewriteCond %(REQUEST_URI) ^/ demo
+     RewriteCond %{REQUEST_URI} ^/ demo
      RewriteRule ^/demo$/demo/
      RewriteRule ^/demo/(.*) http://127.0.0.1:8080/https/$1 [L,P]
 
@@ -63,7 +63,7 @@
    and we will file in the all-in-one.conf of the instance:::
 
      base-url = http://localhost/demo
-     https-url = `https://localhost/demo`
+     https-url = https://localhost/demo
 
 Setting up the web client
 -------------------------
--- a/i18n/en.po	Fri Mar 12 15:05:33 2010 +0100
+++ b/i18n/en.po	Fri Mar 12 16:11:56 2010 +0100
@@ -369,6 +369,9 @@
 msgid "From:"
 msgstr ""
 
+msgid "Garbage collection information"
+msgstr ""
+
 msgid "Help"
 msgstr ""
 
@@ -390,6 +393,12 @@
 msgid "Interval_plural"
 msgstr "Intervals"
 
+msgid "Looked up classes"
+msgstr ""
+
+msgid "Most referenced classes"
+msgstr ""
+
 msgid "New BaseTransition"
 msgstr "XXX"
 
@@ -648,6 +657,9 @@
 msgid "UniqueConstraint"
 msgstr "unique constraint"
 
+msgid "Unreachable objects"
+msgstr ""
+
 msgid "Update permissions"
 msgstr ""
 
@@ -2717,6 +2729,9 @@
 msgid "may"
 msgstr ""
 
+msgid "memory leak debugging"
+msgstr ""
+
 msgid "milestone"
 msgstr ""
 
--- a/i18n/es.po	Fri Mar 12 15:05:33 2010 +0100
+++ b/i18n/es.po	Fri Mar 12 16:11:56 2010 +0100
@@ -377,6 +377,9 @@
 msgid "From:"
 msgstr "De: "
 
+msgid "Garbage collection information"
+msgstr ""
+
 msgid "Help"
 msgstr ""
 
@@ -398,6 +401,12 @@
 msgid "Interval_plural"
 msgstr "Duraciones"
 
+msgid "Looked up classes"
+msgstr ""
+
+msgid "Most referenced classes"
+msgstr ""
+
 msgid "New BaseTransition"
 msgstr ""
 
@@ -656,6 +665,9 @@
 msgid "UniqueConstraint"
 msgstr ""
 
+msgid "Unreachable objects"
+msgstr ""
+
 msgid "Update permissions"
 msgstr "Autorización de modificar"
 
@@ -2785,6 +2797,9 @@
 msgid "may"
 msgstr "Mayo"
 
+msgid "memory leak debugging"
+msgstr ""
+
 msgid "milestone"
 msgstr "Milestone"
 
--- a/i18n/fr.po	Fri Mar 12 15:05:33 2010 +0100
+++ b/i18n/fr.po	Fri Mar 12 16:11:56 2010 +0100
@@ -376,6 +376,9 @@
 msgid "From:"
 msgstr "De :"
 
+msgid "Garbage collection information"
+msgstr "Information sur le ramasse-miette"
+
 msgid "Help"
 msgstr "Aide"
 
@@ -397,6 +400,12 @@
 msgid "Interval_plural"
 msgstr "Durées"
 
+msgid "Looked up classes"
+msgstr "Classes recherchées"
+
+msgid "Most referenced classes"
+msgstr "Classes les plus référencées"
+
 msgid "New BaseTransition"
 msgstr "XXX"
 
@@ -655,6 +664,9 @@
 msgid "UniqueConstraint"
 msgstr "contrainte d'unicité"
 
+msgid "Unreachable objects"
+msgstr "Objets inacessible"
+
 msgid "Update permissions"
 msgstr "Permissions de modifier"
 
@@ -2811,6 +2823,9 @@
 msgid "may"
 msgstr "mai"
 
+msgid "memory leak debugging"
+msgstr "Déboguage des fuites de mémoire"
+
 msgid "milestone"
 msgstr "jalon"
 
--- a/req.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/req.py	Fri Mar 12 16:11:56 2010 +0100
@@ -7,9 +7,10 @@
 """
 __docformat__ = "restructuredtext en"
 
+from urlparse import urlsplit, urlunsplit
 from urllib import quote as urlquote, unquote as urlunquote
 from datetime import time, datetime, timedelta
-from cgi import parse_qsl
+from cgi import parse_qs, parse_qsl
 
 from logilab.common.decorators import cached
 from logilab.common.deprecation import deprecated
@@ -239,7 +240,7 @@
     def build_url_params(self, **kwargs):
         """return encoded params to incorporate them in an URL"""
         args = []
-        for param, values in kwargs.items():
+        for param, values in kwargs.iteritems():
             if not isinstance(values, (list, tuple)):
                 values = (values,)
             for value in values:
@@ -279,6 +280,25 @@
             except UnicodeDecodeError: # might occurs on manually typed URLs
                 yield unicode(key, 'iso-8859-1'), unicode(val, 'iso-8859-1')
 
+
+    def rebuild_url(self, url, **newparams):
+        """return the given url with newparams inserted. If any new params
+        is already specified in the url, it's overriden by the new value
+
+        newparams may only be mono-valued.
+        """
+        if isinstance(url, unicode):
+            url = url.encode(self.encoding)
+        schema, netloc, path, query, fragment = urlsplit(url)
+        query = parse_qs(query)
+        # sort for testing predictability
+        for key, val in sorted(newparams.iteritems()):
+            query[key] = (self.url_quote(val),)
+        query = '&'.join(u'%s=%s' % (param, value)
+                         for param, values in query.items()
+                         for value in values)
+        return urlunsplit((schema, netloc, path, query, fragment))
+
     # bound user related methods ###############################################
 
     @cached
--- a/server/migractions.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/server/migractions.py	Fri Mar 12 16:11:56 2010 +0100
@@ -147,9 +147,9 @@
         try:
             for source in repo.sources:
                 try:
-                    source.backup(osp.join(tmpdir, source.uri))
-                except Exception, exc:
-                    print '-> error trying to backup %s [%s]' % (source.uri, exc)
+                    source.backup(osp.join(tmpdir, source.uri, self.confirm))
+                except Exception, ex:
+                    print '-> error trying to backup %s [%s]' % (source.uri, ex)
                     if not self.confirm('Continue anyway?', default='n'):
                         raise SystemExit(1)
                     else:
@@ -189,7 +189,6 @@
             bkup = tarfile.open(backupfile, 'r|gz')
             bkup.extractall(path=tmpdir)
             bkup.close()
-
         self.config.open_connections_pools = False
         repo = self.repo_connect()
         for source in repo.sources:
--- a/server/repository.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/server/repository.py	Fri Mar 12 16:11:56 2010 +0100
@@ -360,10 +360,15 @@
     def stats(self): # XXX restrict to managers session?
         import threading
         results = {}
-        for hits, misses, title in (
-            (self.querier.cache_hit, self.querier.cache_miss, 'rqlt_st'),
-            (self.system_source.cache_hit, self.system_source.cache_miss, 'sql'),
+        querier = self.querier
+        source = self.system_source
+        for size, maxsize, hits, misses, title in (
+            (len(querier._rql_cache), self.config['rql-cache-size'],
+            querier.cache_hit, querier.cache_miss, 'rqlt_st'),
+            (len(source._cache), self.config['rql-cache-size'],
+            source.cache_hit, source.cache_miss, 'sql'),
             ):
+            results['%s_cache_size' % title] =  '%s / %s' % (size, maxsize)
             results['%s_cache_hit' % title] =  hits
             results['%s_cache_miss' % title] = misses
             results['%s_cache_hit_percent' % title] = (hits * 100) / (hits + misses)
--- a/server/session.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/server/session.py	Fri Mar 12 16:11:56 2010 +0100
@@ -741,6 +741,7 @@
                 self.error('thread %s still alive after 10 seconds, will close '
                            'session anyway', thread)
         self.rollback()
+        del self._threaddata
 
     # transaction data/operations management ##################################
 
--- a/server/sources/extlite.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/server/sources/extlite.py	Fri Mar 12 16:11:56 2010 +0100
@@ -87,11 +87,11 @@
         AbstractSource.__init__(self, repo, appschema, source_config,
                                 *args, **kwargs)
 
-    def backup(self, backupfile):
+    def backup(self, backupfile, confirm):
         """method called to create a backup of the source's data"""
         self.close_pool_connections()
         try:
-            self.sqladapter.backup_to_file(backupfile)
+            self.sqladapter.backup_to_file(backupfile, confirm)
         finally:
             self.open_pool_connections()
 
--- a/server/sources/native.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/server/sources/native.py	Fri Mar 12 16:11:56 2010 +0100
@@ -13,7 +13,7 @@
 """
 __docformat__ = "restructuredtext en"
 
-from threading import Lock
+from o_threading import Lock
 from datetime import datetime
 from base64 import b64decode, b64encode
 
@@ -205,11 +205,11 @@
         pool.pool_reset()
         self.repo._free_pool(pool)
 
-    def backup(self, backupfile):
+    def backup(self, backupfile, confirm):
         """method called to create a backup of the source's data"""
         self.close_pool_connections()
         try:
-            self.backup_to_file(backupfile)
+            self.backup_to_file(backupfile, confirm)
         finally:
             self.open_pool_connections()
 
--- a/server/sqlutils.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/server/sqlutils.py	Fri Mar 12 16:11:56 2010 +0100
@@ -159,7 +159,7 @@
         """open and return a connection to the database"""
         return self.dbhelper.get_connection()
 
-    def backup_to_file(self, backupfile):
+    def backup_to_file(self, backupfile, confirm):
         for cmd in self.dbhelper.backup_commands(backupfile,
                                                  keepownership=False):
             if _run_command(cmd):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/unittest_req.py	Fri Mar 12 16:11:56 2010 +0100
@@ -0,0 +1,16 @@
+from logilab.common.testlib import TestCase, unittest_main
+from cubicweb.req import RequestSessionBase
+
+class RebuildURLTC(TestCase):
+    def test(self):
+        rebuild_url = RequestSessionBase(None).rebuild_url
+        self.assertEquals(rebuild_url('http://logilab.fr?__message=pouet', __message='hop'),
+                          'http://logilab.fr?__message=hop')
+        self.assertEquals(rebuild_url('http://logilab.fr', __message='hop'),
+                          'http://logilab.fr?__message=hop')
+        self.assertEquals(rebuild_url('http://logilab.fr?vid=index', __message='hop'),
+                          'http://logilab.fr?__message=hop&vid=index')
+
+
+if __name__ == '__main__':
+    unittest_main()
--- a/test/unittest_utils.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/test/unittest_utils.py	Fri Mar 12 16:11:56 2010 +0100
@@ -59,7 +59,7 @@
             l.extend(extension)
             yield self.assertEquals, l, expected
 
-class JSONEncoerTests(TestCase):
+class JSONEncoderTC(TestCase):
     def setUp(self):
         if simplejson is None:
             self.skip('simplejson not available')
@@ -81,5 +81,6 @@
     def test_encoding_unknown_stuff(self):
         self.assertEquals(self.encode(TestCase), 'null')
 
+
 if __name__ == '__main__':
     unittest_main()
--- a/utils.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/utils.py	Fri Mar 12 16:11:56 2010 +0100
@@ -160,7 +160,6 @@
             warn('[3.7] specifying jsoncall is not needed anymore',
                  DeprecationWarning, stacklevel=2)
         self.add_post_inline_script(u"""jQuery(CubicWeb).one('server-response', function(event) {
-%s
 });""" % jscode)
 
 
@@ -182,10 +181,10 @@
         if (cssfile, media) not in self.cssfiles:
             self.cssfiles.append( (cssfile, media) )
 
-    def add_ie_css(self, cssfile, media='all'):
+    def add_ie_css(self, cssfile, media='all', iespec=u'[if lt IE 8]'):
         """registers some IE specific CSS"""
-        if (cssfile, media) not in self.ie_cssfiles:
-            self.ie_cssfiles.append( (cssfile, media) )
+        if (cssfile, media, iespec) not in self.ie_cssfiles:
+            self.ie_cssfiles.append( (cssfile, media, iespec) )
 
     def add_unload_pagedata(self):
         """registers onunload callback to clean page data on server"""
@@ -215,8 +214,8 @@
               (media, xml_escape(cssfile)))
         # 3/ ie css if necessary
         if self.ie_cssfiles:
-            w(u'<!--[if lt IE 8]>\n')
-            for cssfile, media in self.ie_cssfiles:
+            for cssfile, media, iespec in self.ie_cssfiles:
+                w(u'<!--%s>\n' % iespec)
                 w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
                   (media, xml_escape(cssfile)))
             w(u'<![endif]--> \n')
--- a/web/data/jquery.autocomplete.js	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/data/jquery.autocomplete.js	Fri Mar 12 16:11:56 2010 +0100
@@ -1,15 +1,13 @@
 /*
- * Autocomplete - jQuery plugin 1.0.2
+ * jQuery Autocomplete plugin 1.1
  *
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ * Copyright (c) 2009 Jörn Zaefferer
  *
  * Dual licensed under the MIT and GPL licenses:
  *   http://www.opensource.org/licenses/mit-license.php
  *   http://www.gnu.org/licenses/gpl.html
  *
- * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
- *
- */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){v=words.slice(0,words.length-1).join(options.multipleSeparator)+options.multipleSeparator+v;}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&&currentValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value){return[""];}var words=value.split(options.multipleSeparator);var result=[];$.each(words,function(i,value){if($.trim(value))result[i]=$.trim(value);});return result;}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$.Autocompleter.Selection(input,previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else
-$input.val("");}});}if(wasVisible)$.Autocompleter.Selection(input,input.value.length,input.value.length);};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){hasFocus=1;lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){var seperator=options.multipleSeparator.length;var cursorAt=$(input).selection().start;var wordAt,progress=0;$.each(words,function(i,word){progress+=word.length;if(cursorAt<=progress){wordAt=i;return false;}progress+=seperator;});words[wordAt]=v;v=words.join(options.multipleSeparator);}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&&currentValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value)return[""];if(!options.multiple)return[$.trim(value)];return $.map(value.split(options.multipleSeparator),function(word){return $.trim(value).length?$.trim(word):null;});}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);if(words.length==1)return words[0];var cursorAt=$(input).selection().start;if(cursorAt==value.length){words=trimWords(value)}else{words=trimWords(value.replace(value.substring(cursorAt),""));}return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$(input).selection(previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else{$input.val("");$input.trigger("result",null);}}});}};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(options.matchContains=="word"){i=s.toLowerCase().search("\\b"+sub.toLowerCase());}if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
 if(data[q]){return data[q];}else
-if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.Autocompleter.Selection=function(field,start,end){if(field.createTextRange){var selRange=field.createTextRange();selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}else if(field.setSelectionRange){field.setSelectionRange(start,end);}else{if(field.selectionStart){field.selectionStart=start;field.selectionEnd=end;}}field.focus();};})(jQuery);
\ No newline at end of file
+if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName.toUpperCase()!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.fn.selection=function(start,end){if(start!==undefined){return this.each(function(){if(this.createTextRange){var selRange=this.createTextRange();if(end===undefined||start==end){selRange.move("character",start);selRange.select();}else{selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}}else if(this.setSelectionRange){this.setSelectionRange(start,end);}else if(this.selectionStart){this.selectionStart=start;this.selectionEnd=end;}});}var field=this[0];if(field.createTextRange){var range=document.selection.createRange(),orig=field.value,teststring="<->",textLength=range.text.length;range.text=teststring;var caretAt=field.value.indexOf(teststring);field.value=orig;this.selection(caretAt,caretAt+textLength);return{start:caretAt,end:caretAt+textLength}}else if(field.selectionStart!==undefined){return{start:field.selectionStart,end:field.selectionEnd}}};})(jQuery);
\ No newline at end of file
--- a/web/formfields.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/formfields.py	Fri Mar 12 16:11:56 2010 +0100
@@ -14,7 +14,6 @@
 
 from logilab.mtconverter import xml_escape
 from logilab.common.date import ustrftime
-from logilab.common.decorators import cached
 
 from yams.schema import KNOWN_METAATTRIBUTES
 from yams.constraints import (SizeConstraint, StaticVocabularyConstraint,
@@ -189,19 +188,28 @@
         """return the widget instance associated to this field"""
         return self.widget
 
-    # cached is necessary else we get some pb on entity creation : entity.eid is
-    # modified from creation mark (eg 'X') to its actual eid (eg 123), and then
-    # `field.input_name()` won't return the right key anymore if not cached
-    # (first call to input_name done *before* eventual eid affectation).
-    @cached
     def input_name(self, form, suffix=None):
         """return 'qualified name' for this field"""
-        name = self.role_name()
-        if suffix is not None:
-            name += suffix
-        if self.eidparam:
-            return eid_param(name, form.edited_entity.eid)
-        return name
+        # caching is necessary else we get some pb on entity creation :
+        # entity.eid is modified from creation mark (eg 'X') to its actual eid
+        # (eg 123), and then `field.input_name()` won't return the right key
+        # anymore if not cached (first call to input_name done *before* eventual
+        # eid affectation).
+        #
+        # note that you should NOT use @cached else it will create a memory leak
+        # on persistent fields (eg created once for all on a form class) because
+        # of the 'form' appobject argument: the cache will keep growing as new
+        # form are created...
+        try:
+            return form.formvalues[(self, 'input_name', suffix)]
+        except KeyError:
+            name = self.role_name()
+            if suffix is not None:
+                name += suffix
+            if self.eidparam:
+                name = eid_param(name, form.edited_entity.eid)
+            form.formvalues[(self, 'input_name', suffix)] = name
+            return name
 
     def role_name(self):
         """return <field.name>-<field.role> if role is specified, else field.name"""
--- a/web/formwidgets.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/formwidgets.py	Fri Mar 12 16:11:56 2010 +0100
@@ -456,16 +456,17 @@
     needs_js = ('jquery.timePicker.js',)
     needs_css = ('jquery.timepicker.css',)
 
-    def __init__(self, timestr=None, timesteps=30, **kwargs):
+    def __init__(self, timestr=None, timesteps=30, separator=u':', **kwargs):
         super(JQueryTimePicker, self).__init__(**kwargs)
         self.timestr = timestr
         self.timesteps = timesteps
+        self.separator = separator
 
     def _render(self, form, field, renderer):
         req = form._cw
         domid = field.dom_id(form, self.suffix)
-        req.add_onload(u'jqNode("%s").timePicker({selectedTime: "%s", step: %s})' % (
-            domid, self.timestr, self.timesteps))
+        req.add_onload(u'jqNode("%s").timePicker({selectedTime: "%s", step: %s, separator: "%s"})' % (
+            domid, self.timestr, self.timesteps, self.separator))
         if self.timestr is None:
             value = self.values(form, field)[0]
         else:
--- a/web/request.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/request.py	Fri Mar 12 16:11:56 2010 +0100
@@ -311,7 +311,11 @@
             if breadcrumbs is None:
                 breadcrumbs = SizeConstrainedList(10)
                 self.set_session_data('breadcrumbs', breadcrumbs)
-            breadcrumbs.append(self.url())
+                breadcrumbs.append(self.url())
+            else:
+                url = self.url()
+                if breadcrumbs[-1] != url:
+                    breadcrumbs.append(url)
 
     def last_visited_page(self):
         breadcrumbs = self.get_session_data('breadcrumbs', None)
@@ -516,26 +520,33 @@
                 jsfile = self.datadir_url + jsfile
             self.html_headers.add_js(jsfile)
 
-    def add_css(self, cssfiles, media=u'all', localfile=True, ieonly=False):
+    def add_css(self, cssfiles, media=u'all', localfile=True, ieonly=False,
+                iespec=u'[if lt IE 8]'):
         """specify a CSS file to include in the HTML headers
         :param cssfiles: a CSS filename or a list of CSS filenames
         :param media: the CSS's media if necessary
         :param localfile: if True, the default data dir prefix is added to the
                           CSS filename
+        :param ieonly: True if this css is specific to IE
+        :param iespec: conditional expression that will be used around
+                       the css inclusion. cf:
+                       http://msdn.microsoft.com/en-us/library/ms537512(VS.85).aspx
         """
         if isinstance(cssfiles, basestring):
             cssfiles = (cssfiles,)
         if ieonly:
             if self.ie_browser():
+                extraargs = [iespec]
                 add_css = self.html_headers.add_ie_css
             else:
                 return # no need to do anything on non IE browsers
         else:
+            extraargs = []
             add_css = self.html_headers.add_css
         for cssfile in cssfiles:
             if localfile:
                 cssfile = self.datadir_url + cssfile
-            add_css(cssfile, media)
+            add_css(cssfile, media, *extraargs)
 
     def build_ajax_replace_url(self, nodeid, rql, vid, replacemode='replace',
                                **extraparams):
--- a/web/views/authentication.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/authentication.py	Fri Mar 12 16:11:56 2010 +0100
@@ -114,8 +114,11 @@
                 login, authinfo = retreiver.authentication_information(req)
             except NoAuthInfo:
                 continue
-            cnx = self._authenticate(req, login, authinfo)
-            break
+            try:
+                cnx = self._authenticate(req, login, authinfo)
+                break
+            except ExplicitLogin:
+                continue # the next one may succeed
         else:
             raise ExplicitLogin()
         for retreiver_ in self.authinforetreivers:
@@ -124,7 +127,6 @@
 
     def _authenticate(self, req, login, authinfo):
         # remove possibly cached cursor coming from closed connection
-        clear_cache(req, 'cursor')
         cnxprops = ConnectionProperties(self.vreg.config.repo_method,
                                         close=False, log=self.log_queries)
         try:
--- a/web/views/debug.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/debug.py	Fri Mar 12 16:11:56 2010 +0100
@@ -27,13 +27,13 @@
 
 
 class ProcessInformationView(StartupView):
+    """display various web server /repository information"""
     __regid__ = 'info'
     __select__ = none_rset() & match_user_groups('managers')
 
     title = _('server information')
 
     def call(self, **kwargs):
-        """display server information"""
         req = self._cw
         dtformat = req.property_value('ui.datetime-format')
         _ = req._
@@ -111,24 +111,59 @@
 
 
 class RegistryView(StartupView):
+    """display vregistry content"""
     __regid__ = 'registry'
     __select__ = StartupView.__select__ & match_user_groups('managers')
     title = _('registry')
 
     def call(self, **kwargs):
-        """The default view representing the instance's management"""
         self.w(u'<h1>%s</h1>' % _("Registry's content"))
         keys = sorted(self._cw.vreg)
-        self.w(u'<p>%s</p>\n' % ' - '.join('<a href="/_registry#%s">%s</a>'
-                                           % (key, key) for key in keys))
+        url = self._cw.url()
+        self.w(u'<p>%s</p>\n' % ' - '.join('<a href="%s#%s">%s</a>'
+                                           % (url, key, key) for key in keys))
         for key in keys:
-            self.w(u'<h2><a name="%s">%s</a></h2>' % (key, key))
-            items = self._cw.vreg[key].items()
-            if items:
-                self.w(u'<table><tbody>')
-                for key, value in sorted(items):
-                    self.w(u'<tr><td>%s</td><td>%s</td></tr>'
-                           % (key, xml_escape(repr(value))))
-                self.w(u'</tbody></table>\n')
+            self.w(u'<h2 id="%s">%s</h2>' % (key, key))
+            if self._cw.vreg[key]:
+                values = sorted(self._cw.vreg[key].iteritems())
+                self.wview('pyvaltable', pyvalue=[(key, xml_escape(repr(val)))
+                                                  for key, val in values])
             else:
                 self.w(u'<p>Empty</p>\n')
+
+
+class GCView(StartupView):
+    """display garbage collector information"""
+    __regid__ = 'gc'
+    __select__ = StartupView.__select__ & match_user_groups('managers')
+    title = _('memory leak debugging')
+
+    def call(self, **kwargs):
+        from cubicweb._gcdebug import gc_info
+        from rql.stmts import Union
+        from cubicweb.appobject import AppObject
+        from cubicweb.rset import ResultSet
+        from cubicweb.dbapi import Connection, Cursor
+        from cubicweb.web.request import CubicWebRequestBase
+        lookupclasses = (AppObject,
+                         Union, ResultSet,
+                         Connection, Cursor,
+                         CubicWebRequestBase)
+        try:
+            from cubicweb.server.session import Session, ChildSession, InternalSession
+            lookupclasses += (InternalSession, ChildSession, Session)
+        except ImportError:
+            pass # no server part installed
+        self.w(u'<h1>%s</h1>' % _('Garbage collection information'))
+        counters, ocounters, garbage = gc_info(lookupclasses,
+                                               viewreferrersclasses=())
+        self.w(u'<h3>%s</h3>' % _('Looked up classes'))
+        values = sorted(counters.iteritems(), key=lambda x: x[1], reverse=True)
+        self.wview('pyvaltable', pyvalue=values)
+        self.w(u'<h3>%s</h3>' % _('Most referenced classes'))
+        values = sorted(ocounters.iteritems(), key=lambda x: x[1], reverse=True)
+        self.wview('pyvaltable', pyvalue=values[:self._cw.form.get('nb', 20)])
+        if garbage:
+            self.w(u'<h3>%s</h3>' % _('Unreachable objects'))
+            values = sorted(xml_escape(repr(o) for o in garbage))
+            self.wview('pyvallist', pyvalue=values)
--- a/web/views/pyviews.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/pyviews.py	Fri Mar 12 16:11:56 2010 +0100
@@ -17,18 +17,23 @@
     def call(self, pyvalue, headers=None):
         if headers is None:
             headers = self._cw.form.get('headers')
-        self.w(u'<table class="listing">\n')
+        w = self.w
+        w(u'<table class="listing">\n')
         if headers:
-            self.w(u'<tr>')
+            w(u'<thead>')
+            w(u'<tr>')
             for header in headers:
-                self.w(u'<th>%s</th>' % header)
-            self.w(u'</tr>\n')
+                w(u'<th>%s</th>' % header)
+            w(u'</tr>\n')
+            w(u'</thead>')
+        w(u'<tbody>')
         for row in pyvalue:
-            self.w(u'<tr>')
+            w(u'<tr>')
             for cell in row:
-                self.w(u'<td>%s</td>' % cell)
-            self.w(u'</tr>\n')
-        self.w(u'</table>\n')
+                w(u'<td>%s</td>' % cell)
+            w(u'</tr>\n')
+        w(u'</tbody>')
+        w(u'</table>\n')
 
 
 class PyValListView(View):
--- a/web/views/xmlrss.py	Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/xmlrss.py	Fri Mar 12 16:11:56 2010 +0100
@@ -148,6 +148,7 @@
     content_type = 'text/xml'
     http_cache_manager = httpcache.MaxAgeHTTPCacheManager
     cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+    item_vid = 'rssitem'
 
     def _open(self):
         req = self._cw
@@ -174,7 +175,7 @@
         self._close()
 
     def cell_call(self, row, col):
-        self.wview('rssitem', self.cw_rset, row=row, col=col)
+        self.wview(self.item_vid, self.cw_rset, row=row, col=col)
 
 
 class RSSItemView(EntityView):