changeset 857:3d0661b8aaa4

merged with beta branch
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 18 Dec 2010 14:45:58 +0100
parents 06cfcede13ab (current diff) 86cbf8e6d76a (diff)
children 4c123ade8485
files celeryconfig.py docs/changelog.rst docs/index.rst docs/installation.rst docs/setup.rst rhodecode/__init__.py rhodecode/controllers/hg.py rhodecode/lib/celerylib/__init__.py rhodecode/lib/helpers.py rhodecode/lib/hooks.py rhodecode/lib/utils.py rhodecode/model/db.py rhodecode/model/hg_model.py rhodecode/model/permission_model.py rhodecode/model/repo_model.py rhodecode/model/user_model.py rhodecode/public/css/style.css rhodecode/public/images/hgicon.png rhodecode/public/images/icons/success.png rhodecode/public/images/icons/warning.png rhodecode/public/images/title_tab_selected.png rhodecode/public/js/yui2.js rhodecode/templates/files/files_browser.html rhodecode/templates/summary/summary.html rhodecode/tests/__init__.py rhodecode/tests/functional/test_changelog.py rhodecode/tests/functional/test_hg.py rhodecode/tests/functional/test_permissions.py rhodecode/tests/functional/test_repos.py rhodecode/tests/functional/test_users.py rhodecode/tests/vcs_test.tar.gz setup.cfg setup.py
diffstat 198 files changed, 12323 insertions(+), 3425 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Nov 18 21:35:52 2010 +0100
+++ b/.hgignore	Sat Dec 18 14:45:58 2010 +0100
@@ -1,5 +1,11 @@
+syntax: glob
+*.pyc
+*.swp
 
 syntax: regexp
+^build
+^docs/build/
+^docs/_build/
 ^data$
 ^\.settings$
 ^\.project$
@@ -7,4 +13,4 @@
 ^rhodecode\.db$
 ^test\.db$
 ^repositories\.config$
-^RhodeCode\.egg-info$
\ No newline at end of file
+^RhodeCode\.egg-info$
--- a/MANIFEST.in	Thu Nov 18 21:35:52 2010 +0100
+++ b/MANIFEST.in	Sat Dec 18 14:45:58 2010 +0100
@@ -1,4 +1,5 @@
 include rhodecode/config/deployment.ini_tmpl
+include rhodecode/lib/dbmigrate/migrate.cfg
 
 include README.rst
 recursive-include rhodecode/i18n/ *
@@ -7,7 +8,7 @@
 recursive-include rhodecode/public/css *
 recursive-include rhodecode/public/images *
 #js
-include rhodecode/public/js/yui2.js
+include rhodecode/public/js/yui2a.js
 include rhodecode/public/js/excanvas.min.js
 include rhodecode/public/js/yui.flot.js
 include rhodecode/public/js/graph.js
--- a/README.rst	Thu Nov 18 21:35:52 2010 +0100
+++ b/README.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -1,23 +1,25 @@
 
-RhodeCode (RhodiumCode)
-=======================
+=================================================
+Welcome to RhodeCode (RhodiumCode) documentation!
+=================================================
 
-``RhodeCode`` (formerly hg-app) is Pylons based repository management and 
-serving for mercurial_. It's similar to github or bitbucket, but it's suppose to run
-as standalone app, it's open source and focuses more on restricted access to repositories
-There's no default free access to RhodeCode You have to create an account in order
-to use the application. It's powered by vcs_ library that we created to handle
-many various version control systems.
+``RhodeCode`` (formerly hg-app) is Pylons framework based Mercurial repository 
+browser/management with build in push/pull server and full text search.
+It works on http/https, has build in permission/authentication(+ldap) features 
+It's similar to github or bitbucket, but it's suppose to run as standalone 
+hosted application, it's open source and focuses more on restricted access to 
+repositories. It's powered by vcs_ library that me and Lukasz Balcerzak created 
+to handle many various version control systems.
 
 RhodeCode uses `Semantic Versioning <http://semver.org/>`_
 
-
 RhodeCode demo
 --------------
 
 http://hg.python-works.com
 
-The default access is
+The default access is anonymous but You can login to administrative account
+using those credentials
 
 - username: demo
 - password: demo
@@ -25,14 +27,14 @@
 Source code
 -----------
 
-Source code is along with issue tracker is available at
+The most up to date sources can be obtained from my own RhodeCode instance
+https://rhodecode.org 
+
+Rarely updated source code and issue tracker is available at bitbcuket
 http://bitbucket.org/marcinkuzminski/rhodecode
 
-Also a source codes can be obtained from demo rhodecode instance
-http://hg.python-works.com/rhodecode/summary
-
-Instalation
------------
+Installation
+------------
 
  Please visit http://packages.python.org/RhodeCode/installation.html
 
@@ -40,41 +42,49 @@
 Features
 --------
 
-- Has it's own middleware to handle mercurial_ protocol request. Each request 
-  can be logged and authenticated. Runs on threads unlikely to hgweb You can 
-  make multiple pulls/pushes simultaneous. Supports http/https
-- Full permissions and authentication per project private/read/write/admin. 
-  One account for web interface and mercurial_ push/pull/clone.
+- Has it's own middleware to handle mercurial_ protocol request. 
+  Each request can be logged and authenticated. Runs on threads unlikely to 
+  hgweb. You can make multiple pulls/pushes simultaneous. Supports http/https 
+  and ldap
+- Full permissions (private/read/write/admin) and authentication per project. 
+  One account for web interface and mercurial_ push/pull/clone operations.
 - Mako templates let's you customize look and feel of application.
 - Beautiful diffs, annotations and source codes all colored by pygments.
 - Mercurial_ branch graph and yui-flot powered graphs with zooming and statistics
-- Admin interface with user/permission management. User activity journal logs
-  pulls, pushes, forks,registrations. Possible to disable built in hooks
+- Admin interface with user/permission management. Admin activity journal, logs
+  pulls, pushes, forks, registrations and other actions made by all users.
 - Server side forks, it's possible to fork a project and hack it free without
-  breaking the main.   
-- Full text search on source codes, search on file names. All powered by whoosh
-  and build in indexing daemons
+  breaking the main repository.
+- Full text search powered by Whoosh on source codes, and file names.
+  Build in indexing daemons, with optional incremental index build
   (no external search servers required all in one application)
-- Rss / atom feeds, gravatar support, download sources as zip/tarballs  
+- Setup project descriptions and info inside built in db for easy, non 
+  file-system operations
+- Inteligent cache with invalidation after push or project change, provides high 
+  performance and always up to date data.    
+- Rss / atom feeds, gravatar support, download sources as zip/tar/gz
 - Async tasks for speed and performance using celery_ (works without them too)  
 - Backup scripts can do backup of whole app and send it over scp to desired 
-  location
-- Setup project descriptions and info inside built in db for easy, non 
-  file-system operations
-- Added cache with invalidation on push/repo management for high performance and
-  always up to date data. 
-- Based on pylons 1.0 / sqlalchemy 0.6 / sqlite
+  location 
+- Based on pylons / sqlalchemy / sqlite / whoosh / vcs
 
 
-Incoming
---------
+.. include:: ./docs/screenshots.rst
+    
+    
+Incoming / Plans
+----------------
 
+- project grouping
+- User groups/teams
 - code review (probably based on hg-review)
-- full git_ support, with push/pull server
+- full git_ support, with push/pull server (currently in beta tests)
+- redmine integration
+- public accessible activity feeds
 - commit based build in wiki system
 - clone points and cloning from remote repositories into rhodecode 
   (git_ and mercurial_)
-- some cache optimizations
+- more statistics and graph (global annotation + some more statistics)
 - other cools stuff that i can figure out (or You can help me figure out)
 
 License
@@ -83,8 +93,18 @@
 ``rhodecode`` is released under GPL_ license.
 
 
-Documentation
--------------
+Mailing group Q&A
+-----------------
+
+join the `Google group <http://groups.google.com/group/rhodecode>`_
+
+open an issue at `issue tracker <http://bitbucket.org/marcinkuzminski/rhodecode/issues>`_
+
+join #rhodecode on FreeNode (irc.freenode.net)
+or use http://webchat.freenode.net/?channels=rhodecode for web access to irc.
+
+Online documentation
+--------------------
 
  Online documentation for current version is available at
  http://packages.python.org/RhodeCode/.
@@ -92,13 +112,3 @@
 
    make html
 
-.. _virtualenv: http://pypi.python.org/pypi/virtualenv
-.. _python: http://www.python.org/
-.. _django: http://www.djangoproject.com/
-.. _mercurial: http://mercurial.selenic.com/
-.. _subversion: http://subversion.tigris.org/
-.. _git: http://git-scm.com/
-.. _celery: http://celeryproject.org/
-.. _Sphinx: http://sphinx.pocoo.org/
-.. _GPL: http://www.gnu.org/licenses/gpl.html
-.. _vcs: http://pypi.python.org/pypi/vcs
\ No newline at end of file
--- a/celeryconfig.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-# List of modules to import when celery starts.
-import sys
-import os
-import ConfigParser
-root = os.getcwd()
-
-PYLONS_CONFIG_NAME = 'production.ini'
-
-sys.path.append(root)
-config = ConfigParser.ConfigParser({'here':root})
-config.read('%s/%s' % (root, PYLONS_CONFIG_NAME))
-PYLONS_CONFIG = config
-
-CELERY_IMPORTS = ("rhodecode.lib.celerylib.tasks",)
-
-## Result store settings.
-CELERY_RESULT_BACKEND = "database"
-CELERY_RESULT_DBURI = dict(config.items('app:main'))['sqlalchemy.db1.url']
-CELERY_RESULT_SERIALIZER = 'json'
-
-
-BROKER_CONNECTION_MAX_RETRIES = 30
-
-## Broker settings.
-BROKER_HOST = "localhost"
-BROKER_PORT = 5672
-BROKER_VHOST = "rabbitmqhost"
-BROKER_USER = "rabbitmq"
-BROKER_PASSWORD = "qweqwe"
-
-## Worker settings
-## If you're doing mostly I/O you can have more processes,
-## but if mostly spending CPU, try to keep it close to the
-## number of CPUs on your machine. If not set, the number of CPUs/cores
-## available will be used.
-CELERYD_CONCURRENCY = 2
-# CELERYD_LOG_FILE = "celeryd.log"
-CELERYD_LOG_LEVEL = "DEBUG"
-CELERYD_MAX_TASKS_PER_CHILD = 3
-
-#Tasks will never be sent to the queue, but executed locally instead.
-CELERY_ALWAYS_EAGER = False
-if PYLONS_CONFIG_NAME == 'test.ini':
-    #auto eager for tests
-    CELERY_ALWAYS_EAGER = True
-
-#===============================================================================
-# EMAIL SETTINGS
-#===============================================================================
-pylons_email_config = dict(config.items('DEFAULT'))
-
-CELERY_SEND_TASK_ERROR_EMAILS = True
-
-#List of (name, email_address) tuples for the admins that should receive error e-mails.
-ADMINS = [('Administrator', pylons_email_config.get('email_to'))]
-
-#The e-mail address this worker sends e-mails from. Default is "celery@localhost".
-SERVER_EMAIL = pylons_email_config.get('error_email_from')
-
-#The mail server to use. Default is "localhost".
-MAIL_HOST = pylons_email_config.get('smtp_server')
-
-#Username (if required) to log on to the mail server with.
-MAIL_HOST_USER = pylons_email_config.get('smtp_username')
-
-#Password (if required) to log on to the mail server with.
-MAIL_HOST_PASSWORD = pylons_email_config.get('smtp_password')
-
-MAIL_PORT = pylons_email_config.get('smtp_port')
-
-
-#===============================================================================
-# INSTRUCTIONS FOR RABBITMQ
-#===============================================================================
-# rabbitmqctl add_user rabbitmq qweqwe
-# rabbitmqctl add_vhost rabbitmqhost
-# rabbitmqctl set_permissions -p rabbitmqhost rabbitmq ".*" ".*" ".*"
--- a/development.ini	Thu Nov 18 21:35:52 2010 +0100
+++ b/development.ini	Sat Dec 18 14:45:58 2010 +0100
@@ -1,6 +1,6 @@
 ################################################################################
 ################################################################################
-# rhodecode - Pylons environment configuration                                 #
+# RhodeCode - Pylons environment configuration                                 #
 #                                                                              # 
 # The %(here)s variable will be replaced with the parent directory of this file#
 ################################################################################
@@ -9,8 +9,8 @@
 debug = true
 ################################################################################
 ## Uncomment and replace with the address which should receive                ## 
-## any error reports after application crash								  ##
-## Additionally those settings will be used by rhodecode mailing system       ##
+## any error reports after application crash                                  ##
+## Additionally those settings will be used by RhodeCode mailing system       ##
 ################################################################################
 #email_to = admin@localhost
 #error_email_from = paste_error@localhost
@@ -19,22 +19,23 @@
 
 #smtp_server = mail.server.com
 #smtp_username = 
-#smtp_password =
+#smtp_password = 
 #smtp_port = 
-#smtp_use_tls = 
+#smtp_use_tls = false
+#smtp_use_ssl = true
 
 [server:main]
 ##nr of threads to spawn
 threadpool_workers = 5
 
-##max request before
+##max request before thread respawn
 threadpool_max_requests = 6
 
 ##option to use threads of process
 use_threadpool = false
 
 use = egg:Paste#http
-host = 127.0.0.1
+host = 0.0.0.0
 port = 5000
 
 [app:main]
@@ -43,6 +44,35 @@
 static_files = true
 lang=en
 cache_dir = %(here)s/data
+index_dir = %(here)s/data/index
+cut_off_limit = 256000
+
+####################################
+###        CELERY CONFIG        ####
+####################################
+use_celery = false
+broker.host = localhost
+broker.vhost = rabbitmqhost
+broker.port = 5672
+broker.user = rabbitmq
+broker.password = qweqwe
+
+celery.imports = rhodecode.lib.celerylib.tasks
+
+celery.result.backend = amqp
+celery.result.dburi = amqp://
+celery.result.serialier = json
+
+#celery.send.task.error.emails = true
+#celery.amqp.task.result.expires = 18000
+
+celeryd.concurrency = 2
+#celeryd.log.file = celeryd.log
+celeryd.log.level = debug
+celeryd.max.tasks.per.child = 3
+
+#tasks will never be sent to the queue, but executed locally instead.
+celery.always.eager = false
 
 ####################################
 ###         BEAKER CACHE        ####
@@ -60,9 +90,8 @@
 beaker.cache.long_term.type=memory
 beaker.cache.long_term.expire=36000
 
-
 beaker.cache.sql_cache_short.type=memory
-beaker.cache.sql_cache_short.expire=5
+beaker.cache.sql_cache_short.expire=10
 
 beaker.cache.sql_cache_med.type=memory
 beaker.cache.sql_cache_med.expire=360
@@ -74,7 +103,7 @@
 ###       BEAKER SESSION        ####
 ####################################
 ## Type of storage used for the session, current types are 
-## "dbm", "file", "memcached", "database", and "memory". 
+## dbm, file, memcached, database, and memory. 
 ## The storage uses the Container API 
 ##that is also used by the cache system.
 beaker.session.type = file
@@ -116,7 +145,7 @@
 ### LOGGING CONFIGURATION   ####
 ################################
 [loggers]
-keys = root, routes, rhodecode, sqlalchemy
+keys = root, routes, rhodecode, sqlalchemy,beaker,templates
 
 [handlers]
 keys = console
@@ -136,6 +165,19 @@
 handlers = console
 qualname = routes.middleware
 # "level = DEBUG" logs the route matched and routing variables.
+propagate = 0
+
+[logger_beaker]
+level = ERROR
+handlers = console
+qualname = beaker.container
+propagate = 0
+
+[logger_templates]
+level = INFO
+handlers = console
+qualname = pylons.templating
+propagate = 0
 
 [logger_rhodecode]
 level = DEBUG
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/api/index.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,10 @@
+.. _api:
+
+API Reference
+=============
+
+.. toctree::
+   :maxdepth: 3
+
+   models
+    
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/api/models.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,19 @@
+.. _models:
+
+The :mod:`models` Module
+========================
+
+.. automodule:: rhodecode.model
+   :members:
+   
+.. automodule:: rhodecode.model.permission
+   :members:
+  
+.. automodule:: rhodecode.model.repo
+   :members:   
+
+.. automodule:: rhodecode.model.scm
+   :members:
+
+.. automodule:: rhodecode.model.user
+   :members:      
--- a/docs/changelog.rst	Thu Nov 18 21:35:52 2010 +0100
+++ b/docs/changelog.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -3,22 +3,88 @@
 Changelog
 =========
 
-1.0.2 (**2010-11-XX**)
+1.1.0 (**2010-12-18**)
 ----------------------
 
+:status: in-progress
+:branch: beta
+
+news
+++++
+
+- rewrite of internals for vcs >=0.1.10
+- uses mercurial 1.7 with dotencode disabled for maintaining compatibility 
+  with older clients
+- anonymous access, authentication via ldap
+- performance upgrade for cached repos list - each repository has it's own 
+  cache that's invalidated when needed.
+- performance upgrades on repositories with large amount of commits (20K+)
+- main page quick filter for filtering repositories
+- user dashboards with ability to follow chosen repositories actions
+- sends email to admin on new user registration
+- added cache/statistics reset options into repository settings
+- more detailed action logger (based on hooks) with pushed changesets lists
+  and options to disable those hooks from admin panel
+- introduced new enhanced changelog for merges that shows more accurate results
+- new improved and faster code stats (based on pygments lexers mapping tables, 
+  showing up to 10 trending sources for each repository. Additionally stats
+  can be disabled in repository settings.
+- gui optimizations, fixed application width to 1024px
+- added cut off (for large files/changesets) limit into config files
+- whoosh, celeryd, upgrade moved to paster command
+- other than sqlite database backends can be used
+
+fixes
++++++
+
+- fixes #61 forked repo was showing only after cache expired
+- fixes #76 no confirmation on user deletes
+- fixes #66 Name field misspelled
+- fixes #72 block user removal when he owns repositories
+- fixes #69 added password confirmation fields
+- fixes #87 RhodeCode crashes occasionally on updating repository owner
+- fixes #82 broken annotations on files with more than 1 blank line at the end
+- a lot of fixes and tweaks for file browser
+- fixed detached session issues
+- fixed when user had no repos he would see all repos listed in my account
+- fixed ui() instance bug when global hgrc settings was loaded for server 
+  instance and all hgrc options were merged with our db ui() object
+- numerous small bugfixes
+ 
+(special thanks for TkSoh for detailed feedback)
+
+
+1.0.2 (**2010-11-12**)
+----------------------
+
+news
+++++
+
+- tested under python2.7
+- bumped sqlalchemy and celery versions
+
+fixes
++++++
+
 - fixed #59 missing graph.js
 - fixed repo_size crash when repository had broken symlinks
 - fixed python2.5 crashes.
-- tested under python2.7
-- bumped sqlalcehmy and celery versions
+
 
 1.0.1 (**2010-11-10**)
 ----------------------
 
+news
+++++
+
+- small css updated
+
+fixes
++++++
+
 - fixed #53 python2.5 incompatible enumerate calls
 - fixed #52 disable mercurial extension for web
 - fixed #51 deleting repositories don't delete it's dependent objects
-- small css updated
 
 
 1.0.0 (**2010-11-02**)
@@ -52,3 +118,4 @@
 - Disabled dirsize in file browser, it's causing nasty bug when dir renames 
   occure. After vcs is fixed it'll be put back again.
 - templating/css rewrites, optimized css.
+
--- a/docs/conf.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/docs/conf.py	Sat Dec 18 14:45:58 2010 +0100
@@ -16,7 +16,7 @@
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath('..'))
 
 # -- General configuration -----------------------------------------------------
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/contributing.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,9 @@
+.. _contributing:
+
+Contributing in RhodeCode
+=========================
+
+If You would like to contribute to RhodeCode, please contact me, any help is
+greatly appreciated.
+
+Thank You.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/enable_git.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,21 @@
+.. _enable_git:
+
+Enabling GIT support (beta)
+===========================
+
+
+Git support in RhodeCode 1.1 was disabled due to some instability issues, but
+If You would like to test it fell free to re-enable it. To enable GIT just
+uncomment git line in rhodecode/__init__.py file
+
+.. code-block:: python
+ 
+   BACKENDS = {
+       'hg': 'Mercurial repository',
+       #'git': 'Git repository',
+   }
+
+.. note::
+   Please note that it's not fully stable and it might crash (that's why it 
+   was disabled), so be careful about enabling git support. Don't use it in 
+   production !
\ No newline at end of file
Binary file docs/images/screenshot1_main_page.png has changed
Binary file docs/images/screenshot2_summary_page.png has changed
Binary file docs/images/screenshot3_changelog_page.png has changed
--- a/docs/index.rst	Thu Nov 18 21:35:52 2010 +0100
+++ b/docs/index.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -1,107 +1,43 @@
 .. _index:
 
-Welcome to RhodeCode (RhodiumCode) documentation!
-=================================================
-
-``RhodeCode`` (formerly hg-app) is Pylons based repository management and 
-serving for mercurial_. It's similar to github or bitbucket, but it's suppose to run
-as standalone app, it's open source and focuses more on restricted access to repositories
-There's no default free access to RhodeCode You have to create an account in order
-to use the application. It's powered by vcs_ library that we created to handle
-many various version control systems.
-
-RhodeCode uses `Semantic Versioning <http://semver.org/>`_
-
-
-RhodeCode demo
---------------
-
-http://hg.python-works.com
-
-The default access is
-
-- username: demo
-- password: demo
-
-Source code
------------
-
-Source code is along with issue tracker is available at
-http://bitbucket.org/marcinkuzminski/rhodecode
-
-Also a source codes can be obtained from demo rhodecode instance
-http://hg.python-works.com/rhodecode/summary
-
-Features
---------
-
-- Has it's own middleware to handle mercurial_ protocol request. Each request 
-  can be logged and authenticated. Runs on threads unlikely to hgweb You can 
-  make multiple pulls/pushes simultaneous. Supports http/https
-- Full permissions and authentication per project private/read/write/admin. 
-  One account for web interface and mercurial_ push/pull/clone.
-- Mako templates let's you customize look and feel of application.
-- Beautiful diffs, annotations and source codes all colored by pygments.
-- Mercurial_ branch graph and yui-flot powered graphs with zooming and statistics
-- Admin interface with user/permission management. User activity journal logs
-  pulls, pushes, forks,registrations. Possible to disable built in hooks
-- Server side forks, it's possible to fork a project and hack it free without
-  breaking the main.   
-- Full text search on source codes, search on file names. All powered by whoosh
-  and build in indexing daemons
-  (no external search servers required all in one application)
-- Rss / atom feeds, gravatar support, download sources as zip/tarballs  
-- Async tasks for speed and performance using celery_ (works without them too)  
-- Backup scripts can do backup of whole app and send it over scp to desired 
-  location
-- Setup project descriptions and info inside built in db for easy, non 
-  file-system operations
-- Added cache with invalidation on push/repo management for high performance and
-  always up to date data. 
-- Based on pylons 1.0 / sqlalchemy 0.6 / sqlite
-
-
-.. figure::  images/screenshot1_main_page.png
-   :align:   left
-
-   Main page of RhodeCode
-
-.. figure::  images/screenshot2_summary_page.png
-   :align:   left
-
-   Summary page
-
-
-Incoming
---------
-
-- code review (probably based on hg-review)
-- full git_ support, with push/pull server
-- commit based build in wiki system
-- clone points and cloning from remote repositories into rhodecode 
-  (git_ and mercurial_)
-- more statistics and graph (global annotation + some more statistics)
-- user customized activity dashboards
-- some cache optimizations
-- other cools stuff that i can figure out (or You can help me figure out)
-
-License
--------
-
-``rhodecode`` is released under GPL_ license.
-
+.. include:: ./../README.rst
 
 Documentation
 -------------
 
+**Installation:**
+
 .. toctree::
    :maxdepth: 1
 
    installation
+   setup
    upgrade
-   setup
+   
+**Usage**
+
+.. toctree::
+   :maxdepth: 1
+
+   enable_git
+   statistics
+   
+**Develop**
+
+.. toctree::
+   :maxdepth: 1
+   
+   contributing
    changelog
 
+**API**
+
+.. toctree::
+   :maxdepth: 2
+
+   api/index
+   
+
 Other topics
 ------------
 
--- a/docs/installation.rst	Thu Nov 18 21:35:52 2010 +0100
+++ b/docs/installation.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -5,31 +5,20 @@
 
 ``RhodeCode`` is written entirely in Python, but in order to use it's full
 potential there are some third-party requirements. When RhodeCode is used 
-together with celery_ You have to install some kind of message broker,
+together with celery You have to install some kind of message broker,
 recommended one is rabbitmq_ to make the async tasks work.
 
 Of course RhodeCode works in sync mode also, then You don't have to install
 any third party apps. Celery_ will give You large speed improvement when using
-many big repositories. If You plan to use it for 5 or 10 small repositories, it
+many big repositories. If You plan to use it for 7 or 10 small repositories, it
 will work just fine without celery running.
    
-After You decide to Run it with celery make sure You run celeryd and
-message broker together with the application.   
-
-Requirements for Celery
------------------------
-
-**Message Broker** 
-
-- preferred is `RabbitMq <http://www.rabbitmq.com/>`_
-- possible other is `Redis <http://code.google.com/p/redis/>`_
-
-For installation instructions You can visit: 
-http://ask.github.com/celery/getting-started/index.html
-It's very nice tutorial how to start celery_ with rabbitmq_
+After You decide to Run it with celery make sure You run celeryd using paster
+and message broker together with the application.   
 
 Install from Cheese Shop
 ------------------------
+Rhodecode requires python 2.x greater than version 2.5
 
 Easiest way to install ``rhodecode`` is to run::
 
@@ -42,7 +31,7 @@
 If you prefer to install manually simply grab latest release from
 http://pypi.python.org/pypi/rhodecode, decompres archive and run::
 
- python setup.py install
+   python setup.py install
 
 
 Step by step installation example
@@ -62,7 +51,7 @@
 
 ::
 
-  source /var/www/rhodecode-venv/bin/activate
+  source activate /var/www/rhodecode-venv/bin/activate
      
 - Make a folder for rhodecode somewhere on the filesystem for example 
 
@@ -80,8 +69,28 @@
 - this will install rhodecode together with pylons
   and all other required python libraries
 
+Requirements for Celery (optional)
+----------------------------------
+
+.. note::
+   Installing message broker and using celery is optional, RhodeCode will
+   work without them perfectly fine.
+
+
+**Message Broker** 
+
+- preferred is `RabbitMq <http://www.rabbitmq.com/>`_
+- possible other is `Redis <http://code.google.com/p/redis/>`_
+
+For installation instructions You can visit: 
+http://ask.github.com/celery/getting-started/index.html
+It's very nice tutorial how to start celery_ with rabbitmq_
+
 
 You can now proceed to :ref:`setup`
+-----------------------------------
+
+
 
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv  
 .. _python: http://www.python.org/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/screenshots.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,13 @@
+.. _screenshots:
+
+.. figure::  images/screenshot1_main_page.png
+
+   Main page of RhodeCode
+
+.. figure::  images/screenshot2_summary_page.png
+
+   Summary page
+   
+.. figure::  images/screenshot3_changelog_page.png
+
+   Changelog with DAG graph
\ No newline at end of file
--- a/docs/setup.rst	Thu Nov 18 21:35:52 2010 +0100
+++ b/docs/setup.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -7,13 +7,20 @@
 Setting up the application
 --------------------------
 
+First You'll ned to create RhodeCode config file. Run the following command 
+to do this
+
 ::
  
  paster make-config RhodeCode production.ini
 
 - This will create `production.ini` config inside the directory
-  this config contain various settings for rhodecode, e.g port, email settings
-  static files, cache and logging.
+  this config contains various settings for RhodeCode, e.g proxy port, 
+  email settings, usage of static files, cache, celery settings and logging.
+
+
+
+Next we need to create the database.
 
 ::
 
@@ -24,55 +31,136 @@
   existing ones. RhodeCode will simply add all new found repositories to 
   it's database. Also make sure You specify correct path to repositories.
 - Remember that the given path for mercurial_ repositories must be write 
-  accessible for the application. It's very important since RhodeCode web interface
-  will work even without such an access but, when trying to do a push it'll 
-  eventually fail with permission denied errors. 
-- Run 
+  accessible for the application. It's very important since RhodeCode web 
+  interface will work even without such an access but, when trying to do a 
+  push it'll eventually fail with permission denied errors. 
+
+You are ready to use rhodecode, to run it simply execute
 
 ::
  
  paster serve production.ini
  
-- This command runs the rhodecode server the app should be available at the 
+- This command runs the RhodeCode server the app should be available at the 
   127.0.0.1:5000. This ip and port is configurable via the production.ini 
-  file  created in previous step
+  file created in previous step
 - Use admin account you created to login.
 - Default permissions on each repository is read, and owner is admin. So 
-  remember to update these if needed.
+  remember to update these if needed. In the admin panel You can toggle ldap,
+  anonymous, permissions settings. As well as edit more advanced options on 
+  users and repositories
   
-Note
-----
+    
+Setting up Whoosh full text search
+----------------------------------
 
-RhodeCode when running without the celery it's running all it's task in sync
-mode, for first few times when visiting summary page You can notice few
-slow downs, this is due the statistics building it's cache. After all changesets
-are parsed it'll take the stats from cache and run much faster. Each summary
-page display parse at most 250 changesets in order to not stress the cpu, so
-the full stats are going to be loaded after total_number_of_changesets/250
-summary page visits.
+Index for whoosh can be build starting from version 1.1 using paster command
+passing repo locations to index, as well as Your config file that stores
+whoosh index files locations. There is possible to pass `-f` to the options
+to enable full index rebuild. Without that indexing will run always in in
+incremental mode.
+
+::
 
+ paster make-index production.ini --repo-location=<location for repos> 
 
-    
-Setting up Whoosh
------------------
+for full index rebuild You can use
+
+::
+
+ paster make-index production.ini -f --repo-location=<location for repos>
 
 - For full text search You can either put crontab entry for
 
+This command can be run even from crontab in order to do periodical 
+index builds and keep Your index always up to date. An example entry might 
+look like this
+
 ::
  
- python /var/www/rhodecode/<rhodecode_installation_path>/lib/indexers/daemon.py incremental <put_here_path_to_repos>
+ /path/to/python/bin/paster /path/to/rhodecode/production.ini --repo-location=<location for repos> 
   
-When using incremental mode whoosh will check last modification date of each file
-and add it to reindex if newer file is available. Also indexing daemon checks
-for removed files and removes them from index. Sometime You might want to rebuild
-index from scratch, in admin panel You can check `build from scratch` flag
-and in standalone daemon You can pass `full` instead on incremental to build
-remove previous index and build new one.
+When using incremental(default) mode whoosh will check last modification date 
+of each file and add it to reindex if newer file is available. Also indexing 
+daemon checks for removed files and removes them from index. 
+
+Sometime You might want to rebuild index from scratch. You can do that using 
+the `-f` flag passed to paster command or, in admin panel You can check 
+`build from scratch` flag.
+
+
+Setting up LDAP support
+-----------------------
+
+RhodeCode starting from version 1.1 supports ldap authentication. In order
+to use ldap, You have to install python-ldap package. This package is available
+via pypi, so You can install it by running
+
+::
+
+ easy_install python-ldap
+ 
+::
+
+ pip install python-ldap
+
+.. note::
+   python-ldap requires some certain libs on Your system, so before installing 
+   it check that You have at least `openldap`, and `sasl` libraries.
+
+ldap settings are located in admin->ldap section,
+
+Here's a typical ldap setup::
+
+ Enable ldap  = checked                 #controls if ldap access is enabled
+ Host         = host.domain.org         #actual ldap server to connect
+ Port         = 389 or 689 for ldaps    #ldap server ports
+ Enable LDAPS = unchecked               #enable disable ldaps
+ Account      = <account>               #access for ldap server(if required)
+ Password     = <password>              #password for ldap server(if required)
+ Base DN      = uid=%(user)s,CN=users,DC=host,DC=domain,DC=org
+ 
+
+`Account` and `Password` are optional, and used for two-phase ldap 
+authentication so those are credentials to access Your ldap, if it doesn't 
+support anonymous search/user lookups. 
+
+Base DN must have %(user)s template inside, it's a placer where Your uid used
+to login would go, it allows admins to specify not standard schema for uid 
+variable
+
+If all data are entered correctly, and `python-ldap` is properly installed
+Users should be granted to access RhodeCode wit ldap accounts. When 
+logging at the first time an special ldap account is created inside RhodeCode, 
+so You can control over permissions even on ldap users. If such user exists 
+already in RhodeCode database ldap user with the same username would be not 
+able to access RhodeCode.
+
+If You have problems with ldap access and believe You entered correct 
+information check out the RhodeCode logs,any error messages sent from 
+ldap will be saved there.
+
+
+
+Setting Up Celery
+-----------------
+
+Since version 1.1 celery is configured by the rhodecode ini configuration files
+simply set use_celery=true in the ini file then add / change the configuration 
+variables inside the ini file.
+
+Remember that the ini files uses format with '.' not with '_' like celery
+so for example setting `BROKER_HOST` in celery means setting `broker.host` in
+the config file.
+
+In order to make start using celery run::
+ paster celeryd <configfile.ini>
+
 
 Nginx virtual host example
 --------------------------
 
-Sample config for nginx::
+Sample config for nginx using proxy::
 
  server {
     listen          80;
@@ -122,6 +210,16 @@
 
 To not have the statics served by the application. And improve speed.
 
+Apache reverse proxy
+--------------------
+Tutorial can be found here
+http://wiki.pylonshq.com/display/pylonscookbook/Apache+as+a+reverse+proxy+for+Pylons
+
+
+Apache's example FCGI config
+----------------------------
+
+TODO !
 
 Other configuration files
 -------------------------
@@ -132,6 +230,29 @@
 and also an celeryconfig file can be use from here:
 http://hg.python-works.com/rhodecode/files/tip/celeryconfig.py
 
+Troubleshooting
+---------------
+
+- missing static files ?
+
+ - make sure either to set the `static_files = true` in the .ini file or
+   double check the root path for Your http setup. It should point to 
+   for example:
+   /home/my-virtual-python/lib/python2.6/site-packages/rhodecode/public
+   
+- can't install celery/rabbitmq
+
+ - don't worry RhodeCode works without them too. No extra setup required
+
+- long lasting push timeouts ?
+
+ - make sure You set a longer timeouts in Your proxy/fcgi settings, timeouts
+   are caused by https server and not RhodeCode
+
+- large pushes timeouts ?
+ 
+ - make sure You set a proper max_body_size for the http server
+
 
 
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/statistics.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,32 @@
+.. _statistics:
+
+
+Statistics
+==========
+
+RhodeCode statistics system is heavy on resources, so in order to keep a 
+balance between the usability and performance statistics are cached inside db
+and are gathered incrementally, this is how RhodeCode does this:
+
+With Celery disabled
+++++++++++++++++++++
+
+- on each first visit on summary page a set of 250 commits are parsed and
+  updates statistics cache
+- this happens on each single visit of statistics page until all commits are
+  fetched. Statistics are kept cached until some more commits are added to
+  repository, in such case RhodeCode will fetch only the ones added and will
+  update it's cache.
+
+
+With Celery enabled
++++++++++++++++++++
+
+- on first visit on summary page RhodeCode will create task that will execute
+  on celery workers, that will gather all stats until all commits are parsed,
+  each task will parse 250 commits, and run next task to parse next 250 
+  commits, until all are parsed.
+
+.. note::
+   In any time You can disable statistics on each repository in repository edit
+   form in admin panel, just uncheck the statistics checkbox.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/theme/nature/layout.html	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,14 @@
+{% extends "basic/layout.html" %}
+
+{% block sidebarlogo %}
+<h3>Support my development effort.</h3>
+<div style="text-align:center">
+	<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
+	<input type="hidden" name="cmd" value="_s-xclick">
+	<input type="hidden" name="hosted_button_id" value="8U2LLRPLBKWDU">
+	<input style="border:0px !important" type="image" src="https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif" 
+	border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+	<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
+	</form>
+</div>
+{% endblock %}}
--- a/docs/upgrade.rst	Thu Nov 18 21:35:52 2010 +0100
+++ b/docs/upgrade.rst	Sat Dec 18 14:45:58 2010 +0100
@@ -22,7 +22,26 @@
  paster make-config RhodeCode production.ini
  
 This will display any changes made from new version of RhodeCode To your
-current config. And tries to do an automerge.
+current config. And tries to do an automerge. It's always better to do a backup
+of config file and recheck the content after merge.
+
+It's also good to rebuild the whoosh index since after upgrading the whoosh 
+version there could be introduced incompatible index changes.
+
+
+The last step is to upgrade the database. To do this simply run
+
+::
+
+ paster upgrade-db production.ini
+ 
+This will upgrade schema, as well as update some default on the database,
+always recheck the settings of the application, if there are no new options
+that need to be set.
+
+.. note::
+   Always perform a database backup before doing upgrade.
+
 
 
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv  
--- a/production.ini	Thu Nov 18 21:35:52 2010 +0100
+++ b/production.ini	Sat Dec 18 14:45:58 2010 +0100
@@ -22,6 +22,7 @@
 #smtp_password = 
 #smtp_port = 
 #smtp_use_tls = false
+#smtp_use_ssl = true
 
 [server:main]
 ##nr of threads to spawn
@@ -43,6 +44,35 @@
 static_files = false
 lang=en
 cache_dir = %(here)s/data
+index_dir = %(here)s/data/index
+cut_off_limit = 256000
+
+####################################
+###        CELERY CONFIG        ####
+####################################
+use_celery = false
+broker.host = localhost
+broker.vhost = rabbitmqhost
+broker.port = 5672
+broker.user = rabbitmq
+broker.password = qweqwe
+
+celery.imports = rhodecode.lib.celerylib.tasks
+
+celery.result.backend = amqp
+celery.result.dburi = amqp://
+celery.result.serialier = json
+
+#celery.send.task.error.emails = true
+#celery.amqp.task.result.expires = 18000
+
+celeryd.concurrency = 2
+#celeryd.log.file = celeryd.log
+celeryd.log.level = debug
+celeryd.max.tasks.per.child = 3
+
+#tasks will never be sent to the queue, but executed locally instead.
+celery.always.eager = false
 
 ####################################
 ###         BEAKER CACHE        ####
@@ -136,6 +166,7 @@
 handlers = console
 qualname = routes.middleware
 # "level = DEBUG" logs the route matched and routing variables.
+propagate = 0
 
 [logger_rhodecode]
 level = DEBUG
--- a/rhodecode/__init__.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,16 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# RhodeCode, a web based repository management based on pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# 
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.__init__
+    ~~~~~~~~~~~~~~~~~~
+
+    RhodeCode, a web based repository management based on pylons
+    versioning implementation: http://semver.org/
+
+    :created_on: Apr 9, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,19 +25,28 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on April 9, 2010
-RhodeCode, a web based repository management based on pylons
-versioning implementation: http://semver.org/
-@author: marcink
-"""
+
+
+VERSION = (1, 1, 0)
+__version__ = '.'.join((str(each) for each in VERSION[:4]))
+__dbversion__ = 2 #defines current db version for migrations
 
-VERSION = (1, 0, 2,)
+try:
+    from rhodecode.lib.utils import get_current_revision
+    _rev = get_current_revision()
+except ImportError:
+    #this is needed when doing some setup.py operations
+    _rev = False
 
-__version__ = '.'.join((str(each) for each in VERSION[:4]))
+if len(VERSION) > 3 and _rev:
+    __version__ += ' [rev:%s]' % _rev[0]
 
 def get_version():
-    """
-    Returns shorter version (digit parts only) as string.
-    """
+    """Returns shorter version (digit parts only) as string."""
+
     return '.'.join((str(each) for each in VERSION[:3]))
+
+BACKENDS = {
+    'hg': 'Mercurial repository',
+   #'git': 'Git repository',
+}
--- a/rhodecode/config/deployment.ini_tmpl	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/config/deployment.ini_tmpl	Sat Dec 18 14:45:58 2010 +0100
@@ -1,6 +1,6 @@
 ################################################################################
 ################################################################################
-# rhodecode - Pylons environment configuration                                 #
+# RhodeCode - Pylons environment configuration                                 #
 #                                                                              # 
 # The %(here)s variable will be replaced with the parent directory of this file#
 ################################################################################
@@ -10,7 +10,7 @@
 ################################################################################
 ## Uncomment and replace with the address which should receive                ## 
 ## any error reports after application crash                                  ##
-## Additionally those settings will be used by rhodecode mailing system       ##
+## Additionally those settings will be used by RhodeCode mailing system       ##
 ################################################################################
 #email_to = admin@localhost
 #error_email_from = paste_error@localhost
@@ -22,13 +22,14 @@
 #smtp_password = 
 #smtp_port = 
 #smtp_use_tls = false
+#smtp_use_ssl = true
 
 [server:main]
 ##nr of threads to spawn
 threadpool_workers = 5
 
 ##max request before thread respawn
-threadpool_max_requests = 2
+threadpool_max_requests = 10
 
 ##option to use threads of process
 use_threadpool = true
@@ -43,7 +44,36 @@
 static_files = true
 lang=en
 cache_dir = %(here)s/data
+index_dir = %(here)s/data/index
 app_instance_uuid = ${app_instance_uuid}
+cut_off_limit = 256000
+
+####################################
+###        CELERY CONFIG        ####
+####################################
+use_celery = false
+broker.host = localhost
+broker.vhost = rabbitmqhost
+broker.port = 5672
+broker.user = rabbitmq
+broker.password = qweqwe
+
+celery.imports = rhodecode.lib.celerylib.tasks
+
+celery.result.backend = amqp
+celery.result.dburi = amqp://
+celery.result.serialier = json
+
+#celery.send.task.error.emails = true
+#celery.amqp.task.result.expires = 18000
+
+celeryd.concurrency = 2
+#celeryd.log.file = celeryd.log
+celeryd.log.level = debug
+celeryd.max.tasks.per.child = 3
+
+#tasks will never be sent to the queue, but executed locally instead.
+celery.always.eager = false
 
 ####################################
 ###         BEAKER CACHE        ####
@@ -62,7 +92,7 @@
 beaker.cache.long_term.expire=36000
 
 beaker.cache.sql_cache_short.type=memory
-beaker.cache.sql_cache_short.expire=5
+beaker.cache.sql_cache_short.expire=10
 
 beaker.cache.sql_cache_med.type=memory
 beaker.cache.sql_cache_med.expire=360
@@ -136,6 +166,7 @@
 handlers = console
 qualname = routes.middleware
 # "level = DEBUG" logs the route matched and routing variables.
+propagate = 0
 
 [logger_rhodecode]
 level = DEBUG
--- a/rhodecode/config/environment.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/config/environment.py	Sat Dec 18 14:45:58 2010 +0100
@@ -6,7 +6,7 @@
 from rhodecode.lib.auth import set_available_permissions, set_base_path
 from rhodecode.lib.utils import repo2db_mapper, make_ui, set_rhodecode_config
 from rhodecode.model import init_model
-from rhodecode.model.hg_model import _get_repos_cached_initial
+from rhodecode.model.scm import ScmModel
 from sqlalchemy import engine_from_config
 import logging
 import os
@@ -20,7 +20,7 @@
     object
     """
     config = PylonsConfig()
-    
+
     # Pylons paths
     root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
     paths = dict(root=root,
@@ -34,11 +34,11 @@
     config['routes.map'] = make_map(config)
     config['pylons.app_globals'] = app_globals.Globals(config)
     config['pylons.h'] = rhodecode.lib.helpers
-    
+
     # Setup cache object as early as possible
     import pylons
     pylons.cache._push_object(config['pylons.app_globals'].cache)
-    
+
     # Create the Mako TemplateLookup, with the default auto-escaping
     config['pylons.app_globals'].mako_lookup = TemplateLookup(
         directories=paths['templates'],
@@ -52,9 +52,10 @@
     test = os.path.split(config['__file__'])[-1] == 'test.ini'
     if test:
         from rhodecode.lib.utils import create_test_env, create_test_index
-        create_test_env('/tmp', config)
-        create_test_index('/tmp/*', True)
-        
+        from rhodecode.tests import  TESTS_TMP_PATH
+        create_test_env(TESTS_TMP_PATH, config)
+        create_test_index(TESTS_TMP_PATH, True)
+
     #MULTIPLE DB configs
     # Setup the SQLAlchemy database engine
     if config['debug'] and not test:
@@ -68,12 +69,13 @@
     init_model(sa_engine_db1)
     #init baseui
     config['pylons.app_globals'].baseui = make_ui('db')
-    
-    repo2db_mapper(_get_repos_cached_initial(config['pylons.app_globals'], initial))
+
+    g = config['pylons.app_globals']
+    repo2db_mapper(ScmModel().repo_scan(g.paths[0][1], g.baseui))
     set_available_permissions(config)
     set_base_path(config)
     set_rhodecode_config(config)
     # CONFIGURATION OPTIONS HERE (note: all config options will override
     # any Pylons config options)
-    
+
     return config
--- a/rhodecode/config/middleware.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/config/middleware.py	Sat Dec 18 14:45:58 2010 +0100
@@ -8,8 +8,10 @@
 from pylons.wsgiapp import PylonsApp
 from routes.middleware import RoutesMiddleware
 from rhodecode.lib.middleware.simplehg import SimpleHg
+from rhodecode.lib.middleware.simplegit import SimpleGit
 from rhodecode.lib.middleware.https_fixup import HttpsFixup
 from rhodecode.config.environment import load_environment
+from paste.gzipper import make_gzip_middleware
 
 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
     """Create a Pylons WSGI application and return it
@@ -35,15 +37,16 @@
 
     # The Pylons WSGI app
     app = PylonsApp(config=config)
-    
+
     # Routing/Session/Cache Middleware
     app = RoutesMiddleware(app, config['routes.map'])
     app = SessionMiddleware(app, config)
-    
+
     # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
-    
+
     app = SimpleHg(app, config)
-    
+    app = SimpleGit(app, config)
+
     if asbool(full_stack):
         # Handle Python exceptions
         app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
@@ -54,10 +57,10 @@
             app = StatusCodeRedirect(app)
         else:
             app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
-    
+
     #enable https redirets based on HTTP_X_URL_SCHEME set by proxy
     app = HttpsFixup(app)
-    
+
     # Establish the Registry for this application
     app = RegistryManager(app)
 
@@ -65,7 +68,8 @@
         # Serve static files
         static_app = StaticURLParser(config['pylons.paths']['static_files'])
         app = Cascade([static_app, app])
-    
+        app = make_gzip_middleware(app, global_conf, compress_level=1)
+
     app.config = config
 
     return app
--- a/rhodecode/config/routing.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/config/routing.py	Sat Dec 18 14:45:58 2010 +0100
@@ -35,7 +35,7 @@
     #==========================================================================
 
     #MAIN PAGE
-    map.connect('hg_home', '/', controller='hg', action='index')
+    map.connect('home', '/', controller='home', action='index')
     map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
     map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
     #ADMIN REPOSITORY REST ROUTES
@@ -73,13 +73,27 @@
         m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
              action="delete_perm_user", conditions=dict(method=["DELETE"],
                                                         function=check_repo))
-
+        #settings actions
+        m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
+             action="repo_stats", conditions=dict(method=["DELETE"],
+                                                        function=check_repo))
+        m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
+             action="repo_cache", conditions=dict(method=["DELETE"],
+                                                        function=check_repo))
     #ADMIN USER REST ROUTES
     map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
 
     #ADMIN PERMISSIONS REST ROUTES
     map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
 
+
+    ##ADMIN LDAP SETTINGS
+    map.connect('ldap_settings', '/_admin/ldap', controller='admin/ldap_settings',
+                action='ldap_settings', conditions=dict(method=["POST"]))
+    map.connect('ldap_home', '/_admin/ldap', controller='admin/ldap_settings',)
+
+
+
     #ADMIN SETTINGS REST ROUTES
     with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
         m.connect("admin_settings", "/settings",
@@ -116,6 +130,14 @@
         m.connect('admin_home', '', action='index')#main page
         m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
                   action='add_repo')
+
+
+    #USER JOURNAL
+    map.connect('journal', '/_admin/journal', controller='journal',)
+    map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
+                action='toggle_following', conditions=dict(method=["POST"]))
+
+
     #SEARCH
     map.connect('search', '/_admin/search', controller='search',)
     map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
--- a/rhodecode/controllers/admin/admin.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/admin/admin.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# admin controller for pylons 
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
- 
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.admin.admin
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Controller for Admin panel of Rhodecode
+    
+    :created_on: Apr 7, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,15 +24,10 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on April 7, 2010
-admin controller for pylons
-@author: marcink
-"""
+
 import logging
-from pylons import request, response, session, tmpl_context as c
+from pylons import request, tmpl_context as c
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model import meta
 from rhodecode.model.db import UserLog
 from webhelpers.paginate import Page
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
@@ -33,19 +35,19 @@
 log = logging.getLogger(__name__)
 
 class AdminController(BaseController):
-    
+
     @LoginRequired()
     def __before__(self):
         super(AdminController, self).__before__()
-    
-    @HasPermissionAllDecorator('hg.admin')        
+
+    @HasPermissionAllDecorator('hg.admin')
     def index(self):
-                                 
+
         users_log = self.sa.query(UserLog).order_by(UserLog.action_date.desc())
         p = int(request.params.get('page', 1))
         c.users_log = Page(users_log, page=p, items_per_page=10)
         c.log_data = render('admin/admin_log.html')
         if request.params.get('partial'):
             return c.log_data
-        return render('admin/admin.html')    
-                
+        return render('admin/admin.html')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/controllers/admin/ldap_settings.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.controllers.admin.ldap_settings
+    ~~~~~~~~~~~~~~
+
+    ldap controller for RhodeCode
+    :created_on: Nov 26, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+import logging
+import formencode
+import traceback
+
+from formencode import htmlfill
+
+from pylons import request, response, session, tmpl_context as c, url
+from pylons.controllers.util import abort, redirect
+from pylons.i18n.translation import _
+
+from rhodecode.lib.base import BaseController, render
+from rhodecode.lib import helpers as h
+from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
+from rhodecode.lib.auth_ldap import LdapImportError
+from rhodecode.model.settings import SettingsModel
+from rhodecode.model.forms import LdapSettingsForm
+from sqlalchemy.exc import DatabaseError
+
+log = logging.getLogger(__name__)
+
+
+
+class LdapSettingsController(BaseController):
+
+    @LoginRequired()
+    @HasPermissionAllDecorator('hg.admin')
+    def __before__(self):
+        c.admin_user = session.get('admin_user')
+        c.admin_username = session.get('admin_username')
+        super(LdapSettingsController, self).__before__()
+
+    def index(self):
+        defaults = SettingsModel().get_ldap_settings()
+
+        return htmlfill.render(
+                    render('admin/ldap/ldap.html'),
+                    defaults=defaults,
+                    encoding="UTF-8",
+                    force_defaults=True,)
+
+    def ldap_settings(self):
+        """
+        POST ldap create and store ldap settings
+        """
+
+        settings_model = SettingsModel()
+        _form = LdapSettingsForm()()
+
+        try:
+            form_result = _form.to_python(dict(request.POST))
+            try:
+
+                for k, v in form_result.items():
+                    if k.startswith('ldap_'):
+                        setting = settings_model.get(k)
+                        setting.app_settings_value = v
+                        self.sa.add(setting)
+
+                self.sa.commit()
+                h.flash(_('Ldap settings updated successfully'),
+                    category='success')
+            except (DatabaseError,):
+                raise
+        except LdapImportError:
+            h.flash(_('Unable to activate ldap. The "python-ldap" library '
+                      'is missing.'), category='warning')
+
+        except formencode.Invalid, errors:
+
+            return htmlfill.render(
+                render('admin/ldap/ldap.html'),
+                defaults=errors.value,
+                errors=errors.error_dict or {},
+                prefix_error=False,
+                encoding="UTF-8")
+        except Exception:
+            log.error(traceback.format_exc())
+            h.flash(_('error occured during update of ldap settings'),
+                    category='error')
+
+        return redirect(url('ldap_home'))
--- a/rhodecode/controllers/admin/permissions.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/admin/permissions.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# permissions controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-#
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.admin.permissions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    
+    permissions controller for Rhodecode
+    
+    :created_on: Apr 27, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,11 +24,6 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on April 27, 2010
-permissions controller for pylons
-@author: marcink
-"""
 
 from formencode import htmlfill
 from pylons import request, session, tmpl_context as c, url
@@ -29,11 +31,12 @@
 from pylons.i18n.translation import _
 from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
+from rhodecode.lib.auth_ldap import LdapImportError
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.db import User, UserLog
-from rhodecode.model.forms import UserForm, DefaultPermissionsForm
-from rhodecode.model.permission_model import PermissionModel
-from rhodecode.model.user_model import UserModel
+from rhodecode.model.forms import LdapSettingsForm, DefaultPermissionsForm
+from rhodecode.model.permission import PermissionModel
+from rhodecode.model.settings import SettingsModel
+from rhodecode.model.user import UserModel
 import formencode
 import logging
 import traceback
@@ -45,29 +48,30 @@
     # To properly map this controller, ensure your config/routing.py
     # file has a resource setup:
     #     map.resource('permission', 'permissions')
-    
+
     @LoginRequired()
     @HasPermissionAllDecorator('hg.admin')
     def __before__(self):
         c.admin_user = session.get('admin_user')
         c.admin_username = session.get('admin_username')
         super(PermissionsController, self).__before__()
-        
+
         self.perms_choices = [('repository.none', _('None'),),
                               ('repository.read', _('Read'),),
                               ('repository.write', _('Write'),),
                               ('repository.admin', _('Admin'),)]
         self.register_choices = [
-            ('hg.register.none', 'disabled'),
+            ('hg.register.none',
+                _('disabled')),
             ('hg.register.manual_activate',
-                            _('allowed with manual account activation')),
+                _('allowed with manual account activation')),
             ('hg.register.auto_activate',
-                            _('allowed with automatic account activation')), ]
-        
+                _('allowed with automatic account activation')), ]
+
         self.create_choices = [('hg.create.none', _('Disabled')),
-                               ('hg.create.repository', _('Enabled'))]     
+                               ('hg.create.repository', _('Enabled'))]
 
-        
+
     def index(self, format='html'):
         """GET /permissions: All items in the collection"""
         # url('permissions')
@@ -88,38 +92,39 @@
         #    h.form(url('permission', id=ID),
         #           method='put')
         # url('permission', id=ID)
-                
+
         permission_model = PermissionModel()
-        
+
         _form = DefaultPermissionsForm([x[0] for x in self.perms_choices],
                                        [x[0] for x in self.register_choices],
                                        [x[0] for x in self.create_choices])()
-        
+
         try:
             form_result = _form.to_python(dict(request.POST))
             form_result.update({'perm_user_name':id})
             permission_model.update(form_result)
-            h.flash(_('Default permissions updated succesfully'),
+            h.flash(_('Default permissions updated successfully'),
                     category='success')
-                           
+
         except formencode.Invalid, errors:
             c.perms_choices = self.perms_choices
             c.register_choices = self.register_choices
             c.create_choices = self.create_choices
-                    
+            defaults = errors.value
+
             return htmlfill.render(
                 render('admin/permissions/permissions.html'),
-                defaults=errors.value,
+                defaults=defaults,
                 errors=errors.error_dict or {},
                 prefix_error=False,
-                encoding="UTF-8") 
+                encoding="UTF-8")
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('error occured during update of permissions'),
                     category='error')
-            
+
         return redirect(url('edit_permission', id=id))
-            
+
 
 
     def delete(self, id):
@@ -141,23 +146,26 @@
         c.perms_choices = self.perms_choices
         c.register_choices = self.register_choices
         c.create_choices = self.create_choices
-        
+
         if id == 'default':
-            defaults = {'_method':'put'}
-            for p in UserModel().get_default().user_perms:
+            default_user = UserModel().get_by_username('default')
+            defaults = {'_method':'put',
+                        'anonymous':default_user.active}
+
+            for p in default_user.user_perms:
                 if p.permission.permission_name.startswith('repository.'):
-                    defaults['default_perm'] = p.permission.permission_name 
-                
+                    defaults['default_perm'] = p.permission.permission_name
+
                 if p.permission.permission_name.startswith('hg.register.'):
                     defaults['default_register'] = p.permission.permission_name
-                    
+
                 if p.permission.permission_name.startswith('hg.create.'):
                     defaults['default_create'] = p.permission.permission_name
-                             
+
             return htmlfill.render(
                         render('admin/permissions/permissions.html'),
                         defaults=defaults,
                         encoding="UTF-8",
-                        force_defaults=True,)        
+                        force_defaults=True,)
         else:
             return redirect(url('admin_home'))
--- a/rhodecode/controllers/admin/repos.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/admin/repos.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# repos controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-#
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.admin.repos
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    
+    Admin controller for RhodeCode
+    
+    :created_on: Apr 7, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,17 +24,18 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on April 7, 2010
-admin controller for pylons
-@author: marcink
-"""
+
+import logging
+import traceback
+import formencode
+from operator import itemgetter
 from formencode import htmlfill
-from operator import itemgetter
+
 from paste.httpexceptions import HTTPInternalServerError
 from pylons import request, response, session, tmpl_context as c, url
 from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _
+
 from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
     HasPermissionAnyDecorator
@@ -35,11 +43,9 @@
 from rhodecode.lib.utils import invalidate_cache, action_logger
 from rhodecode.model.db import User
 from rhodecode.model.forms import RepoForm
-from rhodecode.model.hg_model import HgModel
-from rhodecode.model.repo_model import RepoModel
-import formencode
-import logging
-import traceback
+from rhodecode.model.scm import ScmModel
+from rhodecode.model.repo import RepoModel
+
 
 log = logging.getLogger(__name__)
 
@@ -48,22 +54,22 @@
     # To properly map this controller, ensure your config/routing.py
     # file has a resource setup:
     #     map.resource('repo', 'repos')
-    
+
     @LoginRequired()
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
     def __before__(self):
         c.admin_user = session.get('admin_user')
         c.admin_username = session.get('admin_username')
         super(ReposController, self).__before__()
-    
-    @HasPermissionAllDecorator('hg.admin')            
+
+    @HasPermissionAllDecorator('hg.admin')
     def index(self, format='html'):
         """GET /repos: All items in the collection"""
         # url('repos')
-        cached_repo_list = HgModel().get_repos()
+        cached_repo_list = ScmModel().get_repos()
         c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
         return render('admin/repos/repos.html')
-    
+
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
     def create(self):
         """POST /repos: Create a new item"""
@@ -74,7 +80,6 @@
         try:
             form_result = _form.to_python(dict(request.POST))
             repo_model.create(form_result, c.rhodecode_user)
-            invalidate_cache('cached_repo_list')
             h.flash(_('created repository %s') % form_result['repo_name'],
                     category='success')
 
@@ -83,22 +88,22 @@
                               form_result['repo_name'], '', self.sa)
             else:
                 action_logger(self.rhodecode_user, 'admin_created_repo',
-                              form_result['repo_name'], '', self.sa)                
-                                                                             
+                              form_result['repo_name'], '', self.sa)
+
         except formencode.Invalid, errors:
             c.new_repo = errors.value['repo_name']
-            
+
             if request.POST.get('user_created'):
                 r = render('admin/repos/repo_add_create_repository.html')
-            else:              
+            else:
                 r = render('admin/repos/repo_add.html')
-            
+
             return htmlfill.render(
                 r,
                 defaults=errors.value,
                 errors=errors.error_dict or {},
                 prefix_error=False,
-                encoding="UTF-8")      
+                encoding="UTF-8")
 
         except Exception:
             log.error(traceback.format_exc())
@@ -106,9 +111,9 @@
                     % form_result.get('repo_name')
             h.flash(msg, category='error')
         if request.POST.get('user_created'):
-            return redirect(url('hg_home'))    
+            return redirect(url('home'))
         return redirect(url('repos'))
-    
+
     @HasPermissionAllDecorator('hg.admin')
     def new(self, format='html'):
         """GET /repos/new: Form to create a new item"""
@@ -116,7 +121,7 @@
         c.new_repo = h.repo_name_slug(new_repo)
 
         return render('admin/repos/repo_add.html')
-    
+
     @HasPermissionAllDecorator('hg.admin')
     def update(self, repo_name):
         """PUT /repos/repo_name: Update an existing item"""
@@ -129,16 +134,33 @@
         repo_model = RepoModel()
         changed_name = repo_name
         _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
-        
+
         try:
             form_result = _form.to_python(dict(request.POST))
             repo_model.update(repo_name, form_result)
-            invalidate_cache('cached_repo_list')
-            h.flash(_('Repository %s updated succesfully' % repo_name),
+            invalidate_cache('get_repo_cached_%s' % repo_name)
+            h.flash(_('Repository %s updated successfully' % repo_name),
                     category='success')
             changed_name = form_result['repo_name']
+            action_logger(self.rhodecode_user, 'admin_updated_repo',
+                              changed_name, '', self.sa)
+
         except formencode.Invalid, errors:
-            c.repo_info = repo_model.get(repo_name)
+            c.repo_info = repo_model.get_by_repo_name(repo_name)
+            if c.repo_info.stats:
+                last_rev = c.repo_info.stats.stat_on_revision
+            else:
+                last_rev = 0
+            c.stats_revision = last_rev
+            r = ScmModel().get(repo_name)
+            c.repo_last_rev = r.revisions[-1] if r.revisions else 0
+
+            if last_rev == 0:
+                c.stats_percentage = 0
+            else:
+                c.stats_percentage = '%.2f' % ((float((last_rev)) /
+                                                c.repo_last_rev) * 100)
+
             c.users_array = repo_model.get_users_js()
             errors.value.update({'user':c.repo_info.user.username})
             return htmlfill.render(
@@ -147,14 +169,14 @@
                 errors=errors.error_dict or {},
                 prefix_error=False,
                 encoding="UTF-8")
- 
+
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('error occured during update of repository %s') \
+            h.flash(_('error occurred during update of repository %s') \
                     % repo_name, category='error')
-            
+
         return redirect(url('edit_repo', repo_name=changed_name))
-    
+
     @HasPermissionAllDecorator('hg.admin')
     def delete(self, repo_name):
         """DELETE /repos/repo_name: Delete an existing item"""
@@ -164,82 +186,128 @@
         #    h.form(url('repo', repo_name=ID),
         #           method='delete')
         # url('repo', repo_name=ID)
-        
+
         repo_model = RepoModel()
-        repo = repo_model.get(repo_name)
+        repo = repo_model.get_by_repo_name(repo_name)
         if not repo:
-            h.flash(_('%s repository is not mapped to db perhaps' 
+            h.flash(_('%s repository is not mapped to db perhaps'
                       ' it was moved or renamed  from the filesystem'
                       ' please run the application again'
                       ' in order to rescan repositories') % repo_name,
                       category='error')
-        
+
             return redirect(url('repos'))
         try:
             action_logger(self.rhodecode_user, 'admin_deleted_repo',
                               repo_name, '', self.sa)
-            repo_model.delete(repo)            
-            invalidate_cache('cached_repo_list')
+            repo_model.delete(repo)
+            invalidate_cache('get_repo_cached_%s' % repo_name)
             h.flash(_('deleted repository %s') % repo_name, category='success')
-           
+
         except Exception, e:
             log.error(traceback.format_exc())
             h.flash(_('An error occured during deletion of %s') % repo_name,
                     category='error')
-        
+
         return redirect(url('repos'))
-    
-    @HasPermissionAllDecorator('hg.admin')        
+
+    @HasPermissionAllDecorator('hg.admin')
     def delete_perm_user(self, repo_name):
         """
         DELETE an existing repository permission user
         :param repo_name:
         """
-        
+
         try:
             repo_model = RepoModel()
-            repo_model.delete_perm_user(request.POST, repo_name)            
+            repo_model.delete_perm_user(request.POST, repo_name)
         except Exception, e:
             h.flash(_('An error occured during deletion of repository user'),
                     category='error')
             raise HTTPInternalServerError()
-    
-    @HasPermissionAllDecorator('hg.admin')    
+
+    @HasPermissionAllDecorator('hg.admin')
+    def repo_stats(self, repo_name):
+        """
+        DELETE an existing repository statistics
+        :param repo_name:
+        """
+
+        try:
+            repo_model = RepoModel()
+            repo_model.delete_stats(repo_name)
+        except Exception, e:
+            h.flash(_('An error occured during deletion of repository stats'),
+                    category='error')
+        return redirect(url('edit_repo', repo_name=repo_name))
+
+    @HasPermissionAllDecorator('hg.admin')
+    def repo_cache(self, repo_name):
+        """
+        INVALIDATE exisitings repository cache
+        :param repo_name:
+        """
+
+        try:
+            ScmModel().mark_for_invalidation(repo_name)
+        except Exception, e:
+            h.flash(_('An error occurred during cache invalidation'),
+                    category='error')
+        return redirect(url('edit_repo', repo_name=repo_name))
+
+    @HasPermissionAllDecorator('hg.admin')
     def show(self, repo_name, format='html'):
         """GET /repos/repo_name: Show a specific item"""
         # url('repo', repo_name=ID)
-    
-    @HasPermissionAllDecorator('hg.admin')    
+
+    @HasPermissionAllDecorator('hg.admin')
     def edit(self, repo_name, format='html'):
         """GET /repos/repo_name/edit: Form to edit an existing item"""
         # url('edit_repo', repo_name=ID)
         repo_model = RepoModel()
-        c.repo_info = repo = repo_model.get(repo_name)
-        if not repo:
-            h.flash(_('%s repository is not mapped to db perhaps' 
+        r = ScmModel().get(repo_name)
+        c.repo_info = repo_model.get_by_repo_name(repo_name)
+
+        if c.repo_info is None:
+            h.flash(_('%s repository is not mapped to db perhaps'
                       ' it was created or renamed from the filesystem'
                       ' please run the application again'
                       ' in order to rescan repositories') % repo_name,
                       category='error')
-        
-            return redirect(url('repos'))        
-        defaults = c.repo_info.__dict__
+
+            return redirect(url('repos'))
+
+        if c.repo_info.stats:
+            last_rev = c.repo_info.stats.stat_on_revision
+        else:
+            last_rev = 0
+        c.stats_revision = last_rev
+
+        c.repo_last_rev = r.revisions[-1] if r.revisions else 0
+
+        if last_rev == 0:
+            c.stats_percentage = 0
+        else:
+            c.stats_percentage = '%.2f' % ((float((last_rev)) /
+                                            c.repo_last_rev) * 100)
+
+        defaults = c.repo_info.get_dict()
         if c.repo_info.user:
             defaults.update({'user':c.repo_info.user.username})
         else:
             replacement_user = self.sa.query(User)\
             .filter(User.admin == True).first().username
             defaults.update({'user':replacement_user})
-            
+
         c.users_array = repo_model.get_users_js()
-        
+
         for p in c.repo_info.repo_to_perm:
-            defaults.update({'perm_%s' % p.user.username: 
+            defaults.update({'perm_%s' % p.user.username:
                              p.permission.permission_name})
-            
+
         return htmlfill.render(
             render('admin/repos/repo_edit.html'),
             defaults=defaults,
             encoding="UTF-8",
             force_defaults=False
-        )          
+        )
--- a/rhodecode/controllers/admin/settings.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/admin/settings.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,14 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# settings controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-#
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.controllers.admin.settings
+    ~~~~~~~~~~~~~~
+    settings controller for rhodecode admin
+        
+    :created_on: Jul 14, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,11 +23,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on July 14, 2010
-settings controller for pylons
-@author: marcink
-"""
+
 from formencode import htmlfill
 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
     config
@@ -29,20 +31,22 @@
 from pylons.i18n.translation import _
 from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
-    HasPermissionAnyDecorator
+    HasPermissionAnyDecorator, NotAnonymous
 from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.celerylib import tasks, run_task
 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
-    set_rhodecode_config, get_hg_settings, get_hg_ui_settings, make_ui
-from rhodecode.model.db import User, UserLog, RhodeCodeSettings, RhodeCodeUi
+    set_rhodecode_config
+from rhodecode.model.db import RhodeCodeUi, Repository
 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
     ApplicationUiSettingsForm
-from rhodecode.model.hg_model import HgModel
-from rhodecode.model.user_model import UserModel
-from rhodecode.lib.celerylib import tasks, run_task
+from rhodecode.model.scm import ScmModel
+from rhodecode.model.settings import SettingsModel
+from rhodecode.model.user import UserModel
+from sqlalchemy import func
 import formencode
 import logging
 import traceback
- 
+
 log = logging.getLogger(__name__)
 
 
@@ -59,32 +63,32 @@
         c.admin_user = session.get('admin_user')
         c.admin_username = session.get('admin_username')
         super(SettingsController, self).__before__()
-    
-    
-    @HasPermissionAllDecorator('hg.admin')    
+
+
+    @HasPermissionAllDecorator('hg.admin')
     def index(self, format='html'):
         """GET /admin/settings: All items in the collection"""
         # url('admin_settings')
 
-        defaults = get_hg_settings()
-        defaults.update(get_hg_ui_settings())
+        defaults = SettingsModel().get_app_settings()
+        defaults.update(self.get_hg_ui_settings())
         return htmlfill.render(
             render('admin/settings/settings.html'),
             defaults=defaults,
             encoding="UTF-8",
             force_defaults=False
-        )  
-    
+        )
+
     @HasPermissionAllDecorator('hg.admin')
     def create(self):
         """POST /admin/settings: Create a new item"""
         # url('admin_settings')
-    
+
     @HasPermissionAllDecorator('hg.admin')
     def new(self, format='html'):
         """GET /admin/settings/new: Form to create a new item"""
         # url('admin_new_setting')
-        
+
     @HasPermissionAllDecorator('hg.admin')
     def update(self, setting_id):
         """PUT /admin/settings/setting_id: Update an existing item"""
@@ -98,47 +102,48 @@
             rm_obsolete = request.POST.get('destroy', False)
             log.debug('Rescanning directories with destroy=%s', rm_obsolete)
 
-            initial = HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
+            initial = ScmModel().repo_scan(g.paths[0][1], g.baseui)
+            for repo_name in initial.keys():
+                invalidate_cache('get_repo_cached_%s' % repo_name)
+
             repo2db_mapper(initial, rm_obsolete)
-            invalidate_cache('cached_repo_list')
-            h.flash(_('Repositories successfully rescanned'), category='success')            
-        
+
+            h.flash(_('Repositories successfully rescanned'), category='success')
+
         if setting_id == 'whoosh':
-            repo_location = get_hg_ui_settings()['paths_root_path']
+            repo_location = self.get_hg_ui_settings()['paths_root_path']
             full_index = request.POST.get('full_index', False)
             task = run_task(tasks.whoosh_index, repo_location, full_index)
-            
+
             h.flash(_('Whoosh reindex task scheduled'), category='success')
         if setting_id == 'global':
-            
+
             application_form = ApplicationSettingsForm()()
             try:
                 form_result = application_form.to_python(dict(request.POST))
-            
+                settings_model = SettingsModel()
                 try:
-                    hgsettings1 = self.sa.query(RhodeCodeSettings)\
-                    .filter(RhodeCodeSettings.app_settings_name == 'title').one()
-                    hgsettings1.app_settings_value = form_result['rhodecode_title'] 
-                    
-                    hgsettings2 = self.sa.query(RhodeCodeSettings)\
-                    .filter(RhodeCodeSettings.app_settings_name == 'realm').one()
-                    hgsettings2.app_settings_value = form_result['rhodecode_realm'] 
-                    
-                    
+                    hgsettings1 = settings_model.get('title')
+                    hgsettings1.app_settings_value = form_result['rhodecode_title']
+
+                    hgsettings2 = settings_model.get('realm')
+                    hgsettings2.app_settings_value = form_result['rhodecode_realm']
+
+
                     self.sa.add(hgsettings1)
                     self.sa.add(hgsettings2)
                     self.sa.commit()
                     set_rhodecode_config(config)
                     h.flash(_('Updated application settings'),
                             category='success')
-                                    
+
                 except:
                     log.error(traceback.format_exc())
                     h.flash(_('error occurred during updating application settings'),
                             category='error')
-                                
+
                     self.sa.rollback()
-                    
+
 
             except formencode.Invalid, errors:
                 return htmlfill.render(
@@ -146,52 +151,60 @@
                      defaults=errors.value,
                      errors=errors.error_dict or {},
                      prefix_error=False,
-                     encoding="UTF-8") 
-        
+                     encoding="UTF-8")
+
         if setting_id == 'mercurial':
             application_form = ApplicationUiSettingsForm()()
             try:
                 form_result = application_form.to_python(dict(request.POST))
-            
+
                 try:
-                    
+
                     hgsettings1 = self.sa.query(RhodeCodeUi)\
                     .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
                     hgsettings1.ui_value = form_result['web_push_ssl']
-                    
+
                     hgsettings2 = self.sa.query(RhodeCodeUi)\
                     .filter(RhodeCodeUi.ui_key == '/').one()
-                    hgsettings2.ui_value = form_result['paths_root_path']                    
-                    
-                    
+                    hgsettings2.ui_value = form_result['paths_root_path']
+
+
                     #HOOKS
                     hgsettings3 = self.sa.query(RhodeCodeUi)\
                     .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
-                    hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])  
-                    
+                    hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
+
                     hgsettings4 = self.sa.query(RhodeCodeUi)\
                     .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
-                    hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])                                          
-                    
-                    
-                    
-                    
+                    hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
+
+                    hgsettings5 = self.sa.query(RhodeCodeUi)\
+                    .filter(RhodeCodeUi.ui_key == 'pretxnchangegroup.push_logger').one()
+                    hgsettings5.ui_active = bool(form_result['hooks_pretxnchangegroup_push_logger'])
+
+                    hgsettings6 = self.sa.query(RhodeCodeUi)\
+                    .filter(RhodeCodeUi.ui_key == 'preoutgoing.pull_logger').one()
+                    hgsettings6.ui_active = bool(form_result['hooks_preoutgoing_pull_logger'])
+
+
                     self.sa.add(hgsettings1)
                     self.sa.add(hgsettings2)
                     self.sa.add(hgsettings3)
                     self.sa.add(hgsettings4)
+                    self.sa.add(hgsettings5)
+                    self.sa.add(hgsettings6)
                     self.sa.commit()
-                    
+
                     h.flash(_('Updated mercurial settings'),
                             category='success')
-                                    
+
                 except:
                     log.error(traceback.format_exc())
                     h.flash(_('error occurred during updating application settings'),
                             category='error')
-                                
+
                     self.sa.rollback()
-                    
+
 
             except formencode.Invalid, errors:
                 return htmlfill.render(
@@ -199,12 +212,12 @@
                      defaults=errors.value,
                      errors=errors.error_dict or {},
                      prefix_error=False,
-                     encoding="UTF-8") 
-                
-                
-                        
+                     encoding="UTF-8")
+
+
+
         return redirect(url('admin_settings'))
-    
+
     @HasPermissionAllDecorator('hg.admin')
     def delete(self, setting_id):
         """DELETE /admin/settings/setting_id: Delete an existing item"""
@@ -214,41 +227,44 @@
         #    h.form(url('admin_setting', setting_id=ID),
         #           method='delete')
         # url('admin_setting', setting_id=ID)
-    
+
     @HasPermissionAllDecorator('hg.admin')
     def show(self, setting_id, format='html'):
         """GET /admin/settings/setting_id: Show a specific item"""
         # url('admin_setting', setting_id=ID)
-    
-    @HasPermissionAllDecorator('hg.admin')         
+
+    @HasPermissionAllDecorator('hg.admin')
     def edit(self, setting_id, format='html'):
         """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
         # url('admin_edit_setting', setting_id=ID)
 
-
+    @NotAnonymous()
     def my_account(self):
         """
         GET /_admin/my_account Displays info about my account 
         """
         # url('admin_settings_my_account')
-        c.user = self.sa.query(User).get(c.rhodecode_user.user_id)
-        c.user_repos = []
-        for repo in c.cached_repo_list.values():
-            if repo.dbrepo.user.username == c.user.username:
-                c.user_repos.append(repo)
-                
+
+        c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
+        all_repos = self.sa.query(Repository)\
+            .filter(Repository.user_id == c.user.user_id)\
+            .order_by(func.lower(Repository.repo_name))\
+            .all()
+
+        c.user_repos = ScmModel().get_repos(all_repos)
+
         if c.user.username == 'default':
-            h.flash(_("You can't edit this user since it's" 
+            h.flash(_("You can't edit this user since it's"
               " crucial for entire application"), category='warning')
             return redirect(url('users'))
-        
-        defaults = c.user.__dict__
+
+        defaults = c.user.get_dict()
         return htmlfill.render(
             render('admin/users/user_edit_my_account.html'),
             defaults=defaults,
             encoding="UTF-8",
             force_defaults=False
-        ) 
+        )
 
     def my_account_update(self):
         """PUT /_admin/my_account_update: Update an existing item"""
@@ -266,15 +282,18 @@
         try:
             form_result = _form.to_python(dict(request.POST))
             user_model.update_my_account(uid, form_result)
-            h.flash(_('Your account was updated succesfully'),
+            h.flash(_('Your account was updated successfully'),
                     category='success')
-                           
+
         except formencode.Invalid, errors:
-            c.user = self.sa.query(User).get(c.rhodecode_user.user_id)
-            c.user_repos = []
-            for repo in c.cached_repo_list.values():
-                if repo.dbrepo.user.username == c.user.username:
-                    c.user_repos.append(repo)            
+            c.user = user_model.get(c.rhodecode_user.user_id, cache=False)
+            c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
+            all_repos = self.sa.query(Repository)\
+                .filter(Repository.user_id == c.user.user_id)\
+                .order_by(func.lower(Repository.repo_name))\
+                .all()
+            c.user_repos = ScmModel().get_repos(all_repos)
+
             return htmlfill.render(
                 render('admin/users/user_edit_my_account.html'),
                 defaults=errors.value,
@@ -283,11 +302,12 @@
                 encoding="UTF-8")
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('error occured during update of user %s') \
+            h.flash(_('error occurred during update of user %s') \
                     % form_result.get('username'), category='error')
-                    
+
         return redirect(url('my_account'))
-    
+
+    @NotAnonymous()
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
     def create_repository(self):
         """GET /_admin/create_repository: Form to create a new item"""
@@ -295,4 +315,25 @@
         c.new_repo = h.repo_name_slug(new_repo)
 
         return render('admin/repos/repo_add_create_repository.html')
-        
+
+    def get_hg_ui_settings(self):
+        ret = self.sa.query(RhodeCodeUi).all()
+
+        if not ret:
+            raise Exception('Could not get application ui settings !')
+        settings = {}
+        for each in ret:
+            k = each.ui_key
+            v = each.ui_value
+            if k == '/':
+                k = 'root_path'
+
+            if k.find('.') != -1:
+                k = k.replace('.', '_')
+
+            if each.ui_section == 'hooks':
+                v = each.ui_active
+
+            settings[each.ui_section + '_' + k] = v
+
+        return settings
--- a/rhodecode/controllers/admin/users.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/admin/users.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# users controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# 
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.admin.users
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Users crud controller for pylons
+    
+    :created_on: Apr 4, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,26 +24,24 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-from rhodecode.lib.utils import action_logger
-"""
-Created on April 4, 2010
-users controller for pylons
-@author: marcink
-"""
+
+import logging
+import traceback
+import formencode
 
 from formencode import htmlfill
 from pylons import request, session, tmpl_context as c, url
 from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _
+
+from rhodecode.lib.exceptions import *
 from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.db import User, UserLog
+
+from rhodecode.model.db import User
 from rhodecode.model.forms import UserForm
-from rhodecode.model.user_model import UserModel, DefaultUserException
-import formencode
-import logging
-import traceback
+from rhodecode.model.user import UserModel
 
 log = logging.getLogger(__name__)
 
@@ -45,26 +50,26 @@
     # To properly map this controller, ensure your config/routing.py
     # file has a resource setup:
     #     map.resource('user', 'users')
-    
+
     @LoginRequired()
     @HasPermissionAllDecorator('hg.admin')
     def __before__(self):
         c.admin_user = session.get('admin_user')
         c.admin_username = session.get('admin_username')
         super(UsersController, self).__before__()
-    
+
 
     def index(self, format='html'):
         """GET /users: All items in the collection"""
         # url('users')
-        
-        c.users_list = self.sa.query(User).all()     
+
+        c.users_list = self.sa.query(User).all()
         return render('admin/users/users.html')
-    
+
     def create(self):
         """POST /users: Create a new item"""
         # url('users')
-        
+
         user_model = UserModel()
         login_form = UserForm()()
         try:
@@ -79,13 +84,13 @@
                 defaults=errors.value,
                 errors=errors.error_dict or {},
                 prefix_error=False,
-                encoding="UTF-8") 
+                encoding="UTF-8")
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('error occured during creation of user %s') \
-                    % request.POST.get('username'), category='error')            
+                    % request.POST.get('username'), category='error')
         return redirect(url('users'))
-    
+
     def new(self, format='html'):
         """GET /users/new: Form to create a new item"""
         # url('new_user')
@@ -100,8 +105,8 @@
         #           method='put')
         # url('user', id=ID)
         user_model = UserModel()
-        c.user = user_model.get_user(id)
-        
+        c.user = user_model.get(id)
+
         _form = UserForm(edit=True, old_data={'user_id':id,
                                               'email':c.user.email})()
         form_result = {}
@@ -109,21 +114,21 @@
             form_result = _form.to_python(dict(request.POST))
             user_model.update(id, form_result)
             h.flash(_('User updated succesfully'), category='success')
-                           
+
         except formencode.Invalid, errors:
             return htmlfill.render(
                 render('admin/users/user_edit.html'),
                 defaults=errors.value,
                 errors=errors.error_dict or {},
                 prefix_error=False,
-                encoding="UTF-8") 
+                encoding="UTF-8")
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('error occured during update of user %s') \
+            h.flash(_('error occurred during update of user %s') \
                     % form_result.get('username'), category='error')
-            
+
         return redirect(url('users'))
-    
+
     def delete(self, id):
         """DELETE /users/id: Delete an existing item"""
         # Forms posted to this method should contain a hidden field:
@@ -136,18 +141,18 @@
         try:
             user_model.delete(id)
             h.flash(_('sucessfully deleted user'), category='success')
-        except DefaultUserException, e:
+        except (UserOwnsReposException, DefaultUserException), e:
             h.flash(str(e), category='warning')
         except Exception:
             h.flash(_('An error occured during deletion of user'),
-                    category='error')            
+                    category='error')
         return redirect(url('users'))
-        
+
     def show(self, id, format='html'):
         """GET /users/id: Show a specific item"""
         # url('user', id=ID)
-    
-    
+
+
     def edit(self, id, format='html'):
         """GET /users/id/edit: Form to edit an existing item"""
         # url('edit_user', id=ID)
@@ -155,14 +160,13 @@
         if not c.user:
             return redirect(url('users'))
         if c.user.username == 'default':
-            h.flash(_("You can't edit this user since it's" 
-              " crucial for entire application"), category='warning')
+            h.flash(_("You can't edit this user"), category='warning')
             return redirect(url('users'))
-        
-        defaults = c.user.__dict__
+
+        defaults = c.user.get_dict()
         return htmlfill.render(
             render('admin/users/user_edit.html'),
             defaults=defaults,
             encoding="UTF-8",
             force_defaults=False
-        )    
+        )
--- a/rhodecode/controllers/branches.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/branches.py	Sat Dec 18 14:45:58 2010 +0100
@@ -26,7 +26,7 @@
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
 from rhodecode.lib.utils import OrderedDict
-from rhodecode.model.hg_model import HgModel
+from rhodecode.model.scm import ScmModel
 import logging
 log = logging.getLogger(__name__)
 
@@ -38,7 +38,7 @@
         super(BranchesController, self).__before__()
     
     def index(self):
-        hg_model = HgModel()
+        hg_model = ScmModel()
         c.repo_info = hg_model.get_repo(c.repo_name)
         c.repo_branches = OrderedDict()
         for name, hash_ in c.repo_info.branches.items():
--- a/rhodecode/controllers/changelog.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/changelog.py	Sat Dec 18 14:45:58 2010 +0100
@@ -32,19 +32,19 @@
 from pylons import request, session, tmpl_context as c
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.hg_model import HgModel
+from rhodecode.model.scm import ScmModel
 from webhelpers.paginate import Page
 import logging
 log = logging.getLogger(__name__)
 
 class ChangelogController(BaseController):
-    
+
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
-                                   'repository.admin')    
+                                   'repository.admin')
     def __before__(self):
         super(ChangelogController, self).__before__()
-                
+
     def index(self):
         limit = 100
         default = 20
@@ -53,43 +53,47 @@
                 int_size = int(request.params.get('size'))
             except ValueError:
                 int_size = default
-            int_size = int_size if int_size <= limit else limit 
+            int_size = int_size if int_size <= limit else limit
             c.size = int_size
             session['changelog_size'] = c.size
             session.save()
         else:
             c.size = int(session.get('changelog_size', default))
 
-        changesets = HgModel().get_repo(c.repo_name)
-            
+        changesets = ScmModel().get_repo(c.repo_name)
+
         p = int(request.params.get('page', 1))
         c.total_cs = len(changesets)
         c.pagination = Page(changesets, page=p, item_count=c.total_cs,
                             items_per_page=c.size)
-            
+
         self._graph(changesets, c.size, p)
-        
+
         return render('changelog/changelog.html')
 
 
     def _graph(self, repo, size, p):
         revcount = size
-        if not repo.revisions:return json.dumps([]), 0
-        
+        if not repo.revisions or repo.alias == 'git':
+            c.jsdata = json.dumps([])
+            return
+
         max_rev = repo.revisions[-1]
+
         offset = 1 if p == 1 else  ((p - 1) * revcount + 1)
+
         rev_start = repo.revisions[(-1 * offset)]
-        
+
         revcount = min(max_rev, revcount)
         rev_end = max(0, rev_start - revcount)
         dag = graph_rev(repo.repo, rev_start, rev_end)
-        
+
         c.dag = tree = list(colored(dag))
         data = []
         for (id, type, ctx, vtx, edges) in tree:
             if type != CHANGESET:
                 continue
             data.append(('', vtx, edges))
-    
-        c.jsdata = json.dumps(data) 
 
+        c.jsdata = json.dumps(data)
+
--- a/rhodecode/controllers/changeset.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/changeset.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,7 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# changeset controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.changeset
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    changeset controller for pylons
+    
+    :created_on: Apr 25, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -16,97 +24,96 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-from rhodecode.lib.utils import EmptyChangeset
-"""
-Created on April 25, 2010
-changeset controller for pylons
-@author: marcink
-"""
+import logging
+import traceback
+
 from pylons import tmpl_context as c, url, request, response
 from pylons.i18n.translation import _
 from pylons.controllers.util import redirect
+
+import rhodecode.lib.helpers as h
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.hg_model import HgModel
+from rhodecode.lib.utils import EmptyChangeset
+from rhodecode.model.scm import ScmModel
+
 from vcs.exceptions import RepositoryError, ChangesetError
 from vcs.nodes import FileNode
 from vcs.utils import diffs as differ
-import logging
-import traceback
 
 log = logging.getLogger(__name__)
 
 class ChangesetController(BaseController):
-    
+
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
-                                   'repository.admin')       
+                                   'repository.admin')
     def __before__(self):
         super(ChangesetController, self).__before__()
-        
+
     def index(self, revision):
-        hg_model = HgModel()
-        cut_off_limit = 1024 * 250
-        
+        hg_model = ScmModel()
+
         def wrap_to_table(str):
-            
+
             return '''<table class="code-difftable">
                         <tr class="line">
                         <td class="lineno new"></td>
                         <td class="code"><pre>%s</pre></td>
                         </tr>
                       </table>''' % str
-            
+
         try:
             c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
-        except RepositoryError:
+        except RepositoryError, e:
             log.error(traceback.format_exc())
-            return redirect(url('hg_home'))
+            h.flash(str(e), category='warning')
+            return redirect(url('home'))
         else:
             try:
                 c.changeset_old = c.changeset.parents[0]
             except IndexError:
                 c.changeset_old = None
             c.changes = []
-            
+
             #===================================================================
             # ADDED FILES
             #===================================================================
             c.sum_added = 0
             for node in c.changeset.added:
-                
+
                 filenode_old = FileNode(node.path, '', EmptyChangeset())
                 if filenode_old.is_binary or node.is_binary:
                     diff = wrap_to_table(_('binary file'))
                 else:
                     c.sum_added += node.size
-                    if c.sum_added < cut_off_limit:
+                    if c.sum_added < self.cut_off_limit:
                         f_udiff = differ.get_udiff(filenode_old, node)
                         diff = differ.DiffProcessor(f_udiff).as_html()
-                                                    
+
                     else:
                         diff = wrap_to_table(_('Changeset is to big and was cut'
                                             ' off, see raw changeset instead'))
-                        
+
                 cs1 = None
-                cs2 = node.last_changeset.short_id                                        
+                cs2 = node.last_changeset.raw_id
                 c.changes.append(('added', node, diff, cs1, cs2))
-            
+
             #===================================================================
             # CHANGED FILES
             #===================================================================
-            c.sum_removed = 0    
+            c.sum_removed = 0
             for node in c.changeset.changed:
                 try:
                     filenode_old = c.changeset_old.get_node(node.path)
                 except ChangesetError:
                     filenode_old = FileNode(node.path, '', EmptyChangeset())
-                    
+
                 if filenode_old.is_binary or node.is_binary:
                     diff = wrap_to_table(_('binary file'))
                 else:
-                    
-                    if c.sum_removed < cut_off_limit:
+
+                    if c.sum_removed < self.cut_off_limit:
                         f_udiff = differ.get_udiff(filenode_old, node)
                         diff = differ.DiffProcessor(f_udiff).as_html()
                         if diff:
@@ -114,68 +121,72 @@
                     else:
                         diff = wrap_to_table(_('Changeset is to big and was cut'
                                             ' off, see raw changeset instead'))
-                
-                
-                cs1 = filenode_old.last_changeset.short_id
-                cs2 = node.last_changeset.short_id                    
+
+
+                cs1 = filenode_old.last_changeset.raw_id
+                cs2 = node.last_changeset.raw_id
                 c.changes.append(('changed', node, diff, cs1, cs2))
-                
+
             #===================================================================
             # REMOVED FILES    
             #===================================================================
             for node in c.changeset.removed:
-                c.changes.append(('removed', node, None, None, None))            
-            
+                c.changes.append(('removed', node, None, None, None))
+
         return render('changeset/changeset.html')
 
     def raw_changeset(self, revision):
-        
-        hg_model = HgModel()
+
+        hg_model = ScmModel()
         method = request.GET.get('diff', 'show')
         try:
-            c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
+            r = hg_model.get_repo(c.repo_name)
+            c.scm_type = r.alias
+            c.changeset = r.get_changeset(revision)
         except RepositoryError:
             log.error(traceback.format_exc())
-            return redirect(url('hg_home'))
+            return redirect(url('home'))
         else:
             try:
                 c.changeset_old = c.changeset.parents[0]
             except IndexError:
                 c.changeset_old = None
             c.changes = []
-            
+
             for node in c.changeset.added:
                 filenode_old = FileNode(node.path, '')
                 if filenode_old.is_binary or node.is_binary:
-                    diff = _('binary file')
-                else:    
+                    diff = _('binary file') + '\n'
+                else:
                     f_udiff = differ.get_udiff(filenode_old, node)
                     diff = differ.DiffProcessor(f_udiff).raw_diff()
 
                 cs1 = None
-                cs2 = node.last_changeset.short_id                                        
+                cs2 = node.last_changeset.raw_id
                 c.changes.append(('added', node, diff, cs1, cs2))
-                
+
             for node in c.changeset.changed:
                 filenode_old = c.changeset_old.get_node(node.path)
                 if filenode_old.is_binary or node.is_binary:
                     diff = _('binary file')
-                else:    
+                else:
                     f_udiff = differ.get_udiff(filenode_old, node)
                     diff = differ.DiffProcessor(f_udiff).raw_diff()
 
-                cs1 = filenode_old.last_changeset.short_id
-                cs2 = node.last_changeset.short_id                    
-                c.changes.append(('changed', node, diff, cs1, cs2))      
-        
+                cs1 = filenode_old.last_changeset.raw_id
+                cs2 = node.last_changeset.raw_id
+                c.changes.append(('changed', node, diff, cs1, cs2))
+
         response.content_type = 'text/plain'
+
         if method == 'download':
-            response.content_disposition = 'attachment; filename=%s.patch' % revision 
+            response.content_disposition = 'attachment; filename=%s.patch' % revision
+
         parent = True if len(c.changeset.parents) > 0 else False
         c.parent_tmpl = 'Parent  %s' % c.changeset.parents[0].raw_id if parent else ''
-    
+
         c.diffs = ''
         for x in c.changes:
             c.diffs += x[2]
-            
+
         return render('changeset/raw_changeset.html')
--- a/rhodecode/controllers/error.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/error.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,33 +1,58 @@
-import logging
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.controllers.error
+    ~~~~~~~~~~~~~~
+
+    RhodeCode error controller
+    
+    :created_on: Dec 8, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+import os
 import cgi
-import os
+import logging
 import paste.fileapp
-from pylons import tmpl_context as c, app_globals as g, request, config
-from pylons.controllers.util import forward
+
+from pylons import tmpl_context as c, request
 from pylons.i18n.translation import _
+from pylons.middleware import  media_path
+
 from rhodecode.lib.base import BaseController, render
-from pylons.middleware import  media_path
-from rhodecode.lib.utils import check_repo
-import rhodecode.lib.helpers as h
-from rhodecode import __version__
+
 log = logging.getLogger(__name__)
 
 class ErrorController(BaseController):
-    """
-    Generates error documents as and when they are required.
+    """Generates error documents as and when they are required.
 
     The ErrorDocuments middleware forwards to ErrorController when error
     related status codes are returned from the application.
 
-    This behaviour can be altered by changing the parameters to the
+    This behavior can be altered by changing the parameters to the
     ErrorDocuments middleware in your config/middleware.py file.
     """
+
     def __before__(self):
         pass#disable all base actions since we don't need them here
-        
+
     def document(self):
         resp = request.environ.get('pylons.original_response')
-        
+
         log.debug('### %s ###', resp.status)
 
         e = request.environ
@@ -36,7 +61,7 @@
                                                 'host':e.get('HTTP_HOST'),
                                                 }
 
-                
+
         c.error_message = cgi.escape(request.GET.get('code', str(resp.status)))
         c.error_explanation = self.get_error_explanation(resp.status_int)
 
@@ -74,7 +99,7 @@
         if code == 400:
             return _('The request could not be understood by the server due to malformed syntax.')
         if code == 401:
-            return _('Unathorized access to resource')
+            return _('Unauthorized access to resource')
         if code == 403:
             return _("You don't have permission to view this page")
         if code == 404:
--- a/rhodecode/controllers/feed.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/feed.py	Sat Dec 18 14:45:58 2010 +0100
@@ -24,7 +24,7 @@
 """
 from pylons import tmpl_context as c, url, response
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.hg_model import HgModel
+from rhodecode.model.scm import ScmModel
 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
 import logging
 log = logging.getLogger(__name__)
@@ -49,12 +49,12 @@
                          language=self.language,
                          ttl=self.ttl)
         
-        changesets = HgModel().get_repo(repo_name)
+        changesets = ScmModel().get_repo(repo_name)
 
         for cs in changesets[:self.feed_nr]:
             feed.add_item(title=cs.message,
                           link=url('changeset_home', repo_name=repo_name,
-                                   revision=cs.short_id, qualified=True),
+                                   revision=cs.raw_id, qualified=True),
                                    description=str(cs.date))
         
         response.content_type = feed.mime_type
@@ -69,11 +69,11 @@
                          language=self.language,
                          ttl=self.ttl)
         
-        changesets = HgModel().get_repo(repo_name)
+        changesets = ScmModel().get_repo(repo_name)
         for cs in changesets[:self.feed_nr]:
             feed.add_item(title=cs.message,
                           link=url('changeset_home', repo_name=repo_name,
-                                   revision=cs.short_id, qualified=True),
+                                   revision=cs.raw_id, qualified=True),
                           description=str(cs.date))
             
         response.content_type = feed.mime_type
--- a/rhodecode/controllers/files.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/files.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# files controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.files
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+    Files controller for RhodeCode
+    
+    :created_on: Apr 21, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,107 +24,115 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on April 21, 2010
-files controller for pylons
-@author: marcink
-"""
+import tempfile
+import logging
+import rhodecode.lib.helpers as h
+
 from mercurial import archival
+
 from pylons import request, response, session, tmpl_context as c, url
 from pylons.i18n.translation import _
 from pylons.controllers.util import redirect
+
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
 from rhodecode.lib.utils import EmptyChangeset
-from rhodecode.model.hg_model import HgModel
+from rhodecode.model.scm import ScmModel
+
 from vcs.exceptions import RepositoryError, ChangesetError
 from vcs.nodes import FileNode
 from vcs.utils import diffs as differ
-import logging
-import rhodecode.lib.helpers as h
-import tempfile
-        
+
 log = logging.getLogger(__name__)
 
 class FilesController(BaseController):
-    
+
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
-                                   'repository.admin')       
+                                   'repository.admin')
     def __before__(self):
         super(FilesController, self).__before__()
-        c.file_size_limit = 250 * 1024 #limit of file size to display
+        c.cut_off_limit = self.cut_off_limit
 
     def index(self, repo_name, revision, f_path):
-        hg_model = HgModel()
-        c.repo = repo = hg_model.get_repo(c.repo_name)
+        hg_model = ScmModel()
+        c.repo = hg_model.get_repo(c.repo_name)
         revision = request.POST.get('at_rev', None) or revision
-        
+
         def get_next_rev(cur):
             max_rev = len(c.repo.revisions) - 1
             r = cur + 1
             if r > max_rev:
                 r = max_rev
             return r
-            
+
         def get_prev_rev(cur):
             r = cur - 1
             return r
 
         c.f_path = f_path
-     
-        
+
+
         try:
-            cur_rev = repo.get_changeset(revision).revision
-            prev_rev = repo.get_changeset(get_prev_rev(cur_rev)).short_id
-            next_rev = repo.get_changeset(get_next_rev(cur_rev)).short_id
-                    
+            c.changeset = c.repo.get_changeset(revision)
+            cur_rev = c.changeset.revision
+            prev_rev = c.repo.get_changeset(get_prev_rev(cur_rev)).raw_id
+            next_rev = c.repo.get_changeset(get_next_rev(cur_rev)).raw_id
+
             c.url_prev = url('files_home', repo_name=c.repo_name,
-                             revision=prev_rev, f_path=f_path) 
+                             revision=prev_rev, f_path=f_path)
             c.url_next = url('files_home', repo_name=c.repo_name,
-                             revision=next_rev, f_path=f_path)   
-                    
-            c.changeset = repo.get_changeset(revision)
-                        
-            c.cur_rev = c.changeset.short_id
-            c.rev_nr = c.changeset.revision
-            c.files_list = c.changeset.get_node(f_path)
-            c.file_history = self._get_history(repo, c.files_list, f_path)
-            
-        except (RepositoryError, ChangesetError):
-            c.files_list = None
-        
+                         revision=next_rev, f_path=f_path)
+
+            try:
+                c.files_list = c.changeset.get_node(f_path)
+                c.file_history = self._get_history(c.repo, c.files_list, f_path)
+            except RepositoryError, e:
+                h.flash(str(e), category='warning')
+                redirect(h.url('files_home', repo_name=repo_name, revision=revision))
+
+        except RepositoryError, e:
+            h.flash(str(e), category='warning')
+            redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
+
+
+
         return render('files/files.html')
 
     def rawfile(self, repo_name, revision, f_path):
-        hg_model = HgModel()
+        hg_model = ScmModel()
         c.repo = hg_model.get_repo(c.repo_name)
         file_node = c.repo.get_changeset(revision).get_node(f_path)
         response.content_type = file_node.mimetype
         response.content_disposition = 'attachment; filename=%s' \
-                                                    % f_path.split('/')[-1] 
+                                                    % f_path.split('/')[-1]
         return file_node.content
 
     def raw(self, repo_name, revision, f_path):
-        hg_model = HgModel()
+        hg_model = ScmModel()
         c.repo = hg_model.get_repo(c.repo_name)
         file_node = c.repo.get_changeset(revision).get_node(f_path)
         response.content_type = 'text/plain'
-        
+
         return file_node.content
-    
+
     def annotate(self, repo_name, revision, f_path):
-        hg_model = HgModel()
+        hg_model = ScmModel()
         c.repo = hg_model.get_repo(c.repo_name)
-        cs = c.repo.get_changeset(revision)
-        c.file = cs.get_node(f_path)
-        c.file_msg = cs.get_file_message(f_path)
-        c.cur_rev = cs.short_id
-        c.rev_nr = cs.revision        
+
+        try:
+            c.cs = c.repo.get_changeset(revision)
+            c.file = c.cs.get_node(f_path)
+        except RepositoryError, e:
+            h.flash(str(e), category='warning')
+            redirect(h.url('files_home', repo_name=repo_name, revision=revision))
+
+        c.file_history = self._get_history(c.repo, c.file, f_path)
+
         c.f_path = f_path
 
         return render('files/files_annotate.html')
-      
+
     def archivefile(self, repo_name, revision, fileformat):
         archive_specs = {
           '.tar.bz2': ('application/x-tar', 'tbz2'),
@@ -126,7 +141,7 @@
         }
         if not archive_specs.has_key(fileformat):
             return 'Unknown archive type %s' % fileformat
-                        
+
         def read_in_chunks(file_object, chunk_size=1024 * 40):
             """Lazy function (generator) to read a file piece by piece.
             Default chunk size: 40k."""
@@ -134,10 +149,10 @@
                 data = file_object.read(chunk_size)
                 if not data:
                     break
-                yield data        
-            
+                yield data
+
         archive = tempfile.TemporaryFile()
-        repo = HgModel().get_repo(repo_name).repo
+        repo = ScmModel().get_repo(repo_name).repo
         fname = '%s-%s%s' % (repo_name, revision, fileformat)
         archival.archive(repo, archive, revision, archive_specs[fileformat][1],
                          prefix='%s-%s' % (repo_name, revision))
@@ -145,9 +160,9 @@
         response.content_disposition = 'attachment; filename=%s' % fname
         archive.seek(0)
         return read_in_chunks(archive)
-    
+
     def diff(self, repo_name, f_path):
-        hg_model = HgModel()
+        hg_model = ScmModel()
         diff1 = request.GET.get('diff1')
         diff2 = request.GET.get('diff2')
         c.action = request.GET.get('diff')
@@ -162,7 +177,7 @@
             else:
                 c.changeset_1 = EmptyChangeset()
                 node1 = FileNode('.', '', changeset=c.changeset_1)
-                
+
             if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
                 c.changeset_2 = c.repo.get_changeset(diff2)
                 node2 = c.changeset_2.get_node(f_path)
@@ -173,43 +188,66 @@
             return redirect(url('files_home',
                                 repo_name=c.repo_name, f_path=f_path))
 
-        c.diff1 = 'r%s:%s' % (c.changeset_1.revision, c.changeset_1.short_id)
-        c.diff2 = 'r%s:%s' % (c.changeset_2.revision, c.changeset_2.short_id)
-        
         f_udiff = differ.get_udiff(node1, node2)
         diff = differ.DiffProcessor(f_udiff)
-                                
+
         if c.action == 'download':
             diff_name = '%s_vs_%s.diff' % (diff1, diff2)
             response.content_type = 'text/plain'
             response.content_disposition = 'attachment; filename=%s' \
-                                                    % diff_name             
+                                                    % diff_name
             return diff.raw_diff()
-        
+
         elif c.action == 'raw':
-            c.cur_diff = '<pre class="raw">%s</pre>' % h.escape(diff.raw_diff())
+            response.content_type = 'text/plain'
+            return diff.raw_diff()
+
         elif c.action == 'diff':
-            if node1.size > c.file_size_limit or node2.size > c.file_size_limit:
+            if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
                 c.cur_diff = _('Diff is to big to display')
             else:
                 c.cur_diff = diff.as_html()
         else:
             #default option
-            if node1.size > c.file_size_limit or node2.size > c.file_size_limit:
+            if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
                 c.cur_diff = _('Diff is to big to display')
             else:
                 c.cur_diff = diff.as_html()
-        
-        if not c.cur_diff: c.no_changes = True    
+
+        if not c.cur_diff: c.no_changes = True
         return render('files/file_diff.html')
-    
+
     def _get_history(self, repo, node, f_path):
         from vcs.nodes import NodeKind
         if not node.kind is NodeKind.FILE:
             return []
         changesets = node.history
         hist_l = []
+
+        changesets_group = ([], _("Changesets"))
+        branches_group = ([], _("Branches"))
+        tags_group = ([], _("Tags"))
+
         for chs in changesets:
             n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
-            hist_l.append((chs.short_id, n_desc,))
+            changesets_group[0].append((chs.raw_id, n_desc,))
+
+        hist_l.append(changesets_group)
+
+        for name, chs in c.repository_branches.items():
+            #chs = chs.split(':')[-1]
+            branches_group[0].append((chs, name),)
+        hist_l.append(branches_group)
+
+        for name, chs in c.repository_tags.items():
+            #chs = chs.split(':')[-1]
+            tags_group[0].append((chs, name),)
+        hist_l.append(tags_group)
+
         return hist_l
+
+#                [
+#                 ([("u1", "User1"), ("u2", "User2")], "Users"),
+#                 ([("g1", "Group1"), ("g2", "Group2")], "Groups")
+#                 ]
+
--- a/rhodecode/controllers/hg.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# hg controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# 
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; version 2
-# of the License or (at your opinion) any later version of the license.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA  02110-1301, USA.
-"""
-Created on February 18, 2010
-hg controller for pylons
-@author: marcink
-"""
-from operator import itemgetter
-from pylons import tmpl_context as c, request
-from rhodecode.lib.auth import LoginRequired
-from rhodecode.lib.base import BaseController, render
-from rhodecode.model.hg_model import HgModel
-import logging
-log = logging.getLogger(__name__)
-
-class HgController(BaseController):
-
-    @LoginRequired()
-    def __before__(self):
-        super(HgController, self).__before__()
-        
-    def index(self):
-        sortables = ['name', 'description', 'last_change', 'tip', 'contact']
-        current_sort = request.GET.get('sort', 'name')
-        current_sort_slug = current_sort.replace('-', '')
-        
-        if current_sort_slug not in sortables:
-            c.sort_by = 'name'
-            current_sort_slug = c.sort_by
-        else:
-            c.sort_by = current_sort
-        c.sort_slug = current_sort_slug
-        cached_repo_list = HgModel().get_repos()
-        
-        sort_key = current_sort_slug + '_sort'
-        if c.sort_by.startswith('-'):
-            c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=True)
-        else:
-            c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=False)
-            
-        return render('/index.html')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/controllers/home.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# hg controller for pylons
+# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+"""
+Created on February 18, 2010
+hg controller for pylons
+@author: marcink
+"""
+from operator import itemgetter
+from pylons import tmpl_context as c, request
+from rhodecode.lib.auth import LoginRequired
+from rhodecode.lib.base import BaseController, render
+from rhodecode.model.scm import ScmModel
+import logging
+log = logging.getLogger(__name__)
+
+class HomeController(BaseController):
+
+    @LoginRequired()
+    def __before__(self):
+        super(HomeController, self).__before__()
+
+    def index(self):
+        sortables = ['name', 'description', 'last_change', 'tip', 'contact']
+        current_sort = request.GET.get('sort', 'name')
+        current_sort_slug = current_sort.replace('-', '')
+
+        if current_sort_slug not in sortables:
+            c.sort_by = 'name'
+            current_sort_slug = c.sort_by
+        else:
+            c.sort_by = current_sort
+        c.sort_slug = current_sort_slug
+        cached_repo_list = ScmModel().get_repos()
+
+        sort_key = current_sort_slug + '_sort'
+        if c.sort_by.startswith('-'):
+            c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=True)
+        else:
+            c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=False)
+
+        return render('/index.html')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/controllers/journal.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# journal controller for pylons
+# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+"""
+Created on November 21, 2010
+journal controller for pylons
+@author: marcink
+"""
+
+from pylons import request, response, session, tmpl_context as c, url
+from pylons.controllers.util import abort, redirect
+from rhodecode.lib.auth import LoginRequired, NotAnonymous
+from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.helpers import get_token
+from rhodecode.model.db import UserLog, UserFollowing
+from rhodecode.model.scm import ScmModel
+from sqlalchemy import or_
+import logging
+from paste.httpexceptions import HTTPInternalServerError, HTTPNotFound
+
+log = logging.getLogger(__name__)
+
+class JournalController(BaseController):
+
+
+    @LoginRequired()
+    @NotAnonymous()
+    def __before__(self):
+        super(JournalController, self).__before__()
+
+    def index(self):
+        # Return a rendered template
+
+        c.following = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.user_id == c.rhodecode_user.user_id).all()
+
+        repo_ids = [x.follows_repository.repo_id for x in c.following
+                    if x.follows_repository is not None]
+        user_ids = [x.follows_user.user_id for x in c.following
+                    if x.follows_user is not None]
+
+        c.journal = self.sa.query(UserLog)\
+            .filter(or_(
+                        UserLog.repository_id.in_(repo_ids),
+                        UserLog.user_id.in_(user_ids),
+                        ))\
+            .order_by(UserLog.action_date.desc())\
+            .limit(20)\
+            .all()
+        return render('/journal.html')
+
+    def toggle_following(self):
+
+        if request.POST.get('auth_token') == get_token():
+            scm_model = ScmModel()
+
+            user_id = request.POST.get('follows_user_id')
+            if user_id:
+                try:
+                    scm_model.toggle_following_user(user_id,
+                                                    c.rhodecode_user.user_id)
+                    return 'ok'
+                except:
+                    raise HTTPInternalServerError()
+
+            repo_id = request.POST.get('follows_repo_id')
+            if repo_id:
+                try:
+                    scm_model.toggle_following_repo(repo_id,
+                                                    c.rhodecode_user.user_id)
+                    return 'ok'
+                except:
+                    raise HTTPInternalServerError()
+
+
+
+        raise HTTPInternalServerError()
--- a/rhodecode/controllers/login.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/login.py	Sat Dec 18 14:45:58 2010 +0100
@@ -28,10 +28,10 @@
 from pylons.controllers.util import abort, redirect
 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
-import rhodecode.lib.helpers as h 
+import rhodecode.lib.helpers as h
 from pylons.i18n.translation import _
 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
-from rhodecode.model.user_model import UserModel
+from rhodecode.model.user import UserModel
 import formencode
 import logging
 
@@ -45,17 +45,19 @@
     def index(self):
         #redirect if already logged in
         c.came_from = request.GET.get('came_from', None)
-        
-        if c.rhodecode_user.is_authenticated:
-            return redirect(url('hg_home'))
-        
+
+        if c.rhodecode_user.is_authenticated \
+                            and c.rhodecode_user.username != 'default':
+
+            return redirect(url('home'))
+
         if request.POST:
             #import Login Form validator class
             login_form = LoginForm()
             try:
                 c.form_result = login_form.to_python(dict(request.POST))
                 username = c.form_result['username']
-                user = UserModel().get_user_by_name(username)
+                user = UserModel().get_by_username(username, case_insensitive=True)
                 auth_user = AuthUser()
                 auth_user.username = user.username
                 auth_user.is_authenticated = True
@@ -66,14 +68,14 @@
                 session['rhodecode_user'] = auth_user
                 session.save()
                 log.info('user %s is now authenticated', username)
-                
+
                 user.update_lastlogin()
-                                        
+
                 if c.came_from:
                     return redirect(c.came_from)
                 else:
-                    return redirect(url('hg_home'))
-                               
+                    return redirect(url('home'))
+
             except formencode.Invalid, errors:
                 return htmlfill.render(
                     render('/login.html'),
@@ -81,30 +83,30 @@
                     errors=errors.error_dict or {},
                     prefix_error=False,
                     encoding="UTF-8")
-                        
+
         return render('/login.html')
-    
+
     @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
                                'hg.register.manual_activate')
     def register(self):
         user_model = UserModel()
         c.auto_active = False
-        for perm in user_model.get_default().user_perms:
+        for perm in user_model.get_by_username('default', cache=False).user_perms:
             if perm.permission.permission_name == 'hg.register.auto_activate':
                 c.auto_active = True
                 break
-                        
+
         if request.POST:
-                
+
             register_form = RegisterForm()()
             try:
                 form_result = register_form.to_python(dict(request.POST))
                 form_result['active'] = c.auto_active
                 user_model.create_registration(form_result)
                 h.flash(_('You have successfully registered into rhodecode'),
-                            category='success')                
+                            category='success')
                 return redirect(url('login_home'))
-                               
+
             except formencode.Invalid, errors:
                 return htmlfill.render(
                     render('/register.html'),
@@ -112,21 +114,21 @@
                     errors=errors.error_dict or {},
                     prefix_error=False,
                     encoding="UTF-8")
-        
+
         return render('/register.html')
 
     def password_reset(self):
         user_model = UserModel()
         if request.POST:
-                
+
             password_reset_form = PasswordResetForm()()
             try:
                 form_result = password_reset_form.to_python(dict(request.POST))
                 user_model.reset_password(form_result)
                 h.flash(_('Your new password was sent'),
-                            category='success')                 
+                            category='success')
                 return redirect(url('login_home'))
-                               
+
             except formencode.Invalid, errors:
                 return htmlfill.render(
                     render('/password_reset.html'),
@@ -134,11 +136,11 @@
                     errors=errors.error_dict or {},
                     prefix_error=False,
                     encoding="UTF-8")
-        
+
         return render('/password_reset.html')
-        
+
     def logout(self):
         session['rhodecode_user'] = AuthUser()
         session.save()
         log.info('Logging out and setting user as Empty')
-        redirect(url('hg_home'))
+        redirect(url('home'))
--- a/rhodecode/controllers/search.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/search.py	Sat Dec 18 14:45:58 2010 +0100
@@ -22,11 +22,11 @@
 search controller for pylons
 @author: marcink
 """
-from pylons import request, response, session, tmpl_context as c, url
+from pylons import request, response, config, session, tmpl_context as c, url
 from pylons.controllers.util import abort, redirect
 from rhodecode.lib.auth import LoginRequired
 from rhodecode.lib.base import BaseController, render
-from rhodecode.lib.indexers import IDX_LOCATION, SCHEMA, IDX_NAME, ResultWrapper
+from rhodecode.lib.indexers import SCHEMA, IDX_NAME, ResultWrapper
 from webhelpers.paginate import Page
 from webhelpers.util import update_params
 from pylons.i18n.translation import _
@@ -42,7 +42,7 @@
 
     @LoginRequired()
     def __before__(self):
-        super(SearchController, self).__before__()    
+        super(SearchController, self).__before__()
 
     def index(self, search_repo=None):
         c.repo_name = search_repo
@@ -56,15 +56,16 @@
                                       'repository':'repository'}\
                                       .get(c.cur_type, 'content')
 
-        
+
         if c.cur_query:
             cur_query = c.cur_query.lower()
-        
+
         if c.cur_query:
             p = int(request.params.get('page', 1))
             highlight_items = set()
             try:
-                idx = open_dir(IDX_LOCATION, indexname=IDX_NAME)
+                idx = open_dir(config['app_conf']['index_dir']
+                               , indexname=IDX_NAME)
                 searcher = idx.searcher()
 
                 qp = QueryParser(search_type, schema=SCHEMA)
@@ -72,7 +73,7 @@
                     cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
                 try:
                     query = qp.parse(unicode(cur_query))
-                    
+
                     if isinstance(query, Phrase):
                         highlight_items.update(query.words)
                     else:
@@ -81,14 +82,14 @@
                                 highlight_items.add(i[1])
 
                     matcher = query.matcher(searcher)
-                    
+
                     log.debug(query)
                     log.debug(highlight_items)
                     results = searcher.search(query)
                     res_ln = len(results)
                     c.runtime = '%s results (%.3f seconds)' \
                         % (res_ln, results.runtime)
-                    
+
                     def url_generator(**kw):
                         return update_params("?q=%s&type=%s" \
                                            % (c.cur_query, c.cur_search), **kw)
@@ -98,8 +99,8 @@
                                               highlight_items),
                                 page=p, item_count=res_ln,
                                 items_per_page=10, url=url_generator)
-                     
-                    
+
+
                 except QueryParserError:
                     c.runtime = _('Invalid search query. Try quoting it.')
                 searcher.close()
@@ -107,6 +108,6 @@
                 log.error(traceback.format_exc())
                 log.error('Empty Index data')
                 c.runtime = _('There is no index to search in. Please run whoosh indexer')
-                        
+
         # Return a rendered template
         return render('/search/search.html')
--- a/rhodecode/controllers/settings.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/settings.py	Sat Dec 18 14:45:58 2010 +0100
@@ -30,7 +30,7 @@
 from rhodecode.lib.base import BaseController, render
 from rhodecode.lib.utils import invalidate_cache, action_logger
 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
-from rhodecode.model.repo_model import RepoModel
+from rhodecode.model.repo import RepoModel
 import formencode
 import logging
 import rhodecode.lib.helpers as h
@@ -41,35 +41,35 @@
 class SettingsController(BaseController):
 
     @LoginRequired()
-    @HasRepoPermissionAllDecorator('repository.admin')           
+    @HasRepoPermissionAllDecorator('repository.admin')
     def __before__(self):
         super(SettingsController, self).__before__()
-        
+
     def index(self, repo_name):
         repo_model = RepoModel()
-        c.repo_info = repo = repo_model.get(repo_name)
+        c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
         if not repo:
-            h.flash(_('%s repository is not mapped to db perhaps' 
+            h.flash(_('%s repository is not mapped to db perhaps'
                       ' it was created or renamed from the filesystem'
                       ' please run the application again'
                       ' in order to rescan repositories') % repo_name,
                       category='error')
-        
-            return redirect(url('hg_home'))        
-        defaults = c.repo_info.__dict__
+
+            return redirect(url('home'))
+        defaults = c.repo_info.get_dict()
         defaults.update({'user':c.repo_info.user.username})
         c.users_array = repo_model.get_users_js()
-        
+
         for p in c.repo_info.repo_to_perm:
-            defaults.update({'perm_%s' % p.user.username: 
+            defaults.update({'perm_%s' % p.user.username:
                              p.permission.permission_name})
-            
+
         return htmlfill.render(
             render('settings/repo_settings.html'),
             defaults=defaults,
             encoding="UTF-8",
             force_defaults=False
-        )  
+        )
 
     def update(self, repo_name):
         repo_model = RepoModel()
@@ -78,12 +78,14 @@
         try:
             form_result = _form.to_python(dict(request.POST))
             repo_model.update(repo_name, form_result)
-            invalidate_cache('cached_repo_list')
+            invalidate_cache('get_repo_cached_%s' % repo_name)
             h.flash(_('Repository %s updated successfully' % repo_name),
                     category='success')
-            changed_name = form_result['repo_name']               
+            changed_name = form_result['repo_name']
+            action_logger(self.rhodecode_user, 'user_updated_repo',
+                              changed_name, '', self.sa)
         except formencode.Invalid, errors:
-            c.repo_info = repo_model.get(repo_name)
+            c.repo_info = repo_model.get_by_repo_name(repo_name)
             c.users_array = repo_model.get_users_js()
             errors.value.update({'user':c.repo_info.user.username})
             return htmlfill.render(
@@ -91,17 +93,17 @@
                 defaults=errors.value,
                 errors=errors.error_dict or {},
                 prefix_error=False,
-                encoding="UTF-8") 
+                encoding="UTF-8")
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('error occured during update of repository %s') \
+            h.flash(_('error occurred during update of repository %s') \
                     % repo_name, category='error')
-                    
+
         return redirect(url('repo_settings_home', repo_name=changed_name))
 
 
 
-    def delete(self, repo_name):    
+    def delete(self, repo_name):
         """DELETE /repos/repo_name: Delete an existing item"""
         # Forms posted to this method should contain a hidden field:
         #    <input type="hidden" name="_method" value="DELETE" />
@@ -109,67 +111,68 @@
         #    h.form(url('repo_settings_delete', repo_name=ID),
         #           method='delete')
         # url('repo_settings_delete', repo_name=ID)
-        
+
         repo_model = RepoModel()
-        repo = repo_model.get(repo_name)
+        repo = repo_model.get_by_repo_name(repo_name)
         if not repo:
-            h.flash(_('%s repository is not mapped to db perhaps' 
+            h.flash(_('%s repository is not mapped to db perhaps'
                       ' it was moved or renamed  from the filesystem'
                       ' please run the application again'
                       ' in order to rescan repositories') % repo_name,
                       category='error')
-        
-            return redirect(url('hg_home'))
+
+            return redirect(url('home'))
         try:
             action_logger(self.rhodecode_user, 'user_deleted_repo',
-                              repo_name, '', self.sa)            
-            repo_model.delete(repo)            
-            invalidate_cache('cached_repo_list')
+                              repo_name, '', self.sa)
+            repo_model.delete(repo)
+            invalidate_cache('get_repo_cached_%s' % repo_name)
             h.flash(_('deleted repository %s') % repo_name, category='success')
         except Exception:
             h.flash(_('An error occurred during deletion of %s') % repo_name,
                     category='error')
-        
-        return redirect(url('hg_home'))
-    
+
+        return redirect(url('home'))
+
     def fork(self, repo_name):
         repo_model = RepoModel()
-        c.repo_info = repo = repo_model.get(repo_name)
+        c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
         if not repo:
-            h.flash(_('%s repository is not mapped to db perhaps' 
+            h.flash(_('%s repository is not mapped to db perhaps'
                       ' it was created or renamed from the filesystem'
                       ' please run the application again'
                       ' in order to rescan repositories') % repo_name,
                       category='error')
-        
-            return redirect(url('hg_home'))
-        
+
+            return redirect(url('home'))
+
         return render('settings/repo_fork.html')
-    
-    
-    
+
+
+
     def fork_create(self, repo_name):
         repo_model = RepoModel()
-        c.repo_info = repo_model.get(repo_name)
-        _form = RepoForkForm()()
+        c.repo_info = repo_model.get_by_repo_name(repo_name)
+        _form = RepoForkForm(old_data={'repo_type':c.repo_info.repo_type})()
         form_result = {}
         try:
             form_result = _form.to_python(dict(request.POST))
             form_result.update({'repo_name':repo_name})
             repo_model.create_fork(form_result, c.rhodecode_user)
-            h.flash(_('fork %s repository as %s task added') \
+            h.flash(_('forked %s repository as %s') \
                       % (repo_name, form_result['fork_name']),
                     category='success')
-            action_logger(self.rhodecode_user, 'user_forked_repo',
-                            repo_name, '', self.sa)                                                 
+            action_logger(self.rhodecode_user,
+                          'user_forked_repo:%s' % form_result['fork_name'],
+                           repo_name, '', self.sa)
         except formencode.Invalid, errors:
             c.new_repo = errors.value['fork_name']
             r = render('settings/repo_fork.html')
-            
+
             return htmlfill.render(
                 r,
                 defaults=errors.value,
                 errors=errors.error_dict or {},
                 prefix_error=False,
-                encoding="UTF-8")   
-        return redirect(url('hg_home'))
+                encoding="UTF-8")
+        return redirect(url('home'))
--- a/rhodecode/controllers/shortlog.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/shortlog.py	Sat Dec 18 14:45:58 2010 +0100
@@ -25,7 +25,7 @@
 from pylons import tmpl_context as c, request
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.hg_model import HgModel
+from rhodecode.model.scm import ScmModel
 from webhelpers.paginate import Page
 import logging
 log = logging.getLogger(__name__)
@@ -40,7 +40,7 @@
         
     def index(self):
         p = int(request.params.get('page', 1))
-        repo = HgModel().get_repo(c.repo_name)
+        repo = ScmModel().get_repo(c.repo_name)
         c.repo_changesets = Page(repo, page=p, items_per_page=20)
         c.shortlog_data = render('shortlog/shortlog_data.html')
         if request.params.get('partial'):
--- a/rhodecode/controllers/summary.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/summary.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# summary controller for pylons
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# 
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.controllers.summary
+    ~~~~~~~~~~~~~~
+
+    Summary controller for Rhodecode
+    
+    :created_on: Apr 18, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,24 +24,29 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-"""
-Created on April 18, 2010
-summary controller for pylons
-@author: marcink
-"""
+
+import calendar
+import logging
+from time import mktime
+from datetime import datetime, timedelta
+
+from vcs.exceptions import ChangesetError
+
 from pylons import tmpl_context as c, request, url
+from pylons.i18n.translation import _
+
+from rhodecode.model.scm import ScmModel
+from rhodecode.model.db import Statistics
+
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
-from rhodecode.lib.utils import OrderedDict
-from rhodecode.model.hg_model import HgModel
-from rhodecode.model.db import Statistics
-from webhelpers.paginate import Page
+from rhodecode.lib.utils import OrderedDict, EmptyChangeset
+
 from rhodecode.lib.celerylib import run_task
 from rhodecode.lib.celerylib.tasks import get_commits_stats
-from datetime import datetime, timedelta
-from time import mktime
-import calendar
-import logging
+
+from webhelpers.paginate import Page
+
 try:
     import json
 except ImportError:
@@ -43,66 +55,90 @@
 log = logging.getLogger(__name__)
 
 class SummaryController(BaseController):
-    
+
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
-                                   'repository.admin')           
+                                   'repository.admin')
     def __before__(self):
         super(SummaryController, self).__before__()
-                
+
     def index(self):
-        hg_model = HgModel()
-        c.repo_info = hg_model.get_repo(c.repo_name)
-        c.repo_changesets = Page(list(c.repo_info[:10]), page=1, items_per_page=20)
+        scm_model = ScmModel()
+        c.repo_info = scm_model.get_repo(c.repo_name)
+        c.following = scm_model.is_following_repo(c.repo_name,
+                                             c.rhodecode_user.user_id)
+        def url_generator(**kw):
+            return url('shortlog_home', repo_name=c.repo_name, **kw)
+
+        c.repo_changesets = Page(c.repo_info, page=1, items_per_page=10,
+                                 url=url_generator)
+
         e = request.environ
-            
-        uri = u'%(protocol)s://%(user)s@%(host)s%(prefix)s/%(repo_name)s' % {
+
+        if self.rhodecode_user.username == 'default':
+            password = ':default'
+        else:
+            password = ''
+
+        uri = u'%(protocol)s://%(user)s%(password)s@%(host)s%(prefix)s/%(repo_name)s' % {
                                         'protocol': e.get('wsgi.url_scheme'),
                                         'user':str(c.rhodecode_user.username),
+                                        'password':password,
                                         'host':e.get('HTTP_HOST'),
                                         'prefix':e.get('SCRIPT_NAME'),
                                         'repo_name':c.repo_name, }
         c.clone_repo_url = uri
         c.repo_tags = OrderedDict()
         for name, hash in c.repo_info.tags.items()[:10]:
-            c.repo_tags[name] = c.repo_info.get_changeset(hash)
-        
+            try:
+                c.repo_tags[name] = c.repo_info.get_changeset(hash)
+            except ChangesetError:
+                c.repo_tags[name] = EmptyChangeset(hash)
+
         c.repo_branches = OrderedDict()
         for name, hash in c.repo_info.branches.items()[:10]:
-            c.repo_branches[name] = c.repo_info.get_changeset(hash)
-        
-        td = datetime.today() + timedelta(days=1) 
+            try:
+                c.repo_branches[name] = c.repo_info.get_changeset(hash)
+            except ChangesetError:
+                c.repo_branches[name] = EmptyChangeset(hash)
+
+        td = datetime.today() + timedelta(days=1)
         y, m, d = td.year, td.month, td.day
-        
+
         ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
                             d, 0, 0, 0, 0, 0, 0,))
         ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
                             d, 0, 0, 0, 0, 0, 0,))
-        
+
         ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
-            
-        run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
+        if c.repo_info.dbrepo.enable_statistics:
+            c.no_data_msg = _('No data loaded yet')
+            run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
+        else:
+            c.no_data_msg = _('Statistics update are disabled for this repository')
         c.ts_min = ts_min_m
         c.ts_max = ts_max_y
-        
+
         stats = self.sa.query(Statistics)\
             .filter(Statistics.repository == c.repo_info.dbrepo)\
             .scalar()
-        
-        
+
+
         if stats and stats.languages:
+            c.no_data = False is c.repo_info.dbrepo.enable_statistics
             lang_stats = json.loads(stats.languages)
             c.commit_data = stats.commit_activity
             c.overview_data = stats.commit_activity_combined
             c.trending_languages = json.dumps(OrderedDict(
                                        sorted(lang_stats.items(), reverse=True,
-                                            key=lambda k: k[1])[:2]
+                                            key=lambda k: k[1])[:10]
                                         )
                                     )
         else:
             c.commit_data = json.dumps({})
-            c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 0] ])
+            c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10] ])
             c.trending_languages = json.dumps({})
-        
+            c.no_data = True
+
         return render('summary/summary.html')
 
--- a/rhodecode/controllers/tags.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/controllers/tags.py	Sat Dec 18 14:45:58 2010 +0100
@@ -26,7 +26,7 @@
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
 from rhodecode.lib.utils import OrderedDict
-from rhodecode.model.hg_model import HgModel
+from rhodecode.model.scm import ScmModel
 import logging
 log = logging.getLogger(__name__)
 
@@ -38,7 +38,7 @@
         super(TagsController, self).__before__()
         
     def index(self):
-        hg_model = HgModel()
+        hg_model = ScmModel()
         c.repo_info = hg_model.get_repo(c.repo_name)
         c.repo_tags = OrderedDict()
         for name, hash_ in c.repo_info.tags.items():
--- a/rhodecode/lib/app_globals.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/app_globals.py	Sat Dec 18 14:45:58 2010 +0100
@@ -19,13 +19,13 @@
         self.cache = CacheManager(**parse_cache_config_options(config))
         self.available_permissions = None   # propagated after init_model
         self.baseui = None                  # propagated after init_model        
-        
+
     @LazyProperty
     def paths(self):
         if self.baseui:
             return self.baseui.configitems('paths')
-    
+
     @LazyProperty
     def base_path(self):
         if self.baseui:
-            return self.paths[0][1].replace('*', '')            
+            return self.paths[0][1]
--- a/rhodecode/lib/auth.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/auth.py	Sat Dec 18 14:45:58 2010 +0100
@@ -22,22 +22,23 @@
 
 @author: marcink
 """
-from beaker.cache import cache_region
 from pylons import config, session, url, request
 from pylons.controllers.util import abort, redirect
+from rhodecode.lib.exceptions import *
 from rhodecode.lib.utils import get_repo_slug
+from rhodecode.lib.auth_ldap import AuthLdap
 from rhodecode.model import meta
+from rhodecode.model.user import UserModel
 from rhodecode.model.caching_query import FromCache
 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
     UserToPerm
-from sqlalchemy.exc import OperationalError
-from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
 import bcrypt
 from decorator import decorator
 import logging
 import random
+import traceback
 
-log = logging.getLogger(__name__) 
+log = logging.getLogger(__name__)
 
 class PasswordGenerator(object):
     """This is a simple class for generating password from
@@ -56,7 +57,7 @@
     ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
     ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
     ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
-            
+
     def __init__(self, passwd=''):
         self.passwd = passwd
 
@@ -64,40 +65,93 @@
         self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
         return self.passwd
 
-    
+
 def get_crypt_password(password):
     """Cryptographic function used for password hashing based on sha1
     :param password: password to hash
-    """    
+    """
     return bcrypt.hashpw(password, bcrypt.gensalt(10))
 
 def check_password(password, hashed):
     return bcrypt.hashpw(password, hashed) == hashed
 
-@cache_region('super_short_term', 'cached_user')
-def get_user_cached(username):
-    sa = meta.Session
-    try:
-        user = sa.query(User).filter(User.username == username).one()
-    finally:
-        meta.Session.remove()
-    return user
+def authfunc(environ, username, password):
+    """
+    Dummy authentication function used in Mercurial/Git/ and access control,
+    
+    :param environ: needed only for using in Basic auth
+    """
+    return authenticate(username, password)
+
 
-def authfunc(environ, username, password):
-    try:
-        user = get_user_cached(username)
-    except (NoResultFound, MultipleResultsFound, OperationalError), e:
-        log.error(e)
-        user = None
-        
-    if user:
+def authenticate(username, password):
+    """
+    Authentication function used for access control,
+    firstly checks for db authentication then if ldap is enabled for ldap
+    authentication, also creates ldap user if not in database
+    
+    :param username: username
+    :param password: password
+    """
+    user_model = UserModel()
+    user = user_model.get_by_username(username, cache=False)
+
+    log.debug('Authenticating user using RhodeCode account')
+    if user is not None and user.is_ldap is False:
         if user.active:
-            if user.username == username and check_password(password, user.password):
+
+            if user.username == 'default' and user.active:
+                log.info('user %s authenticated correctly as anonymous user',
+                         username)
+                return True
+
+            elif user.username == username and check_password(password, user.password):
                 log.info('user %s authenticated correctly', username)
                 return True
         else:
-            log.error('user %s is disabled', username)
-            
+            log.warning('user %s is disabled', username)
+
+    else:
+        log.debug('Regular authentication failed')
+        user_obj = user_model.get_by_username(username, cache=False,
+                                            case_insensitive=True)
+
+        if user_obj is not None and user_obj.is_ldap is False:
+            log.debug('this user already exists as non ldap')
+            return False
+
+        from rhodecode.model.settings import SettingsModel
+        ldap_settings = SettingsModel().get_ldap_settings()
+
+        #======================================================================
+        # FALLBACK TO LDAP AUTH IN ENABLE                
+        #======================================================================
+        if ldap_settings.get('ldap_active', False):
+            log.debug("Authenticating user using ldap")
+            kwargs = {
+                  'server':ldap_settings.get('ldap_host', ''),
+                  'base_dn':ldap_settings.get('ldap_base_dn', ''),
+                  'port':ldap_settings.get('ldap_port'),
+                  'bind_dn':ldap_settings.get('ldap_dn_user'),
+                  'bind_pass':ldap_settings.get('ldap_dn_pass'),
+                  'use_ldaps':ldap_settings.get('ldap_ldaps'),
+                  'ldap_version':3,
+                  }
+            log.debug('Checking for ldap authentication')
+            try:
+                aldap = AuthLdap(**kwargs)
+                res = aldap.authenticate_ldap(username, password)
+                log.debug('Got ldap response %s', res)
+
+                if user_model.create_ldap(username, password):
+                    log.info('created new ldap user')
+
+                return True
+            except (LdapUsernameError, LdapPasswordError,):
+                pass
+            except (Exception,):
+                log.error(traceback.format_exc())
+                pass
     return False
 
 class  AuthUser(object):
@@ -114,6 +168,8 @@
         self.is_admin = False
         self.permissions = {}
 
+    def __repr__(self):
+        return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
 
 def set_available_permissions(config):
     """
@@ -125,82 +181,62 @@
     """
     log.info('getting information about all available permissions')
     try:
-        sa = meta.Session
+        sa = meta.Session()
         all_perms = sa.query(Permission).all()
+    except:
+        pass
     finally:
         meta.Session.remove()
-    
+
     config['available_permissions'] = [x.permission_name for x in all_perms]
 
 def set_base_path(config):
     config['base_path'] = config['pylons.app_globals'].base_path
 
-def fill_data(user):
-    """
-    Fills user data with those from database and log out user if not present
-    in database
-    :param user:
-    """
-    sa = meta.Session
-    dbuser = sa.query(User).options(FromCache('sql_cache_short',
-                                              'getuser_%s' % user.user_id))\
-        .get(user.user_id)
-    if dbuser:
-        user.username = dbuser.username
-        user.is_admin = dbuser.admin
-        user.name = dbuser.name
-        user.lastname = dbuser.lastname
-        user.email = dbuser.email
-    else:
-        user.is_authenticated = False
-    meta.Session.remove()
-    return user
-            
+
 def fill_perms(user):
     """
     Fills user permission attribute with permissions taken from database
     :param user:
     """
-    
-    sa = meta.Session
+
+    sa = meta.Session()
     user.permissions['repositories'] = {}
     user.permissions['global'] = set()
-    
+
     #===========================================================================
     # fetch default permissions
     #===========================================================================
-    default_user = sa.query(User)\
-        .options(FromCache('sql_cache_short','getuser_%s' % 'default'))\
-        .filter(User.username == 'default').scalar()
-                                            
+    default_user = UserModel().get_by_username('default', cache=True)
+
     default_perms = sa.query(RepoToPerm, Repository, Permission)\
         .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
         .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
         .filter(RepoToPerm.user == default_user).all()
-                                            
+
     if user.is_admin:
         #=======================================================================
         # #admin have all default rights set to admin        
         #=======================================================================
         user.permissions['global'].add('hg.admin')
-        
+
         for perm in default_perms:
             p = 'repository.admin'
             user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
-    
+
     else:
         #=======================================================================
         # set default permissions
         #=======================================================================
-        
+
         #default global
         default_global_perms = sa.query(UserToPerm)\
-            .filter(UserToPerm.user == sa.query(User).filter(User.username == 
-            'default').one())
-        
+            .filter(UserToPerm.user == sa.query(User)\
+                   .filter(User.username == 'default').one())
+
         for perm in default_global_perms:
             user.permissions['global'].add(perm.permission.permission_name)
-                    
+
         #default repositories
         for perm in default_perms:
             if perm.Repository.private and not perm.Repository.user_id == user.user_id:
@@ -211,9 +247,9 @@
                 p = 'repository.admin'
             else:
                 p = perm.Permission.permission_name
-                
+
             user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
-                                                
+
         #=======================================================================
         # #overwrite default with user permissions if any
         #=======================================================================
@@ -221,38 +257,52 @@
             .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
             .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
             .filter(RepoToPerm.user_id == user.user_id).all()
-            
+
         for perm in user_perms:
             if perm.Repository.user_id == user.user_id:#set admin if owner
                 p = 'repository.admin'
             else:
                 p = perm.Permission.permission_name
             user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
-    meta.Session.remove()         
+    meta.Session.remove()
     return user
-    
+
 def get_user(session):
     """
     Gets user from session, and wraps permissions into user
     :param session:
     """
     user = session.get('rhodecode_user', AuthUser())
+    #if the user is not logged in we check for anonymous access
+    #if user is logged and it's a default user check if we still have anonymous
+    #access enabled
+    if user.user_id is None or user.username == 'default':
+        anonymous_user = UserModel().get_by_username('default', cache=True)
+        if anonymous_user.active is True:
+            #then we set this user is logged in
+            user.is_authenticated = True
+            user.user_id = anonymous_user.user_id
+        else:
+            user.is_authenticated = False
+
     if user.is_authenticated:
-        user = fill_data(user)
+        user = UserModel().fill_data(user)
+
     user = fill_perms(user)
     session['rhodecode_user'] = user
     session.save()
     return user
-        
+
 #===============================================================================
 # CHECK DECORATORS
 #===============================================================================
 class LoginRequired(object):
-    """Must be logged in to execute this function else redirect to login page"""
-   
+    """Must be logged in to execute this function else 
+    redirect to login page"""
+
     def __call__(self, func):
         return decorator(self.__wrapper, func)
-    
+
     def __wrapper(self, func, *fargs, **fkwargs):
         user = session.get('rhodecode_user', AuthUser())
         log.debug('Checking login required for user:%s', user.username)
@@ -261,21 +311,46 @@
             return func(*fargs, **fkwargs)
         else:
             log.warn('user %s not authenticated', user.username)
-            
+
             p = ''
             if request.environ.get('SCRIPT_NAME') != '/':
                 p += request.environ.get('SCRIPT_NAME')
-                
+
             p += request.environ.get('PATH_INFO')
             if request.environ.get('QUERY_STRING'):
                 p += '?' + request.environ.get('QUERY_STRING')
-                
-            log.debug('redirecting to login page with %s', p)                
+
+            log.debug('redirecting to login page with %s', p)
             return redirect(url('login_home', came_from=p))
 
+class NotAnonymous(object):
+    """Must be logged in to execute this function else 
+    redirect to login page"""
+
+    def __call__(self, func):
+        return decorator(self.__wrapper, func)
+
+    def __wrapper(self, func, *fargs, **fkwargs):
+        user = session.get('rhodecode_user', AuthUser())
+        log.debug('Checking if user is not anonymous')
+
+        anonymous = user.username == 'default'
+
+        if anonymous:
+            p = ''
+            if request.environ.get('SCRIPT_NAME') != '/':
+                p += request.environ.get('SCRIPT_NAME')
+
+            p += request.environ.get('PATH_INFO')
+            if request.environ.get('QUERY_STRING'):
+                p += '?' + request.environ.get('QUERY_STRING')
+            return redirect(url('login_home', came_from=p))
+        else:
+            return func(*fargs, **fkwargs)
+
 class PermsDecorator(object):
     """Base class for decorators"""
-    
+
     def __init__(self, *required_perms):
         available_perms = config['available_permissions']
         for perm in required_perms:
@@ -283,32 +358,33 @@
                 raise Exception("'%s' permission is not defined" % perm)
         self.required_perms = set(required_perms)
         self.user_perms = None
-        
+
     def __call__(self, func):
         return decorator(self.__wrapper, func)
-    
-    
+
+
     def __wrapper(self, func, *fargs, **fkwargs):
 #        _wrapper.__name__ = func.__name__
 #        _wrapper.__dict__.update(func.__dict__)
 #        _wrapper.__doc__ = func.__doc__
+        self.user = session.get('rhodecode_user', AuthUser())
+        self.user_perms = self.user.permissions
+        log.debug('checking %s permissions %s for %s %s',
+           self.__class__.__name__, self.required_perms, func.__name__,
+               self.user)
 
-        self.user_perms = session.get('rhodecode_user', AuthUser()).permissions
-        log.debug('checking %s permissions %s for %s',
-           self.__class__.__name__, self.required_perms, func.__name__)
-        
         if self.check_permissions():
-            log.debug('Permission granted for %s', func.__name__)
-            
+            log.debug('Permission granted for %s %s', func.__name__, self.user)
+
             return func(*fargs, **fkwargs)
-        
+
         else:
-            log.warning('Permission denied for %s', func.__name__)
+            log.warning('Permission denied for %s %s', func.__name__, self.user)
             #redirect with forbidden ret code
             return abort(403)
 
-        
-        
+
+
     def check_permissions(self):
         """Dummy function for overriding"""
         raise Exception('You have to write this function in child class')
@@ -317,18 +393,18 @@
     """Checks for access permission for all given predicates. All of them 
     have to be meet in order to fulfill the request
     """
-        
+
     def check_permissions(self):
         if self.required_perms.issubset(self.user_perms.get('global')):
             return True
         return False
-            
+
 
 class HasPermissionAnyDecorator(PermsDecorator):
     """Checks for access permission for any of given predicates. In order to 
     fulfill the request any of predicates must be meet
     """
-    
+
     def check_permissions(self):
         if self.required_perms.intersection(self.user_perms.get('global')):
             return True
@@ -338,7 +414,7 @@
     """Checks for access permission for all given predicates for specific 
     repository. All of them have to be meet in order to fulfill the request
     """
-            
+
     def check_permissions(self):
         repo_name = get_repo_slug(request)
         try:
@@ -348,16 +424,16 @@
         if self.required_perms.issubset(user_perms):
             return True
         return False
-            
+
 
 class HasRepoPermissionAnyDecorator(PermsDecorator):
     """Checks for access permission for any of given predicates for specific 
     repository. In order to fulfill the request any of predicates must be meet
     """
-            
+
     def check_permissions(self):
         repo_name = get_repo_slug(request)
-        
+
         try:
             user_perms = set([self.user_perms['repositories'][repo_name]])
         except KeyError:
@@ -371,10 +447,10 @@
 
 class PermsFunction(object):
     """Base function for other check functions"""
-    
+
     def __init__(self, *perms):
         available_perms = config['available_permissions']
-        
+
         for perm in perms:
             if perm not in available_perms:
                 raise Exception("'%s' permission in not defined" % perm)
@@ -382,29 +458,30 @@
         self.user_perms = None
         self.granted_for = ''
         self.repo_name = None
-        
+
     def __call__(self, check_Location=''):
         user = session.get('rhodecode_user', False)
         if not user:
             return False
         self.user_perms = user.permissions
-        self.granted_for = user.username        
-        log.debug('checking %s %s', self.__class__.__name__, self.required_perms)            
-        
+        self.granted_for = user.username
+        log.debug('checking %s %s %s', self.__class__.__name__,
+                  self.required_perms, user)
+
         if self.check_permissions():
-            log.debug('Permission granted for %s @%s', self.granted_for,
-                      check_Location)
+            log.debug('Permission granted for %s @ %s %s', self.granted_for,
+                      check_Location, user)
             return True
-        
+
         else:
-            log.warning('Permission denied for %s @%s', self.granted_for,
-                        check_Location)
-            return False 
-    
+            log.warning('Permission denied for %s @ %s %s', self.granted_for,
+                        check_Location, user)
+            return False
+
     def check_permissions(self):
         """Dummy function for overriding"""
         raise Exception('You have to write this function in child class')
-        
+
 class HasPermissionAll(PermsFunction):
     def check_permissions(self):
         if self.required_perms.issubset(self.user_perms.get('global')):
@@ -418,11 +495,11 @@
         return False
 
 class HasRepoPermissionAll(PermsFunction):
-    
+
     def __call__(self, repo_name=None, check_Location=''):
         self.repo_name = repo_name
         return super(HasRepoPermissionAll, self).__call__(check_Location)
-            
+
     def check_permissions(self):
         if not self.repo_name:
             self.repo_name = get_repo_slug(request)
@@ -432,17 +509,17 @@
                                    [self.repo_name]])
         except KeyError:
             return False
-        self.granted_for = self.repo_name       
+        self.granted_for = self.repo_name
         if self.required_perms.issubset(self.user_perms):
             return True
         return False
-            
+
 class HasRepoPermissionAny(PermsFunction):
-    
+
     def __call__(self, repo_name=None, check_Location=''):
         self.repo_name = repo_name
         return super(HasRepoPermissionAny, self).__call__(check_Location)
-        
+
     def check_permissions(self):
         if not self.repo_name:
             self.repo_name = get_repo_slug(request)
@@ -464,13 +541,13 @@
 class HasPermissionAnyMiddleware(object):
     def __init__(self, *perms):
         self.required_perms = set(perms)
-    
+
     def __call__(self, user, repo_name):
         usr = AuthUser()
         usr.user_id = user.user_id
         usr.username = user.username
         usr.is_admin = user.admin
-        
+
         try:
             self.user_perms = set([fill_perms(usr)\
                                    .permissions['repositories'][repo_name]])
@@ -478,9 +555,9 @@
             self.user_perms = set()
         self.granted_for = ''
         self.username = user.username
-        self.repo_name = repo_name        
+        self.repo_name = repo_name
         return self.check_permissions()
-            
+
     def check_permissions(self):
         log.debug('checking mercurial protocol '
                   'permissions for user:%s repository:%s',
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/auth_ldap.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# ldap authentication lib
+# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+"""
+Created on Nov 17, 2010
+
+@author: marcink
+"""
+
+from rhodecode.lib.exceptions import *
+import logging
+
+log = logging.getLogger(__name__)
+
+try:
+    import ldap
+except ImportError:
+    pass
+
+class AuthLdap(object):
+
+    def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
+                 use_ldaps=False, ldap_version=3):
+        self.ldap_version = ldap_version
+        if use_ldaps:
+            port = port or 689
+        self.LDAP_USE_LDAPS = use_ldaps
+        self.LDAP_SERVER_ADDRESS = server
+        self.LDAP_SERVER_PORT = port
+
+        #USE FOR READ ONLY BIND TO LDAP SERVER
+        self.LDAP_BIND_DN = bind_dn
+        self.LDAP_BIND_PASS = bind_pass
+
+        ldap_server_type = 'ldap'
+        if self.LDAP_USE_LDAPS:ldap_server_type = ldap_server_type + 's'
+        self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
+                                               self.LDAP_SERVER_ADDRESS,
+                                               self.LDAP_SERVER_PORT)
+
+        self.BASE_DN = base_dn
+
+    def authenticate_ldap(self, username, password):
+        """Authenticate a user via LDAP and return his/her LDAP properties.
+    
+        Raises AuthenticationError if the credentials are rejected, or
+        EnvironmentError if the LDAP server can't be reached.
+        
+        :param username: username
+        :param password: password
+        """
+
+        from rhodecode.lib.helpers import chop_at
+
+        uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
+
+        if "," in username:
+            raise LdapUsernameError("invalid character in username: ,")
+        try:
+            ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
+            ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
+            server = ldap.initialize(self.LDAP_SERVER)
+            if self.ldap_version == 2:
+                server.protocol = ldap.VERSION2
+            else:
+                server.protocol = ldap.VERSION3
+
+            if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
+                server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
+
+            dn = self.BASE_DN % {'user':uid}
+            log.debug("Authenticating %r at %s", dn, self.LDAP_SERVER)
+            server.simple_bind_s(dn, password)
+
+            properties = server.search_s(dn, ldap.SCOPE_SUBTREE)
+            if not properties:
+                raise ldap.NO_SUCH_OBJECT()
+        except ldap.NO_SUCH_OBJECT, e:
+            log.debug("LDAP says no such user '%s' (%s)", uid, username)
+            raise LdapUsernameError()
+        except ldap.INVALID_CREDENTIALS, e:
+            log.debug("LDAP rejected password for user '%s' (%s)", uid, username)
+            raise LdapPasswordError()
+        except ldap.SERVER_DOWN, e:
+            raise LdapConnectionError("LDAP can't access authentication server")
+
+        return properties[0]
+
--- a/rhodecode/lib/base.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/base.py	Sat Dec 18 14:45:58 2010 +0100
@@ -9,30 +9,36 @@
 from rhodecode.lib import auth
 from rhodecode.lib.utils import get_repo_slug
 from rhodecode.model import meta
-from rhodecode.model.hg_model import _get_repos_cached, \
-    _get_repos_switcher_cached
+from rhodecode.model.scm import ScmModel
+from rhodecode import BACKENDS
 
 class BaseController(WSGIController):
-    
+
     def __before__(self):
         c.rhodecode_version = __version__
         c.rhodecode_name = config['rhodecode_title']
         c.repo_name = get_repo_slug(request)
-        c.cached_repo_list = _get_repos_cached()
-        c.repo_switcher_list = _get_repos_switcher_cached(c.cached_repo_list)
-        
+        c.cached_repo_list = ScmModel().get_repos()
+        c.backends = BACKENDS.keys()
+        self.cut_off_limit = int(config['cut_off_limit'])
+        self.sa = meta.Session()
+        scm_model = ScmModel(self.sa)
+        #c.unread_journal = scm_model.get_unread_journal()
+
         if c.repo_name:
-            cached_repo = c.cached_repo_list.get(c.repo_name)
-            
+            cached_repo = scm_model.get(c.repo_name)
             if cached_repo:
                 c.repository_tags = cached_repo.tags
                 c.repository_branches = cached_repo.branches
+                c.repository_followers = scm_model.get_followers(cached_repo.dbrepo.repo_id)
+                c.repository_forks = scm_model.get_forks(cached_repo.dbrepo.repo_id)
             else:
                 c.repository_tags = {}
                 c.repository_branches = {}
-                    
-        self.sa = meta.Session
-    
+                c.repository_followers = 0
+                c.repository_forks = 0
+
+
     def __call__(self, environ, start_response):
         """Invoke the Controller"""
         # WSGIController.__call__ dispatches to the Controller method
--- a/rhodecode/lib/celerylib/__init__.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/celerylib/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,14 +1,54 @@
-from rhodecode.lib.pidlock import DaemonLock, LockHeld
-from vcs.utils.lazy import LazyProperty
-from decorator import decorator
-import logging
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.lib.celerylib.__init__
+    ~~~~~~~~~~~~~~
+
+    celery libs for RhodeCode
+    
+    :created_on: Nov 27, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+
 import os
 import sys
+import socket
 import traceback
+import logging
+
 from hashlib import md5
-import socket
+from decorator import decorator
+from vcs.utils.lazy import LazyProperty
+
+from rhodecode.lib.pidlock import DaemonLock, LockHeld
+
+from pylons import  config
+
 log = logging.getLogger(__name__)
 
+def str2bool(v):
+    return v.lower() in ["yes", "true", "t", "1"] if v else None
+
+try:
+    CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
+except KeyError:
+    CELERY_ON = False
+
 class ResultWrapper(object):
     def __init__(self, task):
         self.task = task
@@ -18,27 +58,22 @@
         return self.task
 
 def run_task(task, *args, **kwargs):
-    try:
-        t = task.delay(*args, **kwargs)
-        log.info('running task %s', t.task_id)
-        return t
-    except socket.error, e:
-
+    if CELERY_ON:
         try:
-            conn_failed = e.errno == 111
-        except AttributeError:
-            conn_failed = False
+            t = task.delay(*args, **kwargs)
+            log.info('running task %s:%s', t.task_id, task)
+            return t
+        except socket.error, e:
+            if  e.errno == 111:
+                log.debug('Unable to connect to celeryd. Sync execution')
+            else:
+                log.error(traceback.format_exc())
+        except KeyError, e:
+                log.debug('Unable to connect to celeryd. Sync execution')
+        except Exception, e:
+            log.error(traceback.format_exc())
 
-        if  conn_failed:
-            log.debug('Unable to connect to celeryd. Sync execution')
-        else:
-            log.debug('Unable to connect to celeryd. Sync execution')
-
-    except KeyError, e:
-            log.debug('Unable to connect to celeryd. Sync execution')
-    except Exception, e:
-        log.error(traceback.format_exc())
-
+    log.debug('executing task %s in sync mode', task)
     return ResultWrapper(task(*args, **kwargs))
 
 
--- a/rhodecode/lib/celerylib/tasks.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/celerylib/tasks.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,14 +1,26 @@
 from celery.decorators import task
 
+import os
+import traceback
+from time import mktime
 from operator import itemgetter
+
+from pylons import config
 from pylons.i18n.translation import _
-from rhodecode.lib.celerylib import run_task, locked_task
+
+from rhodecode.lib.celerylib import run_task, locked_task, str2bool
 from rhodecode.lib.helpers import person
 from rhodecode.lib.smtp_mailer import SmtpMailer
-from rhodecode.lib.utils import OrderedDict
-from time import mktime
-from vcs.backends.hg import MercurialRepository
-import traceback
+from rhodecode.lib.utils import OrderedDict, add_cache
+from rhodecode.model import init_model
+from rhodecode.model import meta
+from rhodecode.model.db import RhodeCodeUi
+
+from vcs.backends import get_repo
+
+from sqlalchemy import engine_from_config
+
+add_cache(config)
 
 try:
     import json
@@ -16,96 +28,56 @@
     #python 2.5 compatibility
     import simplejson as json
 
-try:
-    from celeryconfig import PYLONS_CONFIG as config
-    celery_on = True
-except ImportError:
-    #if celeryconfig is not present let's just load our pylons
-    #config instead
-    from pylons import config
-    celery_on = False
-
-
 __all__ = ['whoosh_index', 'get_commits_stats',
            'reset_user_password', 'send_email']
 
+CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
+
 def get_session():
-    if celery_on:
-        from sqlalchemy import engine_from_config
-        from sqlalchemy.orm import sessionmaker, scoped_session
-        engine = engine_from_config(dict(config.items('app:main')), 'sqlalchemy.db1.')
-        sa = scoped_session(sessionmaker(bind=engine))
-    else:
-        #If we don't use celery reuse our current application Session
-        from rhodecode.model.meta import Session
-        sa = Session
-        
+    if CELERY_ON:
+        engine = engine_from_config(config, 'sqlalchemy.db1.')
+        init_model(engine)
+    sa = meta.Session()
     return sa
 
-def get_hg_settings():
-    from rhodecode.model.db import RhodeCodeSettings
-    sa = get_session()
-    ret = sa.query(RhodeCodeSettings).all()
-        
-    if not ret:
-        raise Exception('Could not get application settings !')
-    settings = {}
-    for each in ret:
-        settings['rhodecode_' + each.app_settings_name] = each.app_settings_value    
-    
-    return settings
-
-def get_hg_ui_settings():
-    from rhodecode.model.db import RhodeCodeUi
+def get_repos_path():
     sa = get_session()
-    ret = sa.query(RhodeCodeUi).all()
-        
-    if not ret:
-        raise Exception('Could not get application ui settings !')
-    settings = {}
-    for each in ret:
-        k = each.ui_key
-        v = each.ui_value
-        if k == '/':
-            k = 'root_path'
-        
-        if k.find('.') != -1:
-            k = k.replace('.', '_')
-        
-        if each.ui_section == 'hooks':
-            v = each.ui_active
-        
-        settings[each.ui_section + '_' + k] = v  
-    
-    return settings   
+    q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
+    return q.ui_value
 
 @task
 @locked_task
 def whoosh_index(repo_location, full_index):
     log = whoosh_index.get_logger()
     from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
-    WhooshIndexingDaemon(repo_location=repo_location).run(full_index=full_index)
+    index_location = config['index_dir']
+    WhooshIndexingDaemon(index_location=index_location,
+                         repo_location=repo_location, sa=get_session())\
+                         .run(full_index=full_index)
 
 @task
 @locked_task
 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
     from rhodecode.model.db import Statistics, Repository
     log = get_commits_stats.get_logger()
-    author_key_cleaner = lambda k: person(k).replace('"', "") #for js data compatibilty
-    
+
+    #for js data compatibilty
+    author_key_cleaner = lambda k: person(k).replace('"', "")
+
     commits_by_day_author_aggregate = {}
     commits_by_day_aggregate = {}
-    repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
-    repo = MercurialRepository(repos_path + repo_name)
+    repos_path = get_repos_path()
+    p = os.path.join(repos_path, repo_name)
+    repo = get_repo(p)
 
     skip_date_limit = True
-    parse_limit = 350 #limit for single task changeset parsing optimal for
+    parse_limit = 250 #limit for single task changeset parsing optimal for
     last_rev = 0
     last_cs = None
     timegetter = itemgetter('time')
-    
+
     sa = get_session()
-    
+
     dbrepo = sa.query(Repository)\
         .filter(Repository.repo_name == repo_name).scalar()
     cur_stats = sa.query(Statistics)\
@@ -114,26 +86,27 @@
         last_rev = cur_stats.stat_on_revision
     if not repo.revisions:
         return True
-    
+
     if last_rev == repo.revisions[-1] and len(repo.revisions) > 1:
-        #pass silently without any work if we're not on first revision or current
-        #state of parsing revision(from db marker) is the last revision
+        #pass silently without any work if we're not on first revision or 
+        #current state of parsing revision(from db marker) is the last revision
         return True
-    
+
     if cur_stats:
         commits_by_day_aggregate = OrderedDict(
                                        json.loads(
                                         cur_stats.commit_activity_combined))
         commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
-    
+
     log.debug('starting parsing %s', parse_limit)
-    for cnt, rev in enumerate(repo.revisions[last_rev:]):
+    lmktime = mktime
+
+    last_rev = last_rev + 1 if last_rev > 0 else last_rev
+    for rev in repo.revisions[last_rev:last_rev + parse_limit]:
         last_cs = cs = repo.get_changeset(rev)
-        k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
-                          cs.date.timetuple()[2])
-        timetupple = [int(x) for x in k.split('-')]
-        timetupple.extend([0 for _ in xrange(6)])
-        k = mktime(timetupple)
+        k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
+                      cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
+
         if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
             try:
                 l = [timegetter(x) for x in commits_by_day_author_aggregate\
@@ -141,20 +114,20 @@
                 time_pos = l.index(k)
             except ValueError:
                 time_pos = False
-                
+
             if time_pos >= 0 and time_pos is not False:
-                
+
                 datadict = commits_by_day_author_aggregate\
                     [author_key_cleaner(cs.author)]['data'][time_pos]
-                
+
                 datadict["commits"] += 1
                 datadict["added"] += len(cs.added)
                 datadict["changed"] += len(cs.changed)
                 datadict["removed"] += len(cs.removed)
-                
+
             else:
                 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
-                    
+
                     datadict = {"time":k,
                                 "commits":1,
                                 "added":len(cs.added),
@@ -163,7 +136,7 @@
                                }
                     commits_by_day_author_aggregate\
                         [author_key_cleaner(cs.author)]['data'].append(datadict)
-                                        
+
         else:
             if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
                 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
@@ -175,23 +148,15 @@
                                              "removed":len(cs.removed),
                                              }],
                                     "schema":["commits"],
-                                    }               
-    
+                                    }
+
         #gather all data by day
         if commits_by_day_aggregate.has_key(k):
             commits_by_day_aggregate[k] += 1
         else:
             commits_by_day_aggregate[k] = 1
-        
-        if cnt >= parse_limit:
-            #don't fetch to much data since we can freeze application
-            break
 
-    overview_data = []
-    for k, v in commits_by_day_aggregate.items():
-        overview_data.append([k, v])
-    overview_data = sorted(overview_data, key=itemgetter(0))
-        
+    overview_data = sorted(commits_by_day_aggregate.items(), key=itemgetter(0))
     if not commits_by_day_author_aggregate:
         commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
             "label":author_key_cleaner(repo.contact),
@@ -206,23 +171,24 @@
     log.debug('last revison %s', last_rev)
     leftovers = len(repo.revisions[last_rev:])
     log.debug('revisions to parse %s', leftovers)
-    
-    if last_rev == 0 or leftovers < parse_limit:    
+
+    if last_rev == 0 or leftovers < parse_limit:
+        log.debug('getting code trending stats')
         stats.languages = json.dumps(__get_codes_stats(repo_name))
-        
+
     stats.repository = dbrepo
     stats.stat_on_revision = last_cs.revision
-    
+
     try:
         sa.add(stats)
-        sa.commit()    
+        sa.commit()
     except:
         log.error(traceback.format_exc())
         sa.rollback()
         return False
     if len(repo.revisions) > 1:
         run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
-                            
+
     return True
 
 @task
@@ -230,7 +196,7 @@
     log = reset_user_password.get_logger()
     from rhodecode.lib import auth
     from rhodecode.model.db import User
-    
+
     try:
         try:
             sa = get_session()
@@ -244,38 +210,52 @@
                 log.info('change password for %s', user_email)
             if new_passwd is None:
                 raise Exception('unable to generate new password')
-            
+
         except:
             log.error(traceback.format_exc())
             sa.rollback()
-        
+
         run_task(send_email, user_email,
                  "Your new rhodecode password",
                  'Your new rhodecode password:%s' % (new_passwd))
         log.info('send new password mail to %s', user_email)
-        
-        
+
+
     except:
         log.error('Failed to update user password')
         log.error(traceback.format_exc())
+
     return True
 
-@task    
+@task
 def send_email(recipients, subject, body):
+    """
+    Sends an email with defined parameters from the .ini files.
+    
+    
+    :param recipients: list of recipients, it this is empty the defined email
+        address from field 'email_to' is used instead
+    :param subject: subject of the mail
+    :param body: body of the mail
+    """
     log = send_email.get_logger()
-    email_config = dict(config.items('DEFAULT')) 
+    email_config = config
+
+    if not recipients:
+        recipients = [email_config.get('email_to')]
+
     mail_from = email_config.get('app_email_from')
     user = email_config.get('smtp_username')
     passwd = email_config.get('smtp_password')
     mail_server = email_config.get('smtp_server')
     mail_port = email_config.get('smtp_port')
-    tls = email_config.get('smtp_use_tls')
-    ssl = False
-    
+    tls = str2bool(email_config.get('smtp_use_tls'))
+    ssl = str2bool(email_config.get('smtp_use_ssl'))
+
     try:
         m = SmtpMailer(mail_from, user, passwd, mail_server,
                        mail_port, ssl, tls)
-        m.send(recipients, subject, body)  
+        m.send(recipients, subject, body)
     except:
         log.error('Mail sending failed')
         log.error(traceback.format_exc())
@@ -284,45 +264,96 @@
 
 @task
 def create_repo_fork(form_data, cur_user):
-    import os
-    from rhodecode.model.repo_model import RepoModel
-    sa = get_session()
-    rm = RepoModel(sa)
-    
-    rm.create(form_data, cur_user, just_db=True, fork=True)
-    
-    repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
-    repo_path = os.path.join(repos_path, form_data['repo_name'])
+    from rhodecode.model.repo import RepoModel
+    from vcs import get_backend
+    log = create_repo_fork.get_logger()
+    repo_model = RepoModel(get_session())
+    repo_model.create(form_data, cur_user, just_db=True, fork=True)
+    repo_name = form_data['repo_name']
+    repos_path = get_repos_path()
+    repo_path = os.path.join(repos_path, repo_name)
     repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
-    
-    MercurialRepository(str(repo_fork_path), True, clone_url=str(repo_path))
+    alias = form_data['repo_type']
 
-    
+    log.info('creating repo fork %s as %s', repo_name, repo_path)
+    backend = get_backend(alias)
+    backend(str(repo_fork_path), create=True, src_url=str(repo_path))
+
 def __get_codes_stats(repo_name):
-    LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx', 'aspx', 'asx', 'axd', 'c',
-                    'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el', 'erl',
-                    'h', 'java', 'js', 'jsp', 'jspx', 'lisp',
-                    'lua', 'm', 'mako', 'ml', 'pas', 'patch', 'php', 'php3',
-                    'php4', 'phtml', 'pm', 'py', 'rb', 'rst', 's', 'sh',
-                    'tpl', 'txt', 'vim', 'wss', 'xhtml', 'xml', 'xsl', 'xslt',
-                    'yaws']
-    repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
-    repo = MercurialRepository(repos_path + repo_name)
+    LANGUAGES_EXTENSIONS_MAP = {'scm': 'Scheme', 'asmx': 'VbNetAspx', 'Rout':
+    'RConsole', 'rest': 'Rst', 'abap': 'ABAP', 'go': 'Go', 'phtml': 'HtmlPhp',
+    'ns2': 'Newspeak', 'xml': 'EvoqueXml', 'sh-session': 'BashSession', 'ads':
+    'Ada', 'clj': 'Clojure', 'll': 'Llvm', 'ebuild': 'Bash', 'adb': 'Ada',
+    'ada': 'Ada', 'c++-objdump': 'CppObjdump', 'aspx':
+    'VbNetAspx', 'ksh': 'Bash', 'coffee': 'CoffeeScript', 'vert': 'GLShader',
+    'Makefile.*': 'Makefile', 'di': 'D', 'dpatch': 'DarcsPatch', 'rake':
+    'Ruby', 'moo': 'MOOCode', 'erl-sh': 'ErlangShell', 'geo': 'GLShader',
+    'pov': 'Povray', 'bas': 'VbNet', 'bat': 'Batch', 'd': 'D', 'lisp':
+    'CommonLisp', 'h': 'C', 'rbx': 'Ruby', 'tcl': 'Tcl', 'c++': 'Cpp', 'md':
+    'MiniD', '.vimrc': 'Vim', 'xsd': 'Xml', 'ml': 'Ocaml', 'el': 'CommonLisp',
+    'befunge': 'Befunge', 'xsl': 'Xslt', 'pyx': 'Cython', 'cfm':
+    'ColdfusionHtml', 'evoque': 'Evoque', 'cfg': 'Ini', 'htm': 'Html',
+    'Makefile': 'Makefile', 'cfc': 'ColdfusionHtml', 'tex': 'Tex', 'cs':
+    'CSharp', 'mxml': 'Mxml', 'patch': 'Diff', 'apache.conf': 'ApacheConf',
+    'scala': 'Scala', 'applescript': 'AppleScript', 'GNUmakefile': 'Makefile',
+    'c-objdump': 'CObjdump', 'lua': 'Lua', 'apache2.conf': 'ApacheConf', 'rb':
+    'Ruby', 'gemspec': 'Ruby', 'rl': 'RagelObjectiveC', 'vala': 'Vala', 'tmpl':
+    'Cheetah', 'bf': 'Brainfuck', 'plt': 'Gnuplot', 'G': 'AntlrRuby', 'xslt':
+    'Xslt', 'flxh': 'Felix', 'asax': 'VbNetAspx', 'Rakefile': 'Ruby', 'S': 'S',
+    'wsdl': 'Xml', 'js': 'Javascript', 'autodelegate': 'Myghty', 'properties':
+    'Ini', 'bash': 'Bash', 'c': 'C', 'g': 'AntlrRuby', 'r3': 'Rebol', 's':
+    'Gas', 'ashx': 'VbNetAspx', 'cxx': 'Cpp', 'boo': 'Boo', 'prolog': 'Prolog',
+    'sqlite3-console': 'SqliteConsole', 'cl': 'CommonLisp', 'cc': 'Cpp', 'pot':
+    'Gettext', 'vim': 'Vim', 'pxi': 'Cython', 'yaml': 'Yaml', 'SConstruct':
+    'Python', 'diff': 'Diff', 'txt': 'Text', 'cw': 'Redcode', 'pxd': 'Cython',
+    'plot': 'Gnuplot', 'java': 'Java', 'hrl': 'Erlang', 'py': 'Python',
+    'makefile': 'Makefile', 'squid.conf': 'SquidConf', 'asm': 'Nasm', 'toc':
+    'Tex', 'kid': 'Genshi', 'rhtml': 'Rhtml', 'po': 'Gettext', 'pl': 'Prolog',
+    'pm': 'Perl', 'hx': 'Haxe', 'ascx': 'VbNetAspx', 'ooc': 'Ooc', 'asy':
+    'Asymptote', 'hs': 'Haskell', 'SConscript': 'Python', 'pytb':
+    'PythonTraceback', 'myt': 'Myghty', 'hh': 'Cpp', 'R': 'S', 'aux': 'Tex',
+    'rst': 'Rst', 'cpp-objdump': 'CppObjdump', 'lgt': 'Logtalk', 'rss': 'Xml',
+    'flx': 'Felix', 'b': 'Brainfuck', 'f': 'Fortran', 'rbw': 'Ruby',
+    '.htaccess': 'ApacheConf', 'cxx-objdump': 'CppObjdump', 'j': 'ObjectiveJ',
+    'mll': 'Ocaml', 'yml': 'Yaml', 'mu': 'MuPAD', 'r': 'Rebol', 'ASM': 'Nasm',
+    'erl': 'Erlang', 'mly': 'Ocaml', 'mo': 'Modelica', 'def': 'Modula2', 'ini':
+    'Ini', 'control': 'DebianControl', 'vb': 'VbNet', 'vapi': 'Vala', 'pro':
+    'Prolog', 'spt': 'Cheetah', 'mli': 'Ocaml', 'as': 'ActionScript3', 'cmd':
+    'Batch', 'cpp': 'Cpp', 'io': 'Io', 'tac': 'Python', 'haml': 'Haml', 'rkt':
+    'Racket', 'st':'Smalltalk', 'inc': 'Povray', 'pas': 'Delphi', 'cmake':
+    'CMake', 'csh':'Tcsh', 'hpp': 'Cpp', 'feature': 'Gherkin', 'html': 'Html',
+    'php':'Php', 'php3':'Php', 'php4':'Php', 'php5':'Php', 'xhtml': 'Html',
+    'hxx': 'Cpp', 'eclass': 'Bash', 'css': 'Css',
+    'frag': 'GLShader', 'd-objdump': 'DObjdump', 'weechatlog': 'IrcLogs',
+    'tcsh': 'Tcsh', 'objdump': 'Objdump', 'pyw': 'Python', 'h++': 'Cpp',
+    'py3tb': 'Python3Traceback', 'jsp': 'Jsp', 'sql': 'Sql', 'mak': 'Makefile',
+    'php': 'Php', 'mao': 'Mako', 'man': 'Groff', 'dylan': 'Dylan', 'sass':
+    'Sass', 'cfml': 'ColdfusionHtml', 'darcspatch': 'DarcsPatch', 'tpl':
+    'Smarty', 'm': 'ObjectiveC', 'f90': 'Fortran', 'mod': 'Modula2', 'sh':
+    'Bash', 'lhs': 'LiterateHaskell', 'sources.list': 'SourcesList', 'axd':
+    'VbNetAspx', 'sc': 'Python'}
+
+    repos_path = get_repos_path()
+    p = os.path.join(repos_path, repo_name)
+    repo = get_repo(p)
     tip = repo.get_changeset()
-    
     code_stats = {}
-    for topnode, dirs, files in tip.walk('/'):
-        for f in files:
-            k = f.mimetype
-            if f.extension in LANGUAGES_EXTENSIONS:
-                if code_stats.has_key(k):
-                    code_stats[k] += 1
+
+    def aggregate(cs):
+        for f in cs[2]:
+            ext = f.extension
+            key = LANGUAGES_EXTENSIONS_MAP.get(ext, ext)
+            key = key or ext
+            if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
+                if code_stats.has_key(key):
+                    code_stats[key] += 1
                 else:
-                    code_stats[k] = 1
-                    
+                    code_stats[key] = 1
+
+    map(aggregate, tip.walk('/'))
+
     return code_stats or {}
 
 
-            
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/celerypylons/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,16 @@
+"""
+Automatically sets the environment variable `CELERY_LOADER` to
+`celerypylons.loader:PylonsLoader`.  This ensures the loader is
+specified when accessing the rest of this package, and allows celery
+to be installed in a webapp just by importing celerypylons::
+
+    import celerypylons
+
+"""
+import os
+import warnings
+
+CELERYPYLONS_LOADER = 'rhodecode.lib.celerypylons.loader.PylonsLoader'
+if os.environ.get('CELERY_LOADER', CELERYPYLONS_LOADER) != CELERYPYLONS_LOADER:
+    warnings.warn("'CELERY_LOADER' environment variable will be overridden by celery-pylons.")
+os.environ['CELERY_LOADER'] = CELERYPYLONS_LOADER
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/celerypylons/commands.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,90 @@
+from rhodecode.lib.utils import BasePasterCommand, Command
+
+
+__all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand',
+           'CAMQPAdminCommand', 'CeleryEventCommand']
+
+
+class CeleryDaemonCommand(BasePasterCommand):
+    """Start the celery worker
+
+    Starts the celery worker that uses a paste.deploy configuration
+    file.
+    """
+    usage = 'CONFIG_FILE [celeryd options...]'
+    summary = __doc__.splitlines()[0]
+    description = "".join(__doc__.splitlines()[2:])
+
+    parser = Command.standard_parser(quiet=True)
+
+    def update_parser(self):
+        from celery.bin import celeryd
+        for x in celeryd.WorkerCommand().get_options():
+            self.parser.add_option(x)
+
+    def command(self):
+        from celery.bin import celeryd
+        return celeryd.WorkerCommand().run(**vars(self.options))
+
+
+class CeleryBeatCommand(BasePasterCommand):
+    """Start the celery beat server
+
+    Starts the celery beat server using a paste.deploy configuration
+    file.
+    """
+    usage = 'CONFIG_FILE [celerybeat options...]'
+    summary = __doc__.splitlines()[0]
+    description = "".join(__doc__.splitlines()[2:])
+
+    parser = Command.standard_parser(quiet=True)
+
+    def update_parser(self):
+        from celery.bin import celerybeat
+        for x in celerybeat.BeatCommand().get_options():
+            self.parser.add_option(x)
+
+    def command(self):
+        from celery.bin import celerybeat
+        return celerybeat.BeatCommand(**vars(self.options))
+
+class CAMQPAdminCommand(BasePasterCommand):
+    """CAMQP Admin
+
+    CAMQP celery admin tool.
+    """
+    usage = 'CONFIG_FILE [camqadm options...]'
+    summary = __doc__.splitlines()[0]
+    description = "".join(__doc__.splitlines()[2:])
+
+    parser = Command.standard_parser(quiet=True)
+
+    def update_parser(self):
+        from celery.bin import camqadm
+        for x in camqadm.OPTION_LIST:
+            self.parser.add_option(x)
+
+    def command(self):
+        from celery.bin import camqadm
+        return camqadm.camqadm(*self.args, **vars(self.options))
+
+
+class CeleryEventCommand(BasePasterCommand):
+    """Celery event commandd.
+
+    Capture celery events.
+    """
+    usage = 'CONFIG_FILE [celeryev options...]'
+    summary = __doc__.splitlines()[0]
+    description = "".join(__doc__.splitlines()[2:])
+
+    parser = Command.standard_parser(quiet=True)
+
+    def update_parser(self):
+        from celery.bin import celeryev
+        for x in celeryev.OPTION_LIST:
+            self.parser.add_option(x)
+
+    def command(self):
+        from celery.bin import celeryev
+        return celeryev.run_celeryev(**vars(self.options))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/celerypylons/loader.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,55 @@
+from celery.loaders.base import BaseLoader
+from pylons import config
+
+to_pylons = lambda x: x.replace('_', '.').lower()
+to_celery = lambda x: x.replace('.', '_').upper()
+
+LIST_PARAMS = """CELERY_IMPORTS ADMINS ROUTES""".split()
+
+
+class PylonsSettingsProxy(object):
+    """Pylons Settings Proxy
+
+    Proxies settings from pylons.config
+
+    """
+    def __getattr__(self, key):
+        pylons_key = to_pylons(key)
+        try:
+            value = config[pylons_key]
+            if key in LIST_PARAMS: return value.split()
+            return self.type_converter(value)
+        except KeyError:
+            raise AttributeError(pylons_key)
+
+    def __setattr__(self, key, value):
+        pylons_key = to_pylons(key)
+        config[pylons_key] = value
+
+
+    def type_converter(self, value):
+        #cast to int
+        if value.isdigit():
+            return int(value)
+
+        #cast to bool
+        if value.lower() in ['true', 'false']:
+            return value.lower() == 'true'
+
+        return value
+
+class PylonsLoader(BaseLoader):
+    """Pylons celery loader
+
+    Maps the celery config onto pylons.config
+
+    """
+    def read_configuration(self):
+        self.configured = True
+        return PylonsSettingsProxy()
+
+    def on_worker_init(self):
+        """
+        Import task modules.
+        """
+        self.import_default_modules()
--- a/rhodecode/lib/db_manage.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/db_manage.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,16 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# database management for RhodeCode
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-#
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.db_manage
+    ~~~~~~~~~~~~~~~~~~~~~~~
+
+    Database creation, and setup module for RhodeCode. Used for creation
+    of database as well as for migration operations
+    
+    :created_on: Apr 10, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -18,51 +26,50 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
 
-"""
-Created on April 10, 2010
-database management and creation for RhodeCode
-@author: marcink
-"""
-
-from os.path import dirname as dn, join as jn
 import os
 import sys
 import uuid
+import logging
+from os.path import dirname as dn, join as jn
+
+from rhodecode import __dbversion__
+from rhodecode.model import meta
 
 from rhodecode.lib.auth import get_crypt_password
 from rhodecode.lib.utils import ask_ok
 from rhodecode.model import init_model
 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
-    UserToPerm
-from rhodecode.model import meta
+    UserToPerm, DbMigrateVersion
+
 from sqlalchemy.engine import create_engine
-import logging
 
 log = logging.getLogger(__name__)
 
 class DbManage(object):
-    def __init__(self, log_sql, dbname, root, tests=False):
-        self.dbname = dbname
+    def __init__(self, log_sql, dbconf, root, tests=False):
+        self.dbname = dbconf.split('/')[-1]
         self.tests = tests
         self.root = root
-        dburi = 'sqlite:////%s' % jn(self.root, self.dbname)
-        engine = create_engine(dburi, echo=log_sql) 
+        self.dburi = dbconf
+        engine = create_engine(self.dburi, echo=log_sql)
         init_model(engine)
-        self.sa = meta.Session
+        self.sa = meta.Session()
         self.db_exists = False
-    
+
     def check_for_db(self, override):
         db_path = jn(self.root, self.dbname)
-        log.info('checking for existing db in %s', db_path)
-        if os.path.isfile(db_path):
-            self.db_exists = True
-            if not override:
-                raise Exception('database already exists')
+        if self.dburi.startswith('sqlite'):
+            log.info('checking for existing db in %s', db_path)
+            if os.path.isfile(db_path):
+
+                self.db_exists = True
+                if not override:
+                    raise Exception('database already exists')
 
     def create_tables(self, override=False):
+        """Create a auth database
         """
-        Create a auth database
-        """
+
         self.check_for_db(override)
         if self.db_exists:
             log.info("database exist and it's going to be destroyed")
@@ -77,34 +84,163 @@
         checkfirst = not override
         meta.Base.metadata.create_all(checkfirst=checkfirst)
         log.info('Created tables for %s', self.dbname)
-    
+
+
+
+    def set_db_version(self):
+        try:
+            ver = DbMigrateVersion()
+            ver.version = __dbversion__
+            ver.repository_id = 'rhodecode_db_migrations'
+            ver.repository_path = 'versions'
+            self.sa.add(ver)
+            self.sa.commit()
+        except:
+            self.sa.rollback()
+            raise
+        log.info('db version set to: %s', __dbversion__)
+
+
+    def upgrade(self):
+        """Upgrades given database schema to given revision following 
+        all needed steps,  
+        
+        :param revision: revision to upgrade to
+        """
+
+        from rhodecode.lib.dbmigrate.migrate.versioning import api
+        from rhodecode.lib.dbmigrate.migrate.exceptions import \
+            DatabaseNotControlledError
+
+        upgrade = ask_ok('You are about to perform database upgrade, make '
+                         'sure You backed up your database before. '
+                         'Continue ? [y/n]')
+        if not upgrade:
+            sys.exit('Nothing done')
+
+        repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
+                             'rhodecode/lib/dbmigrate')
+        db_uri = self.dburi
+
+        try:
+            curr_version = api.db_version(db_uri, repository_path)
+            msg = ('Found current database under version'
+                 ' control with version %s' % curr_version)
+
+        except (RuntimeError, DatabaseNotControlledError), e:
+            curr_version = 1
+            msg = ('Current database is not under version control. Setting'
+                   ' as version %s' % curr_version)
+            api.version_control(db_uri, repository_path, curr_version)
+
+        print (msg)
+
+        if curr_version == __dbversion__:
+            sys.exit('This database is already at the newest version')
+
+        #======================================================================
+        # UPGRADE STEPS
+        #======================================================================
+        class UpgradeSteps(object):
+
+            def __init__(self, klass):
+                self.klass = klass
+
+            def step_0(self):
+                #step 0 is the schema upgrade, and than follow proper upgrades
+                print ('attempting to do database upgrade to version %s' \
+                                % __dbversion__)
+                api.upgrade(db_uri, repository_path, __dbversion__)
+                print ('Schema upgrade completed')
+
+            def step_1(self):
+                pass
+
+            def step_2(self):
+                print ('Patching repo paths for newer version of RhodeCode')
+                self.klass.fix_repo_paths()
+
+                print ('Patching default user of RhodeCode')
+                self.klass.fix_default_user()
+
+                log.info('Changing ui settings')
+                self.klass.create_ui_settings()
+
+
+        upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
+
+        #CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
+        for step in upgrade_steps:
+            print ('performing upgrade step %s' % step)
+            callable = getattr(UpgradeSteps(self), 'step_%s' % step)()
+
+
+
+    def fix_repo_paths(self):
+        """Fixes a old rhodecode version path into new one without a '*'
+        """
+
+        paths = self.sa.query(RhodeCodeUi)\
+                .filter(RhodeCodeUi.ui_key == '/')\
+                .scalar()
+
+        paths.ui_value = paths.ui_value.replace('*', '')
+
+        try:
+            self.sa.add(paths)
+            self.sa.commit()
+        except:
+            self.sa.rollback()
+            raise
+
+    def fix_default_user(self):
+        """Fixes a old default user with some 'nicer' default values,
+        used mostly for anonymous access
+        """
+        def_user = self.sa.query(User)\
+                .filter(User.username == 'default')\
+                .one()
+
+        def_user.name = 'Anonymous'
+        def_user.lastname = 'User'
+        def_user.email = 'anonymous@rhodecode.org'
+
+        try:
+            self.sa.add(def_user)
+            self.sa.commit()
+        except:
+            self.sa.rollback()
+            raise
+
+
+
     def admin_prompt(self, second=False):
         if not self.tests:
             import getpass
-            
-            
+
+
             def get_password():
                 password = getpass.getpass('Specify admin password (min 6 chars):')
                 confirm = getpass.getpass('Confirm password:')
-            
+
                 if password != confirm:
                     log.error('passwords mismatch')
                     return False
                 if len(password) < 6:
                     log.error('password is to short use at least 6 characters')
                     return False
-                                
+
                 return password
-            
+
             username = raw_input('Specify admin username:')
-            
+
             password = get_password()
             if not password:
                 #second try
                 password = get_password()
                 if not password:
                     sys.exit()
-                
+
             email = raw_input('Specify admin email:')
             self.create_user(username, password, email, True)
         else:
@@ -112,71 +248,121 @@
             self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
             self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
             self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
-            
+
+    def create_ui_settings(self):
+        """Creates ui settings, fills out hooks
+        and disables dotencode
         
-    
+        """
+        #HOOKS
+        hooks1_key = 'changegroup.update'
+        hooks1_ = self.sa.query(RhodeCodeUi)\
+            .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
+
+        hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
+        hooks1.ui_section = 'hooks'
+        hooks1.ui_key = hooks1_key
+        hooks1.ui_value = 'hg update >&2'
+        hooks1.ui_active = False
+
+        hooks2_key = 'changegroup.repo_size'
+        hooks2_ = self.sa.query(RhodeCodeUi)\
+            .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
+
+        hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
+        hooks2.ui_section = 'hooks'
+        hooks2.ui_key = hooks2_key
+        hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
+
+        hooks3 = RhodeCodeUi()
+        hooks3.ui_section = 'hooks'
+        hooks3.ui_key = 'pretxnchangegroup.push_logger'
+        hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
+
+        hooks4 = RhodeCodeUi()
+        hooks4.ui_section = 'hooks'
+        hooks4.ui_key = 'preoutgoing.pull_logger'
+        hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
+
+        #For mercurial 1.7 set backward comapatibility with format
+        dotencode_disable = RhodeCodeUi()
+        dotencode_disable.ui_section = 'format'
+        dotencode_disable.ui_key = 'dotencode'
+        dotencode_disable.ui_value = 'false'
+
+        try:
+            self.sa.add(hooks1)
+            self.sa.add(hooks2)
+            self.sa.add(hooks3)
+            self.sa.add(hooks4)
+            self.sa.add(dotencode_disable)
+            self.sa.commit()
+        except:
+            self.sa.rollback()
+            raise
+
+
+    def create_ldap_options(self):
+        """Creates ldap settings"""
+
+        try:
+            for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps',
+                      'ldap_dn_user', 'ldap_dn_pass', 'ldap_base_dn']:
+
+                setting = RhodeCodeSettings(k, '')
+                self.sa.add(setting)
+            self.sa.commit()
+        except:
+            self.sa.rollback()
+            raise
+
     def config_prompt(self, test_repo_path=''):
         log.info('Setting up repositories config')
-        
+
         if not self.tests and not test_repo_path:
             path = raw_input('Specify valid full path to your repositories'
                         ' you can change this later in application settings:')
         else:
             path = test_repo_path
-            
+
         if not os.path.isdir(path):
             log.error('You entered wrong path: %s', path)
             sys.exit()
-        
-        hooks1 = RhodeCodeUi()
-        hooks1.ui_section = 'hooks'
-        hooks1.ui_key = 'changegroup.update'
-        hooks1.ui_value = 'hg update >&2'
-        hooks1.ui_active = False
-        
-        hooks2 = RhodeCodeUi()
-        hooks2.ui_section = 'hooks'
-        hooks2.ui_key = 'changegroup.repo_size'
-        hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size' 
-                
+
+        self.create_ui_settings()
+
+        #HG UI OPTIONS
         web1 = RhodeCodeUi()
         web1.ui_section = 'web'
         web1.ui_key = 'push_ssl'
         web1.ui_value = 'false'
-                
+
         web2 = RhodeCodeUi()
         web2.ui_section = 'web'
         web2.ui_key = 'allow_archive'
         web2.ui_value = 'gz zip bz2'
-                
+
         web3 = RhodeCodeUi()
         web3.ui_section = 'web'
         web3.ui_key = 'allow_push'
         web3.ui_value = '*'
-        
+
         web4 = RhodeCodeUi()
         web4.ui_section = 'web'
         web4.ui_key = 'baseurl'
-        web4.ui_value = '/'                        
-        
+        web4.ui_value = '/'
+
         paths = RhodeCodeUi()
         paths.ui_section = 'paths'
         paths.ui_key = '/'
-        paths.ui_value = os.path.join(path, '*')
-        
-        
-        hgsettings1 = RhodeCodeSettings()
-        
-        hgsettings1.app_settings_name = 'realm'
-        hgsettings1.app_settings_value = 'RhodeCode authentication'
-        
-        hgsettings2 = RhodeCodeSettings()
-        hgsettings2.app_settings_name = 'title'
-        hgsettings2.app_settings_value = 'RhodeCode'      
-        
+        paths.ui_value = path
+
+
+        hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
+        hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
+
+
         try:
-            self.sa.add(hooks1)
-            self.sa.add(hooks2)
             self.sa.add(web1)
             self.sa.add(web2)
             self.sa.add(web3)
@@ -184,12 +370,16 @@
             self.sa.add(paths)
             self.sa.add(hgsettings1)
             self.sa.add(hgsettings2)
+
             self.sa.commit()
         except:
             self.sa.rollback()
-            raise        
+            raise
+
+        self.create_ldap_options()
+
         log.info('created ui config')
-                    
+
     def create_user(self, username, password, email='', admin=False):
         log.info('creating administrator user %s', username)
         new_user = User()
@@ -200,7 +390,7 @@
         new_user.email = email
         new_user.admin = admin
         new_user.active = True
-        
+
         try:
             self.sa.add(new_user)
             self.sa.commit()
@@ -214,9 +404,9 @@
         def_user = User()
         def_user.username = 'default'
         def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
-        def_user.name = 'default'
-        def_user.lastname = 'default'
-        def_user.email = 'default@default.com'
+        def_user.name = 'Anonymous'
+        def_user.lastname = 'User'
+        def_user.email = 'anonymous@rhodecode.org'
         def_user.admin = False
         def_user.active = False
         try:
@@ -225,7 +415,7 @@
         except:
             self.sa.rollback()
             raise
-    
+
     def create_permissions(self):
         #module.(access|create|change|delete)_[name]
         #module.(read|write|owner)
@@ -240,7 +430,7 @@
                  ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
                  ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
                 ]
-        
+
         for p in perms:
             new_perm = Permission()
             new_perm.permission_name = p[0]
@@ -254,28 +444,28 @@
 
     def populate_default_permissions(self):
         log.info('creating default user permissions')
-        
+
         default_user = self.sa.query(User)\
         .filter(User.username == 'default').scalar()
-        
+
         reg_perm = UserToPerm()
         reg_perm.user = default_user
         reg_perm.permission = self.sa.query(Permission)\
         .filter(Permission.permission_name == 'hg.register.manual_activate')\
-        .scalar() 
-        
+        .scalar()
+
         create_repo_perm = UserToPerm()
         create_repo_perm.user = default_user
         create_repo_perm.permission = self.sa.query(Permission)\
         .filter(Permission.permission_name == 'hg.create.repository')\
-        .scalar() 
-        
+        .scalar()
+
         default_repo_perm = UserToPerm()
         default_repo_perm.user = default_user
         default_repo_perm.permission = self.sa.query(Permission)\
         .filter(Permission.permission_name == 'repository.read')\
-        .scalar() 
-                
+        .scalar()
+
         try:
             self.sa.add(reg_perm)
             self.sa.add(create_repo_perm)
@@ -283,5 +473,5 @@
             self.sa.commit()
         except:
             self.sa.rollback()
-            raise        
-        
+            raise
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.dbmigrate.__init__
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    
+    Database migration modules
+    
+    :created_on: Dec 11, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+
+import logging
+from sqlalchemy import engine_from_config
+
+
+from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
+from rhodecode.lib.db_manage import DbManage
+
+log = logging.getLogger(__name__)
+
+class UpgradeDb(BasePasterCommand):
+    """Command used for paster to upgrade our database to newer version
+    """
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    summary = "Upgrades current db to newer version given configuration file"
+    group_name = "RhodeCode"
+
+    parser = Command.standard_parser(verbose=True)
+
+    def command(self):
+        from pylons import config
+
+        add_cache(config)
+
+        db_uri = config['sqlalchemy.db1.url']
+
+        dbmanage = DbManage(log_sql=True, dbconf=db_uri,
+                            root=config['here'], tests=False)
+
+        dbmanage.upgrade()
+
+
+
+    def update_parser(self):
+        self.parser.add_option('--sql',
+                      action='store_true',
+                      dest='just_sql',
+                      help="Prints upgrade sql for further investigation",
+                      default=False)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate.cfg	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,20 @@
+[db_settings]
+# Used to identify which repository this database is versioned under.
+# You can use the name of your project.
+repository_id=rhodecode_db_migrations
+
+# The name of the database table used to track the schema version.
+# This name shouldn't already be used by your project.
+# If this is changed once a database is under version control, you'll need to 
+# change the table name in each database too. 
+version_table=db_migrate_version
+
+# When committing a change script, Migrate will attempt to generate the 
+# sql for all supported databases; normally, if one of them fails - probably
+# because you don't have that database installed - it is ignored and the 
+# commit continues, perhaps ending successfully. 
+# Databases in this list MUST compile successfully during a commit, or the 
+# entire commit will fail. List the databases your application will actually 
+# be using to ensure your updates to that database work properly.
+# This must be a list; example: ['postgres','sqlite']
+required_dbs=['sqlite']
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,9 @@
+"""
+   SQLAlchemy migrate provides two APIs :mod:`migrate.versioning` for
+   database schema version and repository management and
+   :mod:`migrate.changeset` that allows to define database schema changes
+   using Python.
+"""
+
+from rhodecode.lib.dbmigrate.migrate.versioning import *
+from rhodecode.lib.dbmigrate.migrate.changeset import *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,28 @@
+"""
+   This module extends SQLAlchemy and provides additional DDL [#]_
+   support.
+
+   .. [#] SQL Data Definition Language
+"""
+import re
+import warnings
+
+import sqlalchemy
+from sqlalchemy import __version__ as _sa_version
+
+warnings.simplefilter('always', DeprecationWarning)
+
+_sa_version = tuple(int(re.match("\d+", x).group(0)) for x in _sa_version.split("."))
+SQLA_06 = _sa_version >= (0, 6)
+
+del re
+del _sa_version
+
+from rhodecode.lib.dbmigrate.migrate.changeset.schema import *
+from rhodecode.lib.dbmigrate.migrate.changeset.constraint import *
+
+sqlalchemy.schema.Table.__bases__ += (ChangesetTable, )
+sqlalchemy.schema.Column.__bases__ += (ChangesetColumn, )
+sqlalchemy.schema.Index.__bases__ += (ChangesetIndex, )
+
+sqlalchemy.schema.DefaultClause.__bases__ += (ChangesetDefaultClause, )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,358 @@
+"""
+   Extensions to SQLAlchemy for altering existing tables.
+
+   At the moment, this isn't so much based off of ANSI as much as
+   things that just happen to work with multiple databases.
+"""
+import StringIO
+
+import sqlalchemy as sa
+from sqlalchemy.schema import SchemaVisitor
+from sqlalchemy.engine.default import DefaultDialect
+from sqlalchemy.sql import ClauseElement
+from sqlalchemy.schema import (ForeignKeyConstraint,
+                               PrimaryKeyConstraint,
+                               CheckConstraint,
+                               UniqueConstraint,
+                               Index)
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.changeset import constraint, SQLA_06
+
+if not SQLA_06:
+    from sqlalchemy.sql.compiler import SchemaGenerator, SchemaDropper
+else:
+    from sqlalchemy.schema import AddConstraint, DropConstraint
+    from sqlalchemy.sql.compiler import DDLCompiler
+    SchemaGenerator = SchemaDropper = DDLCompiler
+
+
+class AlterTableVisitor(SchemaVisitor):
+    """Common operations for ``ALTER TABLE`` statements."""
+
+    if SQLA_06:
+        # engine.Compiler looks for .statement
+        # when it spawns off a new compiler
+        statement = ClauseElement()
+
+    def append(self, s):
+        """Append content to the SchemaIterator's query buffer."""
+
+        self.buffer.write(s)
+
+    def execute(self):
+        """Execute the contents of the SchemaIterator's buffer."""
+        try:
+            return self.connection.execute(self.buffer.getvalue())
+        finally:
+            self.buffer.truncate(0)
+
+    def __init__(self, dialect, connection, **kw):
+        self.connection = connection
+        self.buffer = StringIO.StringIO()
+        self.preparer = dialect.identifier_preparer
+        self.dialect = dialect
+
+    def traverse_single(self, elem):
+        ret = super(AlterTableVisitor, self).traverse_single(elem)
+        if ret:
+            # adapt to 0.6 which uses a string-returning
+            # object
+            self.append(" %s" % ret)
+            
+    def _to_table(self, param):
+        """Returns the table object for the given param object."""
+        if isinstance(param, (sa.Column, sa.Index, sa.schema.Constraint)):
+            ret = param.table
+        else:
+            ret = param
+        return ret
+
+    def start_alter_table(self, param):
+        """Returns the start of an ``ALTER TABLE`` SQL-Statement.
+
+        Use the param object to determine the table name and use it
+        for building the SQL statement.
+
+        :param param: object to determine the table from
+        :type param: :class:`sqlalchemy.Column`, :class:`sqlalchemy.Index`,
+          :class:`sqlalchemy.schema.Constraint`, :class:`sqlalchemy.Table`,
+          or string (table name)
+        """
+        table = self._to_table(param)
+        self.append('\nALTER TABLE %s ' % self.preparer.format_table(table))
+        return table
+
+
+class ANSIColumnGenerator(AlterTableVisitor, SchemaGenerator):
+    """Extends ansisql generator for column creation (alter table add col)"""
+
+    def visit_column(self, column):
+        """Create a column (table already exists).
+
+        :param column: column object
+        :type column: :class:`sqlalchemy.Column` instance
+        """
+        if column.default is not None:
+            self.traverse_single(column.default)
+
+        table = self.start_alter_table(column)
+        self.append("ADD ")
+        self.append(self.get_column_specification(column))
+
+        for cons in column.constraints:
+            self.traverse_single(cons)
+        self.execute()
+
+        # ALTER TABLE STATEMENTS
+
+        # add indexes and unique constraints
+        if column.index_name:
+            Index(column.index_name,column).create()
+        elif column.unique_name:
+            constraint.UniqueConstraint(column,
+                                        name=column.unique_name).create()
+
+        # SA bounds FK constraints to table, add manually
+        for fk in column.foreign_keys:
+            self.add_foreignkey(fk.constraint)
+
+        # add primary key constraint if needed
+        if column.primary_key_name:
+            cons = constraint.PrimaryKeyConstraint(column,
+                                                   name=column.primary_key_name)
+            cons.create()
+
+    if SQLA_06:
+        def add_foreignkey(self, fk):
+            self.connection.execute(AddConstraint(fk))
+
+class ANSIColumnDropper(AlterTableVisitor, SchemaDropper):
+    """Extends ANSI SQL dropper for column dropping (``ALTER TABLE
+    DROP COLUMN``).
+    """
+
+    def visit_column(self, column):
+        """Drop a column from its table.
+
+        :param column: the column object
+        :type column: :class:`sqlalchemy.Column`
+        """
+        table = self.start_alter_table(column)
+        self.append('DROP COLUMN %s' % self.preparer.format_column(column))
+        self.execute()
+
+
+class ANSISchemaChanger(AlterTableVisitor, SchemaGenerator):
+    """Manages changes to existing schema elements.
+
+    Note that columns are schema elements; ``ALTER TABLE ADD COLUMN``
+    is in SchemaGenerator.
+
+    All items may be renamed. Columns can also have many of their properties -
+    type, for example - changed.
+
+    Each function is passed a tuple, containing (object, name); where
+    object is a type of object you'd expect for that function
+    (ie. table for visit_table) and name is the object's new
+    name. NONE means the name is unchanged.
+    """
+
+    def visit_table(self, table):
+        """Rename a table. Other ops aren't supported."""
+        self.start_alter_table(table)
+        self.append("RENAME TO %s" % self.preparer.quote(table.new_name,
+                                                         table.quote))
+        self.execute()
+
+    def visit_index(self, index):
+        """Rename an index"""
+        if hasattr(self, '_validate_identifier'):
+            # SA <= 0.6.3
+            self.append("ALTER INDEX %s RENAME TO %s" % (
+                    self.preparer.quote(
+                        self._validate_identifier(
+                            index.name, True), index.quote),
+                    self.preparer.quote(
+                        self._validate_identifier(
+                            index.new_name, True), index.quote)))
+        else:
+            # SA >= 0.6.5
+            self.append("ALTER INDEX %s RENAME TO %s" % (
+                    self.preparer.quote(
+                        self._index_identifier(
+                            index.name), index.quote),
+                    self.preparer.quote(
+                        self._index_identifier(
+                            index.new_name), index.quote)))
+        self.execute()
+
+    def visit_column(self, delta):
+        """Rename/change a column."""
+        # ALTER COLUMN is implemented as several ALTER statements
+        keys = delta.keys()
+        if 'type' in keys:
+            self._run_subvisit(delta, self._visit_column_type)
+        if 'nullable' in keys:
+            self._run_subvisit(delta, self._visit_column_nullable)
+        if 'server_default' in keys:
+            # Skip 'default': only handle server-side defaults, others
+            # are managed by the app, not the db.
+            self._run_subvisit(delta, self._visit_column_default)
+        if 'name' in keys:
+            self._run_subvisit(delta, self._visit_column_name, start_alter=False)
+
+    def _run_subvisit(self, delta, func, start_alter=True):
+        """Runs visit method based on what needs to be changed on column"""
+        table = self._to_table(delta.table)
+        col_name = delta.current_name
+        if start_alter:
+            self.start_alter_column(table, col_name)
+        ret = func(table, delta.result_column, delta)
+        self.execute()
+
+    def start_alter_column(self, table, col_name):
+        """Starts ALTER COLUMN"""
+        self.start_alter_table(table)
+        self.append("ALTER COLUMN %s " % self.preparer.quote(col_name, table.quote))
+
+    def _visit_column_nullable(self, table, column, delta):
+        nullable = delta['nullable']
+        if nullable:
+            self.append("DROP NOT NULL")
+        else:
+            self.append("SET NOT NULL")
+
+    def _visit_column_default(self, table, column, delta):
+        default_text = self.get_column_default_string(column)
+        if default_text is not None:
+            self.append("SET DEFAULT %s" % default_text)
+        else:
+            self.append("DROP DEFAULT")
+
+    def _visit_column_type(self, table, column, delta):
+        type_ = delta['type']
+        if SQLA_06:
+            type_text = str(type_.compile(dialect=self.dialect))
+        else:
+            type_text = type_.dialect_impl(self.dialect).get_col_spec()
+        self.append("TYPE %s" % type_text)
+
+    def _visit_column_name(self, table, column, delta):
+        self.start_alter_table(table)
+        col_name = self.preparer.quote(delta.current_name, table.quote)
+        new_name = self.preparer.format_column(delta.result_column)
+        self.append('RENAME COLUMN %s TO %s' % (col_name, new_name))
+
+
+class ANSIConstraintCommon(AlterTableVisitor):
+    """
+    Migrate's constraints require a separate creation function from
+    SA's: Migrate's constraints are created independently of a table;
+    SA's are created at the same time as the table.
+    """
+
+    def get_constraint_name(self, cons):
+        """Gets a name for the given constraint.
+
+        If the name is already set it will be used otherwise the
+        constraint's :meth:`autoname <migrate.changeset.constraint.ConstraintChangeset.autoname>`
+        method is used.
+
+        :param cons: constraint object
+        """
+        if cons.name is not None:
+            ret = cons.name
+        else:
+            ret = cons.name = cons.autoname()
+        return self.preparer.quote(ret, cons.quote)
+
+    def visit_migrate_primary_key_constraint(self, *p, **k):
+        self._visit_constraint(*p, **k)
+
+    def visit_migrate_foreign_key_constraint(self, *p, **k):
+        self._visit_constraint(*p, **k)
+
+    def visit_migrate_check_constraint(self, *p, **k):
+        self._visit_constraint(*p, **k)
+
+    def visit_migrate_unique_constraint(self, *p, **k):
+        self._visit_constraint(*p, **k)
+
+if SQLA_06:
+    class ANSIConstraintGenerator(ANSIConstraintCommon, SchemaGenerator):
+        def _visit_constraint(self, constraint):
+            constraint.name = self.get_constraint_name(constraint)
+            self.append(self.process(AddConstraint(constraint)))
+            self.execute()
+
+    class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper):
+        def _visit_constraint(self, constraint):
+            constraint.name = self.get_constraint_name(constraint)
+            self.append(self.process(DropConstraint(constraint, cascade=constraint.cascade)))
+            self.execute()
+
+else:
+    class ANSIConstraintGenerator(ANSIConstraintCommon, SchemaGenerator):
+
+        def get_constraint_specification(self, cons, **kwargs):
+            """Constaint SQL generators.
+        
+            We cannot use SA visitors because they append comma.
+            """
+        
+            if isinstance(cons, PrimaryKeyConstraint):
+                if cons.name is not None:
+                    self.append("CONSTRAINT %s " % self.preparer.format_constraint(cons))
+                self.append("PRIMARY KEY ")
+                self.append("(%s)" % ', '.join(self.preparer.quote(c.name, c.quote)
+                                               for c in cons))
+                self.define_constraint_deferrability(cons)
+            elif isinstance(cons, ForeignKeyConstraint):
+                self.define_foreign_key(cons)
+            elif isinstance(cons, CheckConstraint):
+                if cons.name is not None:
+                    self.append("CONSTRAINT %s " %
+                                self.preparer.format_constraint(cons))
+                self.append("CHECK (%s)" % cons.sqltext)
+                self.define_constraint_deferrability(cons)
+            elif isinstance(cons, UniqueConstraint):
+                if cons.name is not None:
+                    self.append("CONSTRAINT %s " %
+                                self.preparer.format_constraint(cons))
+                self.append("UNIQUE (%s)" % \
+                    (', '.join(self.preparer.quote(c.name, c.quote) for c in cons)))
+                self.define_constraint_deferrability(cons)
+            else:
+                raise exceptions.InvalidConstraintError(cons)
+
+        def _visit_constraint(self, constraint):
+        
+            table = self.start_alter_table(constraint)
+            constraint.name = self.get_constraint_name(constraint)
+            self.append("ADD ")
+            self.get_constraint_specification(constraint)
+            self.execute()
+    
+
+    class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper):
+
+        def _visit_constraint(self, constraint):
+            self.start_alter_table(constraint)
+            self.append("DROP CONSTRAINT ")
+            constraint.name = self.get_constraint_name(constraint)
+            self.append(self.preparer.format_constraint(constraint))
+            if constraint.cascade:
+                self.cascade_constraint(constraint)
+            self.execute()
+
+        def cascade_constraint(self, constraint):
+            self.append(" CASCADE")
+
+
+class ANSIDialect(DefaultDialect):
+    columngenerator = ANSIColumnGenerator
+    columndropper = ANSIColumnDropper
+    schemachanger = ANSISchemaChanger
+    constraintgenerator = ANSIConstraintGenerator
+    constraintdropper = ANSIConstraintDropper
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/constraint.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,202 @@
+"""
+   This module defines standalone schema constraint classes.
+"""
+from sqlalchemy import schema
+
+from rhodecode.lib.dbmigrate.migrate.exceptions import *
+from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
+
+class ConstraintChangeset(object):
+    """Base class for Constraint classes."""
+
+    def _normalize_columns(self, cols, table_name=False):
+        """Given: column objects or names; return col names and
+        (maybe) a table"""
+        colnames = []
+        table = None
+        for col in cols:
+            if isinstance(col, schema.Column):
+                if col.table is not None and table is None:
+                    table = col.table
+                if table_name:
+                    col = '.'.join((col.table.name, col.name))
+                else:
+                    col = col.name
+            colnames.append(col)
+        return colnames, table
+
+    def __do_imports(self, visitor_name, *a, **kw):
+        engine = kw.pop('engine', self.table.bind)
+        from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import (get_engine_visitor,
+                                                         run_single_visitor)
+        visitorcallable = get_engine_visitor(engine, visitor_name)
+        run_single_visitor(engine, visitorcallable, self, *a, **kw)
+
+    def create(self, *a, **kw):
+        """Create the constraint in the database.
+
+        :param engine: the database engine to use. If this is \
+        :keyword:`None` the instance's engine will be used
+        :type engine: :class:`sqlalchemy.engine.base.Engine`
+        :param connection: reuse connection istead of creating new one.
+        :type connection: :class:`sqlalchemy.engine.base.Connection` instance
+        """
+        # TODO: set the parent here instead of in __init__
+        self.__do_imports('constraintgenerator', *a, **kw)
+
+    def drop(self, *a, **kw):
+        """Drop the constraint from the database.
+
+        :param engine: the database engine to use. If this is
+          :keyword:`None` the instance's engine will be used
+        :param cascade: Issue CASCADE drop if database supports it
+        :type engine: :class:`sqlalchemy.engine.base.Engine`
+        :type cascade: bool
+        :param connection: reuse connection istead of creating new one.
+        :type connection: :class:`sqlalchemy.engine.base.Connection` instance
+        :returns: Instance with cleared columns
+        """
+        self.cascade = kw.pop('cascade', False)
+        self.__do_imports('constraintdropper', *a, **kw)
+        # the spirit of Constraint objects is that they
+        # are immutable (just like in a DB.  they're only ADDed
+        # or DROPped).
+        #self.columns.clear()
+        return self
+
+
+class PrimaryKeyConstraint(ConstraintChangeset, schema.PrimaryKeyConstraint):
+    """Construct PrimaryKeyConstraint
+
+    Migrate's additional parameters:
+
+    :param cols: Columns in constraint.
+    :param table: If columns are passed as strings, this kw is required
+    :type table: Table instance
+    :type cols: strings or Column instances
+    """
+
+    __migrate_visit_name__ = 'migrate_primary_key_constraint'
+
+    def __init__(self, *cols, **kwargs):
+        colnames, table = self._normalize_columns(cols)
+        table = kwargs.pop('table', table)
+        super(PrimaryKeyConstraint, self).__init__(*colnames, **kwargs)
+        if table is not None:
+            self._set_parent(table)
+
+
+    def autoname(self):
+        """Mimic the database's automatic constraint names"""
+        return "%s_pkey" % self.table.name
+
+
+class ForeignKeyConstraint(ConstraintChangeset, schema.ForeignKeyConstraint):
+    """Construct ForeignKeyConstraint
+
+    Migrate's additional parameters:
+
+    :param columns: Columns in constraint
+    :param refcolumns: Columns that this FK reffers to in another table.
+    :param table: If columns are passed as strings, this kw is required
+    :type table: Table instance
+    :type columns: list of strings or Column instances
+    :type refcolumns: list of strings or Column instances
+    """
+
+    __migrate_visit_name__ = 'migrate_foreign_key_constraint'
+
+    def __init__(self, columns, refcolumns, *args, **kwargs):
+        colnames, table = self._normalize_columns(columns)
+        table = kwargs.pop('table', table)
+        refcolnames, reftable = self._normalize_columns(refcolumns,
+                                                        table_name=True)
+        super(ForeignKeyConstraint, self).__init__(colnames, refcolnames, *args,
+                                                   **kwargs)
+        if table is not None:
+            self._set_parent(table)
+
+    @property
+    def referenced(self):
+        return [e.column for e in self.elements]
+
+    @property
+    def reftable(self):
+        return self.referenced[0].table
+
+    def autoname(self):
+        """Mimic the database's automatic constraint names"""
+        if hasattr(self.columns, 'keys'):
+            # SA <= 0.5
+            firstcol = self.columns[self.columns.keys()[0]]
+            ret = "%(table)s_%(firstcolumn)s_fkey" % dict(
+                table=firstcol.table.name,
+                firstcolumn=firstcol.name,)
+        else:
+            # SA >= 0.6
+            ret = "%(table)s_%(firstcolumn)s_fkey" % dict(
+                table=self.table.name,
+                firstcolumn=self.columns[0],)
+        return ret
+
+
+class CheckConstraint(ConstraintChangeset, schema.CheckConstraint):
+    """Construct CheckConstraint
+
+    Migrate's additional parameters:
+
+    :param sqltext: Plain SQL text to check condition
+    :param columns: If not name is applied, you must supply this kw\
+    to autoname constraint
+    :param table: If columns are passed as strings, this kw is required
+    :type table: Table instance
+    :type columns: list of Columns instances
+    :type sqltext: string
+    """
+
+    __migrate_visit_name__ = 'migrate_check_constraint'
+
+    def __init__(self, sqltext, *args, **kwargs):
+        cols = kwargs.pop('columns', [])
+        if not cols and not kwargs.get('name', False):
+            raise InvalidConstraintError('You must either set "name"'
+                'parameter or "columns" to autogenarate it.')
+        colnames, table = self._normalize_columns(cols)
+        table = kwargs.pop('table', table)
+        schema.CheckConstraint.__init__(self, sqltext, *args, **kwargs)
+        if table is not None:
+            if not SQLA_06:
+                self.table = table
+            self._set_parent(table)
+        self.colnames = colnames
+
+    def autoname(self):
+        return "%(table)s_%(cols)s_check" % \
+            dict(table=self.table.name, cols="_".join(self.colnames))
+
+
+class UniqueConstraint(ConstraintChangeset, schema.UniqueConstraint):
+    """Construct UniqueConstraint
+
+    Migrate's additional parameters:
+
+    :param cols: Columns in constraint.
+    :param table: If columns are passed as strings, this kw is required
+    :type table: Table instance
+    :type cols: strings or Column instances
+
+    .. versionadded:: 0.6.0
+    """
+
+    __migrate_visit_name__ = 'migrate_unique_constraint'
+
+    def __init__(self, *cols, **kwargs):
+        self.colnames, table = self._normalize_columns(cols)
+        table = kwargs.pop('table', table)
+        super(UniqueConstraint, self).__init__(*self.colnames, **kwargs)
+        if table is not None:
+            self._set_parent(table)
+
+    def autoname(self):
+        """Mimic the database's automatic constraint names"""
+        return "%s_%s_key" % (self.table.name, self.colnames[0])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,10 @@
+"""
+   This module contains database dialect specific changeset
+   implementations.
+"""
+__all__ = [
+    'postgres',
+    'sqlite',
+    'mysql',
+    'oracle',
+]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,80 @@
+"""
+   Firebird database specific implementations of changeset classes.
+"""
+from sqlalchemy.databases import firebird as sa_base
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+
+
+if SQLA_06:
+    FBSchemaGenerator = sa_base.FBDDLCompiler
+else:
+    FBSchemaGenerator = sa_base.FBSchemaGenerator
+
+class FBColumnGenerator(FBSchemaGenerator, ansisql.ANSIColumnGenerator):
+    """Firebird column generator implementation."""
+
+
+class FBColumnDropper(ansisql.ANSIColumnDropper):
+    """Firebird column dropper implementation."""
+
+    def visit_column(self, column):
+        """Firebird supports 'DROP col' instead of 'DROP COLUMN col' syntax
+
+        Drop primary key and unique constraints if dropped column is referencing it."""
+        if column.primary_key:
+            if column.table.primary_key.columns.contains_column(column):
+                column.table.primary_key.drop()
+                # TODO: recreate primary key if it references more than this column
+        if column.unique or getattr(column, 'unique_name', None):
+            for cons in column.table.constraints:
+                if cons.contains_column(column):
+                    cons.drop()
+                    # TODO: recreate unique constraint if it refenrences more than this column
+
+        table = self.start_alter_table(column)
+        self.append('DROP %s' % self.preparer.format_column(column))
+        self.execute()
+
+
+class FBSchemaChanger(ansisql.ANSISchemaChanger):
+    """Firebird schema changer implementation."""
+
+    def visit_table(self, table):
+        """Rename table not supported"""
+        raise exceptions.NotSupportedError(
+            "Firebird does not support renaming tables.")
+
+    def _visit_column_name(self, table, column, delta):
+        self.start_alter_table(table)
+        col_name = self.preparer.quote(delta.current_name, table.quote)
+        new_name = self.preparer.format_column(delta.result_column)
+        self.append('ALTER COLUMN %s TO %s' % (col_name, new_name))
+
+    def _visit_column_nullable(self, table, column, delta):
+        """Changing NULL is not supported"""
+        # TODO: http://www.firebirdfaq.org/faq103/
+        raise exceptions.NotSupportedError(
+            "Firebird does not support altering NULL bevahior.")
+
+
+class FBConstraintGenerator(ansisql.ANSIConstraintGenerator):
+    """Firebird constraint generator implementation."""
+
+
+class FBConstraintDropper(ansisql.ANSIConstraintDropper):
+    """Firebird constaint dropper implementation."""
+
+    def cascade_constraint(self, constraint):
+        """Cascading constraints is not supported"""
+        raise exceptions.NotSupportedError(
+            "Firebird does not support cascading constraints")
+
+
+class FBDialect(ansisql.ANSIDialect):
+    columngenerator = FBColumnGenerator
+    columndropper = FBColumnDropper
+    schemachanger = FBSchemaChanger
+    constraintgenerator = FBConstraintGenerator
+    constraintdropper = FBConstraintDropper
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/mysql.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,94 @@
+"""
+   MySQL database specific implementations of changeset classes.
+"""
+
+from sqlalchemy.databases import mysql as sa_base
+from sqlalchemy import types as sqltypes
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+
+
+if not SQLA_06:
+    MySQLSchemaGenerator = sa_base.MySQLSchemaGenerator
+else:
+    MySQLSchemaGenerator = sa_base.MySQLDDLCompiler
+
+class MySQLColumnGenerator(MySQLSchemaGenerator, ansisql.ANSIColumnGenerator):
+    pass
+
+
+class MySQLColumnDropper(ansisql.ANSIColumnDropper):
+    pass
+
+
+class MySQLSchemaChanger(MySQLSchemaGenerator, ansisql.ANSISchemaChanger):
+
+    def visit_column(self, delta):
+        table = delta.table
+        colspec = self.get_column_specification(delta.result_column)
+        if delta.result_column.autoincrement:
+            primary_keys = [c for c in table.primary_key.columns
+                       if (c.autoincrement and
+                            isinstance(c.type, sqltypes.Integer) and
+                            not c.foreign_keys)]
+
+            if primary_keys:
+                first = primary_keys.pop(0)
+                if first.name == delta.current_name:
+                    colspec += " AUTO_INCREMENT"
+        old_col_name = self.preparer.quote(delta.current_name, table.quote)
+
+        self.start_alter_table(table)
+
+        self.append("CHANGE COLUMN %s " % old_col_name)
+        self.append(colspec)
+        self.execute()
+
+    def visit_index(self, param):
+        # If MySQL can do this, I can't find how
+        raise exceptions.NotSupportedError("MySQL cannot rename indexes")
+
+
+class MySQLConstraintGenerator(ansisql.ANSIConstraintGenerator):
+    pass
+
+if SQLA_06:
+    class MySQLConstraintDropper(MySQLSchemaGenerator, ansisql.ANSIConstraintDropper):
+        def visit_migrate_check_constraint(self, *p, **k):
+            raise exceptions.NotSupportedError("MySQL does not support CHECK"
+                " constraints, use triggers instead.")
+
+else:
+    class MySQLConstraintDropper(ansisql.ANSIConstraintDropper):
+
+        def visit_migrate_primary_key_constraint(self, constraint):
+            self.start_alter_table(constraint)
+            self.append("DROP PRIMARY KEY")
+            self.execute()
+
+        def visit_migrate_foreign_key_constraint(self, constraint):
+            self.start_alter_table(constraint)
+            self.append("DROP FOREIGN KEY ")
+            constraint.name = self.get_constraint_name(constraint)
+            self.append(self.preparer.format_constraint(constraint))
+            self.execute()
+
+        def visit_migrate_check_constraint(self, *p, **k):
+            raise exceptions.NotSupportedError("MySQL does not support CHECK"
+                " constraints, use triggers instead.")
+
+        def visit_migrate_unique_constraint(self, constraint, *p, **k):
+            self.start_alter_table(constraint)
+            self.append('DROP INDEX ')
+            constraint.name = self.get_constraint_name(constraint)
+            self.append(self.preparer.format_constraint(constraint))
+            self.execute()
+
+
+class MySQLDialect(ansisql.ANSIDialect):
+    columngenerator = MySQLColumnGenerator
+    columndropper = MySQLColumnDropper
+    schemachanger = MySQLSchemaChanger
+    constraintgenerator = MySQLConstraintGenerator
+    constraintdropper = MySQLConstraintDropper
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/oracle.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,111 @@
+"""
+   Oracle database specific implementations of changeset classes.
+"""
+import sqlalchemy as sa
+from sqlalchemy.databases import oracle as sa_base
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+
+
+if not SQLA_06:
+    OracleSchemaGenerator = sa_base.OracleSchemaGenerator
+else:
+    OracleSchemaGenerator = sa_base.OracleDDLCompiler
+
+
+class OracleColumnGenerator(OracleSchemaGenerator, ansisql.ANSIColumnGenerator):
+    pass
+
+
+class OracleColumnDropper(ansisql.ANSIColumnDropper):
+    pass
+
+
+class OracleSchemaChanger(OracleSchemaGenerator, ansisql.ANSISchemaChanger):
+
+    def get_column_specification(self, column, **kwargs):
+        # Ignore the NOT NULL generated
+        override_nullable = kwargs.pop('override_nullable', None)
+        if override_nullable:
+            orig = column.nullable
+            column.nullable = True
+        ret = super(OracleSchemaChanger, self).get_column_specification(
+            column, **kwargs)
+        if override_nullable:
+            column.nullable = orig
+        return ret
+
+    def visit_column(self, delta):
+        keys = delta.keys()
+
+        if 'name' in keys:
+            self._run_subvisit(delta,
+                               self._visit_column_name,
+                               start_alter=False)
+
+        if len(set(('type', 'nullable', 'server_default')).intersection(keys)):
+            self._run_subvisit(delta,
+                               self._visit_column_change,
+                               start_alter=False)
+
+    def _visit_column_change(self, table, column, delta):
+        # Oracle cannot drop a default once created, but it can set it
+        # to null.  We'll do that if default=None
+        # http://forums.oracle.com/forums/message.jspa?messageID=1273234#1273234
+        dropdefault_hack = (column.server_default is None \
+                                and 'server_default' in delta.keys())
+        # Oracle apparently doesn't like it when we say "not null" if
+        # the column's already not null. Fudge it, so we don't need a
+        # new function
+        notnull_hack = ((not column.nullable) \
+                            and ('nullable' not in delta.keys()))
+        # We need to specify NULL if we're removing a NOT NULL
+        # constraint
+        null_hack = (column.nullable and ('nullable' in delta.keys()))
+
+        if dropdefault_hack:
+            column.server_default = sa.PassiveDefault(sa.sql.null())
+        if notnull_hack:
+            column.nullable = True
+        colspec = self.get_column_specification(column,
+            override_nullable=null_hack)
+        if null_hack:
+            colspec += ' NULL'
+        if notnull_hack:
+            column.nullable = False
+        if dropdefault_hack:
+            column.server_default = None
+
+        self.start_alter_table(table)
+        self.append("MODIFY (")
+        self.append(colspec)
+        self.append(")")
+
+
+class OracleConstraintCommon(object):
+
+    def get_constraint_name(self, cons):
+        # Oracle constraints can't guess their name like other DBs
+        if not cons.name:
+            raise exceptions.NotSupportedError(
+                "Oracle constraint names must be explicitly stated")
+        return cons.name
+
+
+class OracleConstraintGenerator(OracleConstraintCommon,
+                                ansisql.ANSIConstraintGenerator):
+    pass
+
+
+class OracleConstraintDropper(OracleConstraintCommon,
+                              ansisql.ANSIConstraintDropper):
+    pass
+
+
+class OracleDialect(ansisql.ANSIDialect):
+    columngenerator = OracleColumnGenerator
+    columndropper = OracleColumnDropper
+    schemachanger = OracleSchemaChanger
+    constraintgenerator = OracleConstraintGenerator
+    constraintdropper = OracleConstraintDropper
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/postgres.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,46 @@
+"""
+   `PostgreSQL`_ database specific implementations of changeset classes.
+
+   .. _`PostgreSQL`: http://www.postgresql.org/
+"""
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+
+if not SQLA_06:
+    from sqlalchemy.databases import postgres as sa_base
+    PGSchemaGenerator = sa_base.PGSchemaGenerator
+else:
+    from sqlalchemy.databases import postgresql as sa_base
+    PGSchemaGenerator = sa_base.PGDDLCompiler
+
+
+class PGColumnGenerator(PGSchemaGenerator, ansisql.ANSIColumnGenerator):
+    """PostgreSQL column generator implementation."""
+    pass
+
+
+class PGColumnDropper(ansisql.ANSIColumnDropper):
+    """PostgreSQL column dropper implementation."""
+    pass
+
+
+class PGSchemaChanger(ansisql.ANSISchemaChanger):
+    """PostgreSQL schema changer implementation."""
+    pass
+
+
+class PGConstraintGenerator(ansisql.ANSIConstraintGenerator):
+    """PostgreSQL constraint generator implementation."""
+    pass
+
+
+class PGConstraintDropper(ansisql.ANSIConstraintDropper):
+    """PostgreSQL constaint dropper implementation."""
+    pass
+
+
+class PGDialect(ansisql.ANSIDialect):
+    columngenerator = PGColumnGenerator
+    columndropper = PGColumnDropper
+    schemachanger = PGSchemaChanger
+    constraintgenerator = PGConstraintGenerator
+    constraintdropper = PGConstraintDropper
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,148 @@
+"""
+   `SQLite`_ database specific implementations of changeset classes.
+
+   .. _`SQLite`: http://www.sqlite.org/
+"""
+from UserDict import DictMixin
+from copy import copy
+
+from sqlalchemy.databases import sqlite as sa_base
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql, SQLA_06
+
+
+if not SQLA_06:
+    SQLiteSchemaGenerator = sa_base.SQLiteSchemaGenerator
+else:
+    SQLiteSchemaGenerator = sa_base.SQLiteDDLCompiler
+
+class SQLiteCommon(object):
+
+    def _not_supported(self, op):
+        raise exceptions.NotSupportedError("SQLite does not support "
+            "%s; see http://www.sqlite.org/lang_altertable.html" % op)
+
+
+class SQLiteHelper(SQLiteCommon):
+
+    def recreate_table(self,table,column=None,delta=None):
+        table_name = self.preparer.format_table(table)
+
+        # we remove all indexes so as not to have
+        # problems during copy and re-create
+        for index in table.indexes:
+            index.drop()
+
+        self.append('ALTER TABLE %s RENAME TO migration_tmp' % table_name)
+        self.execute()
+
+        insertion_string = self._modify_table(table, column, delta)
+
+        table.create()
+        self.append(insertion_string % {'table_name': table_name})
+        self.execute()
+        self.append('DROP TABLE migration_tmp')
+        self.execute()
+        
+    def visit_column(self, delta):
+        if isinstance(delta, DictMixin):
+            column = delta.result_column
+            table = self._to_table(delta.table)
+        else:
+            column = delta
+            table = self._to_table(column.table)
+        self.recreate_table(table,column,delta)
+
+class SQLiteColumnGenerator(SQLiteSchemaGenerator, 
+                            ansisql.ANSIColumnGenerator,
+                            # at the end so we get the normal
+                            # visit_column by default
+                            SQLiteHelper,
+                            SQLiteCommon
+                            ):
+    """SQLite ColumnGenerator"""
+
+    def _modify_table(self, table, column, delta):
+        columns = ' ,'.join(map(
+                self.preparer.format_column,
+                [c for c in table.columns if c.name!=column.name]))
+        return ('INSERT INTO %%(table_name)s (%(cols)s) '
+                'SELECT %(cols)s from migration_tmp')%{'cols':columns}
+
+    def visit_column(self,column):
+        if column.foreign_keys:
+            SQLiteHelper.visit_column(self,column)
+        else:
+            super(SQLiteColumnGenerator,self).visit_column(column)
+
+class SQLiteColumnDropper(SQLiteHelper, ansisql.ANSIColumnDropper):
+    """SQLite ColumnDropper"""
+
+    def _modify_table(self, table, column, delta):
+        columns = ' ,'.join(map(self.preparer.format_column, table.columns))
+        return 'INSERT INTO %(table_name)s SELECT ' + columns + \
+            ' from migration_tmp'
+
+
+class SQLiteSchemaChanger(SQLiteHelper, ansisql.ANSISchemaChanger):
+    """SQLite SchemaChanger"""
+
+    def _modify_table(self, table, column, delta):
+        return 'INSERT INTO %(table_name)s SELECT * from migration_tmp'
+
+    def visit_index(self, index):
+        """Does not support ALTER INDEX"""
+        self._not_supported('ALTER INDEX')
+
+
+class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator, SQLiteHelper, SQLiteCommon):
+
+    def visit_migrate_primary_key_constraint(self, constraint):
+        tmpl = "CREATE UNIQUE INDEX %s ON %s ( %s )"
+        cols = ', '.join(map(self.preparer.format_column, constraint.columns))
+        tname = self.preparer.format_table(constraint.table)
+        name = self.get_constraint_name(constraint)
+        msg = tmpl % (name, tname, cols)
+        self.append(msg)
+        self.execute()
+
+    def _modify_table(self, table, column, delta):
+        return 'INSERT INTO %(table_name)s SELECT * from migration_tmp'
+
+    def visit_migrate_foreign_key_constraint(self, *p, **k):
+        self.recreate_table(p[0].table)
+
+    def visit_migrate_unique_constraint(self, *p, **k):
+        self.recreate_table(p[0].table)
+
+
+class SQLiteConstraintDropper(ansisql.ANSIColumnDropper,
+                              SQLiteCommon,
+                              ansisql.ANSIConstraintCommon):
+
+    def visit_migrate_primary_key_constraint(self, constraint):
+        tmpl = "DROP INDEX %s "
+        name = self.get_constraint_name(constraint)
+        msg = tmpl % (name)
+        self.append(msg)
+        self.execute()
+
+    def visit_migrate_foreign_key_constraint(self, *p, **k):
+        self._not_supported('ALTER TABLE DROP CONSTRAINT')
+
+    def visit_migrate_check_constraint(self, *p, **k):
+        self._not_supported('ALTER TABLE DROP CONSTRAINT')
+
+    def visit_migrate_unique_constraint(self, *p, **k):
+        self._not_supported('ALTER TABLE DROP CONSTRAINT')
+
+
+# TODO: technically primary key is a NOT NULL + UNIQUE constraint, should add NOT NULL to index
+
+class SQLiteDialect(ansisql.ANSIDialect):
+    columngenerator = SQLiteColumnGenerator
+    columndropper = SQLiteColumnDropper
+    schemachanger = SQLiteSchemaChanger
+    constraintgenerator = SQLiteConstraintGenerator
+    constraintdropper = SQLiteConstraintDropper
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/visitor.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,78 @@
+"""
+   Module for visitor class mapping.
+"""
+import sqlalchemy as sa
+
+from rhodecode.lib.dbmigrate.migrate.changeset import ansisql
+from rhodecode.lib.dbmigrate.migrate.changeset.databases import (sqlite,
+                                         postgres,
+                                         mysql,
+                                         oracle,
+                                         firebird)
+
+
+# Map SA dialects to the corresponding Migrate extensions
+DIALECTS = {
+    "default": ansisql.ANSIDialect,
+    "sqlite": sqlite.SQLiteDialect,
+    "postgres": postgres.PGDialect,
+    "postgresql": postgres.PGDialect,
+    "mysql": mysql.MySQLDialect,
+    "oracle": oracle.OracleDialect,
+    "firebird": firebird.FBDialect,
+}
+
+
+def get_engine_visitor(engine, name):
+    """
+    Get the visitor implementation for the given database engine.
+
+    :param engine: SQLAlchemy Engine
+    :param name: Name of the visitor
+    :type name: string
+    :type engine: Engine
+    :returns: visitor
+    """
+    # TODO: link to supported visitors
+    return get_dialect_visitor(engine.dialect, name)
+
+
+def get_dialect_visitor(sa_dialect, name):
+    """
+    Get the visitor implementation for the given dialect.
+
+    Finds the visitor implementation based on the dialect class and
+    returns and instance initialized with the given name.
+
+    Binds dialect specific preparer to visitor.
+    """
+
+    # map sa dialect to migrate dialect and return visitor
+    sa_dialect_name = getattr(sa_dialect, 'name', 'default')
+    migrate_dialect_cls = DIALECTS[sa_dialect_name]
+    visitor = getattr(migrate_dialect_cls, name)
+
+    # bind preparer
+    visitor.preparer = sa_dialect.preparer(sa_dialect)
+
+    return visitor
+
+def run_single_visitor(engine, visitorcallable, element,
+    connection=None, **kwargs):
+    """Taken from :meth:`sqlalchemy.engine.base.Engine._run_single_visitor`
+    with support for migrate visitors.
+    """
+    if connection is None:
+        conn = engine.contextual_connect(close_with_result=False)
+    else:
+        conn = connection
+    visitor = visitorcallable(engine.dialect, conn)
+    try:
+        if hasattr(element, '__migrate_visit_name__'):
+            fn = getattr(visitor, 'visit_' + element.__migrate_visit_name__)
+        else:
+            fn = getattr(visitor, 'visit_' + element.__visit_name__)
+        fn(element, **kwargs)
+    finally:
+        if connection is None:
+            conn.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/schema.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,669 @@
+"""
+   Schema module providing common schema operations.
+"""
+import warnings
+
+from UserDict import DictMixin
+
+import sqlalchemy
+
+from sqlalchemy.schema import ForeignKeyConstraint
+from sqlalchemy.schema import UniqueConstraint
+
+from rhodecode.lib.dbmigrate.migrate.exceptions import *
+from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
+from rhodecode.lib.dbmigrate.migrate.changeset.databases.visitor import (get_engine_visitor,
+                                                 run_single_visitor)
+
+
+__all__ = [
+    'create_column',
+    'drop_column',
+    'alter_column',
+    'rename_table',
+    'rename_index',
+    'ChangesetTable',
+    'ChangesetColumn',
+    'ChangesetIndex',
+    'ChangesetDefaultClause',
+    'ColumnDelta',
+]
+
+DEFAULT_ALTER_METADATA = True
+
+
+def create_column(column, table=None, *p, **kw):
+    """Create a column, given the table.
+    
+    API to :meth:`ChangesetColumn.create`.
+    """
+    if table is not None:
+        return table.create_column(column, *p, **kw)
+    return column.create(*p, **kw)
+
+
+def drop_column(column, table=None, *p, **kw):
+    """Drop a column, given the table.
+    
+    API to :meth:`ChangesetColumn.drop`.
+    """
+    if table is not None:
+        return table.drop_column(column, *p, **kw)
+    return column.drop(*p, **kw)
+
+
+def rename_table(table, name, engine=None, **kw):
+    """Rename a table.
+
+    If Table instance is given, engine is not used.
+
+    API to :meth:`ChangesetTable.rename`.
+
+    :param table: Table to be renamed.
+    :param name: New name for Table.
+    :param engine: Engine instance.
+    :type table: string or Table instance
+    :type name: string
+    :type engine: obj
+    """
+    table = _to_table(table, engine)
+    table.rename(name, **kw)
+
+
+def rename_index(index, name, table=None, engine=None, **kw):
+    """Rename an index.
+
+    If Index instance is given,
+    table and engine are not used.
+
+    API to :meth:`ChangesetIndex.rename`.
+
+    :param index: Index to be renamed.
+    :param name: New name for index.
+    :param table: Table to which Index is reffered.
+    :param engine: Engine instance.
+    :type index: string or Index instance
+    :type name: string
+    :type table: string or Table instance
+    :type engine: obj
+    """
+    index = _to_index(index, table, engine)
+    index.rename(name, **kw)
+
+
+def alter_column(*p, **k):
+    """Alter a column.
+
+    This is a helper function that creates a :class:`ColumnDelta` and
+    runs it.
+
+    :argument column:
+      The name of the column to be altered or a
+      :class:`ChangesetColumn` column representing it.
+
+    :param table:
+      A :class:`~sqlalchemy.schema.Table` or table name to
+      for the table where the column will be changed.
+
+    :param engine:
+      The :class:`~sqlalchemy.engine.base.Engine` to use for table
+      reflection and schema alterations.
+    
+    :param alter_metadata:
+      If `True`, which is the default, the
+      :class:`~sqlalchemy.schema.Column` will also modified.
+      If `False`, the :class:`~sqlalchemy.schema.Column` will be left
+      as it was.
+    
+    :returns: A :class:`ColumnDelta` instance representing the change.
+
+    
+    """
+
+    k.setdefault('alter_metadata', DEFAULT_ALTER_METADATA)
+
+    if 'table' not in k and isinstance(p[0], sqlalchemy.Column):
+        k['table'] = p[0].table
+    if 'engine' not in k:
+        k['engine'] = k['table'].bind
+
+    # deprecation
+    if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column):
+        warnings.warn(
+            "Passing a Column object to alter_column is deprecated."
+            " Just pass in keyword parameters instead.",
+            MigrateDeprecationWarning
+            )
+    engine = k['engine']
+    delta = ColumnDelta(*p, **k)
+
+    visitorcallable = get_engine_visitor(engine, 'schemachanger')
+    engine._run_visitor(visitorcallable, delta)
+
+    return delta
+
+
+def _to_table(table, engine=None):
+    """Return if instance of Table, else construct new with metadata"""
+    if isinstance(table, sqlalchemy.Table):
+        return table
+
+    # Given: table name, maybe an engine
+    meta = sqlalchemy.MetaData()
+    if engine is not None:
+        meta.bind = engine
+    return sqlalchemy.Table(table, meta)
+
+
+def _to_index(index, table=None, engine=None):
+    """Return if instance of Index, else construct new with metadata"""
+    if isinstance(index, sqlalchemy.Index):
+        return index
+
+    # Given: index name; table name required
+    table = _to_table(table, engine)
+    ret = sqlalchemy.Index(index)
+    ret.table = table
+    return ret
+
+
+class ColumnDelta(DictMixin, sqlalchemy.schema.SchemaItem):
+    """Extracts the differences between two columns/column-parameters
+
+        May receive parameters arranged in several different ways:
+
+        * **current_column, new_column, \*p, \*\*kw**
+            Additional parameters can be specified to override column
+            differences.
+
+        * **current_column, \*p, \*\*kw**
+            Additional parameters alter current_column. Table name is extracted
+            from current_column object.
+            Name is changed to current_column.name from current_name,
+            if current_name is specified.
+
+        * **current_col_name, \*p, \*\*kw**
+            Table kw must specified.
+
+        :param table: Table at which current Column should be bound to.\
+        If table name is given, reflection will be used.
+        :type table: string or Table instance
+        :param alter_metadata: If True, it will apply changes to metadata.
+        :type alter_metadata: bool
+        :param metadata: If `alter_metadata` is true, \
+        metadata is used to reflect table names into
+        :type metadata: :class:`MetaData` instance
+        :param engine: When reflecting tables, either engine or metadata must \
+        be specified to acquire engine object.
+        :type engine: :class:`Engine` instance
+        :returns: :class:`ColumnDelta` instance provides interface for altered attributes to \
+        `result_column` through :func:`dict` alike object.
+
+        * :class:`ColumnDelta`.result_column is altered column with new attributes
+
+        * :class:`ColumnDelta`.current_name is current name of column in db
+
+
+    """
+
+    # Column attributes that can be altered
+    diff_keys = ('name', 'type', 'primary_key', 'nullable',
+        'server_onupdate', 'server_default', 'autoincrement')
+    diffs = dict()
+    __visit_name__ = 'column'
+
+    def __init__(self, *p, **kw):
+        self.alter_metadata = kw.pop("alter_metadata", False)
+        self.meta = kw.pop("metadata", None)
+        self.engine = kw.pop("engine", None)
+
+        # Things are initialized differently depending on how many column
+        # parameters are given. Figure out how many and call the appropriate
+        # method.
+        if len(p) >= 1 and isinstance(p[0], sqlalchemy.Column):
+            # At least one column specified
+            if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column):
+                # Two columns specified
+                diffs = self.compare_2_columns(*p, **kw)
+            else:
+                # Exactly one column specified
+                diffs = self.compare_1_column(*p, **kw)
+        else:
+            # Zero columns specified
+            if not len(p) or not isinstance(p[0], basestring):
+                raise ValueError("First argument must be column name")
+            diffs = self.compare_parameters(*p, **kw)
+
+        self.apply_diffs(diffs)
+
+    def __repr__(self):
+        return '<ColumnDelta altermetadata=%r, %s>' % (self.alter_metadata,
+            super(ColumnDelta, self).__repr__())
+
+    def __getitem__(self, key):
+        if key not in self.keys():
+            raise KeyError("No such diff key, available: %s" % self.diffs)
+        return getattr(self.result_column, key)
+
+    def __setitem__(self, key, value):
+        if key not in self.keys():
+            raise KeyError("No such diff key, available: %s" % self.diffs)
+        setattr(self.result_column, key, value)
+
+    def __delitem__(self, key):
+        raise NotImplementedError
+
+    def keys(self):
+        return self.diffs.keys()
+
+    def compare_parameters(self, current_name, *p, **k):
+        """Compares Column objects with reflection"""
+        self.table = k.pop('table')
+        self.result_column = self._table.c.get(current_name)
+        if len(p):
+            k = self._extract_parameters(p, k, self.result_column)
+        return k
+
+    def compare_1_column(self, col, *p, **k):
+        """Compares one Column object"""
+        self.table = k.pop('table', None)
+        if self.table is None:
+            self.table = col.table
+        self.result_column = col
+        if len(p):
+            k = self._extract_parameters(p, k, self.result_column)
+        return k
+
+    def compare_2_columns(self, old_col, new_col, *p, **k):
+        """Compares two Column objects"""
+        self.process_column(new_col)
+        self.table = k.pop('table', None)
+        # we cannot use bool() on table in SA06 
+        if self.table is None:
+            self.table = old_col.table
+        if self.table is None:
+            new_col.table
+        self.result_column = old_col
+
+        # set differences
+        # leave out some stuff for later comp
+        for key in (set(self.diff_keys) - set(('type',))):
+            val = getattr(new_col, key, None)
+            if getattr(self.result_column, key, None) != val:
+                k.setdefault(key, val)
+
+        # inspect types
+        if not self.are_column_types_eq(self.result_column.type, new_col.type):
+            k.setdefault('type', new_col.type)
+
+        if len(p):
+            k = self._extract_parameters(p, k, self.result_column)
+        return k
+
+    def apply_diffs(self, diffs):
+        """Populate dict and column object with new values"""
+        self.diffs = diffs
+        for key in self.diff_keys:
+            if key in diffs:
+                setattr(self.result_column, key, diffs[key])
+
+        self.process_column(self.result_column)
+
+        # create an instance of class type if not yet
+        if 'type' in diffs and callable(self.result_column.type):
+            self.result_column.type = self.result_column.type()
+
+        # add column to the table
+        if self.table is not None and self.alter_metadata:
+            self.result_column.add_to_table(self.table)
+
+    def are_column_types_eq(self, old_type, new_type):
+        """Compares two types to be equal"""
+        ret = old_type.__class__ == new_type.__class__
+
+        # String length is a special case
+        if ret and isinstance(new_type, sqlalchemy.types.String):
+            ret = (getattr(old_type, 'length', None) == \
+                       getattr(new_type, 'length', None))
+        return ret
+
+    def _extract_parameters(self, p, k, column):
+        """Extracts data from p and modifies diffs"""
+        p = list(p)
+        while len(p):
+            if isinstance(p[0], basestring):
+                k.setdefault('name', p.pop(0))
+            elif isinstance(p[0], sqlalchemy.types.AbstractType):
+                k.setdefault('type', p.pop(0))
+            elif callable(p[0]):
+                p[0] = p[0]()
+            else:
+                break
+
+        if len(p):
+            new_col = column.copy_fixed()
+            new_col._init_items(*p)
+            k = self.compare_2_columns(column, new_col, **k)
+        return k
+
+    def process_column(self, column):
+        """Processes default values for column"""
+        # XXX: this is a snippet from SA processing of positional parameters
+        if not SQLA_06 and column.args:
+            toinit = list(column.args)
+        else:
+            toinit = list()
+
+        if column.server_default is not None:
+            if isinstance(column.server_default, sqlalchemy.FetchedValue):
+                toinit.append(column.server_default)
+            else:
+                toinit.append(sqlalchemy.DefaultClause(column.server_default))
+        if column.server_onupdate is not None:
+            if isinstance(column.server_onupdate, FetchedValue):
+                toinit.append(column.server_default)
+            else:
+                toinit.append(sqlalchemy.DefaultClause(column.server_onupdate,
+                                            for_update=True))
+        if toinit:
+            column._init_items(*toinit)
+
+        if not SQLA_06:
+            column.args = []
+
+    def _get_table(self):
+        return getattr(self, '_table', None)
+
+    def _set_table(self, table):
+        if isinstance(table, basestring):
+            if self.alter_metadata:
+                if not self.meta:
+                    raise ValueError("metadata must be specified for table"
+                        " reflection when using alter_metadata")
+                meta = self.meta
+                if self.engine:
+                    meta.bind = self.engine
+            else:
+                if not self.engine and not self.meta:
+                    raise ValueError("engine or metadata must be specified"
+                        " to reflect tables")
+                if not self.engine:
+                    self.engine = self.meta.bind
+                meta = sqlalchemy.MetaData(bind=self.engine)
+            self._table = sqlalchemy.Table(table, meta, autoload=True)
+        elif isinstance(table, sqlalchemy.Table):
+            self._table = table
+            if not self.alter_metadata:
+                self._table.meta = sqlalchemy.MetaData(bind=self._table.bind)
+
+    def _get_result_column(self):
+        return getattr(self, '_result_column', None)
+
+    def _set_result_column(self, column):
+        """Set Column to Table based on alter_metadata evaluation."""
+        self.process_column(column)
+        if not hasattr(self, 'current_name'):
+            self.current_name = column.name
+        if self.alter_metadata:
+            self._result_column = column
+        else:
+            self._result_column = column.copy_fixed()
+
+    table = property(_get_table, _set_table)
+    result_column = property(_get_result_column, _set_result_column)
+
+
+class ChangesetTable(object):
+    """Changeset extensions to SQLAlchemy tables."""
+
+    def create_column(self, column, *p, **kw):
+        """Creates a column.
+
+        The column parameter may be a column definition or the name of
+        a column in this table.
+
+        API to :meth:`ChangesetColumn.create`
+
+        :param column: Column to be created
+        :type column: Column instance or string
+        """
+        if not isinstance(column, sqlalchemy.Column):
+            # It's a column name
+            column = getattr(self.c, str(column))
+        column.create(table=self, *p, **kw)
+
+    def drop_column(self, column, *p, **kw):
+        """Drop a column, given its name or definition.
+
+        API to :meth:`ChangesetColumn.drop`
+
+        :param column: Column to be droped
+        :type column: Column instance or string
+        """
+        if not isinstance(column, sqlalchemy.Column):
+            # It's a column name
+            try:
+                column = getattr(self.c, str(column))
+            except AttributeError:
+                # That column isn't part of the table. We don't need
+                # its entire definition to drop the column, just its
+                # name, so create a dummy column with the same name.
+                column = sqlalchemy.Column(str(column), sqlalchemy.Integer())
+        column.drop(table=self, *p, **kw)
+
+    def rename(self, name, connection=None, **kwargs):
+        """Rename this table.
+
+        :param name: New name of the table.
+        :type name: string
+        :param alter_metadata: If True, table will be removed from metadata
+        :type alter_metadata: bool
+        :param connection: reuse connection istead of creating new one.
+        :type connection: :class:`sqlalchemy.engine.base.Connection` instance
+        """
+        self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
+        engine = self.bind
+        self.new_name = name
+        visitorcallable = get_engine_visitor(engine, 'schemachanger')
+        run_single_visitor(engine, visitorcallable, self, connection, **kwargs)
+
+        # Fix metadata registration
+        if self.alter_metadata:
+            self.name = name
+            self.deregister()
+            self._set_parent(self.metadata)
+
+    def _meta_key(self):
+        return sqlalchemy.schema._get_table_key(self.name, self.schema)
+
+    def deregister(self):
+        """Remove this table from its metadata"""
+        key = self._meta_key()
+        meta = self.metadata
+        if key in meta.tables:
+            del meta.tables[key]
+
+
+class ChangesetColumn(object):
+    """Changeset extensions to SQLAlchemy columns."""
+
+    def alter(self, *p, **k):
+        """Makes a call to :func:`alter_column` for the column this
+        method is called on. 
+        """
+        if 'table' not in k:
+            k['table'] = self.table
+        if 'engine' not in k:
+            k['engine'] = k['table'].bind
+        return alter_column(self, *p, **k)
+
+    def create(self, table=None, index_name=None, unique_name=None,
+               primary_key_name=None, populate_default=True, connection=None, **kwargs):
+        """Create this column in the database.
+
+        Assumes the given table exists. ``ALTER TABLE ADD COLUMN``,
+        for most databases.
+
+        :param table: Table instance to create on.
+        :param index_name: Creates :class:`ChangesetIndex` on this column.
+        :param unique_name: Creates :class:\
+`~migrate.changeset.constraint.UniqueConstraint` on this column.
+        :param primary_key_name: Creates :class:\
+`~migrate.changeset.constraint.PrimaryKeyConstraint` on this column.
+        :param alter_metadata: If True, column will be added to table object.
+        :param populate_default: If True, created column will be \
+populated with defaults
+        :param connection: reuse connection istead of creating new one.
+        :type table: Table instance
+        :type index_name: string
+        :type unique_name: string
+        :type primary_key_name: string
+        :type alter_metadata: bool
+        :type populate_default: bool
+        :type connection: :class:`sqlalchemy.engine.base.Connection` instance
+
+        :returns: self
+        """
+        self.populate_default = populate_default
+        self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
+        self.index_name = index_name
+        self.unique_name = unique_name
+        self.primary_key_name = primary_key_name
+        for cons in ('index_name', 'unique_name', 'primary_key_name'):
+            self._check_sanity_constraints(cons)
+
+        if self.alter_metadata:
+            self.add_to_table(table)
+        engine = self.table.bind
+        visitorcallable = get_engine_visitor(engine, 'columngenerator')
+        engine._run_visitor(visitorcallable, self, connection, **kwargs)
+
+        # TODO: reuse existing connection
+        if self.populate_default and self.default is not None:
+            stmt = table.update().values({self: engine._execute_default(self.default)})
+            engine.execute(stmt)
+
+        return self
+
+    def drop(self, table=None, connection=None, **kwargs):
+        """Drop this column from the database, leaving its table intact.
+
+        ``ALTER TABLE DROP COLUMN``, for most databases.
+
+        :param alter_metadata: If True, column will be removed from table object.
+        :type alter_metadata: bool
+        :param connection: reuse connection istead of creating new one.
+        :type connection: :class:`sqlalchemy.engine.base.Connection` instance
+        """
+        self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
+        if table is not None:
+            self.table = table
+        engine = self.table.bind
+        if self.alter_metadata:
+            self.remove_from_table(self.table, unset_table=False)
+        visitorcallable = get_engine_visitor(engine, 'columndropper')
+        engine._run_visitor(visitorcallable, self, connection, **kwargs)
+        if self.alter_metadata:
+            self.table = None
+        return self
+
+    def add_to_table(self, table):
+        if table is not None  and self.table is None:
+            self._set_parent(table)
+
+    def _col_name_in_constraint(self, cons, name):
+        return False
+
+    def remove_from_table(self, table, unset_table=True):
+        # TODO: remove primary keys, constraints, etc
+        if unset_table:
+            self.table = None
+
+        to_drop = set()
+        for index in table.indexes:
+            columns = []
+            for col in index.columns:
+                if col.name != self.name:
+                    columns.append(col)
+            if columns:
+                index.columns = columns
+            else:
+                to_drop.add(index)
+        table.indexes = table.indexes - to_drop
+
+        to_drop = set()
+        for cons in table.constraints:
+            # TODO: deal with other types of constraint
+            if isinstance(cons, (ForeignKeyConstraint,
+                                UniqueConstraint)):
+                for col_name in cons.columns:
+                    if not isinstance(col_name, basestring):
+                        col_name = col_name.name
+                    if self.name == col_name:
+                        to_drop.add(cons)
+        table.constraints = table.constraints - to_drop
+
+        if table.c.contains_column(self):
+            table.c.remove(self)
+
+    # TODO: this is fixed in 0.6
+    def copy_fixed(self, **kw):
+        """Create a copy of this ``Column``, with all attributes."""
+        return sqlalchemy.Column(self.name, self.type, self.default,
+            key=self.key,
+            primary_key=self.primary_key,
+            nullable=self.nullable,
+            quote=self.quote,
+            index=self.index,
+            unique=self.unique,
+            onupdate=self.onupdate,
+            autoincrement=self.autoincrement,
+            server_default=self.server_default,
+            server_onupdate=self.server_onupdate,
+            *[c.copy(**kw) for c in self.constraints])
+
+    def _check_sanity_constraints(self, name):
+        """Check if constraints names are correct"""
+        obj = getattr(self, name)
+        if (getattr(self, name[:-5]) and not obj):
+            raise InvalidConstraintError("Column.create() accepts index_name,"
+            " primary_key_name and unique_name to generate constraints")
+        if not isinstance(obj, basestring) and obj is not None:
+            raise InvalidConstraintError(
+            "%s argument for column must be constraint name" % name)
+
+
+class ChangesetIndex(object):
+    """Changeset extensions to SQLAlchemy Indexes."""
+
+    __visit_name__ = 'index'
+
+    def rename(self, name, connection=None, **kwargs):
+        """Change the name of an index.
+
+        :param name: New name of the Index.
+        :type name: string
+        :param alter_metadata: If True, Index object will be altered.
+        :type alter_metadata: bool
+        :param connection: reuse connection istead of creating new one.
+        :type connection: :class:`sqlalchemy.engine.base.Connection` instance
+        """
+        self.alter_metadata = kwargs.pop('alter_metadata', DEFAULT_ALTER_METADATA)
+        engine = self.table.bind
+        self.new_name = name
+        visitorcallable = get_engine_visitor(engine, 'schemachanger')
+        engine._run_visitor(visitorcallable, self, connection, **kwargs)
+        if self.alter_metadata:
+            self.name = name
+
+
+class ChangesetDefaultClause(object):
+    """Implements comparison between :class:`DefaultClause` instances"""
+
+    def __eq__(self, other):
+        if isinstance(other, self.__class__):
+            if self.arg == other.arg:
+                return True
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/exceptions.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,87 @@
+"""
+   Provide exception classes for :mod:`migrate`
+"""
+
+
+class Error(Exception):
+    """Error base class."""
+
+
+class ApiError(Error):
+    """Base class for API errors."""
+
+
+class KnownError(ApiError):
+    """A known error condition."""
+
+
+class UsageError(ApiError):
+    """A known error condition where help should be displayed."""
+
+
+class ControlledSchemaError(Error):
+    """Base class for controlled schema errors."""
+
+
+class InvalidVersionError(ControlledSchemaError):
+    """Invalid version number."""
+
+
+class DatabaseNotControlledError(ControlledSchemaError):
+    """Database should be under version control, but it's not."""
+
+
+class DatabaseAlreadyControlledError(ControlledSchemaError):
+    """Database shouldn't be under version control, but it is"""
+
+
+class WrongRepositoryError(ControlledSchemaError):
+    """This database is under version control by another repository."""
+
+
+class NoSuchTableError(ControlledSchemaError):
+    """The table does not exist."""
+
+
+class PathError(Error):
+    """Base class for path errors."""
+
+
+class PathNotFoundError(PathError):
+    """A path with no file was required; found a file."""
+
+
+class PathFoundError(PathError):
+    """A path with a file was required; found no file."""
+
+
+class RepositoryError(Error):
+    """Base class for repository errors."""
+
+
+class InvalidRepositoryError(RepositoryError):
+    """Invalid repository error."""
+
+
+class ScriptError(Error):
+    """Base class for script errors."""
+
+
+class InvalidScriptError(ScriptError):
+    """Invalid script error."""
+
+
+class InvalidVersionError(Error):
+    """Invalid version error."""
+
+# migrate.changeset
+
+class NotSupportedError(Error):
+    """Not supported error"""
+
+
+class InvalidConstraintError(Error):
+    """Invalid constraint error"""
+
+class MigrateDeprecationWarning(DeprecationWarning):
+    """Warning for deprecated features in Migrate"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,5 @@
+"""
+   This package provides functionality to create and manage
+   repositories of database schema changesets and to apply these
+   changesets to databases.
+"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/api.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,383 @@
+"""
+   This module provides an external API to the versioning system.
+
+   .. versionchanged:: 0.6.0
+    :func:`migrate.versioning.api.test` and schema diff functions
+    changed order of positional arguments so all accept `url` and `repository`
+    as first arguments.
+
+   .. versionchanged:: 0.5.4
+    ``--preview_sql`` displays source file when using SQL scripts.
+    If Python script is used, it runs the action with mocked engine and
+    returns captured SQL statements.
+
+   .. versionchanged:: 0.5.4
+    Deprecated ``--echo`` parameter in favour of new
+    :func:`migrate.versioning.util.construct_engine` behavior.
+"""
+
+# Dear migrate developers,
+#
+# please do not comment this module using sphinx syntax because its
+# docstrings are presented as user help and most users cannot
+# interpret sphinx annotated ReStructuredText.
+#
+# Thanks,
+# Jan Dittberner
+
+import sys
+import inspect
+import logging
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning import repository, schema, version, \
+    script as script_ # command name conflict
+from rhodecode.lib.dbmigrate.migrate.versioning.util import catch_known_errors, with_engine
+
+
+log = logging.getLogger(__name__)
+command_desc = {
+    'help': 'displays help on a given command',
+    'create': 'create an empty repository at the specified path',
+    'script': 'create an empty change Python script',
+    'script_sql': 'create empty change SQL scripts for given database',
+    'version': 'display the latest version available in a repository',
+    'db_version': 'show the current version of the repository under version control',
+    'source': 'display the Python code for a particular version in this repository',
+    'version_control': 'mark a database as under this repository\'s version control',
+    'upgrade': 'upgrade a database to a later version',
+    'downgrade': 'downgrade a database to an earlier version',
+    'drop_version_control': 'removes version control from a database',
+    'manage': 'creates a Python script that runs Migrate with a set of default values',
+    'test': 'performs the upgrade and downgrade command on the given database',
+    'compare_model_to_db': 'compare MetaData against the current database state',
+    'create_model': 'dump the current database as a Python model to stdout',
+    'make_update_script_for_model': 'create a script changing the old MetaData to the new (current) MetaData',
+    'update_db_from_model': 'modify the database to match the structure of the current MetaData',
+}
+__all__ = command_desc.keys()
+
+Repository = repository.Repository
+ControlledSchema = schema.ControlledSchema
+VerNum = version.VerNum
+PythonScript = script_.PythonScript
+SqlScript = script_.SqlScript
+
+
+# deprecated
+def help(cmd=None, **opts):
+    """%prog help COMMAND
+
+    Displays help on a given command.
+    """
+    if cmd is None:
+        raise exceptions.UsageError(None)
+    try:
+        func = globals()[cmd]
+    except:
+        raise exceptions.UsageError(
+            "'%s' isn't a valid command. Try 'help COMMAND'" % cmd)
+    ret = func.__doc__
+    if sys.argv[0]:
+        ret = ret.replace('%prog', sys.argv[0])
+    return ret
+
+@catch_known_errors
+def create(repository, name, **opts):
+    """%prog create REPOSITORY_PATH NAME [--table=TABLE]
+
+    Create an empty repository at the specified path.
+
+    You can specify the version_table to be used; by default, it is
+    'migrate_version'.  This table is created in all version-controlled
+    databases.
+    """
+    repo_path = Repository.create(repository, name, **opts)
+
+
+@catch_known_errors
+def script(description, repository, **opts):
+    """%prog script DESCRIPTION REPOSITORY_PATH
+
+    Create an empty change script using the next unused version number
+    appended with the given description.
+
+    For instance, manage.py script "Add initial tables" creates:
+    repository/versions/001_Add_initial_tables.py
+    """
+    repo = Repository(repository)
+    repo.create_script(description, **opts)
+
+
+@catch_known_errors
+def script_sql(database, repository, **opts):
+    """%prog script_sql DATABASE REPOSITORY_PATH
+
+    Create empty change SQL scripts for given DATABASE, where DATABASE
+    is either specific ('postgres', 'mysql', 'oracle', 'sqlite', etc.)
+    or generic ('default').
+
+    For instance, manage.py script_sql postgres creates:
+    repository/versions/001_postgres_upgrade.sql and
+    repository/versions/001_postgres_postgres.sql
+    """
+    repo = Repository(repository)
+    repo.create_script_sql(database, **opts)
+
+
+def version(repository, **opts):
+    """%prog version REPOSITORY_PATH
+
+    Display the latest version available in a repository.
+    """
+    repo = Repository(repository)
+    return repo.latest
+
+
+@with_engine
+def db_version(url, repository, **opts):
+    """%prog db_version URL REPOSITORY_PATH
+
+    Show the current version of the repository with the given
+    connection string, under version control of the specified
+    repository.
+
+    The url should be any valid SQLAlchemy connection string.
+    """
+    engine = opts.pop('engine')
+    schema = ControlledSchema(engine, repository)
+    return schema.version
+
+
+def source(version, dest=None, repository=None, **opts):
+    """%prog source VERSION [DESTINATION] --repository=REPOSITORY_PATH
+
+    Display the Python code for a particular version in this
+    repository.  Save it to the file at DESTINATION or, if omitted,
+    send to stdout.
+    """
+    if repository is None:
+        raise exceptions.UsageError("A repository must be specified")
+    repo = Repository(repository)
+    ret = repo.version(version).script().source()
+    if dest is not None:
+        dest = open(dest, 'w')
+        dest.write(ret)
+        dest.close()
+        ret = None
+    return ret
+
+
+def upgrade(url, repository, version=None, **opts):
+    """%prog upgrade URL REPOSITORY_PATH [VERSION] [--preview_py|--preview_sql]
+
+    Upgrade a database to a later version.
+
+    This runs the upgrade() function defined in your change scripts.
+
+    By default, the database is updated to the latest available
+    version. You may specify a version instead, if you wish.
+
+    You may preview the Python or SQL code to be executed, rather than
+    actually executing it, using the appropriate 'preview' option.
+    """
+    err = "Cannot upgrade a database of version %s to version %s. "\
+        "Try 'downgrade' instead."
+    return _migrate(url, repository, version, upgrade=True, err=err, **opts)
+
+
+def downgrade(url, repository, version, **opts):
+    """%prog downgrade URL REPOSITORY_PATH VERSION [--preview_py|--preview_sql]
+
+    Downgrade a database to an earlier version.
+
+    This is the reverse of upgrade; this runs the downgrade() function
+    defined in your change scripts.
+
+    You may preview the Python or SQL code to be executed, rather than
+    actually executing it, using the appropriate 'preview' option.
+    """
+    err = "Cannot downgrade a database of version %s to version %s. "\
+        "Try 'upgrade' instead."
+    return _migrate(url, repository, version, upgrade=False, err=err, **opts)
+
+@with_engine
+def test(url, repository, **opts):
+    """%prog test URL REPOSITORY_PATH [VERSION]
+
+    Performs the upgrade and downgrade option on the given
+    database. This is not a real test and may leave the database in a
+    bad state. You should therefore better run the test on a copy of
+    your database.
+    """
+    engine = opts.pop('engine')
+    repos = Repository(repository)
+    script = repos.version(None).script()
+
+    # Upgrade
+    log.info("Upgrading...")
+    script.run(engine, 1)
+    log.info("done")
+
+    log.info("Downgrading...")
+    script.run(engine, -1)
+    log.info("done")
+    log.info("Success")
+
+
+@with_engine
+def version_control(url, repository, version=None, **opts):
+    """%prog version_control URL REPOSITORY_PATH [VERSION]
+
+    Mark a database as under this repository's version control.
+
+    Once a database is under version control, schema changes should
+    only be done via change scripts in this repository.
+
+    This creates the table version_table in the database.
+
+    The url should be any valid SQLAlchemy connection string.
+
+    By default, the database begins at version 0 and is assumed to be
+    empty.  If the database is not empty, you may specify a version at
+    which to begin instead. No attempt is made to verify this
+    version's correctness - the database schema is expected to be
+    identical to what it would be if the database were created from
+    scratch.
+    """
+    engine = opts.pop('engine')
+    ControlledSchema.create(engine, repository, version)
+
+
+@with_engine
+def drop_version_control(url, repository, **opts):
+    """%prog drop_version_control URL REPOSITORY_PATH
+
+    Removes version control from a database.
+    """
+    engine = opts.pop('engine')
+    schema = ControlledSchema(engine, repository)
+    schema.drop()
+
+
+def manage(file, **opts):
+    """%prog manage FILENAME [VARIABLES...]
+
+    Creates a script that runs Migrate with a set of default values.
+
+    For example::
+
+        %prog manage manage.py --repository=/path/to/repository \
+--url=sqlite:///project.db
+
+    would create the script manage.py. The following two commands
+    would then have exactly the same results::
+
+        python manage.py version
+        %prog version --repository=/path/to/repository
+    """
+    Repository.create_manage_file(file, **opts)
+
+
+@with_engine
+def compare_model_to_db(url, repository, model, **opts):
+    """%prog compare_model_to_db URL REPOSITORY_PATH MODEL
+
+    Compare the current model (assumed to be a module level variable
+    of type sqlalchemy.MetaData) against the current database.
+
+    NOTE: This is EXPERIMENTAL.
+    """  # TODO: get rid of EXPERIMENTAL label
+    engine = opts.pop('engine')
+    return ControlledSchema.compare_model_to_db(engine, model, repository)
+
+
+@with_engine
+def create_model(url, repository, **opts):
+    """%prog create_model URL REPOSITORY_PATH [DECLERATIVE=True]
+
+    Dump the current database as a Python model to stdout.
+
+    NOTE: This is EXPERIMENTAL.
+    """  # TODO: get rid of EXPERIMENTAL label
+    engine = opts.pop('engine')
+    declarative = opts.get('declarative', False)
+    return ControlledSchema.create_model(engine, repository, declarative)
+
+
+@catch_known_errors
+@with_engine
+def make_update_script_for_model(url, repository, oldmodel, model, **opts):
+    """%prog make_update_script_for_model URL OLDMODEL MODEL REPOSITORY_PATH
+
+    Create a script changing the old Python model to the new (current)
+    Python model, sending to stdout.
+
+    NOTE: This is EXPERIMENTAL.
+    """  # TODO: get rid of EXPERIMENTAL label
+    engine = opts.pop('engine')
+    return PythonScript.make_update_script_for_model(
+        engine, oldmodel, model, repository, **opts)
+
+
+@with_engine
+def update_db_from_model(url, repository, model, **opts):
+    """%prog update_db_from_model URL REPOSITORY_PATH MODEL
+
+    Modify the database to match the structure of the current Python
+    model. This also sets the db_version number to the latest in the
+    repository.
+
+    NOTE: This is EXPERIMENTAL.
+    """  # TODO: get rid of EXPERIMENTAL label
+    engine = opts.pop('engine')
+    schema = ControlledSchema(engine, repository)
+    schema.update_db_from_model(model)
+
+@with_engine
+def _migrate(url, repository, version, upgrade, err, **opts):
+    engine = opts.pop('engine')
+    url = str(engine.url)
+    schema = ControlledSchema(engine, repository)
+    version = _migrate_version(schema, version, upgrade, err)
+
+    changeset = schema.changeset(version)
+    for ver, change in changeset:
+        nextver = ver + changeset.step
+        log.info('%s -> %s... ', ver, nextver)
+
+        if opts.get('preview_sql'):
+            if isinstance(change, PythonScript):
+                log.info(change.preview_sql(url, changeset.step, **opts))
+            elif isinstance(change, SqlScript):
+                log.info(change.source())
+
+        elif opts.get('preview_py'):
+            if not isinstance(change, PythonScript):
+                raise exceptions.UsageError("Python source can be only displayed"
+                    " for python migration files")
+            source_ver = max(ver, nextver)
+            module = schema.repository.version(source_ver).script().module
+            funcname = upgrade and "upgrade" or "downgrade"
+            func = getattr(module, funcname)
+            log.info(inspect.getsource(func))
+        else:
+            schema.runchange(ver, change, changeset.step)
+            log.info('done')
+
+
+def _migrate_version(schema, version, upgrade, err):
+    if version is None:
+        return version
+    # Version is specified: ensure we're upgrading in the right direction
+    # (current version < target version for upgrading; reverse for down)
+    version = VerNum(version)
+    cur = schema.version
+    if upgrade is not None:
+        if upgrade:
+            direction = cur <= version
+        else:
+            direction = cur >= version
+        if not direction:
+            raise exceptions.KnownError(err % (cur, version))
+    return version
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/cfgparse.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,27 @@
+"""
+   Configuration parser module.
+"""
+
+from ConfigParser import ConfigParser
+
+from rhodecode.lib.dbmigrate.migrate.versioning.config import *
+from rhodecode.lib.dbmigrate.migrate.versioning import pathed
+
+
+class Parser(ConfigParser):
+    """A project configuration file."""
+
+    def to_dict(self, sections=None):
+        """It's easier to access config values like dictionaries"""
+        return self._sections
+
+
+class Config(pathed.Pathed, Parser):
+    """Configuration class."""
+
+    def __init__(self, path, *p, **k):
+        """Confirm the config file exists; read it."""
+        self.require_found(path)
+        pathed.Pathed.__init__(self, path)
+        Parser.__init__(self, *p, **k)
+        self.read(path)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/config.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from sqlalchemy.util import OrderedDict
+
+
+__all__ = ['databases', 'operations']
+
+databases = ('sqlite', 'postgres', 'mysql', 'oracle', 'mssql', 'firebird')
+
+# Map operation names to function names
+operations = OrderedDict()
+operations['upgrade'] = 'upgrade'
+operations['downgrade'] = 'downgrade'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/genmodel.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,253 @@
+"""
+   Code to generate a Python model from a database or differences
+   between a model and database.
+
+   Some of this is borrowed heavily from the AutoCode project at:
+   http://code.google.com/p/sqlautocode/
+"""
+
+import sys
+import logging
+
+import sqlalchemy
+
+from rhodecode.lib.dbmigrate import migrate
+from rhodecode.lib.dbmigrate.migrate import changeset
+
+log = logging.getLogger(__name__)
+HEADER = """
+## File autogenerated by genmodel.py
+
+from sqlalchemy import *
+meta = MetaData()
+"""
+
+DECLARATIVE_HEADER = """
+## File autogenerated by genmodel.py
+
+from sqlalchemy import *
+from sqlalchemy.ext import declarative
+
+Base = declarative.declarative_base()
+"""
+
+
+class ModelGenerator(object):
+
+    def __init__(self, diff, engine, declarative=False):
+        self.diff = diff
+        self.engine = engine
+        self.declarative = declarative
+
+    def column_repr(self, col):
+        kwarg = []
+        if col.key != col.name:
+            kwarg.append('key')
+        if col.primary_key:
+            col.primary_key = True  # otherwise it dumps it as 1
+            kwarg.append('primary_key')
+        if not col.nullable:
+            kwarg.append('nullable')
+        if col.onupdate:
+            kwarg.append('onupdate')
+        if col.default:
+            if col.primary_key:
+                # I found that PostgreSQL automatically creates a
+                # default value for the sequence, but let's not show
+                # that.
+                pass
+            else:
+                kwarg.append('default')
+        ks = ', '.join('%s=%r' % (k, getattr(col, k)) for k in kwarg)
+
+        # crs: not sure if this is good idea, but it gets rid of extra
+        # u''
+        name = col.name.encode('utf8')
+
+        type_ = col.type
+        for cls in col.type.__class__.__mro__:
+            if cls.__module__ == 'sqlalchemy.types' and \
+                not cls.__name__.isupper():
+                if cls is not type_.__class__:
+                    type_ = cls()
+                break
+
+        data = {
+            'name': name,
+            'type': type_,
+            'constraints': ', '.join([repr(cn) for cn in col.constraints]),
+            'args': ks and ks or ''}
+
+        if data['constraints']:
+            if data['args']:
+                data['args'] = ',' + data['args']
+
+        if data['constraints'] or data['args']:
+            data['maybeComma'] = ','
+        else:
+            data['maybeComma'] = ''
+
+        commonStuff = """ %(maybeComma)s %(constraints)s %(args)s)""" % data
+        commonStuff = commonStuff.strip()
+        data['commonStuff'] = commonStuff
+        if self.declarative:
+            return """%(name)s = Column(%(type)r%(commonStuff)s""" % data
+        else:
+            return """Column(%(name)r, %(type)r%(commonStuff)s""" % data
+
+    def getTableDefn(self, table):
+        out = []
+        tableName = table.name
+        if self.declarative:
+            out.append("class %(table)s(Base):" % {'table': tableName})
+            out.append("  __tablename__ = '%(table)s'" % {'table': tableName})
+            for col in table.columns:
+                out.append("  %s" % self.column_repr(col))
+        else:
+            out.append("%(table)s = Table('%(table)s', meta," % \
+                           {'table': tableName})
+            for col in table.columns:
+                out.append("  %s," % self.column_repr(col))
+            out.append(")")
+        return out
+
+    def _get_tables(self, missingA=False, missingB=False, modified=False):
+        to_process = []
+        for bool_, names, metadata in (
+            (missingA, self.diff.tables_missing_from_A, self.diff.metadataB),
+            (missingB, self.diff.tables_missing_from_B, self.diff.metadataA),
+            (modified, self.diff.tables_different, self.diff.metadataA),
+                ):
+            if bool_:
+                for name in names:
+                    yield metadata.tables.get(name)
+
+    def toPython(self):
+        """Assume database is current and model is empty."""
+        out = []
+        if self.declarative:
+            out.append(DECLARATIVE_HEADER)
+        else:
+            out.append(HEADER)
+        out.append("")
+        for table in self._get_tables(missingA=True):
+            out.extend(self.getTableDefn(table))
+            out.append("")
+        return '\n'.join(out)
+
+    def toUpgradeDowngradePython(self, indent='    '):
+        ''' Assume model is most current and database is out-of-date. '''
+        decls = ['from rhodecode.lib.dbmigrate.migrate.changeset import schema',
+                 'meta = MetaData()']
+        for table in self._get_tables(
+            missingA=True, missingB=True, modified=True
+            ):
+            decls.extend(self.getTableDefn(table))
+
+        upgradeCommands, downgradeCommands = [], []
+        for tableName in self.diff.tables_missing_from_A:
+            upgradeCommands.append("%(table)s.drop()" % {'table': tableName})
+            downgradeCommands.append("%(table)s.create()" % \
+                                         {'table': tableName})
+        for tableName in self.diff.tables_missing_from_B:
+            upgradeCommands.append("%(table)s.create()" % {'table': tableName})
+            downgradeCommands.append("%(table)s.drop()" % {'table': tableName})
+
+        for tableName in self.diff.tables_different:
+            dbTable = self.diff.metadataB.tables[tableName]
+            missingInDatabase, missingInModel, diffDecl = \
+                self.diff.colDiffs[tableName]
+            for col in missingInDatabase:
+                upgradeCommands.append('%s.columns[%r].create()' % (
+                        modelTable, col.name))
+                downgradeCommands.append('%s.columns[%r].drop()' % (
+                        modelTable, col.name))
+            for col in missingInModel:
+                upgradeCommands.append('%s.columns[%r].drop()' % (
+                        modelTable, col.name))
+                downgradeCommands.append('%s.columns[%r].create()' % (
+                        modelTable, col.name))
+            for modelCol, databaseCol, modelDecl, databaseDecl in diffDecl:
+                upgradeCommands.append(
+                    'assert False, "Can\'t alter columns: %s:%s=>%s"',
+                    modelTable, modelCol.name, databaseCol.name)
+                downgradeCommands.append(
+                    'assert False, "Can\'t alter columns: %s:%s=>%s"',
+                    modelTable, modelCol.name, databaseCol.name)
+        pre_command = '    meta.bind = migrate_engine'
+
+        return (
+            '\n'.join(decls),
+            '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in upgradeCommands]),
+            '\n'.join([pre_command] + ['%s%s' % (indent, line) for line in downgradeCommands]))
+
+    def _db_can_handle_this_change(self, td):
+        if (td.columns_missing_from_B
+            and not td.columns_missing_from_A
+            and not td.columns_different):
+            # Even sqlite can handle this.
+            return True
+        else:
+            return not self.engine.url.drivername.startswith('sqlite')
+
+    def applyModel(self):
+        """Apply model to current database."""
+
+        meta = sqlalchemy.MetaData(self.engine)
+
+        for table in self._get_tables(missingA=True):
+            table = table.tometadata(meta)
+            table.drop()
+        for table in self._get_tables(missingB=True):
+            table = table.tometadata(meta)
+            table.create()
+        for modelTable in self._get_tables(modified=True):
+            tableName = modelTable.name
+            modelTable = modelTable.tometadata(meta)
+            dbTable = self.diff.metadataB.tables[tableName]
+
+            td = self.diff.tables_different[tableName]
+
+            if self._db_can_handle_this_change(td):
+
+                for col in td.columns_missing_from_B:
+                    modelTable.columns[col].create()
+                for col in td.columns_missing_from_A:
+                    dbTable.columns[col].drop()
+                # XXX handle column changes here.
+            else:
+                # Sqlite doesn't support drop column, so you have to
+                # do more: create temp table, copy data to it, drop
+                # old table, create new table, copy data back.
+                #
+                # I wonder if this is guaranteed to be unique?
+                tempName = '_temp_%s' % modelTable.name
+
+                def getCopyStatement():
+                    preparer = self.engine.dialect.preparer
+                    commonCols = []
+                    for modelCol in modelTable.columns:
+                        if modelCol.name in dbTable.columns:
+                            commonCols.append(modelCol.name)
+                    commonColsStr = ', '.join(commonCols)
+                    return 'INSERT INTO %s (%s) SELECT %s FROM %s' % \
+                        (tableName, commonColsStr, commonColsStr, tempName)
+
+                # Move the data in one transaction, so that we don't
+                # leave the database in a nasty state.
+                connection = self.engine.connect()
+                trans = connection.begin()
+                try:
+                    connection.execute(
+                        'CREATE TEMPORARY TABLE %s as SELECT * from %s' % \
+                            (tempName, modelTable.name))
+                    # make sure the drop takes place inside our
+                    # transaction with the bind parameter
+                    modelTable.drop(bind=connection)
+                    modelTable.create(bind=connection)
+                    connection.execute(getCopyStatement())
+                    connection.execute('DROP TABLE %s' % tempName)
+                    trans.commit()
+                except:
+                    trans.rollback()
+                    raise
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/migrate_repository.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,100 @@
+"""
+   Script to migrate repository from sqlalchemy <= 0.4.4 to the new
+   repository schema. This shouldn't use any other migrate modules, so
+   that it can work in any version.
+"""
+
+import os
+import sys
+import logging
+
+log = logging.getLogger(__name__)
+
+
+def usage():
+    """Gives usage information."""
+    print """Usage: %(prog)s repository-to-migrate
+
+    Upgrade your repository to the new flat format.
+
+    NOTE: You should probably make a backup before running this.
+    """ % {'prog': sys.argv[0]}
+
+    sys.exit(1)
+
+
+def delete_file(filepath):
+    """Deletes a file and prints a message."""
+    log.info('Deleting file: %s' % filepath)
+    os.remove(filepath)
+
+
+def move_file(src, tgt):
+    """Moves a file and prints a message."""
+    log.info('Moving file %s to %s' % (src, tgt))
+    if os.path.exists(tgt):
+        raise Exception(
+            'Cannot move file %s because target %s already exists' % \
+                (src, tgt))
+    os.rename(src, tgt)
+
+
+def delete_directory(dirpath):
+    """Delete a directory and print a message."""
+    log.info('Deleting directory: %s' % dirpath)
+    os.rmdir(dirpath)
+
+
+def migrate_repository(repos):
+    """Does the actual migration to the new repository format."""
+    log.info('Migrating repository at: %s to new format' % repos)
+    versions = '%s/versions' % repos
+    dirs = os.listdir(versions)
+    # Only use int's in list.
+    numdirs = [int(dirname) for dirname in dirs if dirname.isdigit()]
+    numdirs.sort()  # Sort list.
+    for dirname in numdirs:
+        origdir = '%s/%s' % (versions, dirname)
+        log.info('Working on directory: %s' % origdir)
+        files = os.listdir(origdir)
+        files.sort()
+        for filename in files:
+            # Delete compiled Python files.
+            if filename.endswith('.pyc') or filename.endswith('.pyo'):
+                delete_file('%s/%s' % (origdir, filename))
+
+            # Delete empty __init__.py files.
+            origfile = '%s/__init__.py' % origdir
+            if os.path.exists(origfile) and len(open(origfile).read()) == 0:
+                delete_file(origfile)
+
+            # Move sql upgrade scripts.
+            if filename.endswith('.sql'):
+                version, dbms, operation = filename.split('.', 3)[0:3]
+                origfile = '%s/%s' % (origdir, filename)
+                # For instance:  2.postgres.upgrade.sql ->
+                #  002_postgres_upgrade.sql
+                tgtfile = '%s/%03d_%s_%s.sql' % (
+                    versions, int(version), dbms, operation)
+                move_file(origfile, tgtfile)
+
+        # Move Python upgrade script.
+        pyfile = '%s.py' % dirname
+        pyfilepath = '%s/%s' % (origdir, pyfile)
+        if os.path.exists(pyfilepath):
+            tgtfile = '%s/%03d.py' % (versions, int(dirname))
+            move_file(pyfilepath, tgtfile)
+
+        # Try to remove directory. Will fail if it's not empty.
+        delete_directory(origdir)
+
+
+def main():
+    """Main function to be called when using this script."""
+    if len(sys.argv) != 2:
+        usage()
+    migrate_repository(sys.argv[1])
+
+
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/pathed.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,75 @@
+"""
+   A path/directory class.
+"""
+
+import os
+import shutil
+import logging
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning.config import *
+from rhodecode.lib.dbmigrate.migrate.versioning.util import KeyedInstance
+
+
+log = logging.getLogger(__name__)
+
+class Pathed(KeyedInstance):
+    """
+    A class associated with a path/directory tree.
+
+    Only one instance of this class may exist for a particular file;
+    __new__ will return an existing instance if possible
+    """
+    parent = None
+
+    @classmethod
+    def _key(cls, path):
+        return str(path)
+
+    def __init__(self, path):
+        self.path = path
+        if self.__class__.parent is not None:
+            self._init_parent(path)
+
+    def _init_parent(self, path):
+        """Try to initialize this object's parent, if it has one"""
+        parent_path = self.__class__._parent_path(path)
+        self.parent = self.__class__.parent(parent_path)
+        log.debug("Getting parent %r:%r" % (self.__class__.parent, parent_path))
+        self.parent._init_child(path, self)
+
+    def _init_child(self, child, path):
+        """Run when a child of this object is initialized.
+
+        Parameters: the child object; the path to this object (its
+        parent)
+        """
+
+    @classmethod
+    def _parent_path(cls, path):
+        """
+        Fetch the path of this object's parent from this object's path.
+        """
+        # os.path.dirname(), but strip directories like files (like
+        # unix basename)
+        #
+        # Treat directories like files...
+        if path[-1] == '/':
+            path = path[:-1]
+        ret = os.path.dirname(path)
+        return ret
+
+    @classmethod
+    def require_notfound(cls, path):
+        """Ensures a given path does not already exist"""
+        if os.path.exists(path):
+            raise exceptions.PathFoundError(path)
+
+    @classmethod
+    def require_found(cls, path):
+        """Ensures a given path already exists"""
+        if not os.path.exists(path):
+            raise exceptions.PathNotFoundError(path)
+
+    def __str__(self):
+        return self.path
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/repository.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,231 @@
+"""
+   SQLAlchemy migrate repository management.
+"""
+import os
+import shutil
+import string
+import logging
+
+from pkg_resources import resource_filename
+from tempita import Template as TempitaTemplate
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning import version, pathed, cfgparse
+from rhodecode.lib.dbmigrate.migrate.versioning.template import Template
+from rhodecode.lib.dbmigrate.migrate.versioning.config import *
+
+
+log = logging.getLogger(__name__)
+
+class Changeset(dict):
+    """A collection of changes to be applied to a database.
+
+    Changesets are bound to a repository and manage a set of
+    scripts from that repository.
+
+    Behaves like a dict, for the most part. Keys are ordered based on step value.
+    """
+
+    def __init__(self, start, *changes, **k):
+        """
+        Give a start version; step must be explicitly stated.
+        """
+        self.step = k.pop('step', 1)
+        self.start = version.VerNum(start)
+        self.end = self.start
+        for change in changes:
+            self.add(change)
+
+    def __iter__(self):
+        return iter(self.items())
+
+    def keys(self):
+        """
+        In a series of upgrades x -> y, keys are version x. Sorted.
+        """
+        ret = super(Changeset, self).keys()
+        # Reverse order if downgrading
+        ret.sort(reverse=(self.step < 1))
+        return ret
+
+    def values(self):
+        return [self[k] for k in self.keys()]
+
+    def items(self):
+        return zip(self.keys(), self.values())
+
+    def add(self, change):
+        """Add new change to changeset"""
+        key = self.end
+        self.end += self.step
+        self[key] = change
+
+    def run(self, *p, **k):
+        """Run the changeset scripts"""
+        for version, script in self:
+            script.run(*p, **k)
+
+
+class Repository(pathed.Pathed):
+    """A project's change script repository"""
+
+    _config = 'migrate.cfg'
+    _versions = 'versions'
+
+    def __init__(self, path):
+        log.debug('Loading repository %s...' % path)
+        self.verify(path)
+        super(Repository, self).__init__(path)
+        self.config = cfgparse.Config(os.path.join(self.path, self._config))
+        self.versions = version.Collection(os.path.join(self.path,
+                                                      self._versions))
+        log.debug('Repository %s loaded successfully' % path)
+        log.debug('Config: %r' % self.config.to_dict())
+
+    @classmethod
+    def verify(cls, path):
+        """
+        Ensure the target path is a valid repository.
+
+        :raises: :exc:`InvalidRepositoryError <migrate.exceptions.InvalidRepositoryError>`
+        """
+        # Ensure the existence of required files
+        try:
+            cls.require_found(path)
+            cls.require_found(os.path.join(path, cls._config))
+            cls.require_found(os.path.join(path, cls._versions))
+        except exceptions.PathNotFoundError, e:
+            raise exceptions.InvalidRepositoryError(path)
+
+    @classmethod
+    def prepare_config(cls, tmpl_dir, name, options=None):
+        """
+        Prepare a project configuration file for a new project.
+
+        :param tmpl_dir: Path to Repository template
+        :param config_file: Name of the config file in Repository template
+        :param name: Repository name
+        :type tmpl_dir: string
+        :type config_file: string
+        :type name: string
+        :returns: Populated config file
+        """
+        if options is None:
+            options = {}
+        options.setdefault('version_table', 'migrate_version')
+        options.setdefault('repository_id', name)
+        options.setdefault('required_dbs', [])
+
+        tmpl = open(os.path.join(tmpl_dir, cls._config)).read()
+        ret = TempitaTemplate(tmpl).substitute(options)
+
+        # cleanup
+        del options['__template_name__']
+
+        return ret
+
+    @classmethod
+    def create(cls, path, name, **opts):
+        """Create a repository at a specified path"""
+        cls.require_notfound(path)
+        theme = opts.pop('templates_theme', None)
+        t_path = opts.pop('templates_path', None)
+
+        # Create repository
+        tmpl_dir = Template(t_path).get_repository(theme=theme)
+        shutil.copytree(tmpl_dir, path)
+
+        # Edit config defaults
+        config_text = cls.prepare_config(tmpl_dir, name, options=opts)
+        fd = open(os.path.join(path, cls._config), 'w')
+        fd.write(config_text)
+        fd.close()
+
+        opts['repository_name'] = name
+
+        # Create a management script
+        manager = os.path.join(path, 'manage.py')
+        Repository.create_manage_file(manager, templates_theme=theme,
+            templates_path=t_path, **opts)
+
+        return cls(path)
+
+    def create_script(self, description, **k):
+        """API to :meth:`migrate.versioning.version.Collection.create_new_python_version`"""
+        self.versions.create_new_python_version(description, **k)
+
+    def create_script_sql(self, database, **k):
+        """API to :meth:`migrate.versioning.version.Collection.create_new_sql_version`"""
+        self.versions.create_new_sql_version(database, **k)
+
+    @property
+    def latest(self):
+        """API to :attr:`migrate.versioning.version.Collection.latest`"""
+        return self.versions.latest
+
+    @property
+    def version_table(self):
+        """Returns version_table name specified in config"""
+        return self.config.get('db_settings', 'version_table')
+
+    @property
+    def id(self):
+        """Returns repository id specified in config"""
+        return self.config.get('db_settings', 'repository_id')
+
+    def version(self, *p, **k):
+        """API to :attr:`migrate.versioning.version.Collection.version`"""
+        return self.versions.version(*p, **k)
+
+    @classmethod
+    def clear(cls):
+        # TODO: deletes repo
+        super(Repository, cls).clear()
+        version.Collection.clear()
+
+    def changeset(self, database, start, end=None):
+        """Create a changeset to migrate this database from ver. start to end/latest.
+
+        :param database: name of database to generate changeset
+        :param start: version to start at
+        :param end: version to end at (latest if None given)
+        :type database: string
+        :type start: int
+        :type end: int
+        :returns: :class:`Changeset instance <migration.versioning.repository.Changeset>`
+        """
+        start = version.VerNum(start)
+
+        if end is None:
+            end = self.latest
+        else:
+            end = version.VerNum(end)
+
+        if start <= end:
+            step = 1
+            range_mod = 1
+            op = 'upgrade'
+        else:
+            step = -1
+            range_mod = 0
+            op = 'downgrade'
+
+        versions = range(start + range_mod, end + range_mod, step)
+        changes = [self.version(v).script(database, op) for v in versions]
+        ret = Changeset(start, step=step, *changes)
+        return ret
+
+    @classmethod
+    def create_manage_file(cls, file_, **opts):
+        """Create a project management script (manage.py)
+        
+        :param file_: Destination file to be written
+        :param opts: Options that are passed to :func:`migrate.versioning.shell.main`
+        """
+        mng_file = Template(opts.pop('templates_path', None))\
+            .get_manage(theme=opts.pop('templates_theme', None))
+
+        tmpl = open(mng_file).read()
+        fd = open(file_, 'w')
+        fd.write(TempitaTemplate(tmpl).substitute(opts))
+        fd.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/schema.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,213 @@
+"""
+   Database schema version management.
+"""
+import sys
+import logging
+
+from sqlalchemy import (Table, Column, MetaData, String, Text, Integer,
+    create_engine)
+from sqlalchemy.sql import and_
+from sqlalchemy import exceptions as sa_exceptions
+from sqlalchemy.sql import bindparam
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff
+from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository
+from rhodecode.lib.dbmigrate.migrate.versioning.util import load_model
+from rhodecode.lib.dbmigrate.migrate.versioning.version import VerNum
+
+
+log = logging.getLogger(__name__)
+
+class ControlledSchema(object):
+    """A database under version control"""
+
+    def __init__(self, engine, repository):
+        if isinstance(repository, basestring):
+            repository = Repository(repository)
+        self.engine = engine
+        self.repository = repository
+        self.meta = MetaData(engine)
+        self.load()
+
+    def __eq__(self, other):
+        """Compare two schemas by repositories and versions"""
+        return (self.repository is other.repository \
+            and self.version == other.version)
+
+    def load(self):
+        """Load controlled schema version info from DB"""
+        tname = self.repository.version_table
+        try:
+            if not hasattr(self, 'table') or self.table is None:
+                    self.table = Table(tname, self.meta, autoload=True)
+
+            result = self.engine.execute(self.table.select(
+                self.table.c.repository_id == str(self.repository.id)))
+
+            data = list(result)[0]
+        except:
+            cls, exc, tb = sys.exc_info()
+            raise exceptions.DatabaseNotControlledError, exc.__str__(), tb
+
+        self.version = data['version']
+        return data
+
+    def drop(self):
+        """
+        Remove version control from a database.
+        """
+        try:
+            self.table.drop()
+        except (sa_exceptions.SQLError):
+            raise exceptions.DatabaseNotControlledError(str(self.table))
+
+    def changeset(self, version=None):
+        """API to Changeset creation.
+        
+        Uses self.version for start version and engine.name
+        to get database name.
+        """
+        database = self.engine.name
+        start_ver = self.version
+        changeset = self.repository.changeset(database, start_ver, version)
+        return changeset
+
+    def runchange(self, ver, change, step):
+        startver = ver
+        endver = ver + step
+        # Current database version must be correct! Don't run if corrupt!
+        if self.version != startver:
+            raise exceptions.InvalidVersionError("%s is not %s" % \
+                                                     (self.version, startver))
+        # Run the change
+        change.run(self.engine, step)
+
+        # Update/refresh database version
+        self.update_repository_table(startver, endver)
+        self.load()
+
+    def update_repository_table(self, startver, endver):
+        """Update version_table with new information"""
+        update = self.table.update(and_(self.table.c.version == int(startver),
+             self.table.c.repository_id == str(self.repository.id)))
+        self.engine.execute(update, version=int(endver))
+
+    def upgrade(self, version=None):
+        """
+        Upgrade (or downgrade) to a specified version, or latest version.
+        """
+        changeset = self.changeset(version)
+        for ver, change in changeset:
+            self.runchange(ver, change, changeset.step)
+
+    def update_db_from_model(self, model):
+        """
+        Modify the database to match the structure of the current Python model.
+        """
+        model = load_model(model)
+
+        diff = schemadiff.getDiffOfModelAgainstDatabase(
+            model, self.engine, excludeTables=[self.repository.version_table]
+            )
+        genmodel.ModelGenerator(diff,self.engine).applyModel()
+
+        self.update_repository_table(self.version, int(self.repository.latest))
+
+        self.load()
+
+    @classmethod
+    def create(cls, engine, repository, version=None):
+        """
+        Declare a database to be under a repository's version control.
+
+        :raises: :exc:`DatabaseAlreadyControlledError`
+        :returns: :class:`ControlledSchema`
+        """
+        # Confirm that the version # is valid: positive, integer,
+        # exists in repos
+        if isinstance(repository, basestring):
+            repository = Repository(repository)
+        version = cls._validate_version(repository, version)
+        table = cls._create_table_version(engine, repository, version)
+        # TODO: history table
+        # Load repository information and return
+        return cls(engine, repository)
+
+    @classmethod
+    def _validate_version(cls, repository, version):
+        """
+        Ensures this is a valid version number for this repository.
+
+        :raises: :exc:`InvalidVersionError` if invalid
+        :return: valid version number
+        """
+        if version is None:
+            version = 0
+        try:
+            version = VerNum(version) # raises valueerror
+            if version < 0 or version > repository.latest:
+                raise ValueError()
+        except ValueError:
+            raise exceptions.InvalidVersionError(version)
+        return version
+
+    @classmethod
+    def _create_table_version(cls, engine, repository, version):
+        """
+        Creates the versioning table in a database.
+
+        :raises: :exc:`DatabaseAlreadyControlledError`
+        """
+        # Create tables
+        tname = repository.version_table
+        meta = MetaData(engine)
+
+        table = Table(
+            tname, meta,
+            Column('repository_id', String(250), primary_key=True),
+            Column('repository_path', Text),
+            Column('version', Integer), )
+
+        # there can be multiple repositories/schemas in the same db
+        if not table.exists():
+            table.create()
+
+        # test for existing repository_id
+        s = table.select(table.c.repository_id == bindparam("repository_id"))
+        result = engine.execute(s, repository_id=repository.id)
+        if result.fetchone():
+            raise exceptions.DatabaseAlreadyControlledError
+
+        # Insert data
+        engine.execute(table.insert().values(
+                           repository_id=repository.id,
+                           repository_path=repository.path,
+                           version=int(version)))
+        return table
+
+    @classmethod
+    def compare_model_to_db(cls, engine, model, repository):
+        """
+        Compare the current model against the current database.
+        """
+        if isinstance(repository, basestring):
+            repository = Repository(repository)
+        model = load_model(model)
+
+        diff = schemadiff.getDiffOfModelAgainstDatabase(
+            model, engine, excludeTables=[repository.version_table])
+        return diff
+
+    @classmethod
+    def create_model(cls, engine, repository, declarative=False):
+        """
+        Dump the current database as a Python model.
+        """
+        if isinstance(repository, basestring):
+            repository = Repository(repository)
+
+        diff = schemadiff.getDiffOfModelAgainstDatabase(
+            MetaData(), engine, excludeTables=[repository.version_table]
+            )
+        return genmodel.ModelGenerator(diff, engine, declarative).toPython()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,285 @@
+"""
+   Schema differencing support.
+"""
+
+import logging
+import sqlalchemy
+
+from rhodecode.lib.dbmigrate.migrate.changeset import SQLA_06
+from sqlalchemy.types import Float
+
+log = logging.getLogger(__name__)
+
+def getDiffOfModelAgainstDatabase(metadata, engine, excludeTables=None):
+    """
+    Return differences of model against database.
+
+    :return: object which will evaluate to :keyword:`True` if there \
+      are differences else :keyword:`False`.
+    """
+    return SchemaDiff(metadata,
+                      sqlalchemy.MetaData(engine, reflect=True),
+                      labelA='model',
+                      labelB='database',
+                      excludeTables=excludeTables)
+
+
+def getDiffOfModelAgainstModel(metadataA, metadataB, excludeTables=None):
+    """
+    Return differences of model against another model.
+
+    :return: object which will evaluate to :keyword:`True` if there \
+      are differences else :keyword:`False`.
+    """
+    return SchemaDiff(metadataA, metadataB, excludeTables)
+
+
+class ColDiff(object):
+    """
+    Container for differences in one :class:`~sqlalchemy.schema.Column`
+    between two :class:`~sqlalchemy.schema.Table` instances, ``A``
+    and ``B``.
+    
+    .. attribute:: col_A
+
+      The :class:`~sqlalchemy.schema.Column` object for A.
+      
+    .. attribute:: col_B
+
+      The :class:`~sqlalchemy.schema.Column` object for B.
+
+    .. attribute:: type_A
+
+      The most generic type of the :class:`~sqlalchemy.schema.Column`
+      object in A. 
+      
+    .. attribute:: type_B
+
+      The most generic type of the :class:`~sqlalchemy.schema.Column`
+      object in A. 
+      
+    """
+    
+    diff = False
+
+    def __init__(self,col_A,col_B):
+        self.col_A = col_A
+        self.col_B = col_B
+
+        self.type_A = col_A.type
+        self.type_B = col_B.type
+
+        self.affinity_A = self.type_A._type_affinity
+        self.affinity_B = self.type_B._type_affinity
+
+        if self.affinity_A is not self.affinity_B:
+            self.diff = True
+            return
+
+        if isinstance(self.type_A,Float) or isinstance(self.type_B,Float):
+            if not (isinstance(self.type_A,Float) and isinstance(self.type_B,Float)):
+                self.diff=True
+                return
+
+        for attr in ('precision','scale','length'):
+            A = getattr(self.type_A,attr,None)
+            B = getattr(self.type_B,attr,None)
+            if not (A is None or B is None) and A!=B:
+                self.diff=True
+                return
+        
+    def __nonzero__(self):
+        return self.diff
+    
+class TableDiff(object):
+    """
+    Container for differences in one :class:`~sqlalchemy.schema.Table`
+    between two :class:`~sqlalchemy.schema.MetaData` instances, ``A``
+    and ``B``.
+
+    .. attribute:: columns_missing_from_A
+
+      A sequence of column names that were found in B but weren't in
+      A.
+      
+    .. attribute:: columns_missing_from_B
+
+      A sequence of column names that were found in A but weren't in
+      B.
+      
+    .. attribute:: columns_different
+
+      A dictionary containing information about columns that were
+      found to be different.
+      It maps column names to a :class:`ColDiff` objects describing the
+      differences found.
+    """
+    __slots__ = (
+        'columns_missing_from_A',
+        'columns_missing_from_B',
+        'columns_different',
+        )
+
+    def __nonzero__(self):
+        return bool(
+            self.columns_missing_from_A or
+            self.columns_missing_from_B or
+            self.columns_different
+            )
+    
+class SchemaDiff(object):
+    """
+    Compute the difference between two :class:`~sqlalchemy.schema.MetaData`
+    objects.
+
+    The string representation of a :class:`SchemaDiff` will summarise
+    the changes found between the two
+    :class:`~sqlalchemy.schema.MetaData` objects.
+
+    The length of a :class:`SchemaDiff` will give the number of
+    changes found, enabling it to be used much like a boolean in
+    expressions.
+        
+    :param metadataA:
+      First :class:`~sqlalchemy.schema.MetaData` to compare.
+      
+    :param metadataB:
+      Second :class:`~sqlalchemy.schema.MetaData` to compare.
+      
+    :param labelA:
+      The label to use in messages about the first
+      :class:`~sqlalchemy.schema.MetaData`. 
+    
+    :param labelB: 
+      The label to use in messages about the second
+      :class:`~sqlalchemy.schema.MetaData`. 
+    
+    :param excludeTables:
+      A sequence of table names to exclude.
+      
+    .. attribute:: tables_missing_from_A
+
+      A sequence of table names that were found in B but weren't in
+      A.
+      
+    .. attribute:: tables_missing_from_B
+
+      A sequence of table names that were found in A but weren't in
+      B.
+      
+    .. attribute:: tables_different
+
+      A dictionary containing information about tables that were found
+      to be different.
+      It maps table names to a :class:`TableDiff` objects describing the
+      differences found.
+    """
+
+    def __init__(self,
+                 metadataA, metadataB,
+                 labelA='metadataA',
+                 labelB='metadataB',
+                 excludeTables=None):
+
+        self.metadataA, self.metadataB = metadataA, metadataB
+        self.labelA, self.labelB = labelA, labelB
+        self.label_width = max(len(labelA),len(labelB))
+        excludeTables = set(excludeTables or [])
+
+        A_table_names = set(metadataA.tables.keys())
+        B_table_names = set(metadataB.tables.keys())
+
+        self.tables_missing_from_A = sorted(
+            B_table_names - A_table_names - excludeTables
+            )
+        self.tables_missing_from_B = sorted(
+            A_table_names - B_table_names - excludeTables
+            )
+        
+        self.tables_different = {}
+        for table_name in A_table_names.intersection(B_table_names):
+
+            td = TableDiff()
+            
+            A_table = metadataA.tables[table_name]
+            B_table = metadataB.tables[table_name]
+            
+            A_column_names = set(A_table.columns.keys())
+            B_column_names = set(B_table.columns.keys())
+
+            td.columns_missing_from_A = sorted(
+                B_column_names - A_column_names
+                )
+            
+            td.columns_missing_from_B = sorted(
+                A_column_names - B_column_names
+                )
+            
+            td.columns_different = {}
+
+            for col_name in A_column_names.intersection(B_column_names):
+
+                cd = ColDiff(
+                    A_table.columns.get(col_name),
+                    B_table.columns.get(col_name)
+                    )
+
+                if cd:
+                    td.columns_different[col_name]=cd
+                
+            # XXX - index and constraint differences should
+            #       be checked for here
+
+            if td:
+                self.tables_different[table_name]=td
+
+    def __str__(self):
+        ''' Summarize differences. '''
+        out = []
+        column_template ='      %%%is: %%r' % self.label_width
+        
+        for names,label in (
+            (self.tables_missing_from_A,self.labelA),
+            (self.tables_missing_from_B,self.labelB),
+            ):
+            if names:
+                out.append(
+                    '  tables missing from %s: %s' % (
+                        label,', '.join(sorted(names))
+                        )
+                    )
+                
+        for name,td in sorted(self.tables_different.items()):
+            out.append(
+               '  table with differences: %s' % name
+               )
+            for names,label in (
+                (td.columns_missing_from_A,self.labelA),
+                (td.columns_missing_from_B,self.labelB),
+                ):
+                if names:
+                    out.append(
+                        '    %s missing these columns: %s' % (
+                            label,', '.join(sorted(names))
+                            )
+                        )
+            for name,cd in td.columns_different.items():
+                out.append('    column with differences: %s' % name)
+                out.append(column_template % (self.labelA,cd.col_A))
+                out.append(column_template % (self.labelB,cd.col_B))
+                
+        if out:
+            out.insert(0, 'Schema diffs:')
+            return '\n'.join(out)
+        else:
+            return 'No schema diffs'
+
+    def __len__(self):
+        """
+        Used in bool evaluation, return of 0 means no diffs.
+        """
+        return (
+            len(self.tables_missing_from_A) +
+            len(self.tables_missing_from_B) +
+            len(self.tables_different)
+            )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from rhodecode.lib.dbmigrate.migrate.versioning.script.base import BaseScript
+from rhodecode.lib.dbmigrate.migrate.versioning.script.py import PythonScript
+from rhodecode.lib.dbmigrate.migrate.versioning.script.sql import SqlScript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/base.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import logging
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning.config import operations
+from rhodecode.lib.dbmigrate.migrate.versioning import pathed
+
+
+log = logging.getLogger(__name__)
+
+class BaseScript(pathed.Pathed):
+    """Base class for other types of scripts.
+    All scripts have the following properties:
+
+    source (script.source())
+      The source code of the script
+    version (script.version())
+      The version number of the script
+    operations (script.operations())
+      The operations defined by the script: upgrade(), downgrade() or both.
+      Returns a tuple of operations.
+      Can also check for an operation with ex. script.operation(Script.ops.up)
+    """ # TODO: sphinxfy this and implement it correctly
+
+    def __init__(self, path):
+        log.debug('Loading script %s...' % path)
+        self.verify(path)
+        super(BaseScript, self).__init__(path)
+        log.debug('Script %s loaded successfully' % path)
+    
+    @classmethod
+    def verify(cls, path):
+        """Ensure this is a valid script
+        This version simply ensures the script file's existence
+
+        :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>`
+        """
+        try:
+            cls.require_found(path)
+        except:
+            raise exceptions.InvalidScriptError(path)
+
+    def source(self):
+        """:returns: source code of the script.
+        :rtype: string
+        """
+        fd = open(self.path)
+        ret = fd.read()
+        fd.close()
+        return ret
+
+    def run(self, engine):
+        """Core of each BaseScript subclass.
+        This method executes the script.
+        """
+        raise NotImplementedError()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/py.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import shutil
+import warnings
+import logging
+from StringIO import StringIO
+
+from rhodecode.lib.dbmigrate import migrate
+from rhodecode.lib.dbmigrate.migrate.versioning import genmodel, schemadiff
+from rhodecode.lib.dbmigrate.migrate.versioning.config import operations
+from rhodecode.lib.dbmigrate.migrate.versioning.template import Template
+from rhodecode.lib.dbmigrate.migrate.versioning.script import base
+from rhodecode.lib.dbmigrate.migrate.versioning.util import import_path, load_model, with_engine
+from rhodecode.lib.dbmigrate.migrate.exceptions import MigrateDeprecationWarning, InvalidScriptError, ScriptError
+
+log = logging.getLogger(__name__)
+__all__ = ['PythonScript']
+
+
+class PythonScript(base.BaseScript):
+    """Base for Python scripts"""
+
+    @classmethod
+    def create(cls, path, **opts):
+        """Create an empty migration script at specified path
+        
+        :returns: :class:`PythonScript instance <migrate.versioning.script.py.PythonScript>`"""
+        cls.require_notfound(path)
+
+        src = Template(opts.pop('templates_path', None)).get_script(theme=opts.pop('templates_theme', None))
+        shutil.copy(src, path)
+
+        return cls(path)
+
+    @classmethod
+    def make_update_script_for_model(cls, engine, oldmodel,
+                                     model, repository, **opts):
+        """Create a migration script based on difference between two SA models.
+        
+        :param repository: path to migrate repository
+        :param oldmodel: dotted.module.name:SAClass or SAClass object
+        :param model: dotted.module.name:SAClass or SAClass object
+        :param engine: SQLAlchemy engine
+        :type repository: string or :class:`Repository instance <migrate.versioning.repository.Repository>`
+        :type oldmodel: string or Class
+        :type model: string or Class
+        :type engine: Engine instance
+        :returns: Upgrade / Downgrade script
+        :rtype: string
+        """
+
+        if isinstance(repository, basestring):
+            # oh dear, an import cycle!
+            from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository
+            repository = Repository(repository)
+
+        oldmodel = load_model(oldmodel)
+        model = load_model(model)
+
+        # Compute differences.
+        diff = schemadiff.getDiffOfModelAgainstModel(
+            oldmodel,
+            model,
+            excludeTables=[repository.version_table])
+        # TODO: diff can be False (there is no difference?)
+        decls, upgradeCommands, downgradeCommands = \
+            genmodel.ModelGenerator(diff, engine).toUpgradeDowngradePython()
+
+        # Store differences into file.
+        src = Template(opts.pop('templates_path', None)).get_script(opts.pop('templates_theme', None))
+        f = open(src)
+        contents = f.read()
+        f.close()
+
+        # generate source
+        search = 'def upgrade(migrate_engine):'
+        contents = contents.replace(search, '\n\n'.join((decls, search)), 1)
+        if upgradeCommands:
+            contents = contents.replace('    pass', upgradeCommands, 1)
+        if downgradeCommands:
+            contents = contents.replace('    pass', downgradeCommands, 1)
+        return contents
+
+    @classmethod
+    def verify_module(cls, path):
+        """Ensure path is a valid script
+        
+        :param path: Script location
+        :type path: string
+        :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>`
+        :returns: Python module
+        """
+        # Try to import and get the upgrade() func
+        module = import_path(path)
+        try:
+            assert callable(module.upgrade)
+        except Exception, e:
+            raise InvalidScriptError(path + ': %s' % str(e))
+        return module
+
+    def preview_sql(self, url, step, **args):
+        """Mocks SQLAlchemy Engine to store all executed calls in a string 
+        and runs :meth:`PythonScript.run <migrate.versioning.script.py.PythonScript.run>`
+
+        :returns: SQL file
+        """
+        buf = StringIO()
+        args['engine_arg_strategy'] = 'mock'
+        args['engine_arg_executor'] = lambda s, p = '': buf.write(str(s) + p)
+
+        @with_engine
+        def go(url, step, **kw):
+            engine = kw.pop('engine')
+            self.run(engine, step)
+            return buf.getvalue()
+
+        return go(url, step, **args)
+
+    def run(self, engine, step):
+        """Core method of Script file. 
+        Exectues :func:`update` or :func:`downgrade` functions
+
+        :param engine: SQLAlchemy Engine
+        :param step: Operation to run
+        :type engine: string
+        :type step: int
+        """
+        if step > 0:
+            op = 'upgrade'
+        elif step < 0:
+            op = 'downgrade'
+        else:
+            raise ScriptError("%d is not a valid step" % step)
+
+        funcname = base.operations[op]
+        script_func = self._func(funcname)
+
+        try:
+            script_func(engine)
+        except TypeError:
+            warnings.warn("upgrade/downgrade functions must accept engine"
+                " parameter (since version > 0.5.4)", MigrateDeprecationWarning)
+            raise
+
+    @property
+    def module(self):
+        """Calls :meth:`migrate.versioning.script.py.verify_module`
+        and returns it.
+        """
+        if not hasattr(self, '_module'):
+            self._module = self.verify_module(self.path)
+        return self._module
+
+    def _func(self, funcname):
+        if not hasattr(self.module, funcname):
+            msg = "Function '%s' is not defined in this script"
+            raise ScriptError(msg % funcname)
+        return getattr(self.module, funcname)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/script/sql.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import logging
+import shutil
+
+from rhodecode.lib.dbmigrate.migrate.versioning.script import base
+from rhodecode.lib.dbmigrate.migrate.versioning.template import Template
+
+
+log = logging.getLogger(__name__)
+
+class SqlScript(base.BaseScript):
+    """A file containing plain SQL statements."""
+
+    @classmethod
+    def create(cls, path, **opts):
+        """Create an empty migration script at specified path
+        
+        :returns: :class:`SqlScript instance <migrate.versioning.script.sql.SqlScript>`"""
+        cls.require_notfound(path)
+        src = Template(opts.pop('templates_path', None)).get_sql_script(theme=opts.pop('templates_theme', None))
+        shutil.copy(src, path)
+        return cls(path)
+
+    # TODO: why is step parameter even here?
+    def run(self, engine, step=None, executemany=True):
+        """Runs SQL script through raw dbapi execute call"""
+        text = self.source()
+        # Don't rely on SA's autocommit here
+        # (SA uses .startswith to check if a commit is needed. What if script
+        # starts with a comment?)
+        conn = engine.connect()
+        try:
+            trans = conn.begin()
+            try:
+                # HACK: SQLite doesn't allow multiple statements through
+                # its execute() method, but it provides executescript() instead
+                dbapi = conn.engine.raw_connection()
+                if executemany and getattr(dbapi, 'executescript', None):
+                    dbapi.executescript(text)
+                else:
+                    conn.execute(text)
+                trans.commit()
+            except:
+                trans.rollback()
+                raise
+        finally:
+            conn.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/shell.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""The migrate command-line tool."""
+
+import sys
+import inspect
+import logging
+from optparse import OptionParser, BadOptionError
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning import api
+from rhodecode.lib.dbmigrate.migrate.versioning.config import *
+from rhodecode.lib.dbmigrate.migrate.versioning.util import asbool
+
+
+alias = dict(
+    s=api.script,
+    vc=api.version_control,
+    dbv=api.db_version,
+    v=api.version,
+)
+
+def alias_setup():
+    global alias
+    for key, val in alias.iteritems():
+        setattr(api, key, val)
+alias_setup()
+
+
+class PassiveOptionParser(OptionParser):
+
+    def _process_args(self, largs, rargs, values):
+        """little hack to support all --some_option=value parameters"""
+
+        while rargs:
+            arg = rargs[0]
+            if arg == "--":
+                del rargs[0]
+                return
+            elif arg[0:2] == "--":
+                # if parser does not know about the option
+                # pass it along (make it anonymous)
+                try:
+                    opt = arg.split('=', 1)[0]
+                    self._match_long_opt(opt)
+                except BadOptionError:
+                    largs.append(arg)
+                    del rargs[0]
+                else:
+                    self._process_long_opt(rargs, values)
+            elif arg[:1] == "-" and len(arg) > 1:
+                self._process_short_opts(rargs, values)
+            elif self.allow_interspersed_args:
+                largs.append(arg)
+                del rargs[0]
+
+def main(argv=None, **kwargs):
+    """Shell interface to :mod:`migrate.versioning.api`.
+
+    kwargs are default options that can be overriden with passing
+    --some_option as command line option
+
+    :param disable_logging: Let migrate configure logging
+    :type disable_logging: bool
+    """
+    if argv is not None:
+        argv = argv
+    else:
+        argv = list(sys.argv[1:])
+    commands = list(api.__all__)
+    commands.sort()
+
+    usage = """%%prog COMMAND ...
+
+    Available commands:
+        %s
+
+    Enter "%%prog help COMMAND" for information on a particular command.
+    """ % '\n\t'.join(["%s - %s" % (command.ljust(28),
+                    api.command_desc.get(command)) for command in commands])
+
+    parser = PassiveOptionParser(usage=usage)
+    parser.add_option("-d", "--debug",
+                     action="store_true",
+                     dest="debug",
+                     default=False,
+                     help="Shortcut to turn on DEBUG mode for logging")
+    parser.add_option("-q", "--disable_logging",
+                      action="store_true",
+                      dest="disable_logging",
+                      default=False,
+                      help="Use this option to disable logging configuration")
+    help_commands = ['help', '-h', '--help']
+    HELP = False
+
+    try:
+        command = argv.pop(0)
+        if command in help_commands:
+            HELP = True
+            command = argv.pop(0)
+    except IndexError:
+        parser.print_help()
+        return
+
+    command_func = getattr(api, command, None)
+    if command_func is None or command.startswith('_'):
+        parser.error("Invalid command %s" % command)
+
+    parser.set_usage(inspect.getdoc(command_func))
+    f_args, f_varargs, f_kwargs, f_defaults = inspect.getargspec(command_func)
+    for arg in f_args:
+        parser.add_option(
+            "--%s" % arg,
+            dest=arg,
+            action='store',
+            type="string")
+
+    # display help of the current command
+    if HELP:
+        parser.print_help()
+        return
+
+    options, args = parser.parse_args(argv)
+
+    # override kwargs with anonymous parameters
+    override_kwargs = dict()
+    for arg in list(args):
+        if arg.startswith('--'):
+            args.remove(arg)
+            if '=' in arg:
+                opt, value = arg[2:].split('=', 1)
+            else:
+                opt = arg[2:]
+                value = True
+            override_kwargs[opt] = value
+
+    # override kwargs with options if user is overwriting
+    for key, value in options.__dict__.iteritems():
+        if value is not None:
+            override_kwargs[key] = value
+
+    # arguments that function accepts without passed kwargs
+    f_required = list(f_args)
+    candidates = dict(kwargs)
+    candidates.update(override_kwargs)
+    for key, value in candidates.iteritems():
+        if key in f_args:
+            f_required.remove(key)
+
+    # map function arguments to parsed arguments
+    for arg in args:
+        try:
+            kw = f_required.pop(0)
+        except IndexError:
+            parser.error("Too many arguments for command %s: %s" % (command,
+                                                                    arg))
+        kwargs[kw] = arg
+
+    # apply overrides
+    kwargs.update(override_kwargs)
+
+    # configure options
+    for key, value in options.__dict__.iteritems():
+        kwargs.setdefault(key, value)
+
+    # configure logging
+    if not asbool(kwargs.pop('disable_logging', False)):
+        # filter to log =< INFO into stdout and rest to stderr
+        class SingleLevelFilter(logging.Filter):
+            def __init__(self, min=None, max=None):
+                self.min = min or 0
+                self.max = max or 100
+
+            def filter(self, record):
+                return self.min <= record.levelno <= self.max
+
+        logger = logging.getLogger()
+        h1 = logging.StreamHandler(sys.stdout)
+        f1 = SingleLevelFilter(max=logging.INFO)
+        h1.addFilter(f1)
+        h2 = logging.StreamHandler(sys.stderr)
+        f2 = SingleLevelFilter(min=logging.WARN)
+        h2.addFilter(f2)
+        logger.addHandler(h1)
+        logger.addHandler(h2)
+
+        if options.debug:
+            logger.setLevel(logging.DEBUG)
+        else:
+            logger.setLevel(logging.INFO)
+
+    log = logging.getLogger(__name__)
+
+    # check if all args are given
+    try:
+        num_defaults = len(f_defaults)
+    except TypeError:
+        num_defaults = 0
+    f_args_default = f_args[len(f_args) - num_defaults:]
+    required = list(set(f_required) - set(f_args_default))
+    if required:
+        parser.error("Not enough arguments for command %s: %s not specified" \
+            % (command, ', '.join(required)))
+
+    # handle command
+    try:
+        ret = command_func(**kwargs)
+        if ret is not None:
+            log.info(ret)
+    except (exceptions.UsageError, exceptions.KnownError), e:
+        parser.error(e.args[0])
+
+if __name__ == "__main__":
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/template.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import shutil
+import sys
+
+from pkg_resources import resource_filename
+
+from rhodecode.lib.dbmigrate.migrate.versioning.config import *
+from rhodecode.lib.dbmigrate.migrate.versioning import pathed
+
+
+class Collection(pathed.Pathed):
+    """A collection of templates of a specific type"""
+    _mask = None
+
+    def get_path(self, file):
+        return os.path.join(self.path, str(file))
+
+
+class RepositoryCollection(Collection):
+    _mask = '%s'
+
+class ScriptCollection(Collection):
+    _mask = '%s.py_tmpl'
+
+class ManageCollection(Collection):
+    _mask = '%s.py_tmpl'
+
+class SQLScriptCollection(Collection):
+    _mask = '%s.py_tmpl'
+
+class Template(pathed.Pathed):
+    """Finds the paths/packages of various Migrate templates.
+    
+    :param path: Templates are loaded from rhodecode.lib.dbmigrate.migrate package
+    if `path` is not provided.
+    """
+    pkg = 'rhodecode.lib.dbmigrate.migrate.versioning.templates'
+    _manage = 'manage.py_tmpl'
+
+    def __new__(cls, path=None):
+        if path is None:
+            path = cls._find_path(cls.pkg)
+        return super(Template, cls).__new__(cls, path)
+
+    def __init__(self, path=None):
+        if path is None:
+            path = Template._find_path(self.pkg)
+        super(Template, self).__init__(path)
+        self.repository = RepositoryCollection(os.path.join(path, 'repository'))
+        self.script = ScriptCollection(os.path.join(path, 'script'))
+        self.manage = ManageCollection(os.path.join(path, 'manage'))
+        self.sql_script = SQLScriptCollection(os.path.join(path, 'sql_script'))
+
+    @classmethod
+    def _find_path(cls, pkg):
+        """Returns absolute path to dotted python package."""
+        tmp_pkg = pkg.rsplit('.', 1)
+
+        if len(tmp_pkg) != 1:
+            return resource_filename(tmp_pkg[0], tmp_pkg[1])
+        else:
+            return resource_filename(tmp_pkg[0], '')
+
+    def _get_item(self, collection, theme=None):
+        """Locates and returns collection.
+        
+        :param collection: name of collection to locate
+        :param type_: type of subfolder in collection (defaults to "_default")
+        :returns: (package, source)
+        :rtype: str, str
+        """
+        item = getattr(self, collection)
+        theme_mask = getattr(item, '_mask')
+        theme = theme_mask % (theme or 'default')
+        return item.get_path(theme)
+
+    def get_repository(self, *a, **kw):
+        """Calls self._get_item('repository', *a, **kw)"""
+        return self._get_item('repository', *a, **kw)
+
+    def get_script(self, *a, **kw):
+        """Calls self._get_item('script', *a, **kw)"""
+        return self._get_item('script', *a, **kw)
+
+    def get_sql_script(self, *a, **kw):
+        """Calls self._get_item('sql_script', *a, **kw)"""
+        return self._get_item('sql_script', *a, **kw)
+
+    def get_manage(self, *a, **kw):
+        """Calls self._get_item('manage', *a, **kw)"""
+        return self._get_item('manage', *a, **kw)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/manage.py_tmpl	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+from migrate.versioning.shell import main
+
+if __name__ == '__main__':
+    main(%(defaults)s)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/manage/default.py_tmpl	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+from migrate.versioning.shell import main
+
+{{py:
+_vars = locals().copy()
+del _vars['__template_name__']
+_vars.pop('repository_name', None)
+defaults = ", ".join(["%s='%s'" % var for var in _vars.iteritems()])
+}}
+main({{ defaults }})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/manage/pylons.py_tmpl	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+import sys
+
+from sqlalchemy import engine_from_config
+from paste.deploy.loadwsgi import ConfigLoader
+
+from migrate.versioning.shell import main
+from {{ locals().pop('repository_name') }}.model import migrations
+
+
+if '-c' in sys.argv:
+    pos = sys.argv.index('-c')
+    conf_path = sys.argv[pos + 1]
+    del sys.argv[pos:pos + 2]
+else:
+    conf_path = 'development.ini'
+
+{{py:
+_vars = locals().copy()
+del _vars['__template_name__']
+defaults = ", ".join(["%s='%s'" % var for var in _vars.iteritems()])
+}}
+
+conf_dict = ConfigLoader(conf_path).parser._sections['app:main']
+
+# migrate supports passing url as an existing Engine instance (since 0.6.0)
+# usage: migrate -c path/to/config.ini COMMANDS
+main(url=engine_from_config(conf_dict), repository=migrations.__path__[0],{{ defaults }})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/repository/default/README	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,4 @@
+This is a database migration repository.
+
+More information at
+http://code.google.com/p/sqlalchemy-migrate/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/repository/default/migrate.cfg	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,20 @@
+[db_settings]
+# Used to identify which repository this database is versioned under.
+# You can use the name of your project.
+repository_id={{ locals().pop('repository_id') }}
+
+# The name of the database table used to track the schema version.
+# This name shouldn't already be used by your project.
+# If this is changed once a database is under version control, you'll need to 
+# change the table name in each database too. 
+version_table={{ locals().pop('version_table') }}
+
+# When committing a change script, Migrate will attempt to generate the 
+# sql for all supported databases; normally, if one of them fails - probably
+# because you don't have that database installed - it is ignored and the 
+# commit continues, perhaps ending successfully. 
+# Databases in this list MUST compile successfully during a commit, or the 
+# entire commit will fail. List the databases your application will actually 
+# be using to ensure your updates to that database work properly.
+# This must be a list; example: ['postgres','sqlite']
+required_dbs={{ locals().pop('required_dbs') }}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/repository/pylons/README	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,4 @@
+This is a database migration repository.
+
+More information at
+http://code.google.com/p/sqlalchemy-migrate/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/repository/pylons/migrate.cfg	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,20 @@
+[db_settings]
+# Used to identify which repository this database is versioned under.
+# You can use the name of your project.
+repository_id={{ locals().pop('repository_id') }}
+
+# The name of the database table used to track the schema version.
+# This name shouldn't already be used by your project.
+# If this is changed once a database is under version control, you'll need to 
+# change the table name in each database too. 
+version_table={{ locals().pop('version_table') }}
+
+# When committing a change script, Migrate will attempt to generate the 
+# sql for all supported databases; normally, if one of them fails - probably
+# because you don't have that database installed - it is ignored and the 
+# commit continues, perhaps ending successfully. 
+# Databases in this list MUST compile successfully during a commit, or the 
+# entire commit will fail. List the databases your application will actually 
+# be using to ensure your updates to that database work properly.
+# This must be a list; example: ['postgres','sqlite']
+required_dbs={{ locals().pop('required_dbs') }}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/script/default.py_tmpl	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,11 @@
+from sqlalchemy import *
+from migrate import *
+
+def upgrade(migrate_engine):
+    # Upgrade operations go here. Don't create your own engine; bind migrate_engine
+    # to your metadata
+    pass
+
+def downgrade(migrate_engine):
+    # Operations to reverse the above upgrade go here.
+    pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/templates/script/pylons.py_tmpl	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,11 @@
+from sqlalchemy import *
+from migrate import *
+
+def upgrade(migrate_engine):
+    # Upgrade operations go here. Don't create your own engine; bind migrate_engine
+    # to your metadata
+    pass
+
+def downgrade(migrate_engine):
+    # Operations to reverse the above upgrade go here.
+    pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""".. currentmodule:: migrate.versioning.util"""
+
+import warnings
+import logging
+from decorator import decorator
+from pkg_resources import EntryPoint
+
+from sqlalchemy import create_engine
+from sqlalchemy.engine import Engine
+from sqlalchemy.pool import StaticPool
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning.util.keyedinstance import KeyedInstance
+from rhodecode.lib.dbmigrate.migrate.versioning.util.importpath import import_path
+
+
+log = logging.getLogger(__name__)
+
+def load_model(dotted_name):
+    """Import module and use module-level variable".
+
+    :param dotted_name: path to model in form of string: ``some.python.module:Class``
+    
+    .. versionchanged:: 0.5.4
+
+    """
+    if isinstance(dotted_name, basestring):
+        if ':' not in dotted_name:
+            # backwards compatibility
+            warnings.warn('model should be in form of module.model:User '
+                'and not module.model.User', exceptions.MigrateDeprecationWarning)
+            dotted_name = ':'.join(dotted_name.rsplit('.', 1))
+        return EntryPoint.parse('x=%s' % dotted_name).load(False)
+    else:
+        # Assume it's already loaded.
+        return dotted_name
+
+def asbool(obj):
+    """Do everything to use object as bool"""
+    if isinstance(obj, basestring):
+        obj = obj.strip().lower()
+        if obj in ['true', 'yes', 'on', 'y', 't', '1']:
+            return True
+        elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
+            return False
+        else:
+            raise ValueError("String is not true/false: %r" % obj)
+    if obj in (True, False):
+        return bool(obj)
+    else:
+        raise ValueError("String is not true/false: %r" % obj)
+
+def guess_obj_type(obj):
+    """Do everything to guess object type from string
+    
+    Tries to convert to `int`, `bool` and finally returns if not succeded.
+    
+    .. versionadded: 0.5.4
+    """
+
+    result = None
+
+    try:
+        result = int(obj)
+    except:
+        pass
+
+    if result is None:
+        try:
+            result = asbool(obj)
+        except:
+            pass
+
+    if result is not None:
+        return result
+    else:
+        return obj
+
+@decorator
+def catch_known_errors(f, *a, **kw):
+    """Decorator that catches known api errors
+    
+    .. versionadded: 0.5.4
+    """
+
+    try:
+        return f(*a, **kw)
+    except exceptions.PathFoundError, e:
+        raise exceptions.KnownError("The path %s already exists" % e.args[0])
+
+def construct_engine(engine, **opts):
+    """.. versionadded:: 0.5.4
+
+    Constructs and returns SQLAlchemy engine.
+
+    Currently, there are 2 ways to pass create_engine options to :mod:`migrate.versioning.api` functions:
+
+    :param engine: connection string or a existing engine
+    :param engine_dict: python dictionary of options to pass to `create_engine`
+    :param engine_arg_*: keyword parameters to pass to `create_engine` (evaluated with :func:`migrate.versioning.util.guess_obj_type`)
+    :type engine_dict: dict
+    :type engine: string or Engine instance
+    :type engine_arg_*: string
+    :returns: SQLAlchemy Engine
+
+    .. note::
+
+        keyword parameters override ``engine_dict`` values.
+
+    """
+    if isinstance(engine, Engine):
+        return engine
+    elif not isinstance(engine, basestring):
+        raise ValueError("you need to pass either an existing engine or a database uri")
+
+    # get options for create_engine
+    if opts.get('engine_dict') and isinstance(opts['engine_dict'], dict):
+        kwargs = opts['engine_dict']
+    else:
+        kwargs = dict()
+
+    # DEPRECATED: handle echo the old way
+    echo = asbool(opts.get('echo', False))
+    if echo:
+        warnings.warn('echo=True parameter is deprecated, pass '
+            'engine_arg_echo=True or engine_dict={"echo": True}',
+            exceptions.MigrateDeprecationWarning)
+        kwargs['echo'] = echo
+
+    # parse keyword arguments
+    for key, value in opts.iteritems():
+        if key.startswith('engine_arg_'):
+            kwargs[key[11:]] = guess_obj_type(value)
+
+    log.debug('Constructing engine')
+    # TODO: return create_engine(engine, poolclass=StaticPool, **kwargs)
+    # seems like 0.5.x branch does not work with engine.dispose and staticpool
+    return create_engine(engine, **kwargs)
+
+@decorator
+def with_engine(f, *a, **kw):
+    """Decorator for :mod:`migrate.versioning.api` functions
+    to safely close resources after function usage.
+
+    Passes engine parameters to :func:`construct_engine` and
+    resulting parameter is available as kw['engine'].
+
+    Engine is disposed after wrapped function is executed.
+
+    .. versionadded: 0.6.0
+    """
+    url = a[0]
+    engine = construct_engine(url, **kw)
+
+    try:
+        kw['engine'] = engine
+        return f(*a, **kw)
+    finally:
+        if isinstance(engine, Engine):
+            log.debug('Disposing SQLAlchemy engine %s', engine)
+            engine.dispose()
+
+
+class Memoize:
+    """Memoize(fn) - an instance which acts like fn but memoizes its arguments
+       Will only work on functions with non-mutable arguments
+
+       ActiveState Code 52201
+    """
+    def __init__(self, fn):
+        self.fn = fn
+        self.memo = {}
+
+    def __call__(self, *args):
+        if not self.memo.has_key(args):
+            self.memo[args] = self.fn(*args)
+        return self.memo[args]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/util/importpath.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,16 @@
+import os
+import sys
+
+def import_path(fullpath):
+    """ Import a file with full path specification. Allows one to
+        import from anywhere, something __import__ does not do. 
+    """
+    # http://zephyrfalcon.org/weblog/arch_d7_2002_08_31.html
+    path, filename = os.path.split(fullpath)
+    filename, ext = os.path.splitext(filename)
+    sys.path.append(path)
+    module = __import__(filename)
+    reload(module) # Might be out of date during tests
+    del sys.path[-1]
+    return module
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/util/keyedinstance.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+class KeyedInstance(object):
+    """A class whose instances have a unique identifier of some sort
+    No two instances with the same unique ID should exist - if we try to create
+    a second instance, the first should be returned. 
+    """
+
+    _instances = dict()
+
+    def __new__(cls, *p, **k):
+        instances = cls._instances
+        clskey = str(cls)
+        if clskey not in instances:
+            instances[clskey] = dict()
+        instances = instances[clskey]
+
+        key = cls._key(*p, **k)
+        if key not in instances:
+            instances[key] = super(KeyedInstance, cls).__new__(cls)
+        return instances[key]
+
+    @classmethod
+    def _key(cls, *p, **k):
+        """Given a unique identifier, return a dictionary key
+        This should be overridden by child classes, to specify which parameters 
+        should determine an object's uniqueness
+        """
+        raise NotImplementedError()
+
+    @classmethod
+    def clear(cls):
+        # Allow cls.clear() as well as uniqueInstance.clear(cls)
+        if str(cls) in cls._instances:
+            del cls._instances[str(cls)]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/migrate/versioning/version.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import re
+import shutil
+import logging
+
+from rhodecode.lib.dbmigrate.migrate import exceptions
+from rhodecode.lib.dbmigrate.migrate.versioning import pathed, script
+
+
+log = logging.getLogger(__name__)
+
+class VerNum(object):
+    """A version number that behaves like a string and int at the same time"""
+
+    _instances = dict()
+
+    def __new__(cls, value):
+        val = str(value)
+        if val not in cls._instances:
+            cls._instances[val] = super(VerNum, cls).__new__(cls)
+        ret = cls._instances[val]
+        return ret
+
+    def __init__(self,value):
+        self.value = str(int(value))
+        if self < 0:
+            raise ValueError("Version number cannot be negative")
+
+    def __add__(self, value):
+        ret = int(self) + int(value)
+        return VerNum(ret)
+
+    def __sub__(self, value):
+        return self + (int(value) * -1)
+
+    def __cmp__(self, value):
+        return int(self) - int(value)
+
+    def __repr__(self):
+        return "<VerNum(%s)>" % self.value
+
+    def __str__(self):
+        return str(self.value)
+
+    def __int__(self):
+        return int(self.value)
+
+
+class Collection(pathed.Pathed):
+    """A collection of versioning scripts in a repository"""
+
+    FILENAME_WITH_VERSION = re.compile(r'^(\d{3,}).*')
+
+    def __init__(self, path):
+        """Collect current version scripts in repository
+        and store them in self.versions
+        """
+        super(Collection, self).__init__(path)
+        
+        # Create temporary list of files, allowing skipped version numbers.
+        files = os.listdir(path)
+        if '1' in files:
+            # deprecation
+            raise Exception('It looks like you have a repository in the old '
+                'format (with directories for each version). '
+                'Please convert repository before proceeding.')
+
+        tempVersions = dict()
+        for filename in files:
+            match = self.FILENAME_WITH_VERSION.match(filename)
+            if match:
+                num = int(match.group(1))
+                tempVersions.setdefault(num, []).append(filename)
+            else:
+                pass  # Must be a helper file or something, let's ignore it.
+
+        # Create the versions member where the keys
+        # are VerNum's and the values are Version's.
+        self.versions = dict()
+        for num, files in tempVersions.items():
+            self.versions[VerNum(num)] = Version(num, path, files)
+
+    @property
+    def latest(self):
+        """:returns: Latest version in Collection"""
+        return max([VerNum(0)] + self.versions.keys())
+
+    def create_new_python_version(self, description, **k):
+        """Create Python files for new version"""
+        ver = self.latest + 1
+        extra = str_to_filename(description)
+
+        if extra:
+            if extra == '_':
+                extra = ''
+            elif not extra.startswith('_'):
+                extra = '_%s' % extra
+
+        filename = '%03d%s.py' % (ver, extra)
+        filepath = self._version_path(filename)
+
+        script.PythonScript.create(filepath, **k)
+        self.versions[ver] = Version(ver, self.path, [filename])
+        
+    def create_new_sql_version(self, database, **k):
+        """Create SQL files for new version"""
+        ver = self.latest + 1
+        self.versions[ver] = Version(ver, self.path, [])
+
+        # Create new files.
+        for op in ('upgrade', 'downgrade'):
+            filename = '%03d_%s_%s.sql' % (ver, database, op)
+            filepath = self._version_path(filename)
+            script.SqlScript.create(filepath, **k)
+            self.versions[ver].add_script(filepath)
+        
+    def version(self, vernum=None):
+        """Returns latest Version if vernum is not given.
+        Otherwise, returns wanted version"""
+        if vernum is None:
+            vernum = self.latest
+        return self.versions[VerNum(vernum)]
+
+    @classmethod
+    def clear(cls):
+        super(Collection, cls).clear()
+
+    def _version_path(self, ver):
+        """Returns path of file in versions repository"""
+        return os.path.join(self.path, str(ver))
+
+
+class Version(object):
+    """A single version in a collection
+    :param vernum: Version Number 
+    :param path: Path to script files
+    :param filelist: List of scripts
+    :type vernum: int, VerNum
+    :type path: string
+    :type filelist: list
+    """
+
+    def __init__(self, vernum, path, filelist):
+        self.version = VerNum(vernum)
+
+        # Collect scripts in this folder
+        self.sql = dict()
+        self.python = None
+
+        for script in filelist:
+            self.add_script(os.path.join(path, script))
+    
+    def script(self, database=None, operation=None):
+        """Returns SQL or Python Script"""
+        for db in (database, 'default'):
+            # Try to return a .sql script first
+            try:
+                return self.sql[db][operation]
+            except KeyError:
+                continue  # No .sql script exists
+
+        # TODO: maybe add force Python parameter?
+        ret = self.python
+
+        assert ret is not None, \
+            "There is no script for %d version" % self.version
+        return ret
+
+    def add_script(self, path):
+        """Add script to Collection/Version"""
+        if path.endswith(Extensions.py):
+            self._add_script_py(path)
+        elif path.endswith(Extensions.sql):
+            self._add_script_sql(path)
+
+    SQL_FILENAME = re.compile(r'^(\d+)_([^_]+)_([^_]+).sql')
+
+    def _add_script_sql(self, path):
+        basename = os.path.basename(path)
+        match = self.SQL_FILENAME.match(basename)
+
+        if match:
+            version, dbms, op = match.group(1), match.group(2), match.group(3)
+        else:
+            raise exceptions.ScriptError(
+                "Invalid SQL script name %s " % basename + \
+                "(needs to be ###_database_operation.sql)")
+
+        # File the script into a dictionary
+        self.sql.setdefault(dbms, {})[op] = script.SqlScript(path)
+
+    def _add_script_py(self, path):
+        if self.python is not None:
+            raise exceptions.ScriptError('You can only have one Python script '
+                'per version, but you have: %s and %s' % (self.python, path))
+        self.python = script.PythonScript(path)
+
+
+class Extensions:
+    """A namespace for file extensions"""
+    py = 'py'
+    sql = 'sql'
+
+def str_to_filename(s):
+    """Replaces spaces, (double and single) quotes
+    and double underscores to underscores
+    """
+
+    s = s.replace(' ', '_').replace('"', '_').replace("'", '_').replace(".", "_")
+    while '__' in s:
+        s = s.replace('__', '_')
+    return s
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/versions/001_initial_release.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,237 @@
+#==============================================================================
+# DB INITIAL MODEL
+#==============================================================================
+import logging
+import datetime
+
+from sqlalchemy import *
+from sqlalchemy.exc import DatabaseError
+from sqlalchemy.orm import relation, backref, class_mapper
+from sqlalchemy.orm.session import Session
+from rhodecode.model.meta import Base
+
+from rhodecode.lib.dbmigrate.migrate import *
+
+log = logging.getLogger(__name__)
+
+class BaseModel(object):
+
+    @classmethod
+    def _get_keys(cls):
+        """return column names for this model """
+        return class_mapper(cls).c.keys()
+
+    def get_dict(self):
+        """return dict with keys and values corresponding 
+        to this model data """
+
+        d = {}
+        for k in self._get_keys():
+            d[k] = getattr(self, k)
+        return d
+
+    def get_appstruct(self):
+        """return list with keys and values tupples corresponding 
+        to this model data """
+
+        l = []
+        for k in self._get_keys():
+            l.append((k, getattr(self, k),))
+        return l
+
+    def populate_obj(self, populate_dict):
+        """populate model with data from given populate_dict"""
+
+        for k in self._get_keys():
+            if k in populate_dict:
+                setattr(self, k, populate_dict[k])
+
+class RhodeCodeSettings(Base, BaseModel):
+    __tablename__ = 'rhodecode_settings'
+    __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
+    app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+
+    def __init__(self, k, v):
+        self.app_settings_name = k
+        self.app_settings_value = v
+
+    def __repr__(self):
+        return "<RhodeCodeSetting('%s:%s')>" % (self.app_settings_name,
+                                                self.app_settings_value)
+
+class RhodeCodeUi(Base, BaseModel):
+    __tablename__ = 'rhodecode_ui'
+    __table_args__ = {'useexisting':True}
+    ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    ui_section = Column("ui_section", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_key = Column("ui_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_value = Column("ui_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
+
+
+class User(Base, BaseModel):
+    __tablename__ = 'users'
+    __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
+    user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    username = Column("username", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    password = Column("password", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    active = Column("active", Boolean(), nullable=True, unique=None, default=None)
+    admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
+    name = Column("name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    lastname = Column("lastname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    email = Column("email", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
+    is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
+
+    user_log = relation('UserLog', cascade='all')
+    user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
+
+    repositories = relation('Repository')
+    user_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
+
+    @property
+    def full_contact(self):
+        return '%s %s <%s>' % (self.name, self.lastname, self.email)
+
+    def __repr__(self):
+        return "<User('id:%s:%s')>" % (self.user_id, self.username)
+
+    def update_lastlogin(self):
+        """Update user lastlogin"""
+
+        try:
+            session = Session.object_session(self)
+            self.last_login = datetime.datetime.now()
+            session.add(self)
+            session.commit()
+            log.debug('updated user %s lastlogin', self.username)
+        except (DatabaseError,):
+            session.rollback()
+
+
+class UserLog(Base, BaseModel):
+    __tablename__ = 'user_logs'
+    __table_args__ = {'useexisting':True}
+    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
+    repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
+
+    user = relation('User')
+    repository = relation('Repository')
+
+class Repository(Base, BaseModel):
+    __tablename__ = 'repositories'
+    __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
+    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
+    private = Column("private", Boolean(), nullable=True, unique=None, default=None)
+    enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
+    description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    fork_id = Column("fork_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
+
+    user = relation('User')
+    fork = relation('Repository', remote_side=repo_id)
+    repo_to_perm = relation('RepoToPerm', cascade='all')
+    stats = relation('Statistics', cascade='all', uselist=False)
+
+    repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
+
+
+    def __repr__(self):
+        return "<Repository('%s:%s')>" % (self.repo_id, self.repo_name)
+
+class Permission(Base, BaseModel):
+    __tablename__ = 'permissions'
+    __table_args__ = {'useexisting':True}
+    permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+
+    def __repr__(self):
+        return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
+
+class RepoToPerm(Base, BaseModel):
+    __tablename__ = 'repo_to_perm'
+    __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
+    repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
+
+    user = relation('User')
+    permission = relation('Permission')
+    repository = relation('Repository')
+
+class UserToPerm(Base, BaseModel):
+    __tablename__ = 'user_to_perm'
+    __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
+    user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
+
+    user = relation('User')
+    permission = relation('Permission')
+
+class Statistics(Base, BaseModel):
+    __tablename__ = 'statistics'
+    __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
+    stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None)
+    stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
+    commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
+    commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
+    languages = Column("languages", LargeBinary(), nullable=False)#JSON data
+
+    repository = relation('Repository', single_parent=True)
+
+class UserFollowing(Base, BaseModel):
+    __tablename__ = 'user_followings'
+    __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
+                      UniqueConstraint('user_id', 'follows_user_id')
+                      , {'useexisting':True})
+
+    user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
+    follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
+
+    user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
+
+    follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
+    follows_repository = relation('Repository')
+
+
+class CacheInvalidation(Base, BaseModel):
+    __tablename__ = 'cache_invalidation'
+    __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
+    cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
+
+
+    def __init__(self, cache_key, cache_args=''):
+        self.cache_key = cache_key
+        self.cache_args = cache_args
+        self.cache_active = False
+
+    def __repr__(self):
+        return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
+
+
+def upgrade(migrate_engine):
+    # Upgrade operations go here. Don't create your own engine; bind migrate_engine
+    # to your metadata
+    Base.metadata.create_all(bind=migrate_engine, checkfirst=False)
+
+def downgrade(migrate_engine):
+    # Operations to reverse the above upgrade go here.
+    Base.metadata.drop_all(bind=migrate_engine, checkfirst=False)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,127 @@
+import logging
+import datetime
+
+from sqlalchemy import *
+from sqlalchemy.exc import DatabaseError
+from sqlalchemy.orm import relation, backref, class_mapper
+from sqlalchemy.orm.session import Session
+from rhodecode.model.meta import Base
+from rhodecode.model.db import BaseModel
+
+from rhodecode.lib.dbmigrate.migrate import *
+
+log = logging.getLogger(__name__)
+
+def upgrade(migrate_engine):
+    """ Upgrade operations go here. 
+    Don't create your own engine; bind migrate_engine to your metadata
+    """
+
+    #==========================================================================
+    # Upgrade of `users` table
+    #==========================================================================
+    tblname = 'users'
+    tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
+                    autoload_with=migrate_engine)
+
+    #ADD is_ldap column
+    is_ldap = Column("is_ldap", Boolean(), nullable=True,
+                     unique=None, default=False)
+    is_ldap.create(tbl, populate_default=True)
+    is_ldap.alter(nullable=False)
+
+    #==========================================================================
+    # Upgrade of `user_logs` table
+    #==========================================================================    
+
+    tblname = 'users'
+    tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
+                    autoload_with=migrate_engine)
+
+    #ADD revision column
+    revision = Column('revision', TEXT(length=None, convert_unicode=False,
+                                       assert_unicode=None),
+                      nullable=True, unique=None, default=None)
+    revision.create(tbl)
+
+
+
+    #==========================================================================
+    # Upgrade of `repositories` table
+    #==========================================================================    
+    tblname = 'repositories'
+    tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
+                    autoload_with=migrate_engine)
+
+    #ADD repo_type column#
+    repo_type = Column("repo_type", String(length=None, convert_unicode=False,
+                                           assert_unicode=None),
+                       nullable=True, unique=False, default='hg')
+
+    repo_type.create(tbl, populate_default=True)
+    #repo_type.alter(nullable=False)
+
+    #ADD statistics column#
+    enable_statistics = Column("statistics", Boolean(), nullable=True,
+                               unique=None, default=True)
+    enable_statistics.create(tbl)
+
+    #==========================================================================
+    # Add table `user_followings`
+    #==========================================================================
+    tblname = 'user_followings'
+
+    class UserFollowing(Base, BaseModel):
+        __tablename__ = 'user_followings'
+        __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
+                          UniqueConstraint('user_id', 'follows_user_id')
+                          , {'useexisting':True})
+
+        user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+        user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+        follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
+        follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
+
+        user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
+
+        follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
+        follows_repository = relation('Repository')
+
+    Base.metadata.tables[tblname].create(migrate_engine)
+
+    #==========================================================================
+    # Add table `cache_invalidation`
+    #==========================================================================
+    tblname = 'cache_invalidation'
+
+    class CacheInvalidation(Base, BaseModel):
+        __tablename__ = 'cache_invalidation'
+        __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
+        cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+        cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+        cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+        cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
+
+
+        def __init__(self, cache_key, cache_args=''):
+            self.cache_key = cache_key
+            self.cache_args = cache_args
+            self.cache_active = False
+
+        def __repr__(self):
+            return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
+
+    Base.metadata.tables[tblname].create(migrate_engine)
+
+    return
+
+
+
+
+
+
+def downgrade(migrate_engine):
+    meta = MetaData()
+    meta.bind = migrate_engine
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/versions/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.dbmigrate.versions.__init__
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Package containing new versions of database models
+    
+    :created_on: Dec 11, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/exceptions.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Custom Exceptions modules
+# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+"""
+Created on Nov 17, 2010
+Custom Exceptions modules
+@author: marcink
+"""
+
+class LdapUsernameError(Exception):pass
+class LdapPasswordError(Exception):pass
+class LdapConnectionError(Exception):pass
+class LdapImportError(Exception):pass
+
+class DefaultUserException(Exception):pass
+class UserOwnsReposException(Exception):pass
--- a/rhodecode/lib/helpers.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/helpers.py	Sat Dec 18 14:45:58 2010 +0100
@@ -3,6 +3,8 @@
 Consists of functions to typically be used within templates, but also
 available to Controllers. This module is available to both as 'h'.
 """
+import random
+import hashlib
 from pygments.formatters import HtmlFormatter
 from pygments import highlight as code_highlight
 from pylons import url, app_globals as g
@@ -23,6 +25,36 @@
 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
     convert_misc_entities, lchop, plural, rchop, remove_formatting, \
     replace_whitespace, urlify, truncate, wrap_paragraphs
+from webhelpers.date import time_ago_in_words
+
+from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
+    convert_boolean_attrs, NotGiven
+
+def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
+    _set_input_attrs(attrs, type, name, value)
+    _set_id_attr(attrs, id, name)
+    convert_boolean_attrs(attrs, ["disabled"])
+    return HTML.input(**attrs)
+
+reset = _reset
+
+
+def get_token():
+    """Return the current authentication token, creating one if one doesn't
+    already exist.
+    """
+    token_key = "_authentication_token"
+    from pylons import session
+    if not token_key in session:
+        try:
+            token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
+        except AttributeError: # Python < 2.4
+            token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
+        session[token_key] = token
+        if hasattr(session, 'save'):
+            session.save()
+    return session[token_key]
+
 
 #Custom helpers here :)
 class _Link(object):
@@ -93,7 +125,7 @@
                 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
                 
                 for (var i = 0; i < tts.length; i++) {
-                    //if element doesn not have and id autgenerate one for tooltip
+                    //if element doesn't not have and id autgenerate one for tooltip
                     
                     if (!tts[i].id){
                         tts[i].id='tt'+i*100;
@@ -111,7 +143,7 @@
                 showdelay:20,
             });
             
-            //Mouse Over event disabled for new repositories since they dont
+            //Mouse Over event disabled for new repositories since they don't
             //have last commit message
             myToolTips.contextMouseOverEvent.subscribe(
                 function(type, args) {
@@ -270,13 +302,13 @@
         tooltip_html = tooltip_html % (changeset.author,
                                                changeset.date,
                                                tooltip(changeset.message))
-        lnk_format = 'r%-5s:%s' % (changeset.revision,
-                                 changeset.short_id)
+        lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
+                                 short_id(changeset.raw_id))
         uri = link_to(
                 lnk_format,
                 url('changeset_home', repo_name=changeset.repository.name,
-                    revision=changeset.short_id),
-                style=get_color_string(changeset.short_id),
+                    revision=changeset.raw_id),
+                style=get_color_string(changeset.raw_id),
                 class_='tooltip',
                 tooltip_title=tooltip_html
               )
@@ -317,37 +349,168 @@
 flash = _Flash()
 
 
-#===============================================================================
+#==============================================================================
 # MERCURIAL FILTERS available via h.
-#===============================================================================
+#==============================================================================
 from mercurial import util
-from mercurial.templatefilters import age as _age, person as _person
+from mercurial.templatefilters import person as _person
+
+
+
+def _age(curdate):
+    """turns a datetime into an age string."""
+
+    if not curdate:
+        return ''
+
+    from datetime import timedelta, datetime
+
+    agescales = [("year", 3600 * 24 * 365),
+                 ("month", 3600 * 24 * 30),
+                 ("day", 3600 * 24),
+                 ("hour", 3600),
+                 ("minute", 60),
+                 ("second", 1), ]
+
+    age = datetime.now() - curdate
+    age_seconds = (age.days * agescales[2][1]) + age.seconds
+    pos = 1
+    for scale in agescales:
+        if scale[1] <= age_seconds:
+            if pos == 6:pos = 5
+            return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
+        pos += 1
+
+    return _('just now')
 
 age = lambda  x:_age(x)
 capitalize = lambda x: x.capitalize()
-date = lambda x: util.datestr(x)
 email = util.email
 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
 person = lambda x: _person(x)
-hgdate = lambda  x: "%d %d" % x
-isodate = lambda  x: util.datestr(x, '%Y-%m-%d %H:%M %1%2')
-isodatesec = lambda  x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2')
-localdate = lambda  x: (x[0], util.makedate()[1])
-rfc822date = lambda  x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2")
-rfc822date_notz = lambda  x: util.datestr(x, "%a, %d %b %Y %H:%M:%S")
-rfc3339date = lambda  x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2")
-time_ago = lambda x: util.datestr(_age(x), "%a, %d %b %Y %H:%M:%S %1%2")
+short_id = lambda x: x[:12]
+
+
+def bool2icon(value):
+    """
+    Returns True/False values represented as small html image of true/false
+    icons
+    :param value: bool value
+    """
+
+    if value is True:
+        return HTML.tag('img', src="/images/icons/accept.png", alt=_('True'))
+
+    if value is False:
+        return HTML.tag('img', src="/images/icons/cancel.png", alt=_('False'))
+
+    return value
 
 
-#===============================================================================
+def action_parser(user_log):
+    """
+    This helper will map the specified string action into translated
+    fancy names with icons and links
+    
+    @param action:
+    """
+    action = user_log.action
+    action_params = ' '
+
+    x = action.split(':')
+
+    if len(x) > 1:
+        action, action_params = x
+
+    def get_cs_links():
+        if action == 'push':
+            revs_limit = 5
+            revs = action_params.split(',')
+            cs_links = " " + ', '.join ([link(rev,
+                    url('changeset_home',
+                    repo_name=user_log.repository.repo_name,
+                    revision=rev)) for rev in revs[:revs_limit] ])
+            if len(revs) > revs_limit:
+                uniq_id = revs[0]
+                html_tmpl = ('<span> %s '
+                '<a class="show_more" id="_%s" href="#">%s</a> '
+                '%s</span>')
+                cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
+                                            % (len(revs) - revs_limit),
+                                            _('revisions'))
+
+                html_tmpl = '<span id="%s" style="display:none"> %s </span>'
+                cs_links += html_tmpl % (uniq_id, ', '.join([link(rev,
+                    url('changeset_home',
+                    repo_name=user_log.repository.repo_name,
+                    revision=rev)) for rev in revs[:revs_limit] ]))
+
+            return cs_links
+        return ''
+
+    def get_fork_name():
+        if action == 'user_forked_repo':
+            from rhodecode.model.scm import ScmModel
+            repo_name = action_params
+            repo = ScmModel().get(repo_name)
+            if repo is None:
+                return repo_name
+            return link_to(action_params, url('summary_home',
+                                              repo_name=repo.name,),
+                                              title=repo.dbrepo.description)
+        return ''
+    map = {'user_deleted_repo':_('User [deleted] repository'),
+           'user_created_repo':_('User [created] repository'),
+           'user_forked_repo':_('User [forked] repository as: %s') % get_fork_name(),
+           'user_updated_repo':_('User [updated] repository'),
+           'admin_deleted_repo':_('Admin [delete] repository'),
+           'admin_created_repo':_('Admin [created] repository'),
+           'admin_forked_repo':_('Admin [forked] repository'),
+           'admin_updated_repo':_('Admin [updated] repository'),
+           'push':_('[Pushed] %s') % get_cs_links(),
+           'pull':_('[Pulled]'),
+           'started_following_repo':_('User [started following] repository'),
+           'stopped_following_repo':_('User [stopped following] repository'),
+            }
+
+    action_str = map.get(action, action)
+    return literal(action_str.replace('[', '<span class="journal_highlight">')\
+                   .replace(']', '</span>'))
+
+def action_parser_icon(user_log):
+    action = user_log.action
+    action_params = None
+    x = action.split(':')
+
+    if len(x) > 1:
+        action, action_params = x
+
+    tmpl = """<img src="/images/icons/%s" alt="%s"/>"""
+    map = {'user_deleted_repo':'database_delete.png',
+           'user_created_repo':'database_add.png',
+           'user_forked_repo':'arrow_divide.png',
+           'user_updated_repo':'database_edit.png',
+           'admin_deleted_repo':'database_delete.png',
+           'admin_created_repo':'database_ddd.png',
+           'admin_forked_repo':'arrow_divide.png',
+           'admin_updated_repo':'database_edit.png',
+           'push':'script_add.png',
+           'pull':'down_16.png',
+           'started_following_repo':'heart_add.png',
+           'stopped_following_repo':'heart_delete.png',
+            }
+    return literal(tmpl % (map.get(action, action), action))
+
+
+#==============================================================================
 # PERMS
-#===============================================================================
+#==============================================================================
 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
 HasRepoPermissionAny, HasRepoPermissionAll
 
-#===============================================================================
+#==============================================================================
 # GRAVATAR URL
-#===============================================================================
+#==============================================================================
 import hashlib
 import urllib
 from pylons import request
--- a/rhodecode/lib/hooks.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/hooks.py	Sat Dec 18 14:45:58 2010 +0100
@@ -22,12 +22,12 @@
 
 @author: marcink
 """
-
-import sys
+from mercurial.cmdutil import revrange
+from mercurial.node import nullrev
+from rhodecode.lib import helpers as h
+from rhodecode.lib.utils import action_logger
 import os
-from rhodecode.lib import helpers as h
-from rhodecode.model import meta
-from rhodecode.model.db import UserLog, User
+import sys
 
 def repo_size(ui, repo, hooktype=None, **kwargs):
 
@@ -53,32 +53,53 @@
     size_total_f = h.format_byte_size(size_root + size_hg)
     sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
                      % (size_hg_f, size_root_f, size_total_f))
-    
-    user_action_mapper(ui, repo, hooktype, **kwargs)
+
+def log_pull_action(ui, repo, **kwargs):
+    """
+    Logs user last pull action
+    :param ui:
+    :param repo:
+    """
 
-def user_action_mapper(ui, repo, hooktype=None, **kwargs):
+    extra_params = dict(repo.ui.configitems('rhodecode_extras'))
+    username = extra_params['username']
+    repository = extra_params['repository']
+    action = 'pull'
+
+    action_logger(username, action, repository, extra_params['ip'])
+
+    return 0
+
+def log_push_action(ui, repo, **kwargs):
     """
     Maps user last push action to new changeset id, from mercurial
     :param ui:
     :param repo:
-    :param hooktype:
     """
-    
-    try:
-        sa = meta.Session
-        username = kwargs['url'].split(':')[-1]
-        user_log = sa.query(UserLog)\
-            .filter(UserLog.user == sa.query(User)\
-                                    .filter(User.username == username).one())\
-            .order_by(UserLog.user_log_id.desc()).first()
-        
-        if user_log and not user_log.revision:
-            user_log.revision = str(repo['tip'])
-            sa.add(user_log)
-            sa.commit()
-        
-    except Exception, e:
-        sa.rollback()
-        raise
-    finally:
-        meta.Session.remove()    
+
+    extra_params = dict(repo.ui.configitems('rhodecode_extras'))
+    username = extra_params['username']
+    repository = extra_params['repository']
+    action = 'push:%s'
+    node = kwargs['node']
+
+    def get_revs(repo, rev_opt):
+        if rev_opt:
+            revs = revrange(repo, rev_opt)
+
+            if len(revs) == 0:
+                return (nullrev, nullrev)
+            return (max(revs), min(revs))
+        else:
+            return (len(repo) - 1, 0)
+
+    stop, start = get_revs(repo, [node + ':'])
+
+    revs = (str(repo[r]) for r in xrange(start, stop + 1))
+
+    action = action % ','.join(revs)
+
+    action_logger(username, action, repository, extra_params['ip'])
+
+    return 0
+
--- a/rhodecode/lib/indexers/__init__.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/indexers/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,26 +1,28 @@
+import os
+import sys
+import traceback
 from os.path import dirname as dn, join as jn
+
+#to get the rhodecode import
+sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
+
+from rhodecode.model import init_model
+from rhodecode.model.scm import ScmModel
 from rhodecode.config.environment import load_environment
-from rhodecode.model.hg_model import HgModel
+from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
+
 from shutil import rmtree
 from webhelpers.html.builder import escape
 from vcs.utils.lazy import LazyProperty
 
+from sqlalchemy import engine_from_config
+
 from whoosh.analysis import RegexTokenizer, LowercaseFilter, StopFilter
 from whoosh.fields import TEXT, ID, STORED, Schema, FieldType
 from whoosh.index import create_in, open_dir
 from whoosh.formats import Characters
-from whoosh.highlight import highlight, SimpleFragmenter, HtmlFormatter   
-
-import os
-import sys
-import traceback
+from whoosh.highlight import highlight, SimpleFragmenter, HtmlFormatter
 
-#to get the rhodecode import
-sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
-
-
-#LOCATION WE KEEP THE INDEX
-IDX_LOCATION = jn(dn(dn(dn(dn(os.path.abspath(__file__))))), 'data', 'index')
 
 #EXTENSIONS WE WANT TO INDEX CONTENT OFF
 INDEX_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx', 'aspx', 'asx', 'axd', 'c',
@@ -45,9 +47,58 @@
 
 
 IDX_NAME = 'HG_INDEX'
-FORMATTER = HtmlFormatter('span', between='\n<span class="break">...</span>\n') 
+FORMATTER = HtmlFormatter('span', between='\n<span class="break">...</span>\n')
 FRAGMENTER = SimpleFragmenter(200)
-                            
+
+
+class MakeIndex(BasePasterCommand):
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    summary = "Creates index for full text search given configuration file"
+    group_name = "RhodeCode"
+    takes_config_file = -1
+    parser = Command.standard_parser(verbose=True)
+
+    def command(self):
+
+        from pylons import config
+        add_cache(config)
+        engine = engine_from_config(config, 'sqlalchemy.db1.')
+        init_model(engine)
+
+        index_location = config['index_dir']
+        repo_location = self.options.repo_location
+
+        #======================================================================
+        # WHOOSH DAEMON
+        #======================================================================
+        from rhodecode.lib.pidlock import LockHeld, DaemonLock
+        from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
+        try:
+            l = DaemonLock()
+            WhooshIndexingDaemon(index_location=index_location,
+                                 repo_location=repo_location)\
+                .run(full_index=self.options.full_index)
+            l.release()
+        except LockHeld:
+            sys.exit(1)
+
+    def update_parser(self):
+        self.parser.add_option('--repo-location',
+                          action='store',
+                          dest='repo_location',
+                          help="Specifies repositories location to index REQUIRED",
+                          )
+        self.parser.add_option('-f',
+                          action='store_true',
+                          dest='full_index',
+                          help="Specifies that index should be made full i.e"
+                                " destroy old and build from scratch",
+                          default=False)
+
 class ResultWrapper(object):
     def __init__(self, search_type, searcher, matcher, highlight_items):
         self.search_type = search_type
@@ -55,7 +106,7 @@
         self.matcher = matcher
         self.highlight_items = highlight_items
         self.fragment_size = 200 / 2
-    
+
     @LazyProperty
     def doc_ids(self):
         docs_id = []
@@ -64,8 +115,8 @@
             chunks = [offsets for offsets in self.get_chunks()]
             docs_id.append([docnum, chunks])
             self.matcher.next()
-        return docs_id   
-        
+        return docs_id
+
     def __str__(self):
         return '<%s at %s>' % (self.__class__.__name__, len(self.doc_ids))
 
@@ -91,32 +142,32 @@
         slice = []
         for docid in self.doc_ids[i:j]:
             slice.append(self.get_full_content(docid))
-        return slice   
-                            
+        return slice
+
 
     def get_full_content(self, docid):
         res = self.searcher.stored_fields(docid[0])
         f_path = res['path'][res['path'].find(res['repository']) \
                              + len(res['repository']):].lstrip('/')
-        
+
         content_short = self.get_short_content(res, docid[1])
         res.update({'content_short':content_short,
                     'content_short_hl':self.highlight(content_short),
                     'f_path':f_path})
-        
-        return res        
-    
+
+        return res
+
     def get_short_content(self, res, chunks):
-        
+
         return ''.join([res['content'][chunk[0]:chunk[1]] for chunk in chunks])
-    
+
     def get_chunks(self):
         """
         Smart function that implements chunking the content
         but not overlap chunks so it doesn't highlight the same
         close occurrences twice.
-        :param matcher:
-        :param size:
+        @param matcher:
+        @param size:
         """
         memory = [(0, 0)]
         for span in self.matcher.spans():
@@ -124,12 +175,12 @@
             end = span.endchar or 0
             start_offseted = max(0, start - self.fragment_size)
             end_offseted = end + self.fragment_size
-            
+
             if start_offseted < memory[-1][1]:
                 start_offseted = memory[-1][1]
-            memory.append((start_offseted, end_offseted,))    
-            yield (start_offseted, end_offseted,)  
-        
+            memory.append((start_offseted, end_offseted,))
+            yield (start_offseted, end_offseted,)
+
     def highlight(self, content, top=5):
         if self.search_type != 'content':
             return ''
@@ -139,4 +190,4 @@
                  fragmenter=FRAGMENTER,
                  formatter=FORMATTER,
                  top=top)
-        return hl 
+        return hl
--- a/rhodecode/lib/indexers/daemon.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/indexers/daemon.py	Sat Dec 18 14:45:58 2010 +0100
@@ -32,12 +32,12 @@
 project_path = dn(dn(dn(dn(os.path.realpath(__file__)))))
 sys.path.append(project_path)
 
-from rhodecode.lib.pidlock import LockHeld, DaemonLock
-from rhodecode.model.hg_model import HgModel
+
+from rhodecode.model.scm import ScmModel
 from rhodecode.lib.helpers import safe_unicode
 from whoosh.index import create_in, open_dir
 from shutil import rmtree
-from rhodecode.lib.indexers import INDEX_EXTENSIONS, IDX_LOCATION, SCHEMA, IDX_NAME
+from rhodecode.lib.indexers import INDEX_EXTENSIONS, SCHEMA, IDX_NAME
 
 from time import mktime
 from vcs.exceptions import ChangesetError, RepositoryError
@@ -61,55 +61,59 @@
 # add ch to logger
 log.addHandler(ch)
 
-def scan_paths(root_location):
-    return HgModel.repo_scan('/', root_location, None, True)
-
 class WhooshIndexingDaemon(object):
     """
     Deamon for atomic jobs
     """
 
-    def __init__(self, indexname='HG_INDEX', repo_location=None):
+    def __init__(self, indexname='HG_INDEX', index_location=None,
+                 repo_location=None, sa=None):
         self.indexname = indexname
+
+        self.index_location = index_location
+        if not index_location:
+            raise Exception('You have to provide index location')
+
         self.repo_location = repo_location
-        self.repo_paths = scan_paths(self.repo_location)
+        if not repo_location:
+            raise Exception('You have to provide repositories location')
+
+        self.repo_paths = ScmModel(sa).repo_scan(self.repo_location, None)
         self.initial = False
-        if not os.path.isdir(IDX_LOCATION):
-            os.mkdir(IDX_LOCATION)
+        if not os.path.isdir(self.index_location):
+            os.makedirs(self.index_location)
             log.info('Cannot run incremental index since it does not'
                      ' yet exist running full build')
             self.initial = True
-        
+
     def get_paths(self, repo):
-        """
-        recursive walk in root dir and return a set of all path in that dir
+        """recursive walk in root dir and return a set of all path in that dir
         based on repository walk function
         """
         index_paths_ = set()
         try:
-            tip = repo.get_changeset()
-            
-            for topnode, dirs, files in tip.walk('/'):
+            for topnode, dirs, files in repo.walk('/', 'tip'):
                 for f in files:
                     index_paths_.add(jn(repo.path, f.path))
                 for dir in dirs:
                     for f in files:
                         index_paths_.add(jn(repo.path, f.path))
-                
+
         except RepositoryError:
             pass
-        return index_paths_        
-    
+        return index_paths_
+
     def get_node(self, repo, path):
         n_path = path[len(repo.path) + 1:]
         node = repo.get_changeset().get_node(n_path)
         return node
-    
+
     def get_node_mtime(self, node):
         return mktime(node.last_changeset.date.timetuple())
-    
+
     def add_doc(self, writer, path, repo):
-        """Adding doc to writer"""
+        """Adding doc to writer this function itself fetches data from
+        the instance of vcs backend"""
         node = self.get_node(repo, path)
 
         #we just index the content of chosen files
@@ -120,63 +124,63 @@
             log.debug('    >> %s' % path)
             #just index file name without it's content
             u_content = u''
-        
+
         writer.add_document(owner=unicode(repo.contact),
                         repository=safe_unicode(repo.name),
                         path=safe_unicode(path),
                         content=u_content,
                         modtime=self.get_node_mtime(node),
-                        extension=node.extension)             
+                        extension=node.extension)
+
 
-    
     def build_index(self):
-        if os.path.exists(IDX_LOCATION):
+        if os.path.exists(self.index_location):
             log.debug('removing previous index')
-            rmtree(IDX_LOCATION)
-            
-        if not os.path.exists(IDX_LOCATION):
-            os.mkdir(IDX_LOCATION)
-        
-        idx = create_in(IDX_LOCATION, SCHEMA, indexname=IDX_NAME)
+            rmtree(self.index_location)
+
+        if not os.path.exists(self.index_location):
+            os.mkdir(self.index_location)
+
+        idx = create_in(self.index_location, SCHEMA, indexname=IDX_NAME)
         writer = idx.writer()
-        
+
         for cnt, repo in enumerate(self.repo_paths.values()):
             log.debug('building index @ %s' % repo.path)
-        
+
             for idx_path in self.get_paths(repo):
                 self.add_doc(writer, idx_path, repo)
-        
+
         log.debug('>> COMMITING CHANGES <<')
         writer.commit(merge=True)
         log.debug('>>> FINISHED BUILDING INDEX <<<')
-            
-    
+
+
     def update_index(self):
         log.debug('STARTING INCREMENTAL INDEXING UPDATE')
-            
-        idx = open_dir(IDX_LOCATION, indexname=self.indexname)
+
+        idx = open_dir(self.index_location, indexname=self.indexname)
         # The set of all paths in the index
         indexed_paths = set()
         # The set of all paths we need to re-index
         to_index = set()
-        
+
         reader = idx.reader()
         writer = idx.writer()
-    
+
         # Loop over the stored fields in the index
         for fields in reader.all_stored_fields():
             indexed_path = fields['path']
             indexed_paths.add(indexed_path)
-            
+
             repo = self.repo_paths[fields['repository']]
-            
+
             try:
                 node = self.get_node(repo, indexed_path)
             except ChangesetError:
                 # This file was deleted since it was indexed
                 log.debug('removing from index %s' % indexed_path)
                 writer.delete_by_term('path', indexed_path)
-    
+
             else:
                 # Check if this file was changed since it was indexed
                 indexed_time = fields['modtime']
@@ -187,7 +191,7 @@
                     log.debug('adding to reindex list %s' % indexed_path)
                     writer.delete_by_term('path', indexed_path)
                     to_index.add(indexed_path)
-    
+
         # Loop over the files in the filesystem
         # Assume we have a function that gathers the filenames of the
         # documents to be indexed
@@ -198,51 +202,14 @@
                     # that wasn't indexed before. So index it!
                     self.add_doc(writer, path, repo)
                     log.debug('re indexing %s' % path)
-                    
+
         log.debug('>> COMMITING CHANGES <<')
         writer.commit(merge=True)
         log.debug('>>> FINISHED REBUILDING INDEX <<<')
-        
+
     def run(self, full_index=False):
         """Run daemon"""
         if full_index or self.initial:
             self.build_index()
         else:
             self.update_index()
-        
-if __name__ == "__main__":
-    arg = sys.argv[1:]
-    if len(arg) != 2:
-        sys.stderr.write('Please specify indexing type [full|incremental]' 
-                         'and path to repositories as script args \n')
-        sys.exit()
-    
-    
-    if arg[0] == 'full':
-        full_index = True
-    elif arg[0] == 'incremental':
-        # False means looking just for changes
-        full_index = False
-    else:
-        sys.stdout.write('Please use [full|incremental]' 
-                         ' as script first arg \n')
-        sys.exit()
-    
-    if not os.path.isdir(arg[1]):
-        sys.stderr.write('%s is not a valid path \n' % arg[1])
-        sys.exit()
-    else:
-        if arg[1].endswith('/'):
-            repo_location = arg[1] + '*'
-        else:
-            repo_location = arg[1] + '/*'
-    
-    try:
-        l = DaemonLock()
-        WhooshIndexingDaemon(repo_location=repo_location)\
-            .run(full_index=full_index)
-        l.release()
-        reload(logging)
-    except LockHeld:
-        sys.exit(1)
-
--- a/rhodecode/lib/middleware/simplegit.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/middleware/simplegit.py	Sat Dec 18 14:45:58 2010 +0100
@@ -17,6 +17,14 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
+"""
+Created on 2010-04-28
+
+@author: marcink
+SimpleGit middleware for handling git protocol request (push/clone etc.)
+It's implemented with basic auth function
+"""
+
 from dulwich import server as dulserver
 
 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
@@ -54,26 +62,28 @@
 from dulwich.web import HTTPGitApplication
 from paste.auth.basic import AuthBasicAuthenticator
 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
-from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware, \
-    get_user_cached
-from rhodecode.lib.utils import action_logger, is_git, invalidate_cache, \
-    check_repo_fast
+from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
+from rhodecode.lib.utils import invalidate_cache, check_repo_fast
+from rhodecode.model.user import UserModel
 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 import logging
 import os
 import traceback
-"""
-Created on 2010-04-28
-
-@author: marcink
-SimpleGit middleware for handling git protocol request (push/clone etc.)
-It's implemented with basic auth function
-"""
-
-
 
 log = logging.getLogger(__name__)
 
+def is_git(environ):
+    """
+    Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
+    then have git client version given.
+    
+    :param environ:
+    """
+    http_user_agent = environ.get('HTTP_USER_AGENT')
+    if http_user_agent and http_user_agent.startswith('git'):
+        return True
+    return False
+
 class SimpleGit(object):
 
     def __init__(self, application, config):
@@ -81,11 +91,19 @@
         self.config = config
         #authenticate this git request using 
         self.authenticate = AuthBasicAuthenticator('', authfunc)
+        self.ipaddr = '0.0.0.0'
+        self.repository = None
+        self.username = None
+        self.action = None
 
     def __call__(self, environ, start_response):
         if not is_git(environ):
             return self.application(environ, start_response)
 
+        proxy_key = 'HTTP_X_REAL_IP'
+        def_key = 'REMOTE_ADDR'
+        self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
+
         #===================================================================
         # AUTHENTICATE THIS GIT REQUEST
         #===================================================================
@@ -99,10 +117,14 @@
             else:
                 return result.wsgi_application(environ, start_response)
 
+        #=======================================================================
+        # GET REPOSITORY
+        #=======================================================================
         try:
-            self.repo_name = environ['PATH_INFO'].split('/')[1]
-            if self.repo_name.endswith('/'):
-                self.repo_name = self.repo_name.rstrip('/')
+            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
+            if repo_name.endswith('/'):
+                repo_name = repo_name.rstrip('/')
+            self.repository = repo_name
         except:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
@@ -110,20 +132,21 @@
         #===================================================================
         # CHECK PERMISSIONS FOR THIS REQUEST
         #===================================================================
-        action = self.__get_action(environ)
-        if action:
+        self.action = self.__get_action(environ)
+        if self.action:
             username = self.__get_environ_user(environ)
             try:
                 user = self.__get_user(username)
+                self.username = user.username
             except:
                 log.error(traceback.format_exc())
                 return HTTPInternalServerError()(environ, start_response)
 
             #check permissions for this repository
-            if action == 'push':
+            if self.action == 'push':
                 if not HasPermissionAnyMiddleware('repository.write',
                                                   'repository.admin')\
-                                                    (user, self.repo_name):
+                                                    (user, repo_name):
                     return HTTPForbidden()(environ, start_response)
 
             else:
@@ -131,15 +154,13 @@
                 if not HasPermissionAnyMiddleware('repository.read',
                                                   'repository.write',
                                                   'repository.admin')\
-                                                    (user, self.repo_name):
+                                                    (user, repo_name):
                     return HTTPForbidden()(environ, start_response)
 
-            #log action
-            if action in ('push', 'pull', 'clone'):
-                proxy_key = 'HTTP_X_REAL_IP'
-                def_key = 'REMOTE_ADDR'
-                ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
-                self.__log_user_action(user, action, self.repo_name, ipaddr)
+        self.extras = {'ip':self.ipaddr,
+                       'username':self.username,
+                       'action':self.action,
+                       'repository':self.repository}
 
         #===================================================================
         # GIT REQUEST HANDLING
@@ -151,12 +172,12 @@
             return HTTPNotFound()(environ, start_response)
         try:
             app = self.__make_app()
-        except Exception:
+        except:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
 
         #invalidate cache on push
-        if action == 'push':
+        if self.action == 'push':
             self.__invalidate_cache(self.repo_name)
             messages = []
             messages.append('thank you for using rhodecode')
@@ -175,7 +196,7 @@
         return environ.get('REMOTE_USER')
 
     def __get_user(self, username):
-        return get_user_cached(username)
+        return UserModel().get_by_username(username, cache=True)
 
     def __get_action(self, environ):
         """
@@ -193,12 +214,8 @@
         else:
             return 'other'
 
-    def __log_user_action(self, user, action, repo, ipaddr):
-        action_logger(user, action, repo, ipaddr)
-
     def __invalidate_cache(self, repo_name):
         """we know that some change was made to repositories and we should
         invalidate the cache to see the changes right away but only for
         push requests"""
-        invalidate_cache('cached_repo_list')
-        invalidate_cache('full_changelog', repo_name)
+        invalidate_cache('get_repo_cached_%s' % repo_name)
--- a/rhodecode/lib/middleware/simplehg.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/middleware/simplehg.py	Sat Dec 18 14:45:58 2010 +0100
@@ -24,40 +24,57 @@
 SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
 It's implemented with basic auth function
 """
-from itertools import chain
 from mercurial.error import RepoError
 from mercurial.hgweb import hgweb
 from mercurial.hgweb.request import wsgiapplication
 from paste.auth.basic import AuthBasicAuthenticator
 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
-from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware, \
-    get_user_cached
-from rhodecode.lib.utils import is_mercurial, make_ui, invalidate_cache, \
+from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
+from rhodecode.lib.utils import make_ui, invalidate_cache, \
     check_repo_fast, ui_sections
+from rhodecode.model.user import UserModel
 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
-from rhodecode.lib.utils import action_logger
 import logging
 import os
 import traceback
 
 log = logging.getLogger(__name__)
 
+def is_mercurial(environ):
+    """
+    Returns True if request's target is mercurial server - header
+    ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
+    """
+    http_accept = environ.get('HTTP_ACCEPT')
+    if http_accept and http_accept.startswith('application/mercurial'):
+        return True
+    return False
+
 class SimpleHg(object):
 
     def __init__(self, application, config):
         self.application = application
         self.config = config
-        #authenticate this mercurial request using 
+        #authenticate this mercurial request using authfunc
         self.authenticate = AuthBasicAuthenticator('', authfunc)
+        self.ipaddr = '0.0.0.0'
+        self.repository = None
+        self.username = None
+        self.action = None
 
     def __call__(self, environ, start_response):
         if not is_mercurial(environ):
             return self.application(environ, start_response)
 
+        proxy_key = 'HTTP_X_REAL_IP'
+        def_key = 'REMOTE_ADDR'
+        self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
+
         #===================================================================
         # AUTHENTICATE THIS MERCURIAL REQUEST
         #===================================================================
         username = REMOTE_USER(environ)
+
         if not username:
             self.authenticate.realm = self.config['rhodecode_realm']
             result = self.authenticate(environ)
@@ -67,10 +84,14 @@
             else:
                 return result.wsgi_application(environ, start_response)
 
+        #=======================================================================
+        # GET REPOSITORY
+        #=======================================================================
         try:
             repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
             if repo_name.endswith('/'):
                 repo_name = repo_name.rstrip('/')
+            self.repository = repo_name
         except:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
@@ -78,17 +99,18 @@
         #===================================================================
         # CHECK PERMISSIONS FOR THIS REQUEST
         #===================================================================
-        action = self.__get_action(environ)
-        if action:
+        self.action = self.__get_action(environ)
+        if self.action:
             username = self.__get_environ_user(environ)
             try:
                 user = self.__get_user(username)
+                self.username = user.username
             except:
                 log.error(traceback.format_exc())
                 return HTTPInternalServerError()(environ, start_response)
 
             #check permissions for this repository
-            if action == 'push':
+            if self.action == 'push':
                 if not HasPermissionAnyMiddleware('repository.write',
                                                   'repository.admin')\
                                                     (user, repo_name):
@@ -102,12 +124,10 @@
                                                     (user, repo_name):
                     return HTTPForbidden()(environ, start_response)
 
-            #log action
-            if action in ('push', 'pull', 'clone'):
-                proxy_key = 'HTTP_X_REAL_IP'
-                def_key = 'REMOTE_ADDR'
-                ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
-                self.__log_user_action(user, action, repo_name, ipaddr)
+        self.extras = {'ip':self.ipaddr,
+                       'username':self.username,
+                       'action':self.action,
+                       'repository':self.repository}
 
         #===================================================================
         # MERCURIAL REQUEST HANDLING
@@ -130,40 +150,21 @@
             return HTTPInternalServerError()(environ, start_response)
 
         #invalidate cache on push
-        if action == 'push':
+        if self.action == 'push':
             self.__invalidate_cache(repo_name)
-            messages = []
-            messages.append('thank you for using rhodecode')
-
-            return self.msg_wrapper(app, environ, start_response, messages)
-        else:
-            return app(environ, start_response)
-
 
-    def msg_wrapper(self, app, environ, start_response, messages=[]):
-        """
-        Wrapper for custom messages that come out of mercurial respond messages
-        is a list of messages that the user will see at the end of response 
-        from merurial protocol actions that involves remote answers
-        :param app:
-        :param environ:
-        :param start_response:
-        """
-        def custom_messages(msg_list):
-            for msg in msg_list:
-                yield msg + '\n'
-        org_response = app(environ, start_response)
-        return chain(org_response, custom_messages(messages))
+        return app(environ, start_response)
+
 
     def __make_app(self):
         hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
-        return  self.__load_web_settings(hgserve)
+        return  self.__load_web_settings(hgserve, self.extras)
 
     def __get_environ_user(self, environ):
         return environ.get('REMOTE_USER')
 
     def __get_user(self, username):
-        return get_user_cached(username)
+        return UserModel().get_by_username(username, cache=True)
 
     def __get_action(self, environ):
         """
@@ -174,7 +175,7 @@
         mapping = {'changegroup': 'pull',
                    'changegroupsubset': 'pull',
                    'stream_out': 'pull',
-                   #'listkeys': 'pull',
+                   'listkeys': 'pull',
                    'unbundle': 'push',
                    'pushkey': 'push', }
         for qry in environ['QUERY_STRING'].split('&'):
@@ -185,25 +186,26 @@
                 else:
                     return cmd
 
-    def __log_user_action(self, user, action, repo, ipaddr):
-        action_logger(user, action, repo, ipaddr)
-
     def __invalidate_cache(self, repo_name):
         """we know that some change was made to repositories and we should
         invalidate the cache to see the changes right away but only for
         push requests"""
-        invalidate_cache('cached_repo_list')
-        invalidate_cache('full_changelog', repo_name)
+        invalidate_cache('get_repo_cached_%s' % repo_name)
 
 
-    def __load_web_settings(self, hgserve):
+    def __load_web_settings(self, hgserve, extras={}):
         #set the global ui for hgserve instance passed
         hgserve.repo.ui = self.baseui
 
         hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
+
+        #inject some additional parameters that will be available in ui
+        #for hooks
+        for k, v in extras.items():
+            hgserve.repo.ui.setconfig('rhodecode_extras', k, v)
+
         repoui = make_ui('file', hgrc, False)
 
-
         if repoui:
             #overwrite our ui instance with the section from hgrc file
             for section in ui_sections:
--- a/rhodecode/lib/smtp_mailer.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/smtp_mailer.py	Sat Dec 18 14:45:58 2010 +0100
@@ -22,7 +22,7 @@
 
     def __init__(self, mail_from, user, passwd, mail_server,
                     mail_port=None, ssl=False, tls=False):
-        
+
         self.mail_from = mail_from
         self.mail_server = mail_server
         self.mail_port = mail_port
@@ -31,7 +31,7 @@
         self.ssl = ssl
         self.tls = tls
         self.debug = False
-        
+
     def send(self, recipients=[], subject='', body='', attachment_files={}):
 
         if isinstance(recipients, basestring):
@@ -43,11 +43,11 @@
 
         if self.tls:
             smtp_serv.starttls()
-         
-        if self.debug:    
+
+        if self.debug:
             smtp_serv.set_debuglevel(1)
 
-        smtp_serv.ehlo("mailer")
+        smtp_serv.ehlo("rhodecode mailer")
 
         #if server requires authorization you must provide login and password
         smtp_serv.login(self.user, self.passwd)
@@ -82,13 +82,13 @@
                 maintype, subtype = ctype.split('/', 1)
                 if maintype == 'text':
                     # Note: we should handle calculating the charset
-                    file_part = MIMEText(self.get_content(msg_file), 
+                    file_part = MIMEText(self.get_content(msg_file),
                                          _subtype=subtype)
                 elif maintype == 'image':
-                    file_part = MIMEImage(self.get_content(msg_file), 
+                    file_part = MIMEImage(self.get_content(msg_file),
                                           _subtype=subtype)
                 elif maintype == 'audio':
-                    file_part = MIMEAudio(self.get_content(msg_file), 
+                    file_part = MIMEAudio(self.get_content(msg_file),
                                           _subtype=subtype)
                 else:
                     file_part = MIMEBase(maintype, subtype)
@@ -96,13 +96,13 @@
                     # Encode the payload using Base64
                     encoders.encode_base64(msg)
                 # Set the filename parameter
-                file_part.add_header('Content-Disposition', 'attachment', 
+                file_part.add_header('Content-Disposition', 'attachment',
                                      filename=f_name)
                 file_part.add_header('Content-Type', ctype, name=f_name)
                 msg.attach(file_part)
         else:
-            raise Exception('Attachment files should be' 
-                            'a dict in format {"filename":"filepath"}')    
+            raise Exception('Attachment files should be'
+                            'a dict in format {"filename":"filepath"}')
 
     def get_content(self, msg_file):
         '''
--- a/rhodecode/lib/utils.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/lib/utils.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,7 +1,15 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# Utilities for RhodeCode
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.lib.utils
+    ~~~~~~~~~~~~~~~~~~~
+
+    Utilities library for RhodeCode
+    
+    :created_on: Apr 18, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; version 2
@@ -17,21 +25,28 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
 
-"""
-Created on April 18, 2010
-Utilities for RhodeCode
-@author: marcink
-"""
-from beaker.cache import cache_region
+import os
+import logging
+import datetime
+import traceback
+
+from UserDict import DictMixin
+
 from mercurial import ui, config, hg
 from mercurial.error import RepoError
-from rhodecode.model import meta
-from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, UserLog
+
+import paste
+import beaker
+from paste.script.command import Command, BadCommand
+
 from vcs.backends.base import BaseChangeset
 from vcs.utils.lazy import LazyProperty
-import logging
-import datetime
-import os
+
+from rhodecode.model import meta
+from rhodecode.model.caching_query import FromCache
+from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.user import UserModel
 
 log = logging.getLogger(__name__)
 
@@ -39,72 +54,95 @@
 def get_repo_slug(request):
     return request.environ['pylons.routes_dict'].get('repo_name')
 
-def is_mercurial(environ):
-    """
-    Returns True if request's target is mercurial server - header
-    ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
-    """
-    http_accept = environ.get('HTTP_ACCEPT')
-    if http_accept and http_accept.startswith('application/mercurial'):
-        return True
-    return False
-
-def is_git(environ):
+def action_logger(user, action, repo, ipaddr='', sa=None):
     """
-    Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
-    then have git client version given.
+    Action logger for various actions made by users
     
-    :param environ:
-    """
-    http_user_agent = environ.get('HTTP_USER_AGENT')
-    if http_user_agent.startswith('git'):
-        return True
-    return False
-
-def action_logger(user, action, repo, ipaddr, sa=None):
-    """
-    Action logger for various action made by users
+    :param user: user that made this action, can be a unique username string or
+        object containing user_id attribute
+    :param action: action to log, should be on of predefined unique actions for
+        easy translations
+    :param repo: string name of repository or object containing repo_id,
+        that action was made on
+    :param ipaddr: optional ip address from what the action was made
+    :param sa: optional sqlalchemy session
+    
     """
 
     if not sa:
-        sa = meta.Session
+        sa = meta.Session()
 
     try:
+        um = UserModel()
         if hasattr(user, 'user_id'):
-            user_id = user.user_id
+            user_obj = user
         elif isinstance(user, basestring):
-            user_id = sa.query(User).filter(User.username == user).one()
+            user_obj = um.get_by_username(user, cache=False)
         else:
             raise Exception('You have to provide user object or username')
 
-        repo_name = repo.lstrip('/')
+
+        rm = RepoModel()
+        if hasattr(repo, 'repo_id'):
+            repo_obj = rm.get(repo.repo_id, cache=False)
+            repo_name = repo_obj.repo_name
+        elif  isinstance(repo, basestring):
+            repo_name = repo.lstrip('/')
+            repo_obj = rm.get_by_repo_name(repo_name, cache=False)
+        else:
+            raise Exception('You have to provide repository to action logger')
+
+
         user_log = UserLog()
-        user_log.user_id = user_id
+        user_log.user_id = user_obj.user_id
         user_log.action = action
+
+        user_log.repository_id = repo_obj.repo_id
         user_log.repository_name = repo_name
-        user_log.repository = sa.query(Repository)\
-            .filter(Repository.repo_name == repo_name).one()
+
         user_log.action_date = datetime.datetime.now()
         user_log.user_ip = ipaddr
         sa.add(user_log)
         sa.commit()
 
-        log.info('Adding user %s, action %s on %s',
-                                        user.username, action, repo)
-    except Exception, e:
+        log.info('Adding user %s, action %s on %s', user_obj, action, repo)
+    except:
+        log.error(traceback.format_exc())
         sa.rollback()
-        log.error('could not log user action:%s', str(e))
 
-def check_repo_dir(paths):
-    repos_path = paths[0][1].split('/')
-    if repos_path[-1] in ['*', '**']:
-        repos_path = repos_path[:-1]
-    if repos_path[0] != '/':
-        repos_path[0] = '/'
-    if not os.path.isdir(os.path.join(*repos_path)):
-        raise Exception('Not a valid repository in %s' % paths[0][1])
+def get_repos(path, recursive=False, initial=False):
+    """
+    Scans given path for repos and return (name,(type,path)) tuple 
+    :param prefix:
+    :param path:
+    :param recursive:
+    :param initial:
+    """
+    from vcs.utils.helpers import get_scm
+    from vcs.exceptions import VCSError
+
+    try:
+        scm = get_scm(path)
+    except:
+        pass
+    else:
+        raise Exception('The given path %s should not be a repository got %s',
+                        path, scm)
+
+    for dirpath in os.listdir(path):
+        try:
+            yield dirpath, get_scm(os.path.join(path, dirpath))
+        except VCSError:
+            pass
 
 def check_repo_fast(repo_name, base_path):
+    """
+    Check given path for existance of directory
+    :param repo_name:
+    :param base_path:
+    
+    :return False: if this directory is present
+    """
     if os.path.isdir(os.path.join(base_path, repo_name)):return False
     return True
 
@@ -135,57 +173,6 @@
         if retries < 0: raise IOError
         print complaint
 
-@cache_region('super_short_term', 'cached_hg_ui')
-def get_hg_ui_cached():
-    try:
-        sa = meta.Session
-        ret = sa.query(RhodeCodeUi).all()
-    finally:
-        meta.Session.remove()
-    return ret
-
-
-def get_hg_settings():
-    try:
-        sa = meta.Session
-        ret = sa.query(RhodeCodeSettings).all()
-    finally:
-        meta.Session.remove()
-
-    if not ret:
-        raise Exception('Could not get application settings !')
-    settings = {}
-    for each in ret:
-        settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
-
-    return settings
-
-def get_hg_ui_settings():
-    try:
-        sa = meta.Session
-        ret = sa.query(RhodeCodeUi).all()
-    finally:
-        meta.Session.remove()
-
-    if not ret:
-        raise Exception('Could not get application ui settings !')
-    settings = {}
-    for each in ret:
-        k = each.ui_key
-        v = each.ui_value
-        if k == '/':
-            k = 'root_path'
-
-        if k.find('.') != -1:
-            k = k.replace('.', '_')
-
-        if each.ui_section == 'hooks':
-            v = each.ui_active
-
-        settings[each.ui_section + '_' + k] = v
-
-    return settings
-
 #propagated from mercurial documentation
 ui_sections = ['alias', 'auth',
                 'decode/encode', 'defaults',
@@ -210,6 +197,11 @@
 
     baseui = ui.ui()
 
+    #clean the baseui object
+    baseui._ocfg = config.config()
+    baseui._ucfg = config.config()
+    baseui._tcfg = config.config()
+
     if read_from == 'file':
         if not os.path.isfile(path):
             log.warning('Unable to read config file %s' % path)
@@ -219,70 +211,69 @@
         cfg.read(path)
         for section in ui_sections:
             for k, v in cfg.items(section):
+                log.debug('settings ui from file[%s]%s:%s', section, k, v)
                 baseui.setconfig(section, k, v)
-                log.debug('settings ui from file[%s]%s:%s', section, k, v)
-
-        for k, v in baseui.configitems('extensions'):
-            baseui.setconfig('extensions', k, '0')
-        #just enable mq
-        baseui.setconfig('extensions', 'mq', '1')
-        if checkpaths:check_repo_dir(cfg.items('paths'))
 
 
     elif read_from == 'db':
-        hg_ui = get_hg_ui_cached()
+        sa = meta.Session()
+        ret = sa.query(RhodeCodeUi)\
+            .options(FromCache("sql_cache_short",
+                               "get_hg_ui_settings")).all()
+
+        hg_ui = ret
         for ui_ in hg_ui:
             if ui_.ui_active:
-                log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
+                log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
+                          ui_.ui_key, ui_.ui_value)
                 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
 
-
+        meta.Session.remove()
     return baseui
 
 
 def set_rhodecode_config(config):
-    hgsettings = get_hg_settings()
+    """
+    Updates pylons config with new settings from database
+    :param config:
+    """
+    from rhodecode.model.settings import SettingsModel
+    hgsettings = SettingsModel().get_app_settings()
 
     for k, v in hgsettings.items():
         config[k] = v
 
-def invalidate_cache(name, *args):
-    """Invalidates given name cache"""
-
-    from beaker.cache import region_invalidate
-    log.info('INVALIDATING CACHE FOR %s', name)
+def invalidate_cache(cache_key, *args):
+    """
+    Puts cache invalidation task into db for 
+    further global cache invalidation
+    """
+    from rhodecode.model.scm import ScmModel
 
-    """propagate our arguments to make sure invalidation works. First
-    argument has to be the name of cached func name give to cache decorator
-    without that the invalidation would not work"""
-    tmp = [name]
-    tmp.extend(args)
-    args = tuple(tmp)
-
-    if name == 'cached_repo_list':
-        from rhodecode.model.hg_model import _get_repos_cached
-        region_invalidate(_get_repos_cached, None, *args)
-
-    if name == 'full_changelog':
-        from rhodecode.model.hg_model import _full_changelog_cached
-        region_invalidate(_full_changelog_cached, None, *args)
+    if cache_key.startswith('get_repo_cached_'):
+        name = cache_key.split('get_repo_cached_')[-1]
+        ScmModel().mark_for_invalidation(name)
 
 class EmptyChangeset(BaseChangeset):
     """
-    An dummy empty changeset.
+    An dummy empty changeset. It's possible to pass hash when creating
+    an EmptyChangeset
     """
 
-    revision = -1
-    message = ''
-    author = ''
-    date = ''
+    def __init__(self, cs='0' * 40):
+        self._empty_cs = cs
+        self.revision = -1
+        self.message = ''
+        self.author = ''
+        self.date = ''
+
     @LazyProperty
     def raw_id(self):
         """
-        Returns raw string identifing this changeset, useful for web
+        Returns raw string identifying this changeset, useful for web
         representation.
         """
-        return '0' * 40
+        return self._empty_cs
 
     @LazyProperty
     def short_id(self):
@@ -301,26 +292,25 @@
     """
     maps all found repositories into db
     """
-    from rhodecode.model.repo_model import RepoModel
 
-    sa = meta.Session
+    sa = meta.Session()
+    rm = RepoModel()
     user = sa.query(User).filter(User.admin == True).first()
 
-    rm = RepoModel()
-
     for name, repo in initial_repo_list.items():
-        if not sa.query(Repository).filter(Repository.repo_name == name).scalar():
+        if not rm.get_by_repo_name(name, cache=False):
             log.info('repository %s not found creating default', name)
 
             form_data = {
                          'repo_name':name,
-                         'description':repo.description if repo.description != 'unknown' else \
-                                        'auto description for %s' % name,
+                         'repo_type':repo.alias,
+                         'description':repo.description \
+                            if repo.description != 'unknown' else \
+                                        '%s repository' % name,
                          'private':False
                          }
             rm.create(form_data, user, just_db=True)
 
-
     if remove_obsolete:
         #remove from database those repositories that are not in the filesystem
         for repo in sa.query(Repository).all():
@@ -328,11 +318,6 @@
                 sa.delete(repo)
                 sa.commit()
 
-
-    meta.Session.remove()
-
-from UserDict import DictMixin
-
 class OrderedDict(dict, DictMixin):
 
     def __init__(self, *args, **kwds):
@@ -433,8 +418,51 @@
         return not self == other
 
 
+#set cache regions for beaker so celery can utilise it
+def add_cache(settings):
+    cache_settings = {'regions':None}
+    for key in settings.keys():
+        for prefix in ['beaker.cache.', 'cache.']:
+            if key.startswith(prefix):
+                name = key.split(prefix)[1].strip()
+                cache_settings[name] = settings[key].strip()
+    if cache_settings['regions']:
+        for region in cache_settings['regions'].split(','):
+            region = region.strip()
+            region_settings = {}
+            for key, value in cache_settings.items():
+                if key.startswith(region):
+                    region_settings[key.split('.')[1]] = value
+            region_settings['expire'] = int(region_settings.get('expire',
+                                                                60))
+            region_settings.setdefault('lock_dir',
+                                       cache_settings.get('lock_dir'))
+            if 'type' not in region_settings:
+                region_settings['type'] = cache_settings.get('type',
+                                                             'memory')
+            beaker.cache.cache_regions[region] = region_settings
+
+def get_current_revision():
+    """
+    Returns tuple of (number, id) from repository containing this package
+    or None if repository could not be found.
+    """
+    try:
+        from vcs import get_repo
+        from vcs.utils.helpers import get_scm
+        from vcs.exceptions import RepositoryError, VCSError
+        repopath = os.path.join(os.path.dirname(__file__), '..', '..')
+        scm = get_scm(repopath)[0]
+        repo = get_repo(path=repopath, alias=scm)
+        tip = repo.get_changeset()
+        return (tip.revision, tip.short_id)
+    except (ImportError, RepositoryError, VCSError), err:
+        logging.debug("Cannot retrieve rhodecode's revision. Original error "
+                      "was: %s" % err)
+        return None
+
 #===============================================================================
-# TEST FUNCTIONS
+# TEST FUNCTIONS AND CREATORS
 #===============================================================================
 def create_test_index(repo_location, full_index):
     """Makes default test index
@@ -443,15 +471,16 @@
     """
     from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
     from rhodecode.lib.pidlock import DaemonLock, LockHeld
-    from rhodecode.lib.indexers import IDX_LOCATION
     import shutil
 
-    if os.path.exists(IDX_LOCATION):
-        shutil.rmtree(IDX_LOCATION)
+    index_location = os.path.join(repo_location, 'index')
+    if os.path.exists(index_location):
+        shutil.rmtree(index_location)
 
     try:
         l = DaemonLock()
-        WhooshIndexingDaemon(repo_location=repo_location)\
+        WhooshIndexingDaemon(index_location=index_location,
+                             repo_location=repo_location)\
             .run(full_index=full_index)
         l.release()
     except LockHeld:
@@ -462,10 +491,11 @@
     install test repository into tmp dir
     """
     from rhodecode.lib.db_manage import DbManage
+    from rhodecode.tests import HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, \
+        HG_FORK, GIT_FORK, TESTS_TMP_PATH
     import tarfile
     import shutil
     from os.path import dirname as dn, join as jn, abspath
-    from rhodecode.tests import REPO_PATH, NEW_REPO_PATH, FORK_REPO_PATH
 
     log = logging.getLogger('TestEnvCreator')
     # create logger
@@ -485,10 +515,10 @@
     log.addHandler(ch)
 
     #PART ONE create db
-    dbname = config['sqlalchemy.db1.url'].split('/')[-1]
-    log.debug('making test db %s', dbname)
+    dbconf = config['sqlalchemy.db1.url']
+    log.debug('making test db %s', dbconf)
 
-    dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
+    dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
                         tests=True)
     dbmanage.create_tables(override=True)
     dbmanage.config_prompt(repos_test_path)
@@ -498,18 +528,87 @@
     dbmanage.populate_default_permissions()
 
     #PART TWO make test repo
-    log.debug('making test vcs repo')
-    if os.path.isdir(REPO_PATH):
-        log.debug('REMOVING %s', REPO_PATH)
-        shutil.rmtree(REPO_PATH)
-    if os.path.isdir(NEW_REPO_PATH):
-        log.debug('REMOVING %s', NEW_REPO_PATH)
-        shutil.rmtree(NEW_REPO_PATH)
-    if os.path.isdir(FORK_REPO_PATH):
-        log.debug('REMOVING %s', FORK_REPO_PATH)
-        shutil.rmtree(FORK_REPO_PATH)
+    log.debug('making test vcs repositories')
+
+    #remove old one from previos tests
+    for r in [HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, HG_FORK, GIT_FORK]:
+
+        if os.path.isdir(jn(TESTS_TMP_PATH, r)):
+            log.debug('removing %s', r)
+            shutil.rmtree(jn(TESTS_TMP_PATH, r))
+
+    #CREATE DEFAULT HG REPOSITORY
+    cur_dir = dn(dn(abspath(__file__)))
+    tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
+    tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
+    tar.close()
+
+
+#==============================================================================
+# PASTER COMMANDS
+#==============================================================================
+
+class BasePasterCommand(Command):
+    """
+    Abstract Base Class for paster commands.
+
+    The celery commands are somewhat aggressive about loading
+    celery.conf, and since our module sets the `CELERY_LOADER`
+    environment variable to our loader, we have to bootstrap a bit and
+    make sure we've had a chance to load the pylons config off of the
+    command line, otherwise everything fails.
+    """
+    min_args = 1
+    min_args_error = "Please provide a paster config file as an argument."
+    takes_config_file = 1
+    requires_config_file = True
 
-    cur_dir = dn(dn(abspath(__file__)))
-    tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
-    tar.extractall('/tmp')
-    tar.close()
+    def notify_msg(self, msg, log=False):
+        """Make a notification to user, additionally if logger is passed
+        it logs this action using given logger
+        
+        :param msg: message that will be printed to user
+        :param log: logging instance, to use to additionally log this message
+        
+        """
+        print msg
+        if log and isinstance(log, logging):
+            log(msg)
+
+
+    def run(self, args):
+        """
+        Overrides Command.run
+        
+        Checks for a config file argument and loads it.
+        """
+        if len(args) < self.min_args:
+            raise BadCommand(
+                self.min_args_error % {'min_args': self.min_args,
+                                       'actual_args': len(args)})
+
+        # Decrement because we're going to lob off the first argument.
+        # @@ This is hacky
+        self.min_args -= 1
+        self.bootstrap_config(args[0])
+        self.update_parser()
+        return super(BasePasterCommand, self).run(args[1:])
+
+    def update_parser(self):
+        """
+        Abstract method.  Allows for the class's parser to be updated
+        before the superclass's `run` method is called.  Necessary to
+        allow options/arguments to be passed through to the underlying
+        celery command.
+        """
+        raise NotImplementedError("Abstract Method.")
+
+    def bootstrap_config(self, conf):
+        """
+        Loads the pylons configuration.
+        """
+        from pylons import config as pylonsconfig
+
+        path_to_ini_file = os.path.realpath(conf)
+        conf = paste.deploy.appconfig('config:' + path_to_ini_file)
+        pylonsconfig.init_app(conf.global_conf, conf.local_conf)
--- a/rhodecode/model/__init__.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/model/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,23 +1,71 @@
-"""The application's model objects"""
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.__init__
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+    
+    The application's model objects
+    
+    :created_on: Nov 25, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+    
+    
+    :example:
+    
+        .. code-block:: python
+    
+           from paste.deploy import appconfig
+           from pylons import config
+           from sqlalchemy import engine_from_config
+           from rhodecode.config.environment import load_environment
+           
+           conf = appconfig('config:development.ini', relative_to = './../../')
+           load_environment(conf.global_conf, conf.local_conf)
+           
+           engine = engine_from_config(config, 'sqlalchemy.')
+           init_model(engine)
+           # RUN YOUR CODE HERE
+    
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+
 import logging
 from rhodecode.model import meta
 log = logging.getLogger(__name__)
 
 def init_model(engine):
-    """Call me before using any of the tables or classes in the model"""
-    log.info("INITIALIZING DB MODELS")
+    """Initializes db session, bind the engine with the metadata,
+    Call this before using any of the tables or classes in the model, preferably
+    once in application start
+    
+    :param engine: engine to bind to
+    """
+    log.info("initializing db models for %s", engine)
     meta.Base.metadata.bind = engine
-    #meta.Base2.metadata.bind = engine2
 
-#THIS IS A TEST FOR EXECUTING SCRIPT AND LOAD PYLONS APPLICATION GLOBALS
-#from paste.deploy import appconfig
-#from pylons import config
-#from sqlalchemy import engine_from_config
-#from rhodecode.config.environment import load_environment
-#
-#conf = appconfig('config:development.ini', relative_to = './../../')
-#load_environment(conf.global_conf, conf.local_conf)
-#
-#engine = engine_from_config(config, 'sqlalchemy.')
-#init_model(engine)
-# DO SOMETHING
+class BaseModel(object):
+    """Base Model for all RhodeCode models, it adds sql alchemy session
+    into instance of model
+    
+    :param sa: If passed it reuses this session instead of creating a new one
+    """
+
+    def __init__(self, sa=None):
+        if sa is not None:
+            self.sa = sa
+        else:
+            self.sa = meta.Session()
--- a/rhodecode/model/caching_query.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/model/caching_query.py	Sat Dec 18 14:45:58 2010 +0100
@@ -55,11 +55,11 @@
     the "public" method of configuring this state upon the CachingQuery.
     
     """
-    
+
     def __init__(self, manager, *args, **kw):
         self.cache_manager = manager
         Query.__init__(self, *args, **kw)
-        
+
     def __iter__(self):
         """override __iter__ to pull results from Beaker
            if particular attributes have been configured.
@@ -101,7 +101,7 @@
         """Set the value in the cache for this query."""
 
         cache, cache_key = _get_cache_parameters(self)
-        cache.put(cache_key, value)        
+        cache.put(cache_key, value)
 
 def query_callable(manager):
     def query(*arg, **kw):
@@ -110,11 +110,11 @@
 
 def get_cache_region(name, region):
     if region not in beaker.cache.cache_regions:
-        raise BeakerException('Cache region not configured: %s'
+        raise BeakerException('Cache region `%s` not configured '
             'Check if proper cache settings are in the .ini files' % region)
     kw = beaker.cache.cache_regions[region]
     return beaker.cache.Cache._get_cache(name, kw)
-    
+
 def _get_cache_parameters(query):
     """For a query with cache_region and cache_namespace configured,
     return the correspoinding Cache instance and cache key, based
@@ -125,7 +125,7 @@
         raise ValueError("This Query does not have caching parameters configured.")
 
     region, namespace, cache_key = query._cache_parameters
-    
+
     namespace = _namespace_from_query(namespace, query)
 
     if cache_key is None:
@@ -153,15 +153,15 @@
     return namespace
 
 def _set_cache_parameters(query, region, namespace, cache_key):
-    
+
     if hasattr(query, '_cache_parameters'):
         region, namespace, cache_key = query._cache_parameters
         raise ValueError("This query is already configured "
-                        "for region %r namespace %r" % 
+                        "for region %r namespace %r" %
                         (region, namespace)
                     )
     query._cache_parameters = region, namespace, cache_key
-    
+
 class FromCache(MapperOption):
     """Specifies that a Query should load results from a cache."""
 
@@ -187,10 +187,10 @@
         self.region = region
         self.namespace = namespace
         self.cache_key = cache_key
-    
+
     def process_query(self, query):
         """Process a Query during normal loading operation."""
-        
+
         _set_cache_parameters(query, self.region, self.namespace, self.cache_key)
 
 class RelationshipCache(MapperOption):
@@ -263,13 +263,13 @@
     v = []
     def visit_bindparam(bind):
         value = query._params.get(bind.key, bind.value)
-        
+
         # lazyloader may dig a callable in here, intended
         # to late-evaluate params after autoflush is called.
         # convert to a scalar value.
         if callable(value):
             value = value()
-            
+
         v.append(value)
     if query._criterion is not None:
         visitors.traverse(query._criterion, {}, {'bindparam':visit_bindparam})
--- a/rhodecode/model/db.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/model/db.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,46 +1,119 @@
-from rhodecode.model.meta import Base
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.db
+    ~~~~~~~~~~~~~~~~~~
+    
+    Database Models for RhodeCode
+    
+    :created_on: Apr 08, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+import logging
+import datetime
+
 from sqlalchemy import *
-from sqlalchemy.orm import relation, backref
+from sqlalchemy.exc import DatabaseError
+from sqlalchemy.orm import relation, backref, class_mapper
 from sqlalchemy.orm.session import Session
-from vcs.utils.lazy import LazyProperty
-import logging
+
+from rhodecode.model.meta import Base
 
 log = logging.getLogger(__name__)
 
-class RhodeCodeSettings(Base):
+class BaseModel(object):
+
+    @classmethod
+    def _get_keys(cls):
+        """return column names for this model """
+        return class_mapper(cls).c.keys()
+
+    def get_dict(self):
+        """return dict with keys and values corresponding 
+        to this model data """
+
+        d = {}
+        for k in self._get_keys():
+            d[k] = getattr(self, k)
+        return d
+
+    def get_appstruct(self):
+        """return list with keys and values tupples corresponding 
+        to this model data """
+
+        l = []
+        for k in self._get_keys():
+            l.append((k, getattr(self, k),))
+        return l
+
+    def populate_obj(self, populate_dict):
+        """populate model with data from given populate_dict"""
+
+        for k in self._get_keys():
+            if k in populate_dict:
+                setattr(self, k, populate_dict[k])
+
+class RhodeCodeSettings(Base, BaseModel):
     __tablename__ = 'rhodecode_settings'
     __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
-    app_settings_id = Column("app_settings_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    app_settings_name = Column("app_settings_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
-class RhodeCodeUi(Base):
+    def __init__(self, k, v):
+        self.app_settings_name = k
+        self.app_settings_value = v
+
+    def __repr__(self):
+        return "<RhodeCodeSetting('%s:%s')>" % (self.app_settings_name,
+                                                self.app_settings_value)
+
+class RhodeCodeUi(Base, BaseModel):
     __tablename__ = 'rhodecode_ui'
     __table_args__ = {'useexisting':True}
-    ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    ui_section = Column("ui_section", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
+    ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    ui_section = Column("ui_section", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_key = Column("ui_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_value = Column("ui_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
 
 
-class User(Base):
+class User(Base, BaseModel):
     __tablename__ = 'users'
     __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
-    user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
-    admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
-    name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
+    user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    username = Column("username", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    password = Column("password", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    active = Column("active", Boolean(), nullable=True, unique=None, default=None)
+    admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
+    name = Column("name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    lastname = Column("lastname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    email = Column("email", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
+    is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
 
-    user_log = relation('UserLog')
-    user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
+    user_log = relation('UserLog', cascade='all')
+    user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 
-    @LazyProperty
+    repositories = relation('Repository')
+    user_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
+
+    @property
     def full_contact(self):
         return '%s %s <%s>' % (self.name, self.lastname, self.email)
 
@@ -49,7 +122,6 @@
 
     def update_lastlogin(self):
         """Update user lastlogin"""
-        import datetime
 
         try:
             session = Session.object_session(self)
@@ -57,85 +129,129 @@
             session.add(self)
             session.commit()
             log.debug('updated user %s lastlogin', self.username)
-        except Exception:
+        except (DatabaseError,):
             session.rollback()
 
 
-class UserLog(Base):
+class UserLog(Base, BaseModel):
     __tablename__ = 'user_logs'
     __table_args__ = {'useexisting':True}
-    user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
-    repository_id = Column("repository_id", INTEGER(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
-    repository_name = Column("repository_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
-    revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
+    repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
 
     user = relation('User')
     repository = relation('Repository')
 
-class Repository(Base):
+class Repository(Base, BaseModel):
     __tablename__ = 'repositories'
     __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
-    repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
-    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
-    private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
-    description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
+    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
+    private = Column("private", Boolean(), nullable=True, unique=None, default=None)
+    enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
+    description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    fork_id = Column("fork_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
 
     user = relation('User')
     fork = relation('Repository', remote_side=repo_id)
     repo_to_perm = relation('RepoToPerm', cascade='all')
-    stats = relation('Statistics', cascade='all')
+    stats = relation('Statistics', cascade='all', uselist=False)
+
+    repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
 
 
     def __repr__(self):
-        return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
+        return "<Repository('%s:%s')>" % (self.repo_id, self.repo_name)
 
-class Permission(Base):
+class Permission(Base, BaseModel):
     __tablename__ = 'permissions'
     __table_args__ = {'useexisting':True}
-    permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
     def __repr__(self):
         return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
 
-class RepoToPerm(Base):
+class RepoToPerm(Base, BaseModel):
     __tablename__ = 'repo_to_perm'
     __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
-    repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
-    permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
-    repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
+    repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
 
     user = relation('User')
     permission = relation('Permission')
     repository = relation('Repository')
 
-class UserToPerm(Base):
+class UserToPerm(Base, BaseModel):
     __tablename__ = 'user_to_perm'
     __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
-    user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
-    permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
+    user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
 
     user = relation('User')
     permission = relation('Permission')
 
-class Statistics(Base):
+class Statistics(Base, BaseModel):
     __tablename__ = 'statistics'
     __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
-    stat_id = Column("stat_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
-    repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None)
-    stat_on_revision = Column("stat_on_revision", INTEGER(), nullable=False)
-    commit_activity = Column("commit_activity", BLOB(), nullable=False)#JSON data
-    commit_activity_combined = Column("commit_activity_combined", BLOB(), nullable=False)#JSON data
-    languages = Column("languages", BLOB(), nullable=False)#JSON data
+    stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None)
+    stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
+    commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
+    commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
+    languages = Column("languages", LargeBinary(), nullable=False)#JSON data
 
     repository = relation('Repository', single_parent=True)
 
+class UserFollowing(Base, BaseModel):
+    __tablename__ = 'user_followings'
+    __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
+                      UniqueConstraint('user_id', 'follows_user_id')
+                      , {'useexisting':True})
+
+    user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
+    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
+    follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
+
+    user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
+
+    follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
+    follows_repository = relation('Repository')
+
+
+class CacheInvalidation(Base, BaseModel):
+    __tablename__ = 'cache_invalidation'
+    __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
+    cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
+
+
+    def __init__(self, cache_key, cache_args=''):
+        self.cache_key = cache_key
+        self.cache_args = cache_args
+        self.cache_active = False
+
+    def __repr__(self):
+        return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
+
+class DbMigrateVersion(Base, BaseModel):
+    __tablename__ = 'db_migrate_version'
+    __table_args__ = {'useexisting':True}
+    repository_id = Column('repository_id', String(250), primary_key=True)
+    repository_path = Column('repository_path', Text)
+    version = Column('version', Integer)
+
--- a/rhodecode/model/forms.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/model/forms.py	Sat Dec 18 14:45:58 2010 +0100
@@ -19,29 +19,34 @@
 for SELECT use formencode.All(OneOf(list), Int())
     
 """
+import os
+import re
+import logging
+
+import formencode
 from formencode import All
 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
     Email, Bool, StringBoolean
-from pylons import session
+
 from pylons.i18n.translation import _
-from rhodecode.lib.auth import check_password, get_crypt_password
+
+import rhodecode.lib.helpers as h
+from rhodecode.lib.auth import authenticate, get_crypt_password
+from rhodecode.lib.exceptions import LdapImportError
 from rhodecode.model import meta
-from rhodecode.model.user_model import UserModel
-from rhodecode.model.db import User, Repository
-from sqlalchemy.exc import OperationalError
-from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
+from rhodecode.model.user import UserModel
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.db import User
+from rhodecode import BACKENDS
+
 from webhelpers.pylonslib.secure_form import authentication_token
-import formencode
-import logging
-import os
-import rhodecode.lib.helpers as h
+
 log = logging.getLogger(__name__)
 
-
 #this is needed to translate the messages using _() in validators
 class State_obj(object):
     _ = staticmethod(_)
-    
+
 #===============================================================================
 # VALIDATORS
 #===============================================================================
@@ -53,75 +58,114 @@
         if value != authentication_token():
             raise formencode.Invalid(self.message('invalid_token', state,
                                             search_number=value), value, state)
-            
-def ValidUsername(edit, old_data):             
+
+def ValidUsername(edit, old_data):
     class _ValidUsername(formencode.validators.FancyValidator):
-    
+
         def validate_python(self, value, state):
             if value in ['default', 'new_user']:
                 raise formencode.Invalid(_('Invalid username'), value, state)
-            #check if user is uniq
-            sa = meta.Session
+            #check if user is unique
             old_un = None
             if edit:
-                old_un = sa.query(User).get(old_data.get('user_id')).username
-                
-            if old_un != value or not edit:    
-                if sa.query(User).filter(User.username == value).scalar():
+                old_un = UserModel().get(old_data.get('user_id')).username
+
+            if old_un != value or not edit:
+                if UserModel().get_by_username(value, cache=False,
+                                               case_insensitive=True):
                     raise formencode.Invalid(_('This username already exists') ,
                                              value, state)
-            meta.Session.remove()
-                            
-    return _ValidUsername   
-    
+
+
+            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
+                raise formencode.Invalid(_('Username may only contain '
+                                           'alphanumeric characters underscores '
+                                           'or dashes and must begin with '
+                                           'alphanumeric character'),
+                                      value, state)
+
+
+
+    return _ValidUsername
+
 class ValidPassword(formencode.validators.FancyValidator):
-    
+
     def to_python(self, value, state):
+
         if value:
-            return get_crypt_password(value)
-        
+
+            if value.get('password'):
+                try:
+                    value['password'] = get_crypt_password(value['password'])
+                except UnicodeEncodeError:
+                    e_dict = {'password':_('Invalid characters in password')}
+                    raise formencode.Invalid('', value, state, error_dict=e_dict)
+
+            if value.get('password_confirmation'):
+                try:
+                    value['password_confirmation'] = \
+                        get_crypt_password(value['password_confirmation'])
+                except UnicodeEncodeError:
+                    e_dict = {'password_confirmation':_('Invalid characters in password')}
+                    raise formencode.Invalid('', value, state, error_dict=e_dict)
+
+            if value.get('new_password'):
+                try:
+                    value['new_password'] = \
+                        get_crypt_password(value['new_password'])
+                except UnicodeEncodeError:
+                    e_dict = {'new_password':_('Invalid characters in password')}
+                    raise formencode.Invalid('', value, state, error_dict=e_dict)
+
+            return value
+
+class ValidPasswordsMatch(formencode.validators.FancyValidator):
+
+    def validate_python(self, value, state):
+
+        if value['password'] != value['password_confirmation']:
+            e_dict = {'password_confirmation':
+                   _('Password do not match')}
+            raise formencode.Invalid('', value, state, error_dict=e_dict)
+
 class ValidAuth(formencode.validators.FancyValidator):
     messages = {
             'invalid_password':_('invalid password'),
             'invalid_login':_('invalid user name'),
-            'disabled_account':_('Your acccount is disabled')
-            
+            'disabled_account':_('Your account is disabled')
+
             }
     #error mapping
     e_dict = {'username':messages['invalid_login'],
               'password':messages['invalid_password']}
     e_dict_disable = {'username':messages['disabled_account']}
-    
+
     def validate_python(self, value, state):
         password = value['password']
         username = value['username']
-        user = UserModel().get_user_by_name(username)
-        if user is None:
-            raise formencode.Invalid(self.message('invalid_password',
-                                     state=State_obj), value, state,
-                                     error_dict=self.e_dict)            
-        if user:
-            if user.active:
-                if user.username == username and check_password(password,
-                                                                user.password):
-                    return value
-                else:
-                    log.warning('user %s not authenticated', username)
-                    raise formencode.Invalid(self.message('invalid_password',
-                                             state=State_obj), value, state,
-                                             error_dict=self.e_dict)
-            else:
+        user = UserModel().get_by_username(username)
+
+        if authenticate(username, password):
+            return value
+        else:
+            if user and user.active is False:
                 log.warning('user %s is disabled', username)
                 raise formencode.Invalid(self.message('disabled_account',
                                          state=State_obj),
                                          value, state,
                                          error_dict=self.e_dict_disable)
-                   
+            else:
+                log.warning('user %s not authenticated', username)
+                raise formencode.Invalid(self.message('invalid_password',
+                                         state=State_obj), value, state,
+                                         error_dict=self.e_dict)
+
 class ValidRepoUser(formencode.validators.FancyValidator):
-            
+
     def to_python(self, value, state):
+        sa = meta.Session()
         try:
-            self.user_db = meta.Session.query(User)\
+            self.user_db = sa.query(User)\
                 .filter(User.active == True)\
                 .filter(User.username == value).one()
         except Exception:
@@ -129,31 +173,39 @@
                                      value, state)
         finally:
             meta.Session.remove()
-                        
+
         return self.user_db.user_id
 
-def ValidRepoName(edit, old_data):    
+def ValidRepoName(edit, old_data):
     class _ValidRepoName(formencode.validators.FancyValidator):
-            
+
         def to_python(self, value, state):
             slug = h.repo_name_slug(value)
             if slug in ['_admin']:
                 raise formencode.Invalid(_('This repository name is disallowed'),
                                          value, state)
-            if old_data.get('repo_name') != value or not edit:    
-                sa = meta.Session
-                if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
+            if old_data.get('repo_name') != value or not edit:
+                if RepoModel().get_by_repo_name(slug, cache=False):
                     raise formencode.Invalid(_('This repository already exists') ,
                                              value, state)
-                meta.Session.remove()
-            return slug 
-        
-        
+            return slug
+
+
     return _ValidRepoName
 
+def ValidForkType(old_data):
+    class _ValidForkType(formencode.validators.FancyValidator):
+
+        def to_python(self, value, state):
+            if old_data['repo_type'] != value:
+                raise formencode.Invalid(_('Fork have to be the same type as original'),
+                                         value, state)
+            return value
+    return _ValidForkType
+
 class ValidPerms(formencode.validators.FancyValidator):
     messages = {'perm_new_user_name':_('This username is not valid')}
-    
+
     def to_python(self, value, state):
         perms_update = []
         perms_new = []
@@ -167,7 +219,7 @@
                         if (new_user, new_perm) not in perms_new:
                             perms_new.append((new_user, new_perm))
                 else:
-                    usr = k[5:]                    
+                    usr = k[5:]
                     if usr == 'default':
                         if value['private']:
                             #set none for default when updating to private repo
@@ -184,60 +236,89 @@
             except Exception:
                 msg = self.message('perm_new_user_name',
                                      state=State_obj)
-                raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})            
+                raise formencode.Invalid(msg, value, state,
+                                         error_dict={'perm_new_user_name':msg})
         return value
-    
+
 class ValidSettings(formencode.validators.FancyValidator):
-    
+
     def to_python(self, value, state):
         #settings  form can't edit user
         if value.has_key('user'):
             del['value']['user']
-        
+
         return value
-    
+
 class ValidPath(formencode.validators.FancyValidator):
     def to_python(self, value, state):
-        isdir = os.path.isdir(value.replace('*', ''))
-        if (value.endswith('/*') or value.endswith('/**')) and isdir:
-            return value
-        elif not isdir:
-            msg = _('This is not a valid path') 
-        else:
-            msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
-        
-        raise formencode.Invalid(msg, value, state,
-                                     error_dict={'paths_root_path':msg})            
+
+        if not os.path.isdir(value):
+            msg = _('This is not a valid path')
+            raise formencode.Invalid(msg, value, state,
+                                     error_dict={'paths_root_path':msg})
+        return value
 
 def UniqSystemEmail(old_data):
     class _UniqSystemEmail(formencode.validators.FancyValidator):
         def to_python(self, value, state):
+            value = value.lower()
             if old_data.get('email') != value:
-                sa = meta.Session
+                sa = meta.Session()
                 try:
                     user = sa.query(User).filter(User.email == value).scalar()
                     if user:
-                        raise formencode.Invalid(_("That e-mail address is already taken") ,
+                        raise formencode.Invalid(_("This e-mail address is already taken") ,
                                                  value, state)
                 finally:
                     meta.Session.remove()
-                
+
             return value
-        
+
     return _UniqSystemEmail
-    
+
 class ValidSystemEmail(formencode.validators.FancyValidator):
     def to_python(self, value, state):
+        value = value.lower()
         sa = meta.Session
         try:
             user = sa.query(User).filter(User.email == value).scalar()
             if  user is None:
-                raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
+                raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
                                          value, state)
         finally:
             meta.Session.remove()
-            
-        return value     
+
+        return value
+
+class LdapLibValidator(formencode.validators.FancyValidator):
+
+    def to_python(self, value, state):
+
+        try:
+            import ldap
+        except ImportError:
+            raise LdapImportError
+        return value
+
+class BaseDnValidator(formencode.validators.FancyValidator):
+
+    def to_python(self, value, state):
+
+        try:
+            value % {'user':'valid'}
+
+            if value.find('%(user)s') == -1:
+                raise formencode.Invalid(_("You need to specify %(user)s in "
+                                           "template for example uid=%(user)s "
+                                           ",dc=company...") ,
+                                         value, state)
+
+        except KeyError:
+            raise formencode.Invalid(_("Wrong template used, only %(user)s "
+                                       "is an valid entry") ,
+                                         value, state)
+
+        return value
 
 #===============================================================================
 # FORMS        
@@ -266,65 +347,87 @@
 
     #chained validators have access to all data
     chained_validators = [ValidAuth]
-    
+
 def UserForm(edit=False, old_data={}):
     class _UserForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
-        username = All(UnicodeString(strip=True, min=1, not_empty=True), ValidUsername(edit, old_data))
+        username = All(UnicodeString(strip=True, min=1, not_empty=True),
+                       ValidUsername(edit, old_data))
         if edit:
-            new_password = All(UnicodeString(strip=True, min=6, not_empty=False), ValidPassword)
+            new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
             admin = StringBoolean(if_missing=False)
         else:
-            password = All(UnicodeString(strip=True, min=6, not_empty=True), ValidPassword)
+            password = All(UnicodeString(strip=True, min=6, not_empty=True))
         active = StringBoolean(if_missing=False)
         name = UnicodeString(strip=True, min=1, not_empty=True)
         lastname = UnicodeString(strip=True, min=1, not_empty=True)
         email = All(Email(not_empty=True), UniqSystemEmail(old_data))
-        
+
+        chained_validators = [ValidPassword]
+
     return _UserForm
 
-RegisterForm = UserForm
+def RegisterForm(edit=False, old_data={}):
+    class _RegisterForm(formencode.Schema):
+        allow_extra_fields = True
+        filter_extra_fields = True
+        username = All(ValidUsername(edit, old_data),
+                       UnicodeString(strip=True, min=1, not_empty=True))
+        password = All(UnicodeString(strip=True, min=6, not_empty=True))
+        password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
+        active = StringBoolean(if_missing=False)
+        name = UnicodeString(strip=True, min=1, not_empty=True)
+        lastname = UnicodeString(strip=True, min=1, not_empty=True)
+        email = All(Email(not_empty=True), UniqSystemEmail(old_data))
+
+        chained_validators = [ValidPasswordsMatch, ValidPassword]
+
+    return _RegisterForm
 
 def PasswordResetForm():
     class _PasswordResetForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
-        email = All(ValidSystemEmail(), Email(not_empty=True))             
+        email = All(ValidSystemEmail(), Email(not_empty=True))
     return _PasswordResetForm
 
-def RepoForm(edit=False, old_data={}):
+def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
     class _RepoForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
+        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
+                        ValidRepoName(edit, old_data))
         description = UnicodeString(strip=True, min=1, not_empty=True)
         private = StringBoolean(if_missing=False)
-        
+        enable_statistics = StringBoolean(if_missing=False)
+        repo_type = OneOf(supported_backends)
         if edit:
             user = All(Int(not_empty=True), ValidRepoUser)
-        
+
         chained_validators = [ValidPerms]
     return _RepoForm
 
-def RepoForkForm(edit=False, old_data={}):
+def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
     class _RepoForkForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        fork_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
+        fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
+                        ValidRepoName(edit, old_data))
         description = UnicodeString(strip=True, min=1, not_empty=True)
         private = StringBoolean(if_missing=False)
-        
+        repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
     return _RepoForkForm
 
 def RepoSettingsForm(edit=False, old_data={}):
     class _RepoForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
+        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
+                        ValidRepoName(edit, old_data))
         description = UnicodeString(strip=True, min=1, not_empty=True)
         private = StringBoolean(if_missing=False)
-        
+
         chained_validators = [ValidPerms, ValidSettings]
     return _RepoForm
 
@@ -335,9 +438,9 @@
         filter_extra_fields = False
         rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
         rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
-        
+
     return _ApplicationSettingsForm
- 
+
 def ApplicationUiSettingsForm():
     class _ApplicationUiSettingsForm(formencode.Schema):
         allow_extra_fields = True
@@ -346,16 +449,35 @@
         paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
         hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
         hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
-        
+        hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
+        hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
+
     return _ApplicationUiSettingsForm
 
 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
     class _DefaultPermissionsForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
-        overwrite_default = OneOf(['true', 'false'], if_missing='false')
+        overwrite_default = StringBoolean(if_missing=False)
+        anonymous = OneOf(['True', 'False'], if_missing=False)
         default_perm = OneOf(perms_choices)
         default_register = OneOf(register_choices)
         default_create = OneOf(create_choices)
-        
+
     return _DefaultPermissionsForm
+
+
+def LdapSettingsForm():
+    class _LdapSettingsForm(formencode.Schema):
+        allow_extra_fields = True
+        filter_extra_fields = True
+        pre_validators = [LdapLibValidator]
+        ldap_active = StringBoolean(if_missing=False)
+        ldap_host = UnicodeString(strip=True,)
+        ldap_port = Number(strip=True,)
+        ldap_ldaps = StringBoolean(if_missing=False)
+        ldap_dn_user = UnicodeString(strip=True,)
+        ldap_dn_pass = UnicodeString(strip=True,)
+        ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
+
+    return _LdapSettingsForm
--- a/rhodecode/model/hg_model.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# Model for RhodeCode
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# 
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; version 2
-# of the License or (at your opinion) any later version of the license.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA  02110-1301, USA.
-"""
-Created on April 9, 2010
-Model for RhodeCode
-@author: marcink
-"""
-from beaker.cache import cache_region
-from mercurial import ui
-from mercurial.hgweb.hgwebdir_mod import findrepos
-from pylons.i18n.translation import _
-from rhodecode.lib import helpers as h
-from rhodecode.lib.utils import invalidate_cache
-from rhodecode.lib.auth import HasRepoPermissionAny
-from rhodecode.model import meta
-from rhodecode.model.db import Repository, User
-from sqlalchemy.orm import joinedload
-from vcs.exceptions import RepositoryError, VCSError
-import logging
-import os
-import sys
-log = logging.getLogger(__name__)
-
-try:
-    from vcs.backends.hg import MercurialRepository
-except ImportError:
-    sys.stderr.write('You have to import vcs module')
-    raise Exception('Unable to import vcs')
-
-def _get_repos_cached_initial(app_globals, initial):
-    """return cached dict with repos
-    """
-    g = app_globals
-    return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui, initial)
-
-@cache_region('long_term', 'cached_repo_list')
-def _get_repos_cached():
-    """return cached dict with repos
-    """
-    log.info('getting all repositories list')
-    from pylons import app_globals as g
-    return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
-
-@cache_region('super_short_term', 'cached_repos_switcher_list')
-def _get_repos_switcher_cached(cached_repo_list):
-    repos_lst = []
-    for repo in [x for x in cached_repo_list.values()]:
-        if HasRepoPermissionAny('repository.write', 'repository.read',
-                    'repository.admin')(repo.name, 'main page check'):
-            repos_lst.append((repo.name, repo.dbrepo.private,))
-    
-    return sorted(repos_lst, key=lambda k:k[0].lower())
-
-@cache_region('long_term', 'full_changelog')
-def _full_changelog_cached(repo_name):
-    log.info('getting full changelog for %s', repo_name)
-    return list(reversed(list(HgModel().get_repo(repo_name))))
-
-class HgModel(object):
-    """Mercurial Model
-    """
-
-    def __init__(self):
-        pass
-    
-    @staticmethod
-    def repo_scan(repos_prefix, repos_path, baseui, initial=False):
-        """
-        Listing of repositories in given path. This path should not be a 
-        repository itself. Return a dictionary of repository objects
-        :param repos_path: path to directory it could take syntax with 
-        * or ** for deep recursive displaying repositories
-        """
-        sa = meta.Session()
-        def check_repo_dir(path):
-            """Checks the repository
-            :param path:
-            """
-            repos_path = path.split('/')
-            if repos_path[-1] in ['*', '**']:
-                repos_path = repos_path[:-1]
-            if repos_path[0] != '/':
-                repos_path[0] = '/'
-            if not os.path.isdir(os.path.join(*repos_path)):
-                raise RepositoryError('Not a valid repository in %s' % path)        
-        if not repos_path.endswith('*'):
-            raise VCSError('You need to specify * or ** at the end of path '
-                            'for recursive scanning')
-            
-        check_repo_dir(repos_path)
-        log.info('scanning for repositories in %s', repos_path)
-        repos = findrepos([(repos_prefix, repos_path)])
-        if not isinstance(baseui, ui.ui):
-            baseui = ui.ui()
-    
-        repos_list = {}
-        for name, path in repos:
-            try:
-                #name = name.split('/')[-1]
-                if repos_list.has_key(name):
-                    raise RepositoryError('Duplicate repository name %s found in'
-                                    ' %s' % (name, path))
-                else:
-                    
-                    repos_list[name] = MercurialRepository(path, baseui=baseui)
-                    repos_list[name].name = name
-                    
-                    dbrepo = None
-                    if not initial:
-                        #for initial scann on application first run we don't
-                        #have db repos yet.
-                        dbrepo = sa.query(Repository)\
-                            .options(joinedload(Repository.fork))\
-                            .filter(Repository.repo_name == name)\
-                            .scalar()
-                            
-                    if dbrepo:
-                        log.info('Adding db instance to cached list')
-                        repos_list[name].dbrepo = dbrepo
-                        repos_list[name].description = dbrepo.description
-                        if dbrepo.user:
-                            repos_list[name].contact = dbrepo.user.full_contact
-                        else:
-                            repos_list[name].contact = sa.query(User)\
-                            .filter(User.admin == True).first().full_contact
-            except OSError:
-                continue
-        meta.Session.remove()
-        return repos_list
-        
-    def get_repos(self):
-        for name, repo in _get_repos_cached().items():
-            if repo._get_hidden():
-                #skip hidden web repository
-                continue
-            
-            last_change = repo.last_change
-            tip = h.get_changeset_safe(repo, 'tip')
-                
-            tmp_d = {}
-            tmp_d['name'] = repo.name
-            tmp_d['name_sort'] = tmp_d['name'].lower()
-            tmp_d['description'] = repo.description
-            tmp_d['description_sort'] = tmp_d['description']
-            tmp_d['last_change'] = last_change
-            tmp_d['last_change_sort'] = last_change[1] - last_change[0]
-            tmp_d['tip'] = tip.short_id
-            tmp_d['tip_sort'] = tip.revision 
-            tmp_d['rev'] = tip.revision
-            tmp_d['contact'] = repo.contact
-            tmp_d['contact_sort'] = tmp_d['contact']
-            tmp_d['repo_archives'] = list(repo._get_archives())
-            tmp_d['last_msg'] = tip.message
-            tmp_d['repo'] = repo
-            yield tmp_d
-
-    def get_repo(self, repo_name):
-        try:
-            repo = _get_repos_cached()[repo_name]
-            return repo
-        except KeyError:
-            #i we're here and we got key errors let's try to invalidate the
-            #cahce and try again
-            invalidate_cache('cached_repo_list')
-            repo = _get_repos_cached()[repo_name]
-            return repo
-            
-        
-        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/permission.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.permission
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    permissions model for RhodeCode
+    
+    :created_on: Aug 20, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+
+import logging
+import traceback
+
+from sqlalchemy.exc import DatabaseError
+
+from rhodecode.model import BaseModel
+from rhodecode.model.db import User, Permission, UserToPerm, RepoToPerm
+from rhodecode.model.caching_query import FromCache
+
+log = logging.getLogger(__name__)
+
+
+class PermissionModel(BaseModel):
+    """Permissions model for RhodeCode
+    """
+
+    def get_permission(self, permission_id, cache=False):
+        """Get's permissions by id
+        
+        :param permission_id: id of permission to get from database
+        :param cache: use Cache for this query
+        """
+        perm = self.sa.query(Permission)
+        if cache:
+            perm = perm.options(FromCache("sql_cache_short",
+                                          "get_permission_%s" % permission_id))
+        return perm.get(permission_id)
+
+    def get_permission_by_name(self, name, cache=False):
+        """Get's permissions by given name
+        
+        :param name: name to fetch
+        :param cache: Use cache for this query
+        """
+        perm = self.sa.query(Permission)\
+            .filter(Permission.permission_name == name)
+        if cache:
+            perm = perm.options(FromCache("sql_cache_short",
+                                          "get_permission_%s" % name))
+        return perm.scalar()
+
+    def update(self, form_result):
+        perm_user = self.sa.query(User)\
+                .filter(User.username == form_result['perm_user_name']).scalar()
+        u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all()
+        if len(u2p) != 3:
+            raise Exception('Defined: %s should be 3  permissions for default'
+                            ' user. This should not happen please verify'
+                            ' your database' % len(u2p))
+
+        try:
+            #stage 1 change defaults    
+            for p in u2p:
+                if p.permission.permission_name.startswith('repository.'):
+                    p.permission = self.get_permission_by_name(
+                                       form_result['default_perm'])
+                    self.sa.add(p)
+
+                if p.permission.permission_name.startswith('hg.register.'):
+                    p.permission = self.get_permission_by_name(
+                                       form_result['default_register'])
+                    self.sa.add(p)
+
+                if p.permission.permission_name.startswith('hg.create.'):
+                    p.permission = self.get_permission_by_name(
+                                        form_result['default_create'])
+                    self.sa.add(p)
+
+            #stage 2 update all default permissions for repos if checked
+            if form_result['overwrite_default'] == True:
+                for r2p in self.sa.query(RepoToPerm)\
+                               .filter(RepoToPerm.user == perm_user).all():
+                    r2p.permission = self.get_permission_by_name(
+                                         form_result['default_perm'])
+                    self.sa.add(r2p)
+
+            #stage 3 set anonymous access
+            if perm_user.username == 'default':
+                perm_user.active = bool(form_result['anonymous'])
+                self.sa.add(perm_user)
+
+
+            self.sa.commit()
+        except (DatabaseError,):
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
--- a/rhodecode/model/permission_model.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# Model for permissions
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
- 
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; version 2
-# of the License or (at your opinion) any later version of the license.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA  02110-1301, USA.
-"""
-Created on Aug 20, 2010
-Model for permissions
-@author: marcink
-"""
-
-from pylons.i18n.translation import _
-from rhodecode.model.db import User, Permission, UserToPerm, RepoToPerm
-from rhodecode.model.meta import Session
-import logging
-import traceback
-log = logging.getLogger(__name__)
-
-
-class PermissionModel(object):
-
-    def __init__(self):
-        self.sa = Session() 
-    
-    def get_default(self):
-        return self.sa.query(User).filter(User.username == 'default').scalar()
-    
-    def get_permission(self, id):
-        return self.sa.query(Permission).get(id)
-    
-    def get_permission_by_name(self, name):
-        return self.sa.query(Permission)\
-        .filter(Permission.permission_name == name).scalar()
-    
-    
-    def update(self, form_result):
-        perm_user = self.sa.query(User)\
-                .filter(User.username == form_result['perm_user_name']).scalar()
-        u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all()
-        if len(u2p) != 3:
-            raise Exception('There is more than 3 defined \
-            permissions for defualt user. This should not happen please verify\
-            your database')
-        
-        try:
-            #stage 1 change defaults    
-            for p in u2p:
-                if p.permission.permission_name.startswith('repository.'):
-                    p.permission = self.get_permission_by_name(form_result['default_perm'])
-                    self.sa.add(p)
-                    
-                if p.permission.permission_name.startswith('hg.register.'):
-                    p.permission = self.get_permission_by_name(form_result['default_register'])
-                    self.sa.add(p)
-                    
-                if p.permission.permission_name.startswith('hg.create.'):
-                    p.permission = self.get_permission_by_name(form_result['default_create'])
-                    self.sa.add(p)
-            #stage 2 update all default permissions for repos if checked
-            if form_result['overwrite_default'] == 'true':
-                for r2p in self.sa.query(RepoToPerm).filter(RepoToPerm.user == perm_user).all():
-                    r2p.permission = self.get_permission_by_name(form_result['default_perm'])
-                    self.sa.add(r2p)
-            
-            self.sa.commit()
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise               
-        
-        
-        
-        
-        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/repo.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,263 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.repo
+    ~~~~~~~~~~~~~~~~~~~~
+
+    Repository model for rhodecode
+    
+    :created_on: Jun 5, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+import os
+import shutil
+import logging
+import traceback
+from datetime import datetime
+
+from pylons import app_globals as g
+
+from rhodecode.model import BaseModel
+from rhodecode.model.caching_query import FromCache
+from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
+    Statistics
+from rhodecode.model.user import UserModel
+
+from vcs.backends import get_backend
+
+log = logging.getLogger(__name__)
+
+class RepoModel(BaseModel):
+
+    def get(self, repo_id, cache=False):
+        repo = self.sa.query(Repository)\
+            .filter(Repository.repo_id == repo_id)
+
+        if cache:
+            repo = repo.options(FromCache("sql_cache_short",
+                                          "get_repo_%s" % repo_id))
+        return repo.scalar()
+
+
+    def get_by_repo_name(self, repo_name, cache=False):
+        repo = self.sa.query(Repository)\
+            .filter(Repository.repo_name == repo_name)
+
+        if cache:
+            repo = repo.options(FromCache("sql_cache_short",
+                                          "get_repo_%s" % repo_name))
+        return repo.scalar()
+
+    def get_users_js(self):
+
+        users = self.sa.query(User).filter(User.active == True).all()
+        u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
+        users_array = '[%s];' % '\n'.join([u_tmpl % (u.user_id, u.name,
+                                                    u.lastname, u.username)
+                                        for u in users])
+        return users_array
+
+
+    def update(self, repo_name, form_data):
+        try:
+            cur_repo = self.get_by_repo_name(repo_name, cache=False)
+            user_model = UserModel(self.sa)
+
+            #update permissions
+            for username, perm in form_data['perms_updates']:
+                r2p = self.sa.query(RepoToPerm)\
+                        .filter(RepoToPerm.user == user_model.get_by_username(username))\
+                        .filter(RepoToPerm.repository == cur_repo)\
+                        .one()
+
+                r2p.permission = self.sa.query(Permission)\
+                                    .filter(Permission.permission_name == perm)\
+                                    .scalar()
+                self.sa.add(r2p)
+
+            #set new permissions
+            for username, perm in form_data['perms_new']:
+                r2p = RepoToPerm()
+                r2p.repository = cur_repo
+                r2p.user = user_model.get_by_username(username, cache=False)
+
+                r2p.permission = self.sa.query(Permission)\
+                                    .filter(Permission.permission_name == perm)\
+                                    .scalar()
+                self.sa.add(r2p)
+
+            #update current repo
+            for k, v in form_data.items():
+                if k == 'user':
+                    cur_repo.user = user_model.get(v)
+                else:
+                    setattr(cur_repo, k, v)
+
+            self.sa.add(cur_repo)
+
+            if repo_name != form_data['repo_name']:
+                #rename our data
+                self.__rename_repo(repo_name, form_data['repo_name'])
+
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def create(self, form_data, cur_user, just_db=False, fork=False):
+        try:
+            if fork:
+                #force str since hg doesn't go with unicode
+                repo_name = str(form_data['fork_name'])
+                org_name = str(form_data['repo_name'])
+
+            else:
+                org_name = repo_name = str(form_data['repo_name'])
+            new_repo = Repository()
+            new_repo.enable_statistics = True
+            for k, v in form_data.items():
+                if k == 'repo_name':
+                    v = repo_name
+                setattr(new_repo, k, v)
+
+            if fork:
+                parent_repo = self.sa.query(Repository)\
+                        .filter(Repository.repo_name == org_name).scalar()
+                new_repo.fork = parent_repo
+
+            new_repo.user_id = cur_user.user_id
+            self.sa.add(new_repo)
+
+            #create default permission
+            repo_to_perm = RepoToPerm()
+            default = 'repository.read'
+            for p in UserModel(self.sa).get_by_username('default', cache=False).user_perms:
+                if p.permission.permission_name.startswith('repository.'):
+                    default = p.permission.permission_name
+                    break
+
+            default_perm = 'repository.none' if form_data['private'] else default
+
+            repo_to_perm.permission_id = self.sa.query(Permission)\
+                    .filter(Permission.permission_name == default_perm)\
+                    .one().permission_id
+
+            repo_to_perm.repository_id = new_repo.repo_id
+            repo_to_perm.user_id = UserModel(self.sa)\
+                .get_by_username('default', cache=False).user_id
+
+            self.sa.add(repo_to_perm)
+            self.sa.commit()
+
+
+            #now automatically start following this repository as owner
+            from rhodecode.model.scm import ScmModel
+            ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
+                                             cur_user.user_id)
+
+            if not just_db:
+                self.__create_repo(repo_name, form_data['repo_type'])
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def create_fork(self, form_data, cur_user):
+        from rhodecode.lib.celerylib import tasks, run_task
+        run_task(tasks.create_repo_fork, form_data, cur_user)
+
+    def delete(self, repo):
+        try:
+            self.sa.delete(repo)
+            self.__delete_repo(repo)
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def delete_perm_user(self, form_data, repo_name):
+        try:
+            self.sa.query(RepoToPerm)\
+                .filter(RepoToPerm.repository \
+                        == self.get_by_repo_name(repo_name))\
+                .filter(RepoToPerm.user_id == form_data['user_id']).delete()
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def delete_stats(self, repo_name):
+        try:
+            self.sa.query(Statistics)\
+                .filter(Statistics.repository == \
+                        self.get_by_repo_name(repo_name)).delete()
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+
+    def __create_repo(self, repo_name, alias):
+        """
+        makes repository on filesystem
+        :param repo_name:
+        :param alias:
+        """
+        from rhodecode.lib.utils import check_repo
+        repo_path = os.path.join(g.base_path, repo_name)
+        if check_repo(repo_name, g.base_path):
+            log.info('creating repo %s in %s', repo_name, repo_path)
+            backend = get_backend(alias)
+            backend(repo_path, create=True)
+
+    def __rename_repo(self, old, new):
+        """
+        renames repository on filesystem
+        :param old: old name
+        :param new: new name
+        """
+        log.info('renaming repo from %s to %s', old, new)
+
+        old_path = os.path.join(g.base_path, old)
+        new_path = os.path.join(g.base_path, new)
+        if os.path.isdir(new_path):
+            raise Exception('Was trying to rename to already existing dir %s',
+                            new_path)
+        shutil.move(old_path, new_path)
+
+    def __delete_repo(self, repo):
+        """
+        removes repo from filesystem, the removal is acctually made by
+        added rm__ prefix into dir, and rename internat .hg/.git dirs so this
+        repository is no longer valid for rhodecode, can be undeleted later on
+        by reverting the renames on this repository
+        :param repo: repo object
+        """
+        rm_path = os.path.join(g.base_path, repo.repo_name)
+        log.info("Removing %s", rm_path)
+        #disable hg/git
+        alias = repo.repo_type
+        shutil.move(os.path.join(rm_path, '.%s' % alias),
+                    os.path.join(rm_path, 'rm__.%s' % alias))
+        #disable repo
+        shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
+                                          % (datetime.today(), repo.repo_name)))
--- a/rhodecode/model/repo_model.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,205 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# model for handling repositories actions
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; version 2
-# of the License or (at your opinion) any later version of the license.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA  02110-1301, USA.
-"""
-Created on Jun 5, 2010
-model for handling repositories actions
-@author: marcink
-"""
-from datetime import datetime
-from pylons import app_globals as g
-from rhodecode.lib.utils import check_repo
-from rhodecode.model.db import Repository, RepoToPerm, User, Permission
-from rhodecode.model.meta import Session
-from rhodecode.model.user_model import UserModel
-from rhodecode.lib.celerylib.tasks import create_repo_fork, run_task
-import logging
-import os
-import shutil
-import traceback
-log = logging.getLogger(__name__)
-
-class RepoModel(object):
-    
-    def __init__(self, sa=None):
-        if not sa:
-            self.sa = Session()
-        else:
-            self.sa = sa
-    
-    def get(self, id):
-        return self.sa.query(Repository)\
-            .filter(Repository.repo_name == id).scalar()
-        
-    def get_users_js(self):
-        
-        users = self.sa.query(User).filter(User.active == True).all()
-        u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
-        users_array = '[%s];' % '\n'.join([u_tmpl % (u.user_id, u.name,
-                                                    u.lastname, u.username) 
-                                        for u in users])
-        return users_array        
-        
-    
-    def update(self, repo_name, form_data):
-        try:
-
-            #update permissions
-            for username, perm in form_data['perms_updates']:
-                r2p = self.sa.query(RepoToPerm)\
-                        .filter(RepoToPerm.user == self.sa.query(User)\
-                                .filter(User.username == username).one())\
-                        .filter(RepoToPerm.repository == self.get(repo_name))\
-                        .one()
-                
-                r2p.permission_id = self.sa.query(Permission).filter(
-                                                Permission.permission_name == 
-                                                perm).one().permission_id
-                self.sa.add(r2p)
-            
-            #set new permissions
-            for username, perm in form_data['perms_new']:
-                r2p = RepoToPerm()
-                r2p.repository = self.get(repo_name)
-                r2p.user = self.sa.query(User)\
-                                .filter(User.username == username).one()
-                
-                r2p.permission_id = self.sa.query(Permission).filter(
-                                        Permission.permission_name == perm)\
-                                        .one().permission_id
-                self.sa.add(r2p)
-            
-            #update current repo
-            cur_repo = self.get(repo_name)
-             
-            for k, v in form_data.items():
-                if k == 'user':
-                    cur_repo.user_id = v
-                else:
-                    setattr(cur_repo, k, v)
-                                                        
-            self.sa.add(cur_repo)
-            
-            if repo_name != form_data['repo_name']:
-                #rename our data
-                self.__rename_repo(repo_name, form_data['repo_name'])            
-            
-            self.sa.commit()
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise    
-    
-    def create(self, form_data, cur_user, just_db=False, fork=False):
-        try:
-            if fork:
-                repo_name = str(form_data['fork_name'])
-                org_name = str(form_data['repo_name'])
-                
-            else:
-                org_name = repo_name = str(form_data['repo_name'])
-            new_repo = Repository()
-            for k, v in form_data.items():
-                if k == 'repo_name':
-                    v = repo_name
-                setattr(new_repo, k, v)
-                
-            if fork:
-                parent_repo = self.sa.query(Repository)\
-                        .filter(Repository.repo_name == org_name).scalar()
-                new_repo.fork = parent_repo
-                            
-            new_repo.user_id = cur_user.user_id
-            self.sa.add(new_repo)
-            
-            #create default permission
-            repo_to_perm = RepoToPerm()
-            default = 'repository.read'
-            for p in UserModel(self.sa).get_default().user_perms:
-                if p.permission.permission_name.startswith('repository.'):
-                    default = p.permission.permission_name
-                    break
-            
-            default_perm = 'repository.none' if form_data['private'] else default
-            
-            repo_to_perm.permission_id = self.sa.query(Permission)\
-                    .filter(Permission.permission_name == default_perm)\
-                    .one().permission_id
-                        
-            repo_to_perm.repository_id = new_repo.repo_id
-            repo_to_perm.user_id = self.sa.query(User)\
-                    .filter(User.username == 'default').one().user_id 
-            
-            self.sa.add(repo_to_perm)
-            self.sa.commit()
-            if not just_db:
-                self.__create_repo(repo_name)
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise    
-    
-    def create_fork(self, form_data, cur_user):
-        run_task(create_repo_fork, form_data, cur_user)
-                         
-    def delete(self, repo):
-        try:
-            self.sa.delete(repo)
-            self.sa.commit()
-            self.__delete_repo(repo.repo_name)
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise
-        
-    def delete_perm_user(self, form_data, repo_name):
-        try:
-            self.sa.query(RepoToPerm)\
-                .filter(RepoToPerm.repository == self.get(repo_name))\
-                .filter(RepoToPerm.user_id == form_data['user_id']).delete()
-            self.sa.commit()
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise
-           
-    def __create_repo(self, repo_name):        
-        repo_path = os.path.join(g.base_path, repo_name)
-        if check_repo(repo_name, g.base_path):
-            log.info('creating repo %s in %s', repo_name, repo_path)
-            from vcs.backends.hg import MercurialRepository
-            MercurialRepository(repo_path, create=True)
-
-    def __rename_repo(self, old, new):
-        log.info('renaming repo from %s to %s', old, new)
-        
-        old_path = os.path.join(g.base_path, old)
-        new_path = os.path.join(g.base_path, new)
-        if os.path.isdir(new_path):
-            raise Exception('Was trying to rename to already existing dir %s',
-                            new_path)        
-        shutil.move(old_path, new_path)
-    
-    def __delete_repo(self, name):
-        rm_path = os.path.join(g.base_path, name)
-        log.info("Removing %s", rm_path)
-        #disable hg 
-        shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
-        #disable repo
-        shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
-                                          % (datetime.today(), name)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/scm.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,377 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.scm
+    ~~~~~~~~~~~~~~~~~~~
+
+    Scm model for RhodeCode
+
+    :created_on: Apr 9, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+import os
+import time
+import traceback
+import logging
+
+from vcs import get_backend
+from vcs.utils.helpers import get_scm
+from vcs.exceptions import RepositoryError, VCSError
+from vcs.utils.lazy import LazyProperty
+
+from mercurial import ui
+
+from beaker.cache import cache_region, region_invalidate
+
+from rhodecode import BACKENDS
+from rhodecode.lib import helpers as h
+from rhodecode.lib.auth import HasRepoPermissionAny
+from rhodecode.lib.utils import get_repos, make_ui, action_logger
+from rhodecode.model import BaseModel
+from rhodecode.model.user import UserModel
+
+from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
+    UserFollowing, UserLog
+from rhodecode.model.caching_query import FromCache
+
+from sqlalchemy.orm import joinedload
+from sqlalchemy.orm.session import make_transient
+from sqlalchemy.exc import DatabaseError
+
+log = logging.getLogger(__name__)
+
+
+class UserTemp(object):
+    def __init__(self, user_id):
+        self.user_id = user_id
+class RepoTemp(object):
+    def __init__(self, repo_id):
+        self.repo_id = repo_id
+
+class ScmModel(BaseModel):
+    """Generic Scm Model
+    """
+
+    @LazyProperty
+    def repos_path(self):
+        """Get's the repositories root path from database
+        """
+
+        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
+
+        return q.ui_value
+
+    def repo_scan(self, repos_path, baseui):
+        """Listing of repositories in given path. This path should not be a 
+        repository itself. Return a dictionary of repository objects
+        
+        :param repos_path: path to directory containing repositories
+        :param baseui: baseui instance to instantiate MercurialRepostitory with
+        """
+
+        log.info('scanning for repositories in %s', repos_path)
+
+        if not isinstance(baseui, ui.ui):
+            baseui = make_ui('db')
+        repos_list = {}
+
+        for name, path in get_repos(repos_path):
+            try:
+                if repos_list.has_key(name):
+                    raise RepositoryError('Duplicate repository name %s '
+                                    'found in %s' % (name, path))
+                else:
+
+                    klass = get_backend(path[0])
+
+                    if path[0] == 'hg' and path[0] in BACKENDS.keys():
+                        repos_list[name] = klass(path[1], baseui=baseui)
+
+                    if path[0] == 'git' and path[0] in BACKENDS.keys():
+                        repos_list[name] = klass(path[1])
+            except OSError:
+                continue
+
+        return repos_list
+
+    def get_repos(self, all_repos=None):
+        """Get all repos from db and for each repo create it's backend instance.
+        and fill that backed with information from database
+        
+        :param all_repos: give specific repositories list, good for filtering
+        """
+
+        if all_repos is None:
+            all_repos = self.sa.query(Repository)\
+                .order_by(Repository.repo_name).all()
+
+        #get the repositories that should be invalidated
+        invalidation_list = [str(x.cache_key) for x in \
+                             self.sa.query(CacheInvalidation.cache_key)\
+                             .filter(CacheInvalidation.cache_active == False)\
+                             .all()]
+
+        for r in all_repos:
+
+            repo = self.get(r.repo_name, invalidation_list)
+
+            if repo is not None:
+                last_change = repo.last_change
+                tip = h.get_changeset_safe(repo, 'tip')
+
+                tmp_d = {}
+                tmp_d['name'] = repo.name
+                tmp_d['name_sort'] = tmp_d['name'].lower()
+                tmp_d['description'] = repo.dbrepo.description
+                tmp_d['description_sort'] = tmp_d['description']
+                tmp_d['last_change'] = last_change
+                tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
+                tmp_d['tip'] = tip.raw_id
+                tmp_d['tip_sort'] = tip.revision
+                tmp_d['rev'] = tip.revision
+                tmp_d['contact'] = repo.dbrepo.user.full_contact
+                tmp_d['contact_sort'] = tmp_d['contact']
+                tmp_d['repo_archives'] = list(repo._get_archives())
+                tmp_d['last_msg'] = tip.message
+                tmp_d['repo'] = repo
+                yield tmp_d
+
+    def get_repo(self, repo_name):
+        return self.get(repo_name)
+
+    def get(self, repo_name, invalidation_list=None):
+        """Get's repository from given name, creates BackendInstance and
+        propagates it's data from database with all additional information
+        
+        :param repo_name:
+        :param invalidation_list: if a invalidation list is given the get
+            method should not manually check if this repository needs 
+            invalidation and just invalidate the repositories in list
+            
+        """
+        if not HasRepoPermissionAny('repository.read', 'repository.write',
+                            'repository.admin')(repo_name, 'get repo check'):
+            return
+
+        #======================================================================
+        # CACHE FUNCTION
+        #======================================================================
+        @cache_region('long_term')
+        def _get_repo(repo_name):
+
+            repo_path = os.path.join(self.repos_path, repo_name)
+
+            try:
+                alias = get_scm(repo_path)[0]
+
+                log.debug('Creating instance of %s repository', alias)
+                backend = get_backend(alias)
+            except VCSError:
+                log.error(traceback.format_exc())
+                return
+
+            if alias == 'hg':
+                from pylons import app_globals as g
+                repo = backend(repo_path, create=False, baseui=g.baseui)
+                #skip hidden web repository
+                if repo._get_hidden():
+                    return
+            else:
+                repo = backend(repo_path, create=False)
+
+            dbrepo = self.sa.query(Repository)\
+                .options(joinedload(Repository.fork))\
+                .options(joinedload(Repository.user))\
+                .filter(Repository.repo_name == repo_name)\
+                .scalar()
+
+            make_transient(dbrepo)
+            if dbrepo.user:
+                make_transient(dbrepo.user)
+            if dbrepo.fork:
+                make_transient(dbrepo.fork)
+
+            repo.dbrepo = dbrepo
+            return repo
+
+        pre_invalidate = True
+        if invalidation_list is not None:
+            pre_invalidate = repo_name in invalidation_list
+
+        if pre_invalidate:
+            invalidate = self._should_invalidate(repo_name)
+
+            if invalidate:
+                log.info('invalidating cache for repository %s', repo_name)
+                region_invalidate(_get_repo, None, repo_name)
+                self._mark_invalidated(invalidate)
+
+        return _get_repo(repo_name)
+
+
+
+    def mark_for_invalidation(self, repo_name):
+        """Puts cache invalidation task into db for 
+        further global cache invalidation
+        
+        :param repo_name: this repo that should invalidation take place
+        """
+
+        log.debug('marking %s for invalidation', repo_name)
+        cache = self.sa.query(CacheInvalidation)\
+            .filter(CacheInvalidation.cache_key == repo_name).scalar()
+
+        if cache:
+            #mark this cache as inactive
+            cache.cache_active = False
+        else:
+            log.debug('cache key not found in invalidation db -> creating one')
+            cache = CacheInvalidation(repo_name)
+
+        try:
+            self.sa.add(cache)
+            self.sa.commit()
+        except (DatabaseError,):
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+
+
+    def toggle_following_repo(self, follow_repo_id, user_id):
+
+        f = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.follows_repo_id == follow_repo_id)\
+            .filter(UserFollowing.user_id == user_id).scalar()
+
+        if f is not None:
+
+            try:
+                self.sa.delete(f)
+                self.sa.commit()
+                action_logger(UserTemp(user_id),
+                              'stopped_following_repo',
+                              RepoTemp(follow_repo_id))
+                return
+            except:
+                log.error(traceback.format_exc())
+                self.sa.rollback()
+                raise
+
+
+        try:
+            f = UserFollowing()
+            f.user_id = user_id
+            f.follows_repo_id = follow_repo_id
+            self.sa.add(f)
+            self.sa.commit()
+            action_logger(UserTemp(user_id),
+                          'started_following_repo',
+                          RepoTemp(follow_repo_id))
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def toggle_following_user(self, follow_user_id , user_id):
+        f = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.follows_user_id == follow_user_id)\
+            .filter(UserFollowing.user_id == user_id).scalar()
+
+        if f is not None:
+            try:
+                self.sa.delete(f)
+                self.sa.commit()
+                return
+            except:
+                log.error(traceback.format_exc())
+                self.sa.rollback()
+                raise
+
+        try:
+            f = UserFollowing()
+            f.user_id = user_id
+            f.follows_user_id = follow_user_id
+            self.sa.add(f)
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def is_following_repo(self, repo_name, user_id):
+        r = self.sa.query(Repository)\
+            .filter(Repository.repo_name == repo_name).scalar()
+
+        f = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.follows_repository == r)\
+            .filter(UserFollowing.user_id == user_id).scalar()
+
+        return f is not None
+
+    def is_following_user(self, username, user_id):
+        u = UserModel(self.sa).get_by_username(username)
+
+        f = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.follows_user == u)\
+            .filter(UserFollowing.user_id == user_id).scalar()
+
+        return f is not None
+
+    def get_followers(self, repo_id):
+        return self.sa.query(UserFollowing)\
+                .filter(UserFollowing.follows_repo_id == repo_id).count()
+
+    def get_forks(self, repo_id):
+        return self.sa.query(Repository)\
+                .filter(Repository.fork_id == repo_id).count()
+
+
+    def get_unread_journal(self):
+        return self.sa.query(UserLog).count()
+
+
+    def _should_invalidate(self, repo_name):
+        """Looks up database for invalidation signals for this repo_name
+        
+        :param repo_name:
+        """
+
+        ret = self.sa.query(CacheInvalidation)\
+            .options(FromCache('sql_cache_short',
+                           'get_invalidation_%s' % repo_name))\
+            .filter(CacheInvalidation.cache_key == repo_name)\
+            .filter(CacheInvalidation.cache_active == False)\
+            .scalar()
+
+        return ret
+
+    def _mark_invalidated(self, cache_key):
+        """ Marks all occurences of cache to invaldation as already invalidated
+        
+        :param cache_key:
+        """
+
+        if cache_key:
+            log.debug('marking %s as already invalidated', cache_key)
+        try:
+            cache_key.cache_active = True
+            self.sa.add(cache_key)
+            self.sa.commit()
+        except (DatabaseError,):
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/settings.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Model for RhodeCode settings
+# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+# 
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+"""
+Created on Nov 17, 2010
+Model for RhodeCode
+:author: marcink
+"""
+
+from rhodecode.lib import helpers as h
+from rhodecode.model import BaseModel
+from rhodecode.model.caching_query import FromCache
+from rhodecode.model.db import  RhodeCodeSettings
+from sqlalchemy.orm import joinedload
+import logging
+
+log = logging.getLogger(__name__)
+
+class SettingsModel(BaseModel):
+    """
+    Settings model
+    """
+
+    def get(self, settings_key, cache=False):
+        r = self.sa.query(RhodeCodeSettings)\
+            .filter(RhodeCodeSettings.app_settings_name == settings_key).scalar()
+        if cache:
+            r = r.options(FromCache("sql_cache_short",
+                                          "get_setting_%s" % settings_key))
+        return r
+
+    def get_app_settings(self):
+        ret = self.sa.query(RhodeCodeSettings)\
+            .options(FromCache("sql_cache_short",
+                           "get_hg_settings")).all()
+
+        if not ret:
+            raise Exception('Could not get application settings !')
+        settings = {}
+        for each in ret:
+            settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
+
+        return settings
+
+    def get_ldap_settings(self):
+        """
+        Returns ldap settings from database
+        :returns:
+        ldap_active
+        ldap_host
+        ldap_port 
+        ldap_ldaps
+        ldap_dn_user 
+        ldap_dn_pass 
+        ldap_base_dn
+        """
+
+        r = self.sa.query(RhodeCodeSettings)\
+                .filter(RhodeCodeSettings.app_settings_name\
+                        .startswith('ldap_'))\
+                .all()
+
+        fd = {}
+
+        for row in r:
+            v = row.app_settings_value
+            if v in ['0', '1']:
+                v = v == '1'
+            fd.update({row.app_settings_name:v})
+
+        return fd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/user.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,223 @@
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.model.user
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    users model for RhodeCode
+    
+    :created_on: Apr 9, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+
+import logging
+import traceback
+
+from pylons.i18n.translation import _
+
+from rhodecode.model import BaseModel
+from rhodecode.model.caching_query import FromCache
+from rhodecode.model.db import User
+
+from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
+
+from sqlalchemy.exc import DatabaseError
+
+log = logging.getLogger(__name__)
+
+class UserModel(BaseModel):
+
+    def get(self, user_id, cache=False):
+        user = self.sa.query(User)
+        if cache:
+            user = user.options(FromCache("sql_cache_short",
+                                          "get_user_%s" % user_id))
+        return user.get(user_id)
+
+
+    def get_by_username(self, username, cache=False, case_insensitive=False):
+
+        if case_insensitive:
+            user = self.sa.query(User).filter(User.username.ilike(username))
+        else:
+            user = self.sa.query(User)\
+                .filter(User.username == username)
+        if cache:
+            user = user.options(FromCache("sql_cache_short",
+                                          "get_user_%s" % username))
+        return user.scalar()
+
+    def create(self, form_data):
+        try:
+            new_user = User()
+            for k, v in form_data.items():
+                setattr(new_user, k, v)
+
+            self.sa.add(new_user)
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def create_ldap(self, username, password):
+        """
+        Checks if user is in database, if not creates this user marked
+        as ldap user
+        :param username:
+        :param password:
+        """
+        from rhodecode.lib.auth import get_crypt_password
+        log.debug('Checking for such ldap account in RhodeCode database')
+        if self.get_by_username(username, case_insensitive=True) is None:
+            try:
+                new_user = User()
+                new_user.username = username.lower()#add ldap account always lowercase
+                new_user.password = get_crypt_password(password)
+                new_user.email = '%s@ldap.server' % username
+                new_user.active = True
+                new_user.is_ldap = True
+                new_user.name = '%s@ldap' % username
+                new_user.lastname = ''
+
+
+                self.sa.add(new_user)
+                self.sa.commit()
+                return True
+            except (DatabaseError,):
+                log.error(traceback.format_exc())
+                self.sa.rollback()
+                raise
+        log.debug('this %s user exists skipping creation of ldap account',
+                  username)
+        return False
+
+    def create_registration(self, form_data):
+        from rhodecode.lib.celerylib import tasks, run_task
+        try:
+            new_user = User()
+            for k, v in form_data.items():
+                if k != 'admin':
+                    setattr(new_user, k, v)
+
+            self.sa.add(new_user)
+            self.sa.commit()
+            body = ('New user registration\n'
+                    'username: %s\n'
+                    'email: %s\n')
+            body = body % (form_data['username'], form_data['email'])
+
+            run_task(tasks.send_email, None,
+                     _('[RhodeCode] New User registration'),
+                     body)
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def update(self, user_id, form_data):
+        try:
+            new_user = self.get(user_id, cache=False)
+            if new_user.username == 'default':
+                raise DefaultUserException(
+                                _("You can't Edit this user since it's"
+                                  " crucial for entire application"))
+
+            for k, v in form_data.items():
+                if k == 'new_password' and v != '':
+                    new_user.password = v
+                else:
+                    setattr(new_user, k, v)
+
+            self.sa.add(new_user)
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def update_my_account(self, user_id, form_data):
+        try:
+            new_user = self.get(user_id, cache=False)
+            if new_user.username == 'default':
+                raise DefaultUserException(
+                                _("You can't Edit this user since it's"
+                                  " crucial for entire application"))
+            for k, v in form_data.items():
+                if k == 'new_password' and v != '':
+                    new_user.password = v
+                else:
+                    if k not in ['admin', 'active']:
+                        setattr(new_user, k, v)
+
+            self.sa.add(new_user)
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def delete(self, user_id):
+        try:
+            user = self.get(user_id, cache=False)
+            if user.username == 'default':
+                raise DefaultUserException(
+                                _("You can't remove this user since it's"
+                                  " crucial for entire application"))
+            if user.repositories:
+                raise UserOwnsReposException(_('This user still owns %s '
+                                               'repositories and cannot be '
+                                               'removed. Switch owners or '
+                                               'remove those repositories') \
+                                               % user.repositories)
+            self.sa.delete(user)
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
+
+    def reset_password(self, data):
+        from rhodecode.lib.celerylib import tasks, run_task
+        run_task(tasks.reset_user_password, data['email'])
+
+
+    def fill_data(self, user):
+        """
+        Fills user data with those from database and log out user if not 
+        present in database
+        :param user:
+        """
+
+        if not hasattr(user, 'user_id') or user.user_id is None:
+            raise Exception('passed in user has to have the user_id attribute')
+
+
+        log.debug('filling auth user data')
+        try:
+            dbuser = self.get(user.user_id)
+            user.username = dbuser.username
+            user.is_admin = dbuser.admin
+            user.name = dbuser.name
+            user.lastname = dbuser.lastname
+            user.email = dbuser.email
+        except:
+            log.error(traceback.format_exc())
+            user.is_authenticated = False
+
+        return user
--- a/rhodecode/model/user_model.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-#!/usr/bin/env python
-# encoding: utf-8
-# Model for users
-# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-# 
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; version 2
-# of the License or (at your opinion) any later version of the license.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA  02110-1301, USA.
-
-"""
-Created on April 9, 2010
-Model for users
-@author: marcink
-"""
-from rhodecode.lib import auth
-from pylons.i18n.translation import _
-from rhodecode.lib.celerylib import tasks, run_task
-from rhodecode.model.db import User
-from rhodecode.model.meta import Session
-import traceback
-import logging
-log = logging.getLogger(__name__)
-
-class DefaultUserException(Exception):pass
-
-class UserModel(object):
-
-    def __init__(self, sa=None):
-        if not sa:
-            self.sa = Session()
-        else:
-            self.sa = sa
-    
-    def get_default(self):
-        return self.sa.query(User).filter(User.username == 'default').scalar()
-    
-    def get_user(self, id):
-        return self.sa.query(User).get(id)
-    
-    def get_user_by_name(self, name):
-        return self.sa.query(User).filter(User.username == name).scalar()
-    
-    def create(self, form_data):
-        try:
-            new_user = User()
-            for k, v in form_data.items():
-                setattr(new_user, k, v)
-                
-            self.sa.add(new_user)
-            self.sa.commit()
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise      
-    
-    def create_registration(self, form_data):
-        try:
-            new_user = User()
-            for k, v in form_data.items():
-                if k != 'admin':
-                    setattr(new_user, k, v)
-                
-            self.sa.add(new_user)
-            self.sa.commit()
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise      
-    
-    def update(self, uid, form_data):
-        try:
-            new_user = self.sa.query(User).get(uid)
-            if new_user.username == 'default':
-                raise DefaultUserException(
-                                _("You can't Edit this user since it's" 
-                                  " crucial for entire application"))
-            for k, v in form_data.items():
-                if k == 'new_password' and v != '':
-                    new_user.password = v
-                else:
-                    setattr(new_user, k, v)
-                
-            self.sa.add(new_user)
-            self.sa.commit()
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise      
-        
-    def update_my_account(self, uid, form_data):
-        try:
-            new_user = self.sa.query(User).get(uid)
-            if new_user.username == 'default':
-                raise DefaultUserException(
-                                _("You can't Edit this user since it's" 
-                                  " crucial for entire application"))
-            for k, v in form_data.items():
-                if k == 'new_password' and v != '':
-                    new_user.password = v
-                else:
-                    if k not in ['admin', 'active']:
-                        setattr(new_user, k, v)
-                
-            self.sa.add(new_user)
-            self.sa.commit()
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise 
-                
-    def delete(self, id):
-        try:
-            
-            user = self.sa.query(User).get(id)
-            if user.username == 'default':
-                raise DefaultUserException(
-                                _("You can't remove this user since it's" 
-                                  " crucial for entire application"))
-            self.sa.delete(user)
-            self.sa.commit()            
-        except:
-            log.error(traceback.format_exc())
-            self.sa.rollback()
-            raise        
-
-    def reset_password(self, data):
-        run_task(tasks.reset_user_password, data['email'])
--- a/rhodecode/public/css/diff.css	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/public/css/diff.css	Sat Dec 18 14:45:58 2010 +0100
@@ -62,7 +62,6 @@
 
 .code-difftable .lineno{
 	background:none repeat scroll 0 0 #EEEEEE !important;
-	border-right:1px solid #DDDDDD;
 	padding-left:2px;
 	padding-right:2px;
 	text-align:right;
@@ -70,6 +69,12 @@
 	-moz-user-select:none;
 	-webkit-user-select: none;
 }
+.code-difftable .new {
+	border-right: 1px solid #CCC !important;
+}
+.code-difftable .old {
+    border-right: 1px solid #CCC !important;
+}
 .code-difftable .lineno pre{
 	color:#747474 !important;
 	font:11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
@@ -78,7 +83,8 @@
 	width:20px;
 }
 .code-difftable .lineno a{
-	color:#0000CC !important;
+font-weight: 700;
+cursor: pointer;
 }
 .code-difftable .code td{
 	margin:0;
--- a/rhodecode/public/css/style.css	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/public/css/style.css	Sat Dec 18 14:45:58 2010 +0100
@@ -190,18 +190,32 @@
 padding:0 30px;
 }
 
+
+#header ul#logged-user{
+margin-bottom:5px !important;
+-webkit-border-radius: 0px 0px 8px 8px;
+-khtml-border-radius: 0px 0px 8px 8px; 
+-moz-border-radius: 0px 0px 8px 8px;
+border-radius: 0px 0px 8px 8px;
+height:37px;
+background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
+}
+
 #header ul#logged-user li {
 list-style:none;
 float:left;
-border-left:1px solid #bbb;
-border-right:1px solid #a5a5a5;
-margin:-2px 0 0;
-padding:10px 12px;
+margin:8px 0 0;
+padding:4px 12px;
+border-left: 1px solid #316293;
 }
 
 #header ul#logged-user li.first {
 border-left:none;
-margin:-6px;
+margin:4px;
+}
+
+#header ul#logged-user li.first div.gravatar {
+margin-top:-2px;
 }
 
 #header ul#logged-user li.first div.account {
@@ -214,13 +228,12 @@
 }
 
 #header ul#logged-user li a {
-color:#4e4e4e;
+color:#fff;
 font-weight:700;
 text-decoration:none;
 }
 
 #header ul#logged-user li a:hover {
-color:#376ea6;
 text-decoration:underline;
 }
 
@@ -229,7 +242,7 @@
 }
 
 #header ul#logged-user li.highlight a:hover {
-color:#376ea6;
+color:#FFF;
 }
 
 #header #header-inner {
@@ -258,9 +271,8 @@
 
 #header #header-inner #logo h1 {
 color:#FFF;
-font-size:14px;
-text-transform:uppercase;
-margin:13px 0 0 13px;
+font-size:18px;
+margin:10px 0 0 13px;
 padding:0;
 }
 
@@ -303,6 +315,10 @@
 padding:0;
 }
 
+#header #header-inner #quick li span.short {
+padding:9px 6px 8px 6px;
+}
+
 #header #header-inner #quick li span {
 top:0;
 right:0;
@@ -329,6 +345,15 @@
 padding:8px 8px 4px;
 }
 
+#header #header-inner #quick li span.icon_short {
+top:0;
+left:0;
+border-left:none;
+background:url("../../images/quick_l.png") no-repeat top left;
+border-right:1px solid #2e5c89;
+padding:9px 4px 4px;
+}
+
 #header #header-inner #quick li a:hover {
 background:#4e4e4e url("../../images/quick_l_selected.png") no-repeat top left;
 }
@@ -338,12 +363,13 @@
 background:url("../../images/quick_r_selected.png") no-repeat top right;
 }
 
-#header #header-inner #quick li a:hover span.icon {
+#header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short {
 border-left:none;
 border-right:1px solid #464646;
 background:url("../../images/quick_l_selected.png") no-repeat top left;
 }
 
+
 #header #header-inner #quick ul {
 top:29px;
 right:0;
@@ -364,6 +390,12 @@
 overflow-y:auto;
 }
 
+#header #header-inner #quick .repo_switcher_type{
+position:absolute;
+left:0;
+top:9px; 
+
+}
 #header #header-inner #quick li ul li {
 border-bottom:1px solid #ddd;
 }
@@ -394,7 +426,7 @@
 max-height:275px;
 overflow:auto;
 overflow-x:hidden;
-white-space:nowrap;
+white-space:normal;
 }
 
 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
@@ -418,6 +450,20 @@
 padding:12px 9px 7px 24px;
 }
 
+#header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover {
+background:url("../images/icons/hgicon.png") no-repeat scroll 4px 9px #FFF;
+min-width:167px;
+margin:0 0 0 14px;
+padding:12px 9px 7px 24px;
+}
+
+#header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover {
+background:url("../images/icons/giticon.png") no-repeat scroll 4px 9px #FFF;
+min-width:167px;
+margin:0 0 0 14px;
+padding:12px 9px 7px 24px;
+}
+
 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
 width:167px;
@@ -446,6 +492,13 @@
 padding:12px 9px 7px 24px;
 }
 
+#header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover {
+background:#FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
+width:167px;
+margin:0;
+padding:12px 9px 7px 24px;
+}
+
 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
 width:167px;
@@ -787,7 +840,7 @@
 }
 
 #content div.box div.form div.fields div.field div.label-select {
-padding:2px 0 0 5px;
+padding:5px 0 0 5px;
 }
 
 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
@@ -806,16 +859,8 @@
 #content div.box div.form div.fields div.field div.input {
 margin:0 0 0 200px;
 }
-
 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
-clear:both;
-overflow:hidden;
-border-top:1px solid #b3b3b3;
-border-left:1px solid #b3b3b3;
-border-right:1px solid #eaeaea;
-border-bottom:1px solid #eaeaea;
-margin:0;
-padding:7px 7px 6px;
+margin:0 0 0 0px;
 }
 
 #content div.box div.form div.fields div.field div.input input {
@@ -831,11 +876,7 @@
 padding:7px 7px 6px;
 }
 
-#content div.box-left div.form div.fields div.field div.input input,#content div.box-right div.form div.fields div.field div.input input {
-width:100%;
-border:none;
-padding:0;
-}
+
 
 #content div.box div.form div.fields div.field div.input input.small {
 width:30%;
@@ -1320,7 +1361,6 @@
 }
 
 #register div.title {
-width:420px;
 clear:both;
 overflow:hidden;
 position:relative;
@@ -1330,7 +1370,6 @@
 }
 
 #register div.inner {
-width:380px;
 background:#FFF;
 border-top:none;
 border-bottom:none;
@@ -1339,7 +1378,7 @@
 }
 
 #register div.form div.fields div.field div.label {
-width:100px;
+width:135px;
 float:left;
 text-align:right;
 margin:2px 10px 0 0;
@@ -1347,7 +1386,7 @@
 }
 
 #register div.form div.fields div.field div.input input {
-width:245px;
+width:300px;
 background:#FFF;
 border-top:1px solid #b3b3b3;
 border-left:1px solid #b3b3b3;
@@ -1366,7 +1405,7 @@
 border-top:1px solid #DDD;
 text-align:left;
 margin:0;
-padding:10px 0 0 114px;
+padding:10px 0 0 150px;
 }
 
 #register div.form div.fields div.buttons div.highlight input.ui-state-default {
@@ -1525,6 +1564,7 @@
 float:right;
 text-align:center;
 min-width:15px;
+cursor: help;
 }
 
 .right .changes .added {
@@ -1618,6 +1658,17 @@
 padding-left:20px;
 text-align:left;
 }
+.diffblock .changeset_file{
+background:url("../images/icons/file.png") no-repeat scroll 3px;
+height:16px;
+padding-left:22px;
+text-align:left;
+font-size: 14px;
+}
+
+.diffblock .changeset_header{
+margin-left: 6px !important;
+}
 
 table.code-browser .browser-dir {
 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
@@ -1771,6 +1822,36 @@
 color:#FFF;
 }
 
+.follow{
+background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
+height: 16px;
+width: 20px;
+cursor: pointer;
+display: block;
+float: right;
+margin-top: 2px;
+}
+
+.following{
+background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
+height: 16px;
+width: 20px;
+cursor: pointer;
+display: block;
+float: right;
+margin-top: 2px;
+}
+
+.currently_following{
+padding-left: 10px;
+padding-bottom:5px;
+}
+
+.journal_highlight{
+font-weight: bold;
+text-decoration: underline;
+}
+
 .add_icon {
 background:url("../images/icons/add.png") no-repeat scroll 3px;
 height:16px;
@@ -1795,6 +1876,14 @@
 text-align:left;
 }
 
+.refresh_icon {
+background:url("../images/icons/arrow_refresh.png") no-repeat scroll 3px;
+height:16px;
+padding-left:20px;
+padding-top:1px;
+text-align:left;
+}
+
 .rss_icon {
 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
 height:16px;
@@ -1944,7 +2033,7 @@
 }
 
 #header,#content,#footer {
-min-width:1224px;
+min-width:1024px;
 }
 
 #content {
@@ -2047,10 +2136,6 @@
 padding:0;
 }
 
-#content div.box div.form div.fields div.field div.label-checkbox,#content div.box div.form div.fields div.field div.label-radio,#content div.box div.form div.fields div.field div.label-textarea {
-padding:0 0 0 5px !important;
-}
-
 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span {
 height:1%;
 display:block;
@@ -2079,11 +2164,17 @@
 margin:0;
 }
 
+#content div.box-left div.form div.fields div.field div.select,#content div.box-left div.form div.fields div.field div.checkboxes,#content div.box-left div.form div.fields div.field div.radios,#content div.box-right div.form div.fields div.field div.select,#content div.box-right div.form div.fields div.field div.checkboxes,#content div.box-right div.form div.fields div.field div.radios{
+margin:0 0 0 0px !important;
+padding:0;
+}
+
 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios {
 margin:0 0 0 200px;
 padding:0;
 }
 
+
 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover {
 color:#000;
 text-decoration:none;
@@ -2097,7 +2188,7 @@
 clear:both;
 overflow:hidden;
 margin:0;
-padding:2px 0;
+padding:8px 0 2px;
 }
 
 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input {
@@ -2109,7 +2200,7 @@
 height:1%;
 display:block;
 float:left;
-margin:3px 0 0 4px;
+margin:2px 0 0 4px;
 }
 
 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
@@ -2218,7 +2309,7 @@
 }
 
 #login,#register {
-width:420px;
+width:520px;
 margin:10% auto 0;
 padding:0;
 }
@@ -2259,6 +2350,7 @@
 color:red;
 margin:8px 0 0;
 padding:0;
+max-width: 320px;
 }
 
 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
@@ -2310,4 +2402,13 @@
 border:none !important;
 height:20px !important;
 padding:0 !important;
-}
\ No newline at end of file
+}
+
+#q_filter{
+border:0 none;
+color:#AAAAAA;
+margin-bottom:-4px;
+margin-top:-4px;
+padding-left:3px;
+}
+
Binary file rhodecode/public/images/hgicon.png has changed
Binary file rhodecode/public/images/icons/giticon.png has changed
Binary file rhodecode/public/images/icons/lock_open.png has changed
Binary file rhodecode/public/images/icons/success.png has changed
Binary file rhodecode/public/images/icons/warning.png has changed
Binary file rhodecode/public/images/title_tab_selected.png has changed
--- a/rhodecode/public/js/yui2.js	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
-Copyright (c) 2010, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.8.1
-*/
-if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C<A.length;C=C+1){D=(""+A[C]).split(".");E=YAHOO;for(B=(D[0]=="YAHOO")?1:0;B<D.length;B=B+1){E[D[B]]=E[D[B]]||{};E=E[D[B]];}}return E;};YAHOO.log=function(D,A,C){var B=YAHOO.widget.Logger;if(B&&B.log){return B.log(D,A,C);}else{return false;}};YAHOO.register=function(A,E,D){var I=YAHOO.env.modules,B,H,G,F,C;if(!I[A]){I[A]={versions:[],builds:[]};}B=I[A];H=D.version;G=D.build;F=YAHOO.env.listeners;B.name=A;B.version=H;B.build=G;B.versions.push(H);B.builds.push(G);B.mainClass=E;for(C=0;C<F.length;C=C+1){F[C](B);}if(E){E.VERSION=H;E.BUILD=G;}else{YAHOO.log("mainClass is undefined for module "+A,"warn");}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(A){return YAHOO.env.modules[A]||null;};YAHOO.env.ua=function(){var D=function(H){var I=0;return parseFloat(H.replace(/\./g,function(){return(I++==1)?"":".";}));},G=navigator,F={ie:0,opera:0,gecko:0,webkit:0,mobile:null,air:0,caja:G.cajaVersion,secure:false,os:null},C=navigator&&navigator.userAgent,E=window&&window.location,B=E&&E.href,A;F.secure=B&&(B.toLowerCase().indexOf("https")===0);if(C){if((/windows|win32/i).test(C)){F.os="windows";}else{if((/macintosh/i).test(C)){F.os="macintosh";}}if((/KHTML/).test(C)){F.webkit=1;}A=C.match(/AppleWebKit\/([^\s]*)/);if(A&&A[1]){F.webkit=D(A[1]);if(/ Mobile\//.test(C)){F.mobile="Apple";}else{A=C.match(/NokiaN[^\/]*/);if(A){F.mobile=A[0];}}A=C.match(/AdobeAIR\/([^\s]*)/);if(A){F.air=A[0];}}if(!F.webkit){A=C.match(/Opera[\s\/]([^\s]*)/);if(A&&A[1]){F.opera=D(A[1]);A=C.match(/Opera Mini[^;]*/);if(A){F.mobile=A[0];}}else{A=C.match(/MSIE\s([^;]*)/);if(A&&A[1]){F.ie=D(A[1]);}else{A=C.match(/Gecko\/([^\s]*)/);if(A){F.gecko=1;A=C.match(/rv:([^\s\)]*)/);if(A&&A[1]){F.gecko=D(A[1]);}}}}}}return F;}();(function(){YAHOO.namespace("util","widget","example");if("undefined"!==typeof YAHOO_config){var B=YAHOO_config.listener,A=YAHOO.env.listeners,D=true,C;if(B){for(C=0;C<A.length;C++){if(A[C]==B){D=false;break;}}if(D){A.push(B);}}}})();YAHOO.lang=YAHOO.lang||{};(function(){var B=YAHOO.lang,A=Object.prototype,H="[object Array]",C="[object Function]",G="[object Object]",E=[],F=["toString","valueOf"],D={isArray:function(I){return A.toString.apply(I)===H;},isBoolean:function(I){return typeof I==="boolean";},isFunction:function(I){return(typeof I==="function")||A.toString.apply(I)===C;},isNull:function(I){return I===null;},isNumber:function(I){return typeof I==="number"&&isFinite(I);},isObject:function(I){return(I&&(typeof I==="object"||B.isFunction(I)))||false;},isString:function(I){return typeof I==="string";},isUndefined:function(I){return typeof I==="undefined";},_IEEnumFix:(YAHOO.env.ua.ie)?function(K,J){var I,M,L;for(I=0;I<F.length;I=I+1){M=F[I];L=J[M];if(B.isFunction(L)&&L!=A[M]){K[M]=L;}}}:function(){},extend:function(L,M,K){if(!M||!L){throw new Error("extend failed, please check that "+"all dependencies are included.");}var J=function(){},I;J.prototype=M.prototype;L.prototype=new J();L.prototype.constructor=L;L.superclass=M.prototype;if(M.prototype.constructor==A.constructor){M.prototype.constructor=M;}if(K){for(I in K){if(B.hasOwnProperty(K,I)){L.prototype[I]=K[I];}}B._IEEnumFix(L.prototype,K);}},augmentObject:function(M,L){if(!L||!M){throw new Error("Absorb failed, verify dependencies.");}var I=arguments,K,N,J=I[2];if(J&&J!==true){for(K=2;K<I.length;K=K+1){M[I[K]]=L[I[K]];}}else{for(N in L){if(J||!(N in M)){M[N]=L[N];}}B._IEEnumFix(M,L);}},augmentProto:function(L,K){if(!K||!L){throw new Error("Augment failed, verify dependencies.");}var I=[L.prototype,K.prototype],J;for(J=2;J<arguments.length;J=J+1){I.push(arguments[J]);}B.augmentObject.apply(this,I);},dump:function(I,N){var K,M,P=[],Q="{...}",J="f(){...}",O=", ",L=" => ";if(!B.isObject(I)){return I+"";}else{if(I instanceof Date||("nodeType" in I&&"tagName" in I)){return I;}else{if(B.isFunction(I)){return J;}}}N=(B.isNumber(N))?N:3;if(B.isArray(I)){P.push("[");for(K=0,M=I.length;K<M;K=K+1){if(B.isObject(I[K])){P.push((N>0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}if(P.length>1){P.pop();}P.push("]");}else{P.push("{");for(K in I){if(B.hasOwnProperty(I,K)){P.push(K+L);if(B.isObject(I[K])){P.push((N>0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}}if(P.length>1){P.pop();}P.push("}");}return P.join("");},substitute:function(Y,J,R){var N,M,L,U,V,X,T=[],K,O="dump",S=" ",I="{",W="}",Q,P;for(;;){N=Y.lastIndexOf(I);if(N<0){break;}M=Y.indexOf(W,N);if(N+1>=M){break;}K=Y.substring(N+1,M);U=K;X=null;L=U.indexOf(S);if(L>-1){X=U.substring(L+1);U=U.substring(0,L);}V=J[U];if(R){V=R(U,V,X);}if(B.isObject(V)){if(B.isArray(V)){V=B.dump(V,parseInt(X,10));}else{X=X||"";Q=X.indexOf(O);if(Q>-1){X=X.substring(4);}P=V.toString();if(P===G||Q>-1){V=B.dump(V,parseInt(X,10));}else{V=P;}}}else{if(!B.isString(V)&&!B.isNumber(V)){V="~-"+T.length+"-~";T[T.length]=K;}}Y=Y.substring(0,N)+V+Y.substring(M+1);}for(N=T.length-1;N>=0;N=N-1){Y=Y.replace(new RegExp("~-"+N+"-~"),"{"+T[N]+"}","g");}return Y;},trim:function(I){try{return I.replace(/^\s+|\s+$/g,"");}catch(J){return I;}},merge:function(){var L={},J=arguments,I=J.length,K;for(K=0;K<I;K=K+1){B.augmentObject(L,J[K],true);}return L;},later:function(P,J,Q,L,M){P=P||0;J=J||{};var K=Q,O=L,N,I;if(B.isString(Q)){K=J[Q];}if(!K){throw new TypeError("method undefined");}if(O&&!B.isArray(O)){O=[L];}N=function(){K.apply(J,O||E);};I=(M)?setInterval(N,P):setTimeout(N,P);return{interval:M,cancel:function(){if(this.interval){clearInterval(I);}else{clearTimeout(I);}}};},isValue:function(I){return(B.isObject(I)||B.isString(I)||B.isNumber(I)||B.isBoolean(I));}};B.hasOwnProperty=(A.hasOwnProperty)?function(I,J){return I&&I.hasOwnProperty(J);}:function(I,J){return !B.isUndefined(I[J])&&I.constructor.prototype[J]!==I[J];};D.augmentObject(B,D,true);YAHOO.util.Lang=B;B.augment=B.augmentProto;YAHOO.augment=B.augmentProto;YAHOO.extend=B.extend;})();YAHOO.register("yahoo",YAHOO,{version:"2.8.1",build:"19"});
-YAHOO.util.Get=function(){var M={},L=0,R=0,E=false,N=YAHOO.env.ua,S=YAHOO.lang;var J=function(W,T,X){var U=X||window,Y=U.document,Z=Y.createElement(W);for(var V in T){if(T[V]&&YAHOO.lang.hasOwnProperty(T,V)){Z.setAttribute(V,T[V]);}}return Z;};var I=function(U,V,T){var W={id:"yui__dyn_"+(R++),type:"text/css",rel:"stylesheet",href:U};if(T){S.augmentObject(W,T);}return J("link",W,V);};var P=function(U,V,T){var W={id:"yui__dyn_"+(R++),type:"text/javascript",src:U};if(T){S.augmentObject(W,T);}return J("script",W,V);};var A=function(T,U){return{tId:T.tId,win:T.win,data:T.data,nodes:T.nodes,msg:U,purge:function(){D(this.tId);}};};var B=function(T,W){var U=M[W],V=(S.isString(T))?U.win.document.getElementById(T):T;if(!V){Q(W,"target node not found: "+T);}return V;};var Q=function(W,V){var T=M[W];if(T.onFailure){var U=T.scope||T.win;T.onFailure.call(U,A(T,V));}};var C=function(W){var T=M[W];T.finished=true;if(T.aborted){var V="transaction "+W+" was aborted";Q(W,V);return;}if(T.onSuccess){var U=T.scope||T.win;T.onSuccess.call(U,A(T));}};var O=function(V){var T=M[V];if(T.onTimeout){var U=T.scope||T;T.onTimeout.call(U,A(T));}};var G=function(V,Z){var U=M[V];if(U.timer){U.timer.cancel();}if(U.aborted){var X="transaction "+V+" was aborted";Q(V,X);return;}if(Z){U.url.shift();if(U.varName){U.varName.shift();}}else{U.url=(S.isString(U.url))?[U.url]:U.url;if(U.varName){U.varName=(S.isString(U.varName))?[U.varName]:U.varName;}}var c=U.win,b=c.document,a=b.getElementsByTagName("head")[0],W;if(U.url.length===0){if(U.type==="script"&&N.webkit&&N.webkit<420&&!U.finalpass&&!U.varName){var Y=P(null,U.win,U.attributes);Y.innerHTML='YAHOO.util.Get._finalize("'+V+'");';U.nodes.push(Y);a.appendChild(Y);}else{C(V);}return;}var T=U.url[0];if(!T){U.url.shift();return G(V);}if(U.timeout){U.timer=S.later(U.timeout,U,O,V);}if(U.type==="script"){W=P(T,c,U.attributes);}else{W=I(T,c,U.attributes);}F(U.type,W,V,T,c,U.url.length);U.nodes.push(W);if(U.insertBefore){var e=B(U.insertBefore,V);if(e){e.parentNode.insertBefore(W,e);}}else{a.appendChild(W);}if((N.webkit||N.gecko)&&U.type==="css"){G(V,T);}};var K=function(){if(E){return;}E=true;for(var T in M){var U=M[T];if(U.autopurge&&U.finished){D(U.tId);delete M[T];}}E=false;};var D=function(Z){if(M[Z]){var T=M[Z],U=T.nodes,X=U.length,c=T.win.document,a=c.getElementsByTagName("head")[0],V,Y,W,b;if(T.insertBefore){V=B(T.insertBefore,Z);if(V){a=V.parentNode;}}for(Y=0;Y<X;Y=Y+1){W=U[Y];if(W.clearAttributes){W.clearAttributes();}else{for(b in W){delete W[b];}}a.removeChild(W);}T.nodes=[];}};var H=function(U,T,V){var X="q"+(L++);V=V||{};if(L%YAHOO.util.Get.PURGE_THRESH===0){K();}M[X]=S.merge(V,{tId:X,type:U,url:T,finished:false,aborted:false,nodes:[]});var W=M[X];W.win=W.win||window;W.scope=W.scope||W.win;W.autopurge=("autopurge" in W)?W.autopurge:(U==="script")?true:false;if(V.charset){W.attributes=W.attributes||{};W.attributes.charset=V.charset;}S.later(0,W,G,X);return{tId:X};};var F=function(c,X,W,U,Y,Z,b){var a=b||G;if(N.ie){X.onreadystatechange=function(){var d=this.readyState;if("loaded"===d||"complete"===d){X.onreadystatechange=null;a(W,U);}};}else{if(N.webkit){if(c==="script"){if(N.webkit>=420){X.addEventListener("load",function(){a(W,U);});}else{var T=M[W];if(T.varName){var V=YAHOO.util.Get.POLL_FREQ;T.maxattempts=YAHOO.util.Get.TIMEOUT/V;T.attempts=0;T._cache=T.varName[0].split(".");T.timer=S.later(V,T,function(j){var f=this._cache,e=f.length,d=this.win,g;for(g=0;g<e;g=g+1){d=d[f[g]];if(!d){this.attempts++;if(this.attempts++>this.maxattempts){var h="Over retry limit, giving up";T.timer.cancel();Q(W,h);}else{}return;}}T.timer.cancel();a(W,U);},null,true);}else{S.later(YAHOO.util.Get.POLL_FREQ,null,a,[W,U]);}}}}else{X.onload=function(){a(W,U);};}}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(T){S.later(0,null,C,T);},abort:function(U){var V=(S.isString(U))?U:U.tId;var T=M[V];if(T){T.aborted=true;}},script:function(T,U){return H("script",T,U);},css:function(T,U){return H("css",T,U);}};}();YAHOO.register("get",YAHOO.util.Get,{version:"2.8.1",build:"19"});(function(){var Y=YAHOO,util=Y.util,lang=Y.lang,env=Y.env,PROV="_provides",SUPER="_supersedes",REQ="expanded",AFTER="_after";var YUI={dupsAllowed:{"yahoo":true,"get":true},info:{"root":"2.8.1/build/","base":"http://yui.yahooapis.com/2.8.1/build/","comboBase":"http://yui.yahooapis.com/combo?","skin":{"defaultSkin":"sam","base":"assets/skins/","path":"skin.css","after":["reset","fonts","grids","base"],"rollup":3},dupsAllowed:["yahoo","get"],"moduleInfo":{"animation":{"type":"js","path":"animation/animation-min.js","requires":["dom","event"]},"autocomplete":{"type":"js","path":"autocomplete/autocomplete-min.js","requires":["dom","event","datasource"],"optional":["connection","animation"],"skinnable":true},"base":{"type":"css","path":"base/base-min.css","after":["reset","fonts","grids"]},"button":{"type":"js","path":"button/button-min.js","requires":["element"],"optional":["menu"],"skinnable":true},"calendar":{"type":"js","path":"calendar/calendar-min.js","requires":["event","dom"],supersedes:["datemeth"],"skinnable":true},"carousel":{"type":"js","path":"carousel/carousel-min.js","requires":["element"],"optional":["animation"],"skinnable":true},"charts":{"type":"js","path":"charts/charts-min.js","requires":["element","json","datasource","swf"]},"colorpicker":{"type":"js","path":"colorpicker/colorpicker-min.js","requires":["slider","element"],"optional":["animation"],"skinnable":true},"connection":{"type":"js","path":"connection/connection-min.js","requires":["event"],"supersedes":["connectioncore"]},"connectioncore":{"type":"js","path":"connection/connection_core-min.js","requires":["event"],"pkg":"connection"},"container":{"type":"js","path":"container/container-min.js","requires":["dom","event"],"optional":["dragdrop","animation","connection"],"supersedes":["containercore"],"skinnable":true},"containercore":{"type":"js","path":"container/container_core-min.js","requires":["dom","event"],"pkg":"container"},"cookie":{"type":"js","path":"cookie/cookie-min.js","requires":["yahoo"]},"datasource":{"type":"js","path":"datasource/datasource-min.js","requires":["event"],"optional":["connection"]},"datatable":{"type":"js","path":"datatable/datatable-min.js","requires":["element","datasource"],"optional":["calendar","dragdrop","paginator"],"skinnable":true},datemath:{"type":"js","path":"datemath/datemath-min.js","requires":["yahoo"]},"dom":{"type":"js","path":"dom/dom-min.js","requires":["yahoo"]},"dragdrop":{"type":"js","path":"dragdrop/dragdrop-min.js","requires":["dom","event"]},"editor":{"type":"js","path":"editor/editor-min.js","requires":["menu","element","button"],"optional":["animation","dragdrop"],"supersedes":["simpleeditor"],"skinnable":true},"element":{"type":"js","path":"element/element-min.js","requires":["dom","event"],"optional":["event-mouseenter","event-delegate"]},"element-delegate":{"type":"js","path":"element-delegate/element-delegate-min.js","requires":["element"]},"event":{"type":"js","path":"event/event-min.js","requires":["yahoo"]},"event-simulate":{"type":"js","path":"event-simulate/event-simulate-min.js","requires":["event"]},"event-delegate":{"type":"js","path":"event-delegate/event-delegate-min.js","requires":["event"],"optional":["selector"]},"event-mouseenter":{"type":"js","path":"event-mouseenter/event-mouseenter-min.js","requires":["dom","event"]},"fonts":{"type":"css","path":"fonts/fonts-min.css"},"get":{"type":"js","path":"get/get-min.js","requires":["yahoo"]},"grids":{"type":"css","path":"grids/grids-min.css","requires":["fonts"],"optional":["reset"]},"history":{"type":"js","path":"history/history-min.js","requires":["event"]},"imagecropper":{"type":"js","path":"imagecropper/imagecropper-min.js","requires":["dragdrop","element","resize"],"skinnable":true},"imageloader":{"type":"js","path":"imageloader/imageloader-min.js","requires":["event","dom"]},"json":{"type":"js","path":"json/json-min.js","requires":["yahoo"]},"layout":{"type":"js","path":"layout/layout-min.js","requires":["element"],"optional":["animation","dragdrop","resize","selector"],"skinnable":true},"logger":{"type":"js","path":"logger/logger-min.js","requires":["event","dom"],"optional":["dragdrop"],"skinnable":true},"menu":{"type":"js","path":"menu/menu-min.js","requires":["containercore"],"skinnable":true},"paginator":{"type":"js","path":"paginator/paginator-min.js","requires":["element"],"skinnable":true},"profiler":{"type":"js","path":"profiler/profiler-min.js","requires":["yahoo"]},"profilerviewer":{"type":"js","path":"profilerviewer/profilerviewer-min.js","requires":["profiler","yuiloader","element"],"skinnable":true},"progressbar":{"type":"js","path":"progressbar/progressbar-min.js","requires":["element"],"optional":["animation"],"skinnable":true},"reset":{"type":"css","path":"reset/reset-min.css"},"reset-fonts-grids":{"type":"css","path":"reset-fonts-grids/reset-fonts-grids.css","supersedes":["reset","fonts","grids","reset-fonts"],"rollup":4},"reset-fonts":{"type":"css","path":"reset-fonts/reset-fonts.css","supersedes":["reset","fonts"],"rollup":2},"resize":{"type":"js","path":"resize/resize-min.js","requires":["dragdrop","element"],"optional":["animation"],"skinnable":true},"selector":{"type":"js","path":"selector/selector-min.js","requires":["yahoo","dom"]},"simpleeditor":{"type":"js","path":"editor/simpleeditor-min.js","requires":["element"],"optional":["containercore","menu","button","animation","dragdrop"],"skinnable":true,"pkg":"editor"},"slider":{"type":"js","path":"slider/slider-min.js","requires":["dragdrop"],"optional":["animation"],"skinnable":true},"storage":{"type":"js","path":"storage/storage-min.js","requires":["yahoo","event","cookie"],"optional":["swfstore"]},"stylesheet":{"type":"js","path":"stylesheet/stylesheet-min.js","requires":["yahoo"]},"swf":{"type":"js","path":"swf/swf-min.js","requires":["element"],"supersedes":["swfdetect"]},"swfdetect":{"type":"js","path":"swfdetect/swfdetect-min.js","requires":["yahoo"]},"swfstore":{"type":"js","path":"swfstore/swfstore-min.js","requires":["element","cookie","swf"]},"tabview":{"type":"js","path":"tabview/tabview-min.js","requires":["element"],"optional":["connection"],"skinnable":true},"treeview":{"type":"js","path":"treeview/treeview-min.js","requires":["event","dom"],"optional":["json","animation","calendar"],"skinnable":true},"uploader":{"type":"js","path":"uploader/uploader-min.js","requires":["element"]},"utilities":{"type":"js","path":"utilities/utilities.js","supersedes":["yahoo","event","dragdrop","animation","dom","connection","element","yahoo-dom-event","get","yuiloader","yuiloader-dom-event"],"rollup":8},"yahoo":{"type":"js","path":"yahoo/yahoo-min.js"},"yahoo-dom-event":{"type":"js","path":"yahoo-dom-event/yahoo-dom-event.js","supersedes":["yahoo","event","dom"],"rollup":3},"yuiloader":{"type":"js","path":"yuiloader/yuiloader-min.js","supersedes":["yahoo","get"]},"yuiloader-dom-event":{"type":"js","path":"yuiloader-dom-event/yuiloader-dom-event.js","supersedes":["yahoo","dom","event","get","yuiloader","yahoo-dom-event"],"rollup":5},"yuitest":{"type":"js","path":"yuitest/yuitest-min.js","requires":["logger"],"optional":["event-simulate"],"skinnable":true}}},ObjectUtil:{appendArray:function(o,a){if(a){for(var i=0;
-i<a.length;i=i+1){o[a[i]]=true;}}},keys:function(o,ordered){var a=[],i;for(i in o){if(lang.hasOwnProperty(o,i)){a.push(i);}}return a;}},ArrayUtil:{appendArray:function(a1,a2){Array.prototype.push.apply(a1,a2);},indexOf:function(a,val){for(var i=0;i<a.length;i=i+1){if(a[i]===val){return i;}}return -1;},toObject:function(a){var o={};for(var i=0;i<a.length;i=i+1){o[a[i]]=true;}return o;},uniq:function(a){return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));}}};YAHOO.util.YUILoader=function(o){this._internalCallback=null;this._useYahooListener=false;this.onSuccess=null;this.onFailure=Y.log;this.onProgress=null;this.onTimeout=null;this.scope=this;this.data=null;this.insertBefore=null;this.charset=null;this.varName=null;this.base=YUI.info.base;this.comboBase=YUI.info.comboBase;this.combine=false;this.root=YUI.info.root;this.timeout=0;this.ignore=null;this.force=null;this.allowRollup=true;this.filter=null;this.required={};this.moduleInfo=lang.merge(YUI.info.moduleInfo);this.rollups=null;this.loadOptional=false;this.sorted=[];this.loaded={};this.dirty=true;this.inserted={};var self=this;env.listeners.push(function(m){if(self._useYahooListener){self.loadNext(m.name);}});this.skin=lang.merge(YUI.info.skin);this._config(o);};Y.util.YUILoader.prototype={FILTERS:{RAW:{"searchExp":"-min\\.js","replaceStr":".js"},DEBUG:{"searchExp":"-min\\.js","replaceStr":"-debug.js"}},SKIN_PREFIX:"skin-",_config:function(o){if(o){for(var i in o){if(lang.hasOwnProperty(o,i)){if(i=="require"){this.require(o[i]);}else{this[i]=o[i];}}}}var f=this.filter;if(lang.isString(f)){f=f.toUpperCase();if(f==="DEBUG"){this.require("logger");}if(!Y.widget.LogWriter){Y.widget.LogWriter=function(){return Y;};}this.filter=this.FILTERS[f];}},addModule:function(o){if(!o||!o.name||!o.type||(!o.path&&!o.fullpath)){return false;}o.ext=("ext" in o)?o.ext:true;o.requires=o.requires||[];this.moduleInfo[o.name]=o;this.dirty=true;return true;},require:function(what){var a=(typeof what==="string")?arguments:what;this.dirty=true;YUI.ObjectUtil.appendArray(this.required,a);},_addSkin:function(skin,mod){var name=this.formatSkin(skin),info=this.moduleInfo,sinf=this.skin,ext=info[mod]&&info[mod].ext;if(!info[name]){this.addModule({"name":name,"type":"css","path":sinf.base+skin+"/"+sinf.path,"after":sinf.after,"rollup":sinf.rollup,"ext":ext});}if(mod){name=this.formatSkin(skin,mod);if(!info[name]){var mdef=info[mod],pkg=mdef.pkg||mod;this.addModule({"name":name,"type":"css","after":sinf.after,"path":pkg+"/"+sinf.base+skin+"/"+mod+".css","ext":ext});}}return name;},getRequires:function(mod){if(!mod){return[];}if(!this.dirty&&mod.expanded){return mod.expanded;}mod.requires=mod.requires||[];var i,d=[],r=mod.requires,o=mod.optional,info=this.moduleInfo,m;for(i=0;i<r.length;i=i+1){d.push(r[i]);m=info[r[i]];YUI.ArrayUtil.appendArray(d,this.getRequires(m));}if(o&&this.loadOptional){for(i=0;i<o.length;i=i+1){d.push(o[i]);YUI.ArrayUtil.appendArray(d,this.getRequires(info[o[i]]));}}mod.expanded=YUI.ArrayUtil.uniq(d);return mod.expanded;},getProvides:function(name,notMe){var addMe=!(notMe),ckey=(addMe)?PROV:SUPER,m=this.moduleInfo[name],o={};if(!m){return o;}if(m[ckey]){return m[ckey];}var s=m.supersedes,done={},me=this;var add=function(mm){if(!done[mm]){done[mm]=true;lang.augmentObject(o,me.getProvides(mm));}};if(s){for(var i=0;i<s.length;i=i+1){add(s[i]);}}m[SUPER]=o;m[PROV]=lang.merge(o);m[PROV][name]=true;return m[ckey];},calculate:function(o){if(o||this.dirty){this._config(o);this._setup();this._explode();if(this.allowRollup){this._rollup();}this._reduce();this._sort();this.dirty=false;}},_setup:function(){var info=this.moduleInfo,name,i,j;for(name in info){if(lang.hasOwnProperty(info,name)){var m=info[name];if(m&&m.skinnable){var o=this.skin.overrides,smod;if(o&&o[name]){for(i=0;i<o[name].length;i=i+1){smod=this._addSkin(o[name][i],name);}}else{smod=this._addSkin(this.skin.defaultSkin,name);}m.requires.push(smod);}}}var l=lang.merge(this.inserted);if(!this._sandbox){l=lang.merge(l,env.modules);}if(this.ignore){YUI.ObjectUtil.appendArray(l,this.ignore);}if(this.force){for(i=0;i<this.force.length;i=i+1){if(this.force[i] in l){delete l[this.force[i]];}}}for(j in l){if(lang.hasOwnProperty(l,j)){lang.augmentObject(l,this.getProvides(j));}}this.loaded=l;},_explode:function(){var r=this.required,i,mod;for(i in r){if(lang.hasOwnProperty(r,i)){mod=this.moduleInfo[i];if(mod){var req=this.getRequires(mod);if(req){YUI.ObjectUtil.appendArray(r,req);}}}}},_skin:function(){},formatSkin:function(skin,mod){var s=this.SKIN_PREFIX+skin;if(mod){s=s+"-"+mod;}return s;},parseSkin:function(mod){if(mod.indexOf(this.SKIN_PREFIX)===0){var a=mod.split("-");return{skin:a[1],module:a[2]};}return null;},_rollup:function(){var i,j,m,s,rollups={},r=this.required,roll,info=this.moduleInfo;if(this.dirty||!this.rollups){for(i in info){if(lang.hasOwnProperty(info,i)){m=info[i];if(m&&m.rollup){rollups[i]=m;}}}this.rollups=rollups;}for(;;){var rolled=false;for(i in rollups){if(!r[i]&&!this.loaded[i]){m=info[i];s=m.supersedes;roll=false;if(!m.rollup){continue;}var skin=(m.ext)?false:this.parseSkin(i),c=0;if(skin){for(j in r){if(lang.hasOwnProperty(r,j)){if(i!==j&&this.parseSkin(j)){c++;roll=(c>=m.rollup);if(roll){break;}}}}}else{for(j=0;j<s.length;j=j+1){if(this.loaded[s[j]]&&(!YUI.dupsAllowed[s[j]])){roll=false;break;}else{if(r[s[j]]){c++;roll=(c>=m.rollup);if(roll){break;}}}}}if(roll){r[i]=true;rolled=true;this.getRequires(m);}}}if(!rolled){break;}}},_reduce:function(){var i,j,s,m,r=this.required;for(i in r){if(i in this.loaded){delete r[i];}else{var skinDef=this.parseSkin(i);if(skinDef){if(!skinDef.module){var skin_pre=this.SKIN_PREFIX+skinDef.skin;for(j in r){if(lang.hasOwnProperty(r,j)){m=this.moduleInfo[j];var ext=m&&m.ext;if(!ext&&j!==i&&j.indexOf(skin_pre)>-1){delete r[j];}}}}}else{m=this.moduleInfo[i];s=m&&m.supersedes;if(s){for(j=0;j<s.length;j=j+1){if(s[j] in r){delete r[s[j]];}}}}}}},_onFailure:function(msg){YAHOO.log("Failure","info","loader");var f=this.onFailure;if(f){f.call(this.scope,{msg:"failure: "+msg,data:this.data,success:false});
-}},_onTimeout:function(){YAHOO.log("Timeout","info","loader");var f=this.onTimeout;if(f){f.call(this.scope,{msg:"timeout",data:this.data,success:false});}},_sort:function(){var s=[],info=this.moduleInfo,loaded=this.loaded,checkOptional=!this.loadOptional,me=this;var requires=function(aa,bb){var mm=info[aa];if(loaded[bb]||!mm){return false;}var ii,rr=mm.expanded,after=mm.after,other=info[bb],optional=mm.optional;if(rr&&YUI.ArrayUtil.indexOf(rr,bb)>-1){return true;}if(after&&YUI.ArrayUtil.indexOf(after,bb)>-1){return true;}if(checkOptional&&optional&&YUI.ArrayUtil.indexOf(optional,bb)>-1){return true;}var ss=info[bb]&&info[bb].supersedes;if(ss){for(ii=0;ii<ss.length;ii=ii+1){if(requires(aa,ss[ii])){return true;}}}if(mm.ext&&mm.type=="css"&&!other.ext&&other.type=="css"){return true;}return false;};for(var i in this.required){if(lang.hasOwnProperty(this.required,i)){s.push(i);}}var p=0;for(;;){var l=s.length,a,b,j,k,moved=false;for(j=p;j<l;j=j+1){a=s[j];for(k=j+1;k<l;k=k+1){if(requires(a,s[k])){b=s.splice(k,1);s.splice(j,0,b[0]);moved=true;break;}}if(moved){break;}else{p=p+1;}}if(!moved){break;}}this.sorted=s;},toString:function(){var o={type:"YUILoader",base:this.base,filter:this.filter,required:this.required,loaded:this.loaded,inserted:this.inserted};lang.dump(o,1);},_combine:function(){this._combining=[];var self=this,s=this.sorted,len=s.length,js=this.comboBase,css=this.comboBase,target,startLen=js.length,i,m,type=this.loadType;YAHOO.log("type "+type);for(i=0;i<len;i=i+1){m=this.moduleInfo[s[i]];if(m&&!m.ext&&(!type||type===m.type)){target=this.root+m.path;target+="&";if(m.type=="js"){js+=target;}else{css+=target;}this._combining.push(s[i]);}}if(this._combining.length){YAHOO.log("Attempting to combine: "+this._combining,"info","loader");var callback=function(o){var c=this._combining,len=c.length,i,m;for(i=0;i<len;i=i+1){this.inserted[c[i]]=true;}this.loadNext(o.data);},loadScript=function(){if(js.length>startLen){YAHOO.util.Get.script(self._filter(js),{data:self._loading,onSuccess:callback,onFailure:self._onFailure,onTimeout:self._onTimeout,insertBefore:self.insertBefore,charset:self.charset,timeout:self.timeout,scope:self});}};if(css.length>startLen){YAHOO.util.Get.css(this._filter(css),{data:this._loading,onSuccess:loadScript,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,scope:self});}else{loadScript();}return;}else{this.loadNext(this._loading);}},insert:function(o,type){this.calculate(o);this._loading=true;this.loadType=type;if(this.combine){return this._combine();}if(!type){var self=this;this._internalCallback=function(){self._internalCallback=null;self.insert(null,"js");};this.insert(null,"css");return;}this.loadNext();},sandbox:function(o,type){this._config(o);if(!this.onSuccess){throw new Error("You must supply an onSuccess handler for your sandbox");}this._sandbox=true;var self=this;if(!type||type!=="js"){this._internalCallback=function(){self._internalCallback=null;self.sandbox(null,"js");};this.insert(null,"css");return;}if(!util.Connect){var ld=new YAHOO.util.YUILoader();ld.insert({base:this.base,filter:this.filter,require:"connection",insertBefore:this.insertBefore,charset:this.charset,onSuccess:function(){this.sandbox(null,"js");},scope:this},"js");return;}this._scriptText=[];this._loadCount=0;this._stopCount=this.sorted.length;this._xhr=[];this.calculate();var s=this.sorted,l=s.length,i,m,url;for(i=0;i<l;i=i+1){m=this.moduleInfo[s[i]];if(!m){this._onFailure("undefined module "+m);for(var j=0;j<this._xhr.length;j=j+1){this._xhr[j].abort();}return;}if(m.type!=="js"){this._loadCount++;continue;}url=m.fullpath;url=(url)?this._filter(url):this._url(m.path);var xhrData={success:function(o){var idx=o.argument[0],name=o.argument[2];this._scriptText[idx]=o.responseText;if(this.onProgress){this.onProgress.call(this.scope,{name:name,scriptText:o.responseText,xhrResponse:o,data:this.data});}this._loadCount++;if(this._loadCount>=this._stopCount){var v=this.varName||"YAHOO";var t="(function() {\n";var b="\nreturn "+v+";\n})();";var ref=eval(t+this._scriptText.join("\n")+b);this._pushEvents(ref);if(ref){this.onSuccess.call(this.scope,{reference:ref,data:this.data});}else{this._onFailure.call(this.varName+" reference failure");}}},failure:function(o){this.onFailure.call(this.scope,{msg:"XHR failure",xhrResponse:o,data:this.data});},scope:this,argument:[i,url,s[i]]};this._xhr.push(util.Connect.asyncRequest("GET",url,xhrData));}},loadNext:function(mname){if(!this._loading){return;}if(mname){if(mname!==this._loading){return;}this.inserted[mname]=true;if(this.onProgress){this.onProgress.call(this.scope,{name:mname,data:this.data});}}var s=this.sorted,len=s.length,i,m;for(i=0;i<len;i=i+1){if(s[i] in this.inserted){continue;}if(s[i]===this._loading){return;}m=this.moduleInfo[s[i]];if(!m){this.onFailure.call(this.scope,{msg:"undefined module "+m,data:this.data});return;}if(!this.loadType||this.loadType===m.type){this._loading=s[i];var fn=(m.type==="css")?util.Get.css:util.Get.script,url=m.fullpath,self=this,c=function(o){self.loadNext(o.data);};url=(url)?this._filter(url):this._url(m.path);if(env.ua.webkit&&env.ua.webkit<420&&m.type==="js"&&!m.varName){c=null;this._useYahooListener=true;}fn(url,{data:s[i],onSuccess:c,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,varName:m.varName,scope:self});return;}}this._loading=null;if(this._internalCallback){var f=this._internalCallback;this._internalCallback=null;f.call(this);}else{if(this.onSuccess){this._pushEvents();this.onSuccess.call(this.scope,{data:this.data});}}},_pushEvents:function(ref){var r=ref||YAHOO;if(r.util&&r.util.Event){r.util.Event._load();}},_filter:function(str){var f=this.filter;return(f)?str.replace(new RegExp(f.searchExp,"g"),f.replaceStr):str;},_url:function(path){return this._filter((this.base||"")+path);}};})();YAHOO.register("yuiloader",YAHOO.util.YUILoader,{version:"2.8.1",build:"19"});
-(function(){YAHOO.env._id_counter=YAHOO.env._id_counter||0;var E=YAHOO.util,L=YAHOO.lang,m=YAHOO.env.ua,A=YAHOO.lang.trim,d={},h={},N=/^t(?:able|d|h)$/i,X=/color$/i,K=window.document,W=K.documentElement,e="ownerDocument",n="defaultView",v="documentElement",t="compatMode",b="offsetLeft",P="offsetTop",u="offsetParent",Z="parentNode",l="nodeType",C="tagName",O="scrollLeft",i="scrollTop",Q="getBoundingClientRect",w="getComputedStyle",a="currentStyle",M="CSS1Compat",c="BackCompat",g="class",F="className",J="",B=" ",s="(?:^|\\s)",k="(?= |$)",U="g",p="position",f="fixed",V="relative",j="left",o="top",r="medium",q="borderLeftWidth",R="borderTopWidth",D=m.opera,I=m.webkit,H=m.gecko,T=m.ie;E.Dom={CUSTOM_ATTRIBUTES:(!W.hasAttribute)?{"for":"htmlFor","class":F}:{"htmlFor":"for","className":g},DOT_ATTRIBUTES:{},get:function(z){var AB,x,AA,y,Y,G;if(z){if(z[l]||z.item){return z;}if(typeof z==="string"){AB=z;z=K.getElementById(z);G=(z)?z.attributes:null;if(z&&G&&G.id&&G.id.value===AB){return z;}else{if(z&&K.all){z=null;x=K.all[AB];for(y=0,Y=x.length;y<Y;++y){if(x[y].id===AB){return x[y];}}}}return z;}if(YAHOO.util.Element&&z instanceof YAHOO.util.Element){z=z.get("element");}if("length" in z){AA=[];for(y=0,Y=z.length;y<Y;++y){AA[AA.length]=E.Dom.get(z[y]);}return AA;}return z;}return null;},getComputedStyle:function(G,Y){if(window[w]){return G[e][n][w](G,null)[Y];}else{if(G[a]){return E.Dom.IE_ComputedStyle.get(G,Y);}}},getStyle:function(G,Y){return E.Dom.batch(G,E.Dom._getStyle,Y);},_getStyle:function(){if(window[w]){return function(G,y){y=(y==="float")?y="cssFloat":E.Dom._toCamel(y);var x=G.style[y],Y;if(!x){Y=G[e][n][w](G,null);if(Y){x=Y[y];}}return x;};}else{if(W[a]){return function(G,y){var x;switch(y){case"opacity":x=100;try{x=G.filters["DXImageTransform.Microsoft.Alpha"].opacity;}catch(z){try{x=G.filters("alpha").opacity;}catch(Y){}}return x/100;case"float":y="styleFloat";default:y=E.Dom._toCamel(y);x=G[a]?G[a][y]:null;return(G.style[y]||x);}};}}}(),setStyle:function(G,Y,x){E.Dom.batch(G,E.Dom._setStyle,{prop:Y,val:x});},_setStyle:function(){if(T){return function(Y,G){var x=E.Dom._toCamel(G.prop),y=G.val;if(Y){switch(x){case"opacity":if(L.isString(Y.style.filter)){Y.style.filter="alpha(opacity="+y*100+")";if(!Y[a]||!Y[a].hasLayout){Y.style.zoom=1;}}break;case"float":x="styleFloat";default:Y.style[x]=y;}}else{}};}else{return function(Y,G){var x=E.Dom._toCamel(G.prop),y=G.val;if(Y){if(x=="float"){x="cssFloat";}Y.style[x]=y;}else{}};}}(),getXY:function(G){return E.Dom.batch(G,E.Dom._getXY);},_canPosition:function(G){return(E.Dom._getStyle(G,"display")!=="none"&&E.Dom._inDoc(G));},_getXY:function(){if(K[v][Q]){return function(y){var z,Y,AA,AF,AE,AD,AC,G,x,AB=Math.floor,AG=false;if(E.Dom._canPosition(y)){AA=y[Q]();AF=y[e];z=E.Dom.getDocumentScrollLeft(AF);Y=E.Dom.getDocumentScrollTop(AF);AG=[AB(AA[j]),AB(AA[o])];if(T&&m.ie<8){AE=2;AD=2;AC=AF[t];if(m.ie===6){if(AC!==c){AE=0;AD=0;}}if((AC===c)){G=S(AF[v],q);x=S(AF[v],R);if(G!==r){AE=parseInt(G,10);}if(x!==r){AD=parseInt(x,10);}}AG[0]-=AE;AG[1]-=AD;}if((Y||z)){AG[0]+=z;AG[1]+=Y;}AG[0]=AB(AG[0]);AG[1]=AB(AG[1]);}else{}return AG;};}else{return function(y){var x,Y,AA,AB,AC,z=false,G=y;if(E.Dom._canPosition(y)){z=[y[b],y[P]];x=E.Dom.getDocumentScrollLeft(y[e]);Y=E.Dom.getDocumentScrollTop(y[e]);AC=((H||m.webkit>519)?true:false);while((G=G[u])){z[0]+=G[b];z[1]+=G[P];if(AC){z=E.Dom._calcBorders(G,z);}}if(E.Dom._getStyle(y,p)!==f){G=y;while((G=G[Z])&&G[C]){AA=G[i];AB=G[O];if(H&&(E.Dom._getStyle(G,"overflow")!=="visible")){z=E.Dom._calcBorders(G,z);}if(AA||AB){z[0]-=AB;z[1]-=AA;}}z[0]+=x;z[1]+=Y;}else{if(D){z[0]-=x;z[1]-=Y;}else{if(I||H){z[0]+=x;z[1]+=Y;}}}z[0]=Math.floor(z[0]);z[1]=Math.floor(z[1]);}else{}return z;};}}(),getX:function(G){var Y=function(x){return E.Dom.getXY(x)[0];};return E.Dom.batch(G,Y,E.Dom,true);},getY:function(G){var Y=function(x){return E.Dom.getXY(x)[1];};return E.Dom.batch(G,Y,E.Dom,true);},setXY:function(G,x,Y){E.Dom.batch(G,E.Dom._setXY,{pos:x,noRetry:Y});},_setXY:function(G,z){var AA=E.Dom._getStyle(G,p),y=E.Dom.setStyle,AD=z.pos,Y=z.noRetry,AB=[parseInt(E.Dom.getComputedStyle(G,j),10),parseInt(E.Dom.getComputedStyle(G,o),10)],AC,x;if(AA=="static"){AA=V;y(G,p,AA);}AC=E.Dom._getXY(G);if(!AD||AC===false){return false;}if(isNaN(AB[0])){AB[0]=(AA==V)?0:G[b];}if(isNaN(AB[1])){AB[1]=(AA==V)?0:G[P];}if(AD[0]!==null){y(G,j,AD[0]-AC[0]+AB[0]+"px");}if(AD[1]!==null){y(G,o,AD[1]-AC[1]+AB[1]+"px");}if(!Y){x=E.Dom._getXY(G);if((AD[0]!==null&&x[0]!=AD[0])||(AD[1]!==null&&x[1]!=AD[1])){E.Dom._setXY(G,{pos:AD,noRetry:true});}}},setX:function(Y,G){E.Dom.setXY(Y,[G,null]);},setY:function(G,Y){E.Dom.setXY(G,[null,Y]);},getRegion:function(G){var Y=function(x){var y=false;if(E.Dom._canPosition(x)){y=E.Region.getRegion(x);}else{}return y;};return E.Dom.batch(G,Y,E.Dom,true);},getClientWidth:function(){return E.Dom.getViewportWidth();},getClientHeight:function(){return E.Dom.getViewportHeight();},getElementsByClassName:function(AB,AF,AC,AE,x,AD){AF=AF||"*";AC=(AC)?E.Dom.get(AC):null||K;if(!AC){return[];}var Y=[],G=AC.getElementsByTagName(AF),z=E.Dom.hasClass;for(var y=0,AA=G.length;y<AA;++y){if(z(G[y],AB)){Y[Y.length]=G[y];}}if(AE){E.Dom.batch(Y,AE,x,AD);}return Y;},hasClass:function(Y,G){return E.Dom.batch(Y,E.Dom._hasClass,G);},_hasClass:function(x,Y){var G=false,y;if(x&&Y){y=E.Dom._getAttribute(x,F)||J;if(Y.exec){G=Y.test(y);}else{G=Y&&(B+y+B).indexOf(B+Y+B)>-1;}}else{}return G;},addClass:function(Y,G){return E.Dom.batch(Y,E.Dom._addClass,G);},_addClass:function(x,Y){var G=false,y;if(x&&Y){y=E.Dom._getAttribute(x,F)||J;if(!E.Dom._hasClass(x,Y)){E.Dom.setAttribute(x,F,A(y+B+Y));G=true;}}else{}return G;},removeClass:function(Y,G){return E.Dom.batch(Y,E.Dom._removeClass,G);},_removeClass:function(y,x){var Y=false,AA,z,G;if(y&&x){AA=E.Dom._getAttribute(y,F)||J;E.Dom.setAttribute(y,F,AA.replace(E.Dom._getClassRegex(x),J));z=E.Dom._getAttribute(y,F);if(AA!==z){E.Dom.setAttribute(y,F,A(z));Y=true;if(E.Dom._getAttribute(y,F)===""){G=(y.hasAttribute&&y.hasAttribute(g))?g:F;
-y.removeAttribute(G);}}}else{}return Y;},replaceClass:function(x,Y,G){return E.Dom.batch(x,E.Dom._replaceClass,{from:Y,to:G});},_replaceClass:function(y,x){var Y,AB,AA,G=false,z;if(y&&x){AB=x.from;AA=x.to;if(!AA){G=false;}else{if(!AB){G=E.Dom._addClass(y,x.to);}else{if(AB!==AA){z=E.Dom._getAttribute(y,F)||J;Y=(B+z.replace(E.Dom._getClassRegex(AB),B+AA)).split(E.Dom._getClassRegex(AA));Y.splice(1,0,B+AA);E.Dom.setAttribute(y,F,A(Y.join(J)));G=true;}}}}else{}return G;},generateId:function(G,x){x=x||"yui-gen";var Y=function(y){if(y&&y.id){return y.id;}var z=x+YAHOO.env._id_counter++;if(y){if(y[e]&&y[e].getElementById(z)){return E.Dom.generateId(y,z+x);}y.id=z;}return z;};return E.Dom.batch(G,Y,E.Dom,true)||Y.apply(E.Dom,arguments);},isAncestor:function(Y,x){Y=E.Dom.get(Y);x=E.Dom.get(x);var G=false;if((Y&&x)&&(Y[l]&&x[l])){if(Y.contains&&Y!==x){G=Y.contains(x);}else{if(Y.compareDocumentPosition){G=!!(Y.compareDocumentPosition(x)&16);}}}else{}return G;},inDocument:function(G,Y){return E.Dom._inDoc(E.Dom.get(G),Y);},_inDoc:function(Y,x){var G=false;if(Y&&Y[C]){x=x||Y[e];G=E.Dom.isAncestor(x[v],Y);}else{}return G;},getElementsBy:function(Y,AF,AB,AD,y,AC,AE){AF=AF||"*";AB=(AB)?E.Dom.get(AB):null||K;if(!AB){return[];}var x=[],G=AB.getElementsByTagName(AF);for(var z=0,AA=G.length;z<AA;++z){if(Y(G[z])){if(AE){x=G[z];break;}else{x[x.length]=G[z];}}}if(AD){E.Dom.batch(x,AD,y,AC);}return x;},getElementBy:function(x,G,Y){return E.Dom.getElementsBy(x,G,Y,null,null,null,true);},batch:function(x,AB,AA,z){var y=[],Y=(z)?AA:window;x=(x&&(x[C]||x.item))?x:E.Dom.get(x);if(x&&AB){if(x[C]||x.length===undefined){return AB.call(Y,x,AA);}for(var G=0;G<x.length;++G){y[y.length]=AB.call(Y,x[G],AA);}}else{return false;}return y;},getDocumentHeight:function(){var Y=(K[t]!=M||I)?K.body.scrollHeight:W.scrollHeight,G=Math.max(Y,E.Dom.getViewportHeight());return G;},getDocumentWidth:function(){var Y=(K[t]!=M||I)?K.body.scrollWidth:W.scrollWidth,G=Math.max(Y,E.Dom.getViewportWidth());return G;},getViewportHeight:function(){var G=self.innerHeight,Y=K[t];if((Y||T)&&!D){G=(Y==M)?W.clientHeight:K.body.clientHeight;}return G;},getViewportWidth:function(){var G=self.innerWidth,Y=K[t];if(Y||T){G=(Y==M)?W.clientWidth:K.body.clientWidth;}return G;},getAncestorBy:function(G,Y){while((G=G[Z])){if(E.Dom._testElement(G,Y)){return G;}}return null;},getAncestorByClassName:function(Y,G){Y=E.Dom.get(Y);if(!Y){return null;}var x=function(y){return E.Dom.hasClass(y,G);};return E.Dom.getAncestorBy(Y,x);},getAncestorByTagName:function(Y,G){Y=E.Dom.get(Y);if(!Y){return null;}var x=function(y){return y[C]&&y[C].toUpperCase()==G.toUpperCase();};return E.Dom.getAncestorBy(Y,x);},getPreviousSiblingBy:function(G,Y){while(G){G=G.previousSibling;if(E.Dom._testElement(G,Y)){return G;}}return null;},getPreviousSibling:function(G){G=E.Dom.get(G);if(!G){return null;}return E.Dom.getPreviousSiblingBy(G);},getNextSiblingBy:function(G,Y){while(G){G=G.nextSibling;if(E.Dom._testElement(G,Y)){return G;}}return null;},getNextSibling:function(G){G=E.Dom.get(G);if(!G){return null;}return E.Dom.getNextSiblingBy(G);},getFirstChildBy:function(G,x){var Y=(E.Dom._testElement(G.firstChild,x))?G.firstChild:null;return Y||E.Dom.getNextSiblingBy(G.firstChild,x);},getFirstChild:function(G,Y){G=E.Dom.get(G);if(!G){return null;}return E.Dom.getFirstChildBy(G);},getLastChildBy:function(G,x){if(!G){return null;}var Y=(E.Dom._testElement(G.lastChild,x))?G.lastChild:null;return Y||E.Dom.getPreviousSiblingBy(G.lastChild,x);},getLastChild:function(G){G=E.Dom.get(G);return E.Dom.getLastChildBy(G);},getChildrenBy:function(Y,y){var x=E.Dom.getFirstChildBy(Y,y),G=x?[x]:[];E.Dom.getNextSiblingBy(x,function(z){if(!y||y(z)){G[G.length]=z;}return false;});return G;},getChildren:function(G){G=E.Dom.get(G);if(!G){}return E.Dom.getChildrenBy(G);},getDocumentScrollLeft:function(G){G=G||K;return Math.max(G[v].scrollLeft,G.body.scrollLeft);},getDocumentScrollTop:function(G){G=G||K;return Math.max(G[v].scrollTop,G.body.scrollTop);},insertBefore:function(Y,G){Y=E.Dom.get(Y);G=E.Dom.get(G);if(!Y||!G||!G[Z]){return null;}return G[Z].insertBefore(Y,G);},insertAfter:function(Y,G){Y=E.Dom.get(Y);G=E.Dom.get(G);if(!Y||!G||!G[Z]){return null;}if(G.nextSibling){return G[Z].insertBefore(Y,G.nextSibling);}else{return G[Z].appendChild(Y);}},getClientRegion:function(){var x=E.Dom.getDocumentScrollTop(),Y=E.Dom.getDocumentScrollLeft(),y=E.Dom.getViewportWidth()+Y,G=E.Dom.getViewportHeight()+x;return new E.Region(x,y,G,Y);},setAttribute:function(Y,G,x){E.Dom.batch(Y,E.Dom._setAttribute,{attr:G,val:x});},_setAttribute:function(x,Y){var G=E.Dom._toCamel(Y.attr),y=Y.val;if(x&&x.setAttribute){if(E.Dom.DOT_ATTRIBUTES[G]){x[G]=y;}else{G=E.Dom.CUSTOM_ATTRIBUTES[G]||G;x.setAttribute(G,y);}}else{}},getAttribute:function(Y,G){return E.Dom.batch(Y,E.Dom._getAttribute,G);},_getAttribute:function(Y,G){var x;G=E.Dom.CUSTOM_ATTRIBUTES[G]||G;if(Y&&Y.getAttribute){x=Y.getAttribute(G,2);}else{}return x;},_toCamel:function(Y){var x=d;function G(y,z){return z.toUpperCase();}return x[Y]||(x[Y]=Y.indexOf("-")===-1?Y:Y.replace(/-([a-z])/gi,G));},_getClassRegex:function(Y){var G;if(Y!==undefined){if(Y.exec){G=Y;}else{G=h[Y];if(!G){Y=Y.replace(E.Dom._patterns.CLASS_RE_TOKENS,"\\$1");G=h[Y]=new RegExp(s+Y+k,U);}}}return G;},_patterns:{ROOT_TAG:/^body|html$/i,CLASS_RE_TOKENS:/([\.\(\)\^\$\*\+\?\|\[\]\{\}\\])/g},_testElement:function(G,Y){return G&&G[l]==1&&(!Y||Y(G));},_calcBorders:function(x,y){var Y=parseInt(E.Dom[w](x,R),10)||0,G=parseInt(E.Dom[w](x,q),10)||0;if(H){if(N.test(x[C])){Y=0;G=0;}}y[0]+=G;y[1]+=Y;return y;}};var S=E.Dom[w];if(m.opera){E.Dom[w]=function(Y,G){var x=S(Y,G);if(X.test(G)){x=E.Dom.Color.toRGB(x);}return x;};}if(m.webkit){E.Dom[w]=function(Y,G){var x=S(Y,G);if(x==="rgba(0, 0, 0, 0)"){x="transparent";}return x;};}if(m.ie&&m.ie>=8&&K.documentElement.hasAttribute){E.Dom.DOT_ATTRIBUTES.type=true;}})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this.y=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this.x=B;this[0]=B;
-this.width=this.right-this.left;this.height=this.bottom-this.top;};YAHOO.util.Region.prototype.contains=function(A){return(A.left>=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top),D=Math.min(this.right,E.right),A=Math.min(this.bottom,E.bottom),B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top),D=Math.max(this.right,E.right),A=Math.max(this.bottom,E.bottom),B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+", height: "+this.height+", width: "+this.width+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D),C=F[1],E=F[0]+D.offsetWidth,A=F[1]+D.offsetHeight,B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}YAHOO.util.Point.superclass.constructor.call(this,B,A,B,A);};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var B=YAHOO.util,A="clientTop",F="clientLeft",J="parentNode",K="right",W="hasLayout",I="px",U="opacity",L="auto",D="borderLeftWidth",G="borderTopWidth",P="borderRightWidth",V="borderBottomWidth",S="visible",Q="transparent",N="height",E="width",H="style",T="currentStyle",R=/^width|height$/,O=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,M={get:function(X,Z){var Y="",a=X[T][Z];if(Z===U){Y=B.Dom.getStyle(X,U);}else{if(!a||(a.indexOf&&a.indexOf(I)>-1)){Y=a;}else{if(B.Dom.IE_COMPUTED[Z]){Y=B.Dom.IE_COMPUTED[Z](X,Z);}else{if(O.test(a)){Y=B.Dom.IE.ComputedStyle.getPixel(X,Z);}else{Y=a;}}}}return Y;},getOffset:function(Z,e){var b=Z[T][e],X=e.charAt(0).toUpperCase()+e.substr(1),c="offset"+X,Y="pixel"+X,a="",d;if(b==L){d=Z[c];if(d===undefined){a=0;}a=d;if(R.test(e)){Z[H][e]=d;if(Z[c]>d){a=d-(Z[c]-d);}Z[H][e]=L;}}else{if(!Z[H][Y]&&!Z[H][e]){Z[H][e]=b;}a=Z[H][Y];}return a+I;},getBorderWidth:function(X,Z){var Y=null;if(!X[T][W]){X[H].zoom=1;}switch(Z){case G:Y=X[A];break;case V:Y=X.offsetHeight-X.clientHeight-X[A];break;case D:Y=X[F];break;case P:Y=X.offsetWidth-X.clientWidth-X[F];break;}return Y+I;},getPixel:function(Y,X){var a=null,b=Y[T][K],Z=Y[T][X];Y[H][K]=Z;a=Y[H].pixelRight;Y[H][K]=b;return a+I;},getMargin:function(Y,X){var Z;if(Y[T][X]==L){Z=0+I;}else{Z=B.Dom.IE.ComputedStyle.getPixel(Y,X);}return Z;},getVisibility:function(Y,X){var Z;while((Z=Y[T])&&Z[X]=="inherit"){Y=Y[J];}return(Z)?Z[X]:S;},getColor:function(Y,X){return B.Dom.Color.toRGB(Y[T][X])||Q;},getBorderColor:function(Y,X){var Z=Y[T],a=Z[X]||Z.color;return B.Dom.Color.toRGB(B.Dom.Color.toHex(a));}},C={};C.top=C.right=C.bottom=C.left=C[E]=C[N]=M.getOffset;C.color=M.getColor;C[G]=C[P]=C[V]=C[D]=M.getBorderWidth;C.marginTop=C.marginRight=C.marginBottom=C.marginLeft=M.getMargin;C.visibility=M.getVisibility;C.borderColor=C.borderTopColor=C.borderRightColor=C.borderBottomColor=C.borderLeftColor=M.getBorderColor;B.Dom.IE_COMPUTED=C;B.Dom.IE_ComputedStyle=M;})();(function(){var C="toString",A=parseInt,B=RegExp,D=YAHOO.util;D.Dom.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Dom.Color.re_RGB.test(E)){E=D.Dom.Color.toHex(E);}if(D.Dom.Color.re_hex.exec(E)){E="rgb("+[A(B.$1,16),A(B.$2,16),A(B.$3,16)].join(", ")+")";}return E;},toHex:function(H){H=D.Dom.Color.KEYWORDS[H]||H;if(D.Dom.Color.re_RGB.exec(H)){var G=(B.$1.length===1)?"0"+B.$1:Number(B.$1),F=(B.$2.length===1)?"0"+B.$2:Number(B.$2),E=(B.$3.length===1)?"0"+B.$3:Number(B.$3);H=[G[C](16),F[C](16),E[C](16)].join("");}if(H.length<6){H=H.replace(D.Dom.Color.re_hex3,"$1$1");}if(H!=="transparent"&&H.indexOf("#")<0){H="#"+H;}return H.toLowerCase();}};}());YAHOO.register("dom",YAHOO.util.Dom,{version:"2.8.1",build:"19"});YAHOO.util.CustomEvent=function(D,C,B,A,E){this.type=D;this.scope=C||window;this.silent=B;this.fireOnce=E;this.fired=false;this.firedWith=null;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var F="_YUICEOnSubscribe";if(D!==F){this.subscribeEvent=new YAHOO.util.CustomEvent(F,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,D){if(!B){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,D);}var A=new YAHOO.util.Subscriber(B,C,D);if(this.fireOnce&&this.fired){this.notify(A,this.firedWith);}else{this.subscribers.push(A);}},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B<A;++B){var C=this.subscribers[B];if(C&&C.contains(D,F)){this._delete(B);E=true;}}return E;},fire:function(){this.lastError=null;var H=[],A=this.subscribers.length;var D=[].slice.call(arguments,0),C=true,F,B=false;if(this.fireOnce){if(this.fired){return true;}else{this.firedWith=D;}}this.fired=true;if(!A&&this.silent){return true;}if(!this.silent){}var E=this.subscribers.slice();for(F=0;F<A;++F){var G=E[F];if(!G){B=true;}else{C=this.notify(G,D);if(false===C){if(!this.silent){}break;}}}return(C!==false);},notify:function(F,C){var B,H=null,E=F.getScope(this.scope),A=YAHOO.util.Event.throwErrors;if(!this.silent){}if(this.signature==YAHOO.util.CustomEvent.FLAT){if(C.length>0){H=C[0];}try{B=F.fn.call(E,H,F.obj);}catch(G){this.lastError=G;if(A){throw G;}}}else{try{B=F.fn.call(E,this.type,C,F.obj);}catch(D){this.lastError=D;if(A){throw D;}}}return B;},unsubscribeAll:function(){var A=this.subscribers.length,B;for(B=A-1;B>-1;B--){this._delete(B);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"context: "+this.scope;}};YAHOO.util.Subscriber=function(A,B,C){this.fn=A;this.obj=YAHOO.lang.isUndefined(B)?null:B;this.overrideContext=C;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.overrideContext){if(this.overrideContext===true){return this.obj;}else{return this.overrideContext;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", overrideContext: "+(this.overrideContext||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var G=false,H=[],J=[],A=0,E=[],B=0,C={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9},D=YAHOO.env.ua.ie,F="focusin",I="focusout";return{POLL_RETRYS:500,POLL_INTERVAL:40,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,CAPTURE:7,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:D,_interval:null,_dri:null,_specialTypes:{focusin:(D?"focusin":"focus"),focusout:(D?"focusout":"blur")},DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){this._interval=YAHOO.lang.later(this.POLL_INTERVAL,this,this._tryPreloadAttach,null,true);}},onAvailable:function(Q,M,O,P,N){var K=(YAHOO.lang.isString(Q))?[Q]:Q;for(var L=0;L<K.length;L=L+1){E.push({id:K[L],fn:M,obj:O,overrideContext:P,checkReady:N});}A=this.POLL_RETRYS;this.startInterval();},onContentReady:function(N,K,L,M){this.onAvailable(N,K,L,M,true);},onDOMReady:function(){this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent,arguments);},_addListener:function(M,K,V,P,T,Y){if(!V||!V.call){return false;}if(this._isValidCollection(M)){var W=true;for(var Q=0,S=M.length;Q<S;++Q){W=this.on(M[Q],K,V,P,T)&&W;}return W;}else{if(YAHOO.lang.isString(M)){var O=this.getEl(M);if(O){M=O;}else{this.onAvailable(M,function(){YAHOO.util.Event._addListener(M,K,V,P,T,Y);});return true;}}}if(!M){return false;}if("unload"==K&&P!==this){J[J.length]=[M,K,V,P,T];return true;}var L=M;if(T){if(T===true){L=P;}else{L=T;}}var N=function(Z){return V.call(L,YAHOO.util.Event.getEvent(Z,M),P);};var X=[M,K,V,N,L,P,T,Y];var R=H.length;H[R]=X;try{this._simpleAdd(M,K,N,Y);}catch(U){this.lastError=U;this.removeListener(M,K,V);return false;}return true;},_getType:function(K){return this._specialTypes[K]||K;},addListener:function(M,P,L,N,O){var K=((P==F||P==I)&&!YAHOO.env.ua.ie)?true:false;return this._addListener(M,this._getType(P),L,N,O,K);},addFocusListener:function(L,K,M,N){return this.on(L,F,K,M,N);},removeFocusListener:function(L,K){return this.removeListener(L,F,K);},addBlurListener:function(L,K,M,N){return this.on(L,I,K,M,N);},removeBlurListener:function(L,K){return this.removeListener(L,I,K);},removeListener:function(L,K,R){var M,P,U;K=this._getType(K);if(typeof L=="string"){L=this.getEl(L);}else{if(this._isValidCollection(L)){var S=true;for(M=L.length-1;M>-1;M--){S=(this.removeListener(L[M],K,R)&&S);}return S;}}if(!R||!R.call){return this.purgeElement(L,false,K);}if("unload"==K){for(M=J.length-1;M>-1;M--){U=J[M];if(U&&U[0]==L&&U[1]==K&&U[2]==R){J.splice(M,1);return true;}}return false;}var N=null;var O=arguments[3];if("undefined"===typeof O){O=this._getCacheIndex(H,L,K,R);}if(O>=0){N=H[O];}if(!L||!N){return false;}var T=N[this.CAPTURE]===true?true:false;try{this._simpleRemove(L,K,N[this.WFN],T);}catch(Q){this.lastError=Q;return false;}delete H[O][this.WFN];delete H[O][this.FN];H.splice(O,1);return true;},getTarget:function(M,L){var K=M.target||M.srcElement;return this.resolveTextNode(K);},resolveTextNode:function(L){try{if(L&&3==L.nodeType){return L.parentNode;}}catch(K){}return L;},getPageX:function(L){var K=L.pageX;if(!K&&0!==K){K=L.clientX||0;if(this.isIE){K+=this._getScrollLeft();}}return K;},getPageY:function(K){var L=K.pageY;if(!L&&0!==L){L=K.clientY||0;if(this.isIE){L+=this._getScrollTop();}}return L;},getXY:function(K){return[this.getPageX(K),this.getPageY(K)];},getRelatedTarget:function(L){var K=L.relatedTarget;if(!K){if(L.type=="mouseout"){K=L.toElement;
-}else{if(L.type=="mouseover"){K=L.fromElement;}}}return this.resolveTextNode(K);},getTime:function(M){if(!M.time){var L=new Date().getTime();try{M.time=L;}catch(K){this.lastError=K;return L;}}return M.time;},stopEvent:function(K){this.stopPropagation(K);this.preventDefault(K);},stopPropagation:function(K){if(K.stopPropagation){K.stopPropagation();}else{K.cancelBubble=true;}},preventDefault:function(K){if(K.preventDefault){K.preventDefault();}else{K.returnValue=false;}},getEvent:function(M,K){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break;}N=N.caller;}}return L;},getCharCode:function(L){var K=L.keyCode||L.charCode||0;if(YAHOO.env.ua.webkit&&(K in C)){K=C[K];}return K;},_getCacheIndex:function(M,P,Q,O){for(var N=0,L=M.length;N<L;N=N+1){var K=M[N];if(K&&K[this.FN]==O&&K[this.EL]==P&&K[this.TYPE]==Q){return N;}}return -1;},generateId:function(K){var L=K.id;if(!L){L="yuievtautoid-"+B;++B;K.id=L;}return L;},_isValidCollection:function(L){try{return(L&&typeof L!=="string"&&L.length&&!L.tagName&&!L.alert&&typeof L[0]!=="undefined");}catch(K){return false;}},elCache:{},getEl:function(K){return(typeof K==="string")?document.getElementById(K):K;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent("DOMReady",YAHOO,0,0,1),_load:function(L){if(!G){G=true;var K=YAHOO.util.Event;K._ready();K._tryPreloadAttach();}},_ready:function(L){var K=YAHOO.util.Event;if(!K.DOMReady){K.DOMReady=true;K.DOMReadyEvent.fire();K._simpleRemove(document,"DOMContentLoaded",K._ready);}},_tryPreloadAttach:function(){if(E.length===0){A=0;if(this._interval){this._interval.cancel();this._interval=null;}return;}if(this.locked){return;}if(this.isIE){if(!this.DOMReady){this.startInterval();return;}}this.locked=true;var Q=!G;if(!Q){Q=(A>0&&E.length>0);}var P=[];var R=function(T,U){var S=T;if(U.overrideContext){if(U.overrideContext===true){S=U.obj;}else{S=U.overrideContext;}}U.fn.call(S,U.obj);};var L,K,O,N,M=[];for(L=0,K=E.length;L<K;L=L+1){O=E[L];if(O){N=this.getEl(O.id);if(N){if(O.checkReady){if(G||N.nextSibling||!Q){M.push(O);E[L]=null;}}else{R(N,O);E[L]=null;}}else{P.push(O);}}}for(L=0,K=M.length;L<K;L=L+1){O=M[L];R(this.getEl(O.id),O);}A--;if(Q){for(L=E.length-1;L>-1;L--){O=E[L];if(!O||!O.id){E.splice(L,1);}}this.startInterval();}else{if(this._interval){this._interval.cancel();this._interval=null;}}this.locked=false;},purgeElement:function(O,P,R){var M=(YAHOO.lang.isString(O))?this.getEl(O):O;var Q=this.getListeners(M,R),N,K;if(Q){for(N=Q.length-1;N>-1;N--){var L=Q[N];this.removeListener(M,L.type,L.fn);}}if(P&&M&&M.childNodes){for(N=0,K=M.childNodes.length;N<K;++N){this.purgeElement(M.childNodes[N],P,R);}}},getListeners:function(M,K){var P=[],L;if(!K){L=[H,J];}else{if(K==="unload"){L=[J];}else{K=this._getType(K);L=[H];}}var R=(YAHOO.lang.isString(M))?this.getEl(M):M;for(var O=0;O<L.length;O=O+1){var T=L[O];if(T){for(var Q=0,S=T.length;Q<S;++Q){var N=T[Q];if(N&&N[this.EL]===R&&(!K||K===N[this.TYPE])){P.push({type:N[this.TYPE],fn:N[this.FN],obj:N[this.OBJ],adjust:N[this.OVERRIDE],scope:N[this.ADJ_SCOPE],index:Q});}}}}return(P.length)?P:null;},_unload:function(R){var L=YAHOO.util.Event,O,N,M,Q,P,S=J.slice(),K;for(O=0,Q=J.length;O<Q;++O){M=S[O];if(M){K=window;if(M[L.ADJ_SCOPE]){if(M[L.ADJ_SCOPE]===true){K=M[L.UNLOAD_OBJ];}else{K=M[L.ADJ_SCOPE];}}M[L.FN].call(K,L.getEvent(R,M[L.EL]),M[L.UNLOAD_OBJ]);S[O]=null;}}M=null;K=null;J=null;if(H){for(N=H.length-1;N>-1;N--){M=H[N];if(M){L.removeListener(M[L.EL],M[L.TYPE],M[L.FN],N);}}M=null;}L._simpleRemove(window,"unload",L._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var K=document.documentElement,L=document.body;if(K&&(K.scrollTop||K.scrollLeft)){return[K.scrollTop,K.scrollLeft];}else{if(L){return[L.scrollTop,L.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(M,N,L,K){M.addEventListener(N,L,(K));};}else{if(window.attachEvent){return function(M,N,L,K){M.attachEvent("on"+N,L);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(M,N,L,K){M.removeEventListener(N,L,(K));};}else{if(window.detachEvent){return function(L,M,K){L.detachEvent("on"+M,K);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;EU.onFocus=EU.addFocusListener;EU.onBlur=EU.addBlurListener;
-/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
-if(EU.isIE){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;EU._ready();}};}else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,overrideContext:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A);
-},createEvent:function(B,G){this.__yui_events=this.__yui_events||{};var E=G||{},D=this.__yui_events,F;if(D[B]){}else{F=new YAHOO.util.CustomEvent(B,E.scope||this,E.silent,YAHOO.util.CustomEvent.FLAT,E.fireOnce);D[B]=F;if(E.onSubscribeCallback){F.subscribeEvent.subscribe(E.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var A=this.__yui_subscribers[B];if(A){for(var C=0;C<A.length;++C){F.subscribe(A[C].fn,A[C].obj,A[C].overrideContext);}}}return D[B];},fireEvent:function(B){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[B];if(!D){return null;}var A=[];for(var C=1;C<arguments.length;++C){A.push(arguments[C]);}return D.fire.apply(D,A);},hasEvent:function(A){if(this.__yui_events){if(this.__yui_events[A]){return true;}}return false;}};(function(){var A=YAHOO.util.Event,C=YAHOO.lang;YAHOO.util.KeyListener=function(D,I,E,F){if(!D){}else{if(!I){}else{if(!E){}}}if(!F){F=YAHOO.util.KeyListener.KEYDOWN;}var G=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");if(C.isString(D)){D=document.getElementById(D);}if(C.isFunction(E)){G.subscribe(E);}else{G.subscribe(E.fn,E.scope,E.correctScope);}function H(O,N){if(!I.shift){I.shift=false;}if(!I.alt){I.alt=false;}if(!I.ctrl){I.ctrl=false;}if(O.shiftKey==I.shift&&O.altKey==I.alt&&O.ctrlKey==I.ctrl){var J,M=I.keys,L;if(YAHOO.lang.isArray(M)){for(var K=0;K<M.length;K++){J=M[K];L=A.getCharCode(O);if(J==L){G.fire(L,O);break;}}}else{L=A.getCharCode(O);if(M==L){G.fire(L,O);}}}}this.enable=function(){if(!this.enabled){A.on(D,F,H);this.enabledEvent.fire(I);}this.enabled=true;};this.disable=function(){if(this.enabled){A.removeListener(D,F,H);this.disabledEvent.fire(I);}this.enabled=false;};this.toString=function(){return"KeyListener ["+I.keys+"] "+D.tagName+(D.id?"["+D.id+"]":"");};};var B=YAHOO.util.KeyListener;B.KEYDOWN="keydown";B.KEYUP="keyup";B.KEY={ALT:18,BACK_SPACE:8,CAPS_LOCK:20,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,META:224,NUM_LOCK:144,PAGE_DOWN:34,PAGE_UP:33,PAUSE:19,PRINTSCREEN:44,RIGHT:39,SCROLL_LOCK:145,SHIFT:16,SPACE:32,TAB:9,UP:38};})();YAHOO.register("event",YAHOO.util.Event,{version:"2.8.1",build:"19"});YAHOO.util.Connect={_msxml_progid:["Microsoft.XMLHTTP","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP"],_http_headers:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:"application/x-www-form-urlencoded; charset=UTF-8",_default_form_header:"application/x-www-form-urlencoded",_use_default_xhr_header:true,_default_xhr_header:"XMLHttpRequest",_has_default_headers:true,_default_headers:{},_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,startEvent:new YAHOO.util.CustomEvent("start"),completeEvent:new YAHOO.util.CustomEvent("complete"),successEvent:new YAHOO.util.CustomEvent("success"),failureEvent:new YAHOO.util.CustomEvent("failure"),abortEvent:new YAHOO.util.CustomEvent("abort"),_customEvents:{onStart:["startEvent","start"],onComplete:["completeEvent","complete"],onSuccess:["successEvent","success"],onFailure:["failureEvent","failure"],onUpload:["uploadEvent","upload"],onAbort:["abortEvent","abort"]},setProgId:function(A){this._msxml_progid.unshift(A);},setDefaultPostHeader:function(A){if(typeof A=="string"){this._default_post_header=A;}else{if(typeof A=="boolean"){this._use_default_post_header=A;}}},setDefaultXhrHeader:function(A){if(typeof A=="string"){this._default_xhr_header=A;}else{this._use_default_xhr_header=A;}},setPollingInterval:function(A){if(typeof A=="number"&&isFinite(A)){this._polling_interval=A;}},createXhrObject:function(F){var D,A,B;try{A=new XMLHttpRequest();D={conn:A,tId:F,xhr:true};}catch(C){for(B=0;B<this._msxml_progid.length;++B){try{A=new ActiveXObject(this._msxml_progid[B]);D={conn:A,tId:F,xhr:true};break;}catch(E){}}}finally{return D;}},getConnectionObject:function(A){var C,D=this._transaction_id;try{if(!A){C=this.createXhrObject(D);}else{C={tId:D};if(A==="xdr"){C.conn=this._transport;C.xdr=true;}else{if(A==="upload"){C.upload=true;}}}if(C){this._transaction_id++;}}catch(B){}return C;},asyncRequest:function(G,D,F,A){var E,C,B=(F&&F.argument)?F.argument:null;if(this._isFileUpload){C="upload";}else{if(F.xdr){C="xdr";}}E=this.getConnectionObject(C);if(!E){return null;}else{if(F&&F.customevents){this.initCustomEvents(E,F);}if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(E,F,D,A);return E;}if(G.toUpperCase()=="GET"){if(this._sFormData.length!==0){D+=((D.indexOf("?")==-1)?"?":"&")+this._sFormData;}}else{if(G.toUpperCase()=="POST"){A=A?this._sFormData+"&"+A:this._sFormData;}}}if(G.toUpperCase()=="GET"&&(F&&F.cache===false)){D+=((D.indexOf("?")==-1)?"?":"&")+"rnd="+new Date().valueOf().toString();}if(this._use_default_xhr_header){if(!this._default_headers["X-Requested-With"]){this.initHeader("X-Requested-With",this._default_xhr_header,true);}}if((G.toUpperCase()==="POST"&&this._use_default_post_header)&&this._isFormSubmit===false){this.initHeader("Content-Type",this._default_post_header);}if(E.xdr){this.xdr(E,G,D,F,A);return E;}E.conn.open(G,D,true);if(this._has_default_headers||this._has_http_headers){this.setHeader(E);}this.handleReadyState(E,F);E.conn.send(A||"");if(this._isFormSubmit===true){this.resetFormState();}this.startEvent.fire(E,B);if(E.startEvent){E.startEvent.fire(E,B);}return E;}},initCustomEvents:function(A,C){var B;for(B in C.customevents){if(this._customEvents[B][0]){A[this._customEvents[B][0]]=new YAHOO.util.CustomEvent(this._customEvents[B][1],(C.scope)?C.scope:null);A[this._customEvents[B][0]].subscribe(C.customevents[B]);}}},handleReadyState:function(C,D){var B=this,A=(D&&D.argument)?D.argument:null;if(D&&D.timeout){this._timeOut[C.tId]=window.setTimeout(function(){B.abort(C,D,true);},D.timeout);}this._poll[C.tId]=window.setInterval(function(){if(C.conn&&C.conn.readyState===4){window.clearInterval(B._poll[C.tId]);delete B._poll[C.tId];if(D&&D.timeout){window.clearTimeout(B._timeOut[C.tId]);delete B._timeOut[C.tId];}B.completeEvent.fire(C,A);if(C.completeEvent){C.completeEvent.fire(C,A);}B.handleTransactionResponse(C,D);}},this._polling_interval);},handleTransactionResponse:function(B,I,D){var E,A,G=(I&&I.argument)?I.argument:null,C=(B.r&&B.r.statusText==="xdr:success")?true:false,H=(B.r&&B.r.statusText==="xdr:failure")?true:false,J=D;try{if((B.conn.status!==undefined&&B.conn.status!==0)||C){E=B.conn.status;}else{if(H&&!J){E=0;}else{E=13030;}}}catch(F){E=13030;}if((E>=200&&E<300)||E===1223||C){A=B.xdr?B.r:this.createResponseObject(B,G);if(I&&I.success){if(!I.scope){I.success(A);}else{I.success.apply(I.scope,[A]);}}this.successEvent.fire(A);if(B.successEvent){B.successEvent.fire(A);}}else{switch(E){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:A=this.createExceptionObject(B.tId,G,(D?D:false));if(I&&I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}break;default:A=(B.xdr)?B.response:this.createResponseObject(B,G);if(I&&I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}}this.failureEvent.fire(A);if(B.failureEvent){B.failureEvent.fire(A);}}this.releaseObject(B);A=null;},createResponseObject:function(A,G){var D={},I={},E,C,F,B;try{C=A.conn.getAllResponseHeaders();F=C.split("\n");for(E=0;E<F.length;E++){B=F[E].indexOf(":");if(B!=-1){I[F[E].substring(0,B)]=YAHOO.lang.trim(F[E].substring(B+2));}}}catch(H){}D.tId=A.tId;D.status=(A.conn.status==1223)?204:A.conn.status;D.statusText=(A.conn.status==1223)?"No Content":A.conn.statusText;D.getResponseHeader=I;D.getAllResponseHeaders=C;D.responseText=A.conn.responseText;D.responseXML=A.conn.responseXML;if(G){D.argument=G;}return D;},createExceptionObject:function(H,D,A){var F=0,G="communication failure",C=-1,B="transaction aborted",E={};E.tId=H;if(A){E.status=C;E.statusText=B;}else{E.status=F;E.statusText=G;}if(D){E.argument=D;}return E;},initHeader:function(A,D,C){var B=(C)?this._default_headers:this._http_headers;B[A]=D;if(C){this._has_default_headers=true;}else{this._has_http_headers=true;}},setHeader:function(A){var B;if(this._has_default_headers){for(B in this._default_headers){if(YAHOO.lang.hasOwnProperty(this._default_headers,B)){A.conn.setRequestHeader(B,this._default_headers[B]);}}}if(this._has_http_headers){for(B in this._http_headers){if(YAHOO.lang.hasOwnProperty(this._http_headers,B)){A.conn.setRequestHeader(B,this._http_headers[B]);
-}}this._http_headers={};this._has_http_headers=false;}},resetDefaultHeaders:function(){this._default_headers={};this._has_default_headers=false;},abort:function(E,G,A){var D,B=(G&&G.argument)?G.argument:null;E=E||{};if(E.conn){if(E.xhr){if(this.isCallInProgress(E)){E.conn.abort();window.clearInterval(this._poll[E.tId]);delete this._poll[E.tId];if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{if(E.xdr){E.conn.abort(E.tId);D=true;}}}else{if(E.upload){var C="yuiIO"+E.tId;var F=document.getElementById(C);if(F){YAHOO.util.Event.removeListener(F,"load");document.body.removeChild(F);if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{D=false;}}if(D===true){this.abortEvent.fire(E,B);if(E.abortEvent){E.abortEvent.fire(E,B);}this.handleTransactionResponse(E,G,true);}return D;},isCallInProgress:function(A){A=A||{};if(A.xhr&&A.conn){return A.conn.readyState!==4&&A.conn.readyState!==0;}else{if(A.xdr&&A.conn){return A.conn.isCallInProgress(A.tId);}else{if(A.upload===true){return document.getElementById("yuiIO"+A.tId)?true:false;}else{return false;}}}},releaseObject:function(A){if(A&&A.conn){A.conn=null;A=null;}}};(function(){var G=YAHOO.util.Connect,H={};function D(I){var J='<object id="YUIConnectionSwf" type="application/x-shockwave-flash" data="'+I+'" width="0" height="0">'+'<param name="movie" value="'+I+'">'+'<param name="allowScriptAccess" value="always">'+"</object>",K=document.createElement("div");document.body.appendChild(K);K.innerHTML=J;}function B(L,I,J,M,K){H[parseInt(L.tId)]={"o":L,"c":M};if(K){M.method=I;M.data=K;}L.conn.send(J,M,L.tId);}function E(I){D(I);G._transport=document.getElementById("YUIConnectionSwf");}function C(){G.xdrReadyEvent.fire();}function A(J,I){if(J){G.startEvent.fire(J,I.argument);if(J.startEvent){J.startEvent.fire(J,I.argument);}}}function F(J){var K=H[J.tId].o,I=H[J.tId].c;if(J.statusText==="xdr:start"){A(K,I);return;}J.responseText=decodeURI(J.responseText);K.r=J;if(I.argument){K.r.argument=I.argument;}this.handleTransactionResponse(K,I,J.statusText==="xdr:abort"?true:false);delete H[J.tId];}G.xdr=B;G.swf=D;G.transport=E;G.xdrReadyEvent=new YAHOO.util.CustomEvent("xdrReady");G.xdrReady=C;G.handleXdrResponse=F;})();(function(){var D=YAHOO.util.Connect,F=YAHOO.util.Event;D._isFormSubmit=false;D._isFileUpload=false;D._formNode=null;D._sFormData=null;D._submitElementValue=null;D.uploadEvent=new YAHOO.util.CustomEvent("upload"),D._hasSubmitListener=function(){if(F){F.addListener(document,"click",function(J){var I=F.getTarget(J),H=I.nodeName.toLowerCase();if((H==="input"||H==="button")&&(I.type&&I.type.toLowerCase()=="submit")){D._submitElementValue=encodeURIComponent(I.name)+"="+encodeURIComponent(I.value);}});return true;}return false;}();function G(T,O,J){var S,I,R,P,W,Q=false,M=[],V=0,L,N,K,U,H;this.resetFormState();if(typeof T=="string"){S=(document.getElementById(T)||document.forms[T]);}else{if(typeof T=="object"){S=T;}else{return;}}if(O){this.createFrame(J?J:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=S;return;}for(L=0,N=S.elements.length;L<N;++L){I=S.elements[L];W=I.disabled;R=I.name;if(!W&&R){R=encodeURIComponent(R)+"=";P=encodeURIComponent(I.value);switch(I.type){case"select-one":if(I.selectedIndex>-1){H=I.options[I.selectedIndex];M[V++]=R+encodeURIComponent((H.attributes.value&&H.attributes.value.specified)?H.value:H.text);}break;case"select-multiple":if(I.selectedIndex>-1){for(K=I.selectedIndex,U=I.options.length;K<U;++K){H=I.options[K];if(H.selected){M[V++]=R+encodeURIComponent((H.attributes.value&&H.attributes.value.specified)?H.value:H.text);}}}break;case"radio":case"checkbox":if(I.checked){M[V++]=R+P;}break;case"file":case undefined:case"reset":case"button":break;case"submit":if(Q===false){if(this._hasSubmitListener&&this._submitElementValue){M[V++]=this._submitElementValue;}Q=true;}break;default:M[V++]=R+P;}}}this._isFormSubmit=true;this._sFormData=M.join("&");this.initHeader("Content-Type",this._default_form_header);return this._sFormData;}function C(){this._isFormSubmit=false;this._isFileUpload=false;this._formNode=null;this._sFormData="";}function B(H){var I="yuiIO"+this._transaction_id,J;if(YAHOO.env.ua.ie){J=document.createElement('<iframe id="'+I+'" name="'+I+'" />');if(typeof H=="boolean"){J.src="javascript:false";}}else{J=document.createElement("iframe");J.id=I;J.name=I;}J.style.position="absolute";J.style.top="-1000px";J.style.left="-1000px";document.body.appendChild(J);}function E(H){var K=[],I=H.split("&"),J,L;for(J=0;J<I.length;J++){L=I[J].indexOf("=");if(L!=-1){K[J]=document.createElement("input");K[J].type="hidden";K[J].name=decodeURIComponent(I[J].substring(0,L));K[J].value=decodeURIComponent(I[J].substring(L+1));this._formNode.appendChild(K[J]);}}return K;}function A(K,V,L,J){var Q="yuiIO"+K.tId,R="multipart/form-data",T=document.getElementById(Q),M=(document.documentMode&&document.documentMode===8)?true:false,W=this,S=(V&&V.argument)?V.argument:null,U,P,I,O,H,N;H={action:this._formNode.getAttribute("action"),method:this._formNode.getAttribute("method"),target:this._formNode.getAttribute("target")};this._formNode.setAttribute("action",L);this._formNode.setAttribute("method","POST");this._formNode.setAttribute("target",Q);if(YAHOO.env.ua.ie&&!M){this._formNode.setAttribute("encoding",R);}else{this._formNode.setAttribute("enctype",R);}if(J){U=this.appendPostData(J);}this._formNode.submit();this.startEvent.fire(K,S);if(K.startEvent){K.startEvent.fire(K,S);}if(V&&V.timeout){this._timeOut[K.tId]=window.setTimeout(function(){W.abort(K,V,true);},V.timeout);}if(U&&U.length>0){for(P=0;P<U.length;P++){this._formNode.removeChild(U[P]);}}for(I in H){if(YAHOO.lang.hasOwnProperty(H,I)){if(H[I]){this._formNode.setAttribute(I,H[I]);}else{this._formNode.removeAttribute(I);}}}this.resetFormState();N=function(){if(V&&V.timeout){window.clearTimeout(W._timeOut[K.tId]);delete W._timeOut[K.tId];}W.completeEvent.fire(K,S);if(K.completeEvent){K.completeEvent.fire(K,S);
-}O={tId:K.tId,argument:V.argument};try{O.responseText=T.contentWindow.document.body?T.contentWindow.document.body.innerHTML:T.contentWindow.document.documentElement.textContent;O.responseXML=T.contentWindow.document.XMLDocument?T.contentWindow.document.XMLDocument:T.contentWindow.document;}catch(X){}if(V&&V.upload){if(!V.scope){V.upload(O);}else{V.upload.apply(V.scope,[O]);}}W.uploadEvent.fire(O);if(K.uploadEvent){K.uploadEvent.fire(O);}F.removeListener(T,"load",N);setTimeout(function(){document.body.removeChild(T);W.releaseObject(K);},100);};F.addListener(T,"load",N);}D.setForm=G;D.resetFormState=C;D.createFrame=B;D.appendPostData=E;D.uploadFile=A;})();YAHOO.register("connection",YAHOO.util.Connect,{version:"2.8.1",build:"19"});(function(){var B=YAHOO.util;var A=function(D,C,E,F){if(!D){}this.init(D,C,E,F);};A.NAME="Anim";A.prototype={toString:function(){var C=this.getEl()||{};var D=C.id||C.tagName;return(this.constructor.NAME+": "+D);},patterns:{noNegatives:/width|height|opacity|padding/i,offsetAttribute:/^((width|height)|(top|left))$/,defaultUnit:/width|height|top$|bottom$|left$|right$/i,offsetUnit:/\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i},doMethod:function(C,E,D){return this.method(this.currentFrame,E,D-E,this.totalFrames);},setAttribute:function(C,F,E){var D=this.getEl();if(this.patterns.noNegatives.test(C)){F=(F>0)?F:0;}if(C in D&&!("style" in D&&C in D.style)){D[C]=F;}else{B.Dom.setStyle(D,C,F+E);}},getAttribute:function(C){var E=this.getEl();var G=B.Dom.getStyle(E,C);if(G!=="auto"&&!this.patterns.offsetUnit.test(G)){return parseFloat(G);}var D=this.patterns.offsetAttribute.exec(C)||[];var H=!!(D[3]);var F=!!(D[2]);if("style" in E){if(F||(B.Dom.getStyle(E,"position")=="absolute"&&H)){G=E["offset"+D[0].charAt(0).toUpperCase()+D[0].substr(1)];}else{G=0;}}else{if(C in E){G=E[C];}}return G;},getDefaultUnit:function(C){if(this.patterns.defaultUnit.test(C)){return"px";}return"";},setRuntimeAttribute:function(D){var I;var E;var F=this.attributes;this.runtimeAttributes[D]={};var H=function(J){return(typeof J!=="undefined");};if(!H(F[D]["to"])&&!H(F[D]["by"])){return false;}I=(H(F[D]["from"]))?F[D]["from"]:this.getAttribute(D);if(H(F[D]["to"])){E=F[D]["to"];}else{if(H(F[D]["by"])){if(I.constructor==Array){E=[];for(var G=0,C=I.length;G<C;++G){E[G]=I[G]+F[D]["by"][G]*1;}}else{E=I+F[D]["by"]*1;}}}this.runtimeAttributes[D].start=I;this.runtimeAttributes[D].end=E;this.runtimeAttributes[D].unit=(H(F[D].unit))?F[D]["unit"]:this.getDefaultUnit(D);return true;},init:function(E,J,I,C){var D=false;var F=null;var H=0;E=B.Dom.get(E);this.attributes=J||{};this.duration=!YAHOO.lang.isUndefined(I)?I:1;this.method=C||B.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=B.AnimMgr.fps;this.setEl=function(M){E=B.Dom.get(M);};this.getEl=function(){return E;};this.isAnimated=function(){return D;};this.getStartTime=function(){return F;};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated()){return false;}this.currentFrame=0;this.totalFrames=(this.useSeconds)?Math.ceil(B.AnimMgr.fps*this.duration):this.duration;if(this.duration===0&&this.useSeconds){this.totalFrames=1;}B.AnimMgr.registerElement(this);return true;};this.stop=function(M){if(!this.isAnimated()){return false;}if(M){this.currentFrame=this.totalFrames;this._onTween.fire();}B.AnimMgr.stop(this);};var L=function(){this.onStart.fire();this.runtimeAttributes={};for(var M in this.attributes){this.setRuntimeAttribute(M);}D=true;H=0;F=new Date();};var K=function(){var O={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};O.toString=function(){return("duration: "+O.duration+", currentFrame: "+O.currentFrame);};this.onTween.fire(O);var N=this.runtimeAttributes;for(var M in N){this.setAttribute(M,this.doMethod(M,N[M].start,N[M].end),N[M].unit);}H+=1;};var G=function(){var M=(new Date()-F)/1000;var N={duration:M,frames:H,fps:H/M};N.toString=function(){return("duration: "+N.duration+", frames: "+N.frames+", fps: "+N.fps);};D=false;H=0;this.onComplete.fire(N);};this._onStart=new B.CustomEvent("_start",this,true);this.onStart=new B.CustomEvent("start",this);this.onTween=new B.CustomEvent("tween",this);this._onTween=new B.CustomEvent("_tween",this,true);this.onComplete=new B.CustomEvent("complete",this);this._onComplete=new B.CustomEvent("_complete",this,true);this._onStart.subscribe(L);this._onTween.subscribe(K);this._onComplete.subscribe(G);}};B.Anim=A;})();YAHOO.util.AnimMgr=new function(){var C=null;var B=[];var A=0;this.fps=1000;this.delay=1;this.registerElement=function(F){B[B.length]=F;A+=1;F._onStart.fire();this.start();};this.unRegister=function(G,F){F=F||E(G);if(!G.isAnimated()||F===-1){return false;}G._onComplete.fire();B.splice(F,1);A-=1;if(A<=0){this.stop();}return true;};this.start=function(){if(C===null){C=setInterval(this.run,this.delay);}};this.stop=function(H){if(!H){clearInterval(C);for(var G=0,F=B.length;G<F;++G){this.unRegister(B[0],0);}B=[];C=null;A=0;}else{this.unRegister(H);}};this.run=function(){for(var H=0,F=B.length;H<F;++H){var G=B[H];if(!G||!G.isAnimated()){continue;}if(G.currentFrame<G.totalFrames||G.totalFrames===null){G.currentFrame+=1;if(G.useSeconds){D(G);}G._onTween.fire();}else{YAHOO.util.AnimMgr.stop(G,H);}}};var E=function(H){for(var G=0,F=B.length;G<F;++G){if(B[G]===H){return G;}}return -1;};var D=function(G){var J=G.totalFrames;var I=G.currentFrame;var H=(G.currentFrame*G.duration*1000/G.totalFrames);var F=(new Date()-G.getStartTime());var K=0;if(F<G.duration*1000){K=Math.round((F/H-1)*G.currentFrame);}else{K=J-(I+1);}if(K>0&&isFinite(K)){if(G.currentFrame+K>=J){K=J-(I+1);}G.currentFrame+=K;}};this._queue=B;this._getIndex=E;};YAHOO.util.Bezier=new function(){this.getPosition=function(E,D){var F=E.length;var C=[];for(var B=0;B<F;++B){C[B]=[E[B][0],E[B][1]];}for(var A=1;A<F;++A){for(B=0;B<F-A;++B){C[B][0]=(1-D)*C[B][0]+D*C[parseInt(B+1,10)][0];C[B][1]=(1-D)*C[B][1]+D*C[parseInt(B+1,10)][1];}}return[C[0][0],C[0][1]];};};(function(){var A=function(F,E,G,H){A.superclass.constructor.call(this,F,E,G,H);};A.NAME="ColorAnim";A.DEFAULT_BGCOLOR="#fff";var C=YAHOO.util;YAHOO.extend(A,C.Anim);var D=A.superclass;var B=A.prototype;B.patterns.color=/color$/i;B.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;B.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;B.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;B.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;B.parseColor=function(E){if(E.length==3){return E;}var F=this.patterns.hex.exec(E);if(F&&F.length==4){return[parseInt(F[1],16),parseInt(F[2],16),parseInt(F[3],16)];}F=this.patterns.rgb.exec(E);if(F&&F.length==4){return[parseInt(F[1],10),parseInt(F[2],10),parseInt(F[3],10)];}F=this.patterns.hex3.exec(E);if(F&&F.length==4){return[parseInt(F[1]+F[1],16),parseInt(F[2]+F[2],16),parseInt(F[3]+F[3],16)];
-}return null;};B.getAttribute=function(E){var G=this.getEl();if(this.patterns.color.test(E)){var I=YAHOO.util.Dom.getStyle(G,E);var H=this;if(this.patterns.transparent.test(I)){var F=YAHOO.util.Dom.getAncestorBy(G,function(J){return !H.patterns.transparent.test(I);});if(F){I=C.Dom.getStyle(F,E);}else{I=A.DEFAULT_BGCOLOR;}}}else{I=D.getAttribute.call(this,E);}return I;};B.doMethod=function(F,J,G){var I;if(this.patterns.color.test(F)){I=[];for(var H=0,E=J.length;H<E;++H){I[H]=D.doMethod.call(this,F,J[H],G[H]);}I="rgb("+Math.floor(I[0])+","+Math.floor(I[1])+","+Math.floor(I[2])+")";}else{I=D.doMethod.call(this,F,J,G);}return I;};B.setRuntimeAttribute=function(F){D.setRuntimeAttribute.call(this,F);if(this.patterns.color.test(F)){var H=this.attributes;var J=this.parseColor(this.runtimeAttributes[F].start);var G=this.parseColor(this.runtimeAttributes[F].end);if(typeof H[F]["to"]==="undefined"&&typeof H[F]["by"]!=="undefined"){G=this.parseColor(H[F].by);for(var I=0,E=J.length;I<E;++I){G[I]=J[I]+G[I];}}this.runtimeAttributes[F].start=J;this.runtimeAttributes[F].end=G;}};C.ColorAnim=A;})();
-/*
-TERMS OF USE - EASING EQUATIONS
-Open source under the BSD License.
-Copyright 2001 Robert Penner All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-YAHOO.util.Easing={easeNone:function(B,A,D,C){return D*B/C+A;},easeIn:function(B,A,D,C){return D*(B/=C)*B+A;},easeOut:function(B,A,D,C){return -D*(B/=C)*(B-2)+A;},easeBoth:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B+A;}return -D/2*((--B)*(B-2)-1)+A;},easeInStrong:function(B,A,D,C){return D*(B/=C)*B*B*B+A;},easeOutStrong:function(B,A,D,C){return -D*((B=B/C-1)*B*B*B-1)+A;},easeBothStrong:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B*B*B+A;}return -D/2*((B-=2)*B*B*B-2)+A;},elasticIn:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return -(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;},elasticOut:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return B*Math.pow(2,-10*C)*Math.sin((C*F-D)*(2*Math.PI)/E)+G+A;},elasticBoth:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F/2)==2){return A+G;}if(!E){E=F*(0.3*1.5);}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}if(C<1){return -0.5*(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;}return B*Math.pow(2,-10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E)*0.5+G+A;},backIn:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*(B/=D)*B*((C+1)*B-C)+A;},backOut:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*((B=B/D-1)*B*((C+1)*B+C)+1)+A;},backBoth:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}if((B/=D/2)<1){return E/2*(B*B*(((C*=(1.525))+1)*B-C))+A;}return E/2*((B-=2)*B*(((C*=(1.525))+1)*B+C)+2)+A;},bounceIn:function(B,A,D,C){return D-YAHOO.util.Easing.bounceOut(C-B,0,D,C)+A;},bounceOut:function(B,A,D,C){if((B/=C)<(1/2.75)){return D*(7.5625*B*B)+A;}else{if(B<(2/2.75)){return D*(7.5625*(B-=(1.5/2.75))*B+0.75)+A;}else{if(B<(2.5/2.75)){return D*(7.5625*(B-=(2.25/2.75))*B+0.9375)+A;}}}return D*(7.5625*(B-=(2.625/2.75))*B+0.984375)+A;},bounceBoth:function(B,A,D,C){if(B<C/2){return YAHOO.util.Easing.bounceIn(B*2,0,D,C)*0.5+A;}return YAHOO.util.Easing.bounceOut(B*2-C,0,D,C)*0.5+D*0.5+A;}};(function(){var A=function(H,G,I,J){if(H){A.superclass.constructor.call(this,H,G,I,J);}};A.NAME="Motion";var E=YAHOO.util;YAHOO.extend(A,E.ColorAnim);var F=A.superclass;var C=A.prototype;C.patterns.points=/^points$/i;C.setAttribute=function(G,I,H){if(this.patterns.points.test(G)){H=H||"px";F.setAttribute.call(this,"left",I[0],H);F.setAttribute.call(this,"top",I[1],H);}else{F.setAttribute.call(this,G,I,H);}};C.getAttribute=function(G){if(this.patterns.points.test(G)){var H=[F.getAttribute.call(this,"left"),F.getAttribute.call(this,"top")];}else{H=F.getAttribute.call(this,G);}return H;};C.doMethod=function(G,K,H){var J=null;if(this.patterns.points.test(G)){var I=this.method(this.currentFrame,0,100,this.totalFrames)/100;J=E.Bezier.getPosition(this.runtimeAttributes[G],I);}else{J=F.doMethod.call(this,G,K,H);}return J;};C.setRuntimeAttribute=function(P){if(this.patterns.points.test(P)){var H=this.getEl();var J=this.attributes;var G;var L=J["points"]["control"]||[];var I;var M,O;if(L.length>0&&!(L[0] instanceof Array)){L=[L];}else{var K=[];for(M=0,O=L.length;M<O;++M){K[M]=L[M];}L=K;}if(E.Dom.getStyle(H,"position")=="static"){E.Dom.setStyle(H,"position","relative");}if(D(J["points"]["from"])){E.Dom.setXY(H,J["points"]["from"]);
-}else{E.Dom.setXY(H,E.Dom.getXY(H));}G=this.getAttribute("points");if(D(J["points"]["to"])){I=B.call(this,J["points"]["to"],G);var N=E.Dom.getXY(this.getEl());for(M=0,O=L.length;M<O;++M){L[M]=B.call(this,L[M],G);}}else{if(D(J["points"]["by"])){I=[G[0]+J["points"]["by"][0],G[1]+J["points"]["by"][1]];for(M=0,O=L.length;M<O;++M){L[M]=[G[0]+L[M][0],G[1]+L[M][1]];}}}this.runtimeAttributes[P]=[G];if(L.length>0){this.runtimeAttributes[P]=this.runtimeAttributes[P].concat(L);}this.runtimeAttributes[P][this.runtimeAttributes[P].length]=I;}else{F.setRuntimeAttribute.call(this,P);}};var B=function(G,I){var H=E.Dom.getXY(this.getEl());G=[G[0]-H[0]+I[0],G[1]-H[1]+I[1]];return G;};var D=function(G){return(typeof G!=="undefined");};E.Motion=A;})();(function(){var D=function(F,E,G,H){if(F){D.superclass.constructor.call(this,F,E,G,H);}};D.NAME="Scroll";var B=YAHOO.util;YAHOO.extend(D,B.ColorAnim);var C=D.superclass;var A=D.prototype;A.doMethod=function(E,H,F){var G=null;if(E=="scroll"){G=[this.method(this.currentFrame,H[0],F[0]-H[0],this.totalFrames),this.method(this.currentFrame,H[1],F[1]-H[1],this.totalFrames)];}else{G=C.doMethod.call(this,E,H,F);}return G;};A.getAttribute=function(E){var G=null;var F=this.getEl();if(E=="scroll"){G=[F.scrollLeft,F.scrollTop];}else{G=C.getAttribute.call(this,E);}return G;};A.setAttribute=function(E,H,G){var F=this.getEl();if(E=="scroll"){F.scrollLeft=H[0];F.scrollTop=H[1];}else{C.setAttribute.call(this,E,H,G);}};B.Scroll=D;})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.8.1",build:"19"});if(!YAHOO.util.DragDropMgr){YAHOO.util.DragDropMgr=function(){var A=YAHOO.util.Event,B=YAHOO.util.Dom;return{useShim:false,_shimActive:false,_shimState:false,_debugShim:false,_createShim:function(){var C=document.createElement("div");C.id="yui-ddm-shim";if(document.body.firstChild){document.body.insertBefore(C,document.body.firstChild);}else{document.body.appendChild(C);}C.style.display="none";C.style.backgroundColor="red";C.style.position="absolute";C.style.zIndex="99999";B.setStyle(C,"opacity","0");this._shim=C;A.on(C,"mouseup",this.handleMouseUp,this,true);A.on(C,"mousemove",this.handleMouseMove,this,true);A.on(window,"scroll",this._sizeShim,this,true);},_sizeShim:function(){if(this._shimActive){var C=this._shim;C.style.height=B.getDocumentHeight()+"px";C.style.width=B.getDocumentWidth()+"px";C.style.top="0";C.style.left="0";}},_activateShim:function(){if(this.useShim){if(!this._shim){this._createShim();}this._shimActive=true;var C=this._shim,D="0";if(this._debugShim){D=".5";}B.setStyle(C,"opacity",D);this._sizeShim();C.style.display="block";}},_deactivateShim:function(){this._shim.style.display="none";this._shimActive=false;},_shim:null,ids:{},handleIds:{},dragCurrent:null,dragOvers:{},deltaX:0,deltaY:0,preventDefault:true,stopPropagation:true,initialized:false,locked:false,interactionInfo:null,init:function(){this.initialized=true;},POINT:0,INTERSECT:1,STRICT_INTERSECT:2,mode:0,_execOnAll:function(E,D){for(var F in this.ids){for(var C in this.ids[F]){var G=this.ids[F][C];if(!this.isTypeOfDD(G)){continue;}G[E].apply(G,D);}}},_onLoad:function(){this.init();A.on(document,"mouseup",this.handleMouseUp,this,true);A.on(document,"mousemove",this.handleMouseMove,this,true);A.on(window,"unload",this._onUnload,this,true);A.on(window,"resize",this._onResize,this,true);},_onResize:function(C){this._execOnAll("resetConstraints",[]);},lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isLocked:function(){return this.locked;},locationCache:{},useCache:true,clickPixelThresh:3,clickTimeThresh:1000,dragThreshMet:false,clickTimeout:null,startX:0,startY:0,fromTimeout:false,regDragDrop:function(D,C){if(!this.initialized){this.init();}if(!this.ids[C]){this.ids[C]={};}this.ids[C][D.id]=D;},removeDDFromGroup:function(E,C){if(!this.ids[C]){this.ids[C]={};}var D=this.ids[C];if(D&&D[E.id]){delete D[E.id];}},_remove:function(E){for(var D in E.groups){if(D){var C=this.ids[D];if(C&&C[E.id]){delete C[E.id];}}}delete this.handleIds[E.id];},regHandle:function(D,C){if(!this.handleIds[D]){this.handleIds[D]={};}this.handleIds[D][C]=C;},isDragDrop:function(C){return(this.getDDById(C))?true:false;},getRelated:function(H,D){var G=[];for(var F in H.groups){for(var E in this.ids[F]){var C=this.ids[F][E];if(!this.isTypeOfDD(C)){continue;}if(!D||C.isTarget){G[G.length]=C;}}}return G;},isLegalTarget:function(G,F){var D=this.getRelated(G,true);for(var E=0,C=D.length;E<C;++E){if(D[E].id==F.id){return true;}}return false;},isTypeOfDD:function(C){return(C&&C.__ygDragDrop);},isHandle:function(D,C){return(this.handleIds[D]&&this.handleIds[D][C]);},getDDById:function(D){for(var C in this.ids){if(this.ids[C][D]){return this.ids[C][D];}}return null;},handleMouseDown:function(E,D){this.currentTarget=YAHOO.util.Event.getTarget(E);this.dragCurrent=D;var C=D.getEl();this.startX=YAHOO.util.Event.getPageX(E);this.startY=YAHOO.util.Event.getPageY(E);this.deltaX=this.startX-C.offsetLeft;this.deltaY=this.startY-C.offsetTop;this.dragThreshMet=false;this.clickTimeout=setTimeout(function(){var F=YAHOO.util.DDM;F.startDrag(F.startX,F.startY);F.fromTimeout=true;},this.clickTimeThresh);},startDrag:function(C,E){if(this.dragCurrent&&this.dragCurrent.useShim){this._shimState=this.useShim;this.useShim=true;}this._activateShim();clearTimeout(this.clickTimeout);var D=this.dragCurrent;if(D&&D.events.b4StartDrag){D.b4StartDrag(C,E);D.fireEvent("b4StartDragEvent",{x:C,y:E});}if(D&&D.events.startDrag){D.startDrag(C,E);D.fireEvent("startDragEvent",{x:C,y:E});}this.dragThreshMet=true;},handleMouseUp:function(C){if(this.dragCurrent){clearTimeout(this.clickTimeout);if(this.dragThreshMet){if(this.fromTimeout){this.fromTimeout=false;this.handleMouseMove(C);}this.fromTimeout=false;this.fireEvents(C,true);}else{}this.stopDrag(C);this.stopEvent(C);}},stopEvent:function(C){if(this.stopPropagation){YAHOO.util.Event.stopPropagation(C);}if(this.preventDefault){YAHOO.util.Event.preventDefault(C);}},stopDrag:function(E,D){var C=this.dragCurrent;if(C&&!D){if(this.dragThreshMet){if(C.events.b4EndDrag){C.b4EndDrag(E);C.fireEvent("b4EndDragEvent",{e:E});}if(C.events.endDrag){C.endDrag(E);C.fireEvent("endDragEvent",{e:E});}}if(C.events.mouseUp){C.onMouseUp(E);C.fireEvent("mouseUpEvent",{e:E});}}if(this._shimActive){this._deactivateShim();if(this.dragCurrent&&this.dragCurrent.useShim){this.useShim=this._shimState;this._shimState=false;}}this.dragCurrent=null;this.dragOvers={};},handleMouseMove:function(F){var C=this.dragCurrent;if(C){if(YAHOO.util.Event.isIE&&!F.button){this.stopEvent(F);return this.handleMouseUp(F);}else{if(F.clientX<0||F.clientY<0){}}if(!this.dragThreshMet){var E=Math.abs(this.startX-YAHOO.util.Event.getPageX(F));var D=Math.abs(this.startY-YAHOO.util.Event.getPageY(F));if(E>this.clickPixelThresh||D>this.clickPixelThresh){this.startDrag(this.startX,this.startY);}}if(this.dragThreshMet){if(C&&C.events.b4Drag){C.b4Drag(F);C.fireEvent("b4DragEvent",{e:F});}if(C&&C.events.drag){C.onDrag(F);C.fireEvent("dragEvent",{e:F});}if(C){this.fireEvents(F,false);}}this.stopEvent(F);}},fireEvents:function(V,L){var a=this.dragCurrent;if(!a||a.isLocked()||a.dragOnly){return;}var N=YAHOO.util.Event.getPageX(V),M=YAHOO.util.Event.getPageY(V),P=new YAHOO.util.Point(N,M),K=a.getTargetCoord(P.x,P.y),F=a.getDragEl(),E=["out","over","drop","enter"],U=new YAHOO.util.Region(K.y,K.x+F.offsetWidth,K.y+F.offsetHeight,K.x),I=[],D={},Q=[],c={outEvts:[],overEvts:[],dropEvts:[],enterEvts:[]};for(var S in this.dragOvers){var d=this.dragOvers[S];if(!this.isTypeOfDD(d)){continue;
-}if(!this.isOverTarget(P,d,this.mode,U)){c.outEvts.push(d);}I[S]=true;delete this.dragOvers[S];}for(var R in a.groups){if("string"!=typeof R){continue;}for(S in this.ids[R]){var G=this.ids[R][S];if(!this.isTypeOfDD(G)){continue;}if(G.isTarget&&!G.isLocked()&&G!=a){if(this.isOverTarget(P,G,this.mode,U)){D[R]=true;if(L){c.dropEvts.push(G);}else{if(!I[G.id]){c.enterEvts.push(G);}else{c.overEvts.push(G);}this.dragOvers[G.id]=G;}}}}}this.interactionInfo={out:c.outEvts,enter:c.enterEvts,over:c.overEvts,drop:c.dropEvts,point:P,draggedRegion:U,sourceRegion:this.locationCache[a.id],validDrop:L};for(var C in D){Q.push(C);}if(L&&!c.dropEvts.length){this.interactionInfo.validDrop=false;if(a.events.invalidDrop){a.onInvalidDrop(V);a.fireEvent("invalidDropEvent",{e:V});}}for(S=0;S<E.length;S++){var Y=null;if(c[E[S]+"Evts"]){Y=c[E[S]+"Evts"];}if(Y&&Y.length){var H=E[S].charAt(0).toUpperCase()+E[S].substr(1),X="onDrag"+H,J="b4Drag"+H,O="drag"+H+"Event",W="drag"+H;if(this.mode){if(a.events[J]){a[J](V,Y,Q);a.fireEvent(J+"Event",{event:V,info:Y,group:Q});}if(a.events[W]){a[X](V,Y,Q);a.fireEvent(O,{event:V,info:Y,group:Q});}}else{for(var Z=0,T=Y.length;Z<T;++Z){if(a.events[J]){a[J](V,Y[Z].id,Q[0]);a.fireEvent(J+"Event",{event:V,info:Y[Z].id,group:Q[0]});}if(a.events[W]){a[X](V,Y[Z].id,Q[0]);a.fireEvent(O,{event:V,info:Y[Z].id,group:Q[0]});}}}}}},getBestMatch:function(E){var G=null;var D=E.length;if(D==1){G=E[0];}else{for(var F=0;F<D;++F){var C=E[F];if(this.mode==this.INTERSECT&&C.cursorIsOver){G=C;break;}else{if(!G||!G.overlap||(C.overlap&&G.overlap.getArea()<C.overlap.getArea())){G=C;}}}}return G;},refreshCache:function(D){var F=D||this.ids;for(var C in F){if("string"!=typeof C){continue;}for(var E in this.ids[C]){var G=this.ids[C][E];if(this.isTypeOfDD(G)){var H=this.getLocation(G);if(H){this.locationCache[G.id]=H;}else{delete this.locationCache[G.id];}}}}},verifyEl:function(D){try{if(D){var C=D.offsetParent;if(C){return true;}}}catch(E){}return false;},getLocation:function(H){if(!this.isTypeOfDD(H)){return null;}var F=H.getEl(),K,E,D,M,L,N,C,J,G;try{K=YAHOO.util.Dom.getXY(F);}catch(I){}if(!K){return null;}E=K[0];D=E+F.offsetWidth;M=K[1];L=M+F.offsetHeight;N=M-H.padding[0];C=D+H.padding[1];J=L+H.padding[2];G=E-H.padding[3];return new YAHOO.util.Region(N,C,J,G);},isOverTarget:function(K,C,E,F){var G=this.locationCache[C.id];if(!G||!this.useCache){G=this.getLocation(C);this.locationCache[C.id]=G;}if(!G){return false;}C.cursorIsOver=G.contains(K);var J=this.dragCurrent;if(!J||(!E&&!J.constrainX&&!J.constrainY)){return C.cursorIsOver;}C.overlap=null;if(!F){var H=J.getTargetCoord(K.x,K.y);var D=J.getDragEl();F=new YAHOO.util.Region(H.y,H.x+D.offsetWidth,H.y+D.offsetHeight,H.x);}var I=F.intersect(G);if(I){C.overlap=I;return(E)?true:C.cursorIsOver;}else{return false;}},_onUnload:function(D,C){this.unregAll();},unregAll:function(){if(this.dragCurrent){this.stopDrag();this.dragCurrent=null;}this._execOnAll("unreg",[]);this.ids={};},elementCache:{},getElWrapper:function(D){var C=this.elementCache[D];if(!C||!C.el){C=this.elementCache[D]=new this.ElementWrapper(YAHOO.util.Dom.get(D));}return C;},getElement:function(C){return YAHOO.util.Dom.get(C);},getCss:function(D){var C=YAHOO.util.Dom.get(D);return(C)?C.style:null;},ElementWrapper:function(C){this.el=C||null;this.id=this.el&&C.id;this.css=this.el&&C.style;},getPosX:function(C){return YAHOO.util.Dom.getX(C);},getPosY:function(C){return YAHOO.util.Dom.getY(C);},swapNode:function(E,C){if(E.swapNode){E.swapNode(C);}else{var F=C.parentNode;var D=C.nextSibling;if(D==E){F.insertBefore(E,C);}else{if(C==E.nextSibling){F.insertBefore(C,E);}else{E.parentNode.replaceChild(C,E);F.insertBefore(E,D);}}}},getScroll:function(){var E,C,F=document.documentElement,D=document.body;if(F&&(F.scrollTop||F.scrollLeft)){E=F.scrollTop;C=F.scrollLeft;}else{if(D){E=D.scrollTop;C=D.scrollLeft;}else{}}return{top:E,left:C};},getStyle:function(D,C){return YAHOO.util.Dom.getStyle(D,C);},getScrollTop:function(){return this.getScroll().top;},getScrollLeft:function(){return this.getScroll().left;},moveToEl:function(C,E){var D=YAHOO.util.Dom.getXY(E);YAHOO.util.Dom.setXY(C,D);},getClientHeight:function(){return YAHOO.util.Dom.getViewportHeight();},getClientWidth:function(){return YAHOO.util.Dom.getViewportWidth();},numericSort:function(D,C){return(D-C);},_timeoutCount:0,_addListeners:function(){var C=YAHOO.util.DDM;if(YAHOO.util.Event&&document){C._onLoad();}else{if(C._timeoutCount>2000){}else{setTimeout(C._addListeners,10);if(document&&document.body){C._timeoutCount+=1;}}}},handleWasClicked:function(C,E){if(this.isHandle(E,C.id)){return true;}else{var D=C.parentNode;while(D){if(this.isHandle(E,D.id)){return true;}else{D=D.parentNode;}}}return false;}};}();YAHOO.util.DDM=YAHOO.util.DragDropMgr;YAHOO.util.DDM._addListeners();}(function(){var A=YAHOO.util.Event;var B=YAHOO.util.Dom;YAHOO.util.DragDrop=function(E,C,D){if(E){this.init(E,C,D);}};YAHOO.util.DragDrop.prototype={events:null,on:function(){this.subscribe.apply(this,arguments);},id:null,config:null,dragElId:null,handleElId:null,invalidHandleTypes:null,invalidHandleIds:null,invalidHandleClasses:null,startPageX:0,startPageY:0,groups:null,locked:false,lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isTarget:true,padding:null,dragOnly:false,useShim:false,_domRef:null,__ygDragDrop:true,constrainX:false,constrainY:false,minX:0,maxX:0,minY:0,maxY:0,deltaX:0,deltaY:0,maintainOffset:false,xTicks:null,yTicks:null,primaryButtonOnly:true,available:false,hasOuterHandles:false,cursorIsOver:false,overlap:null,b4StartDrag:function(C,D){},startDrag:function(C,D){},b4Drag:function(C){},onDrag:function(C){},onDragEnter:function(C,D){},b4DragOver:function(C){},onDragOver:function(C,D){},b4DragOut:function(C){},onDragOut:function(C,D){},b4DragDrop:function(C){},onDragDrop:function(C,D){},onInvalidDrop:function(C){},b4EndDrag:function(C){},endDrag:function(C){},b4MouseDown:function(C){},onMouseDown:function(C){},onMouseUp:function(C){},onAvailable:function(){},getEl:function(){if(!this._domRef){this._domRef=B.get(this.id);
-}return this._domRef;},getDragEl:function(){return B.get(this.dragElId);},init:function(F,C,D){this.initTarget(F,C,D);A.on(this._domRef||this.id,"mousedown",this.handleMouseDown,this,true);for(var E in this.events){this.createEvent(E+"Event");}},initTarget:function(E,C,D){this.config=D||{};this.events={};this.DDM=YAHOO.util.DDM;this.groups={};if(typeof E!=="string"){this._domRef=E;E=B.generateId(E);}this.id=E;this.addToGroup((C)?C:"default");this.handleElId=E;A.onAvailable(E,this.handleOnAvailable,this,true);this.setDragElId(E);this.invalidHandleTypes={A:"A"};this.invalidHandleIds={};this.invalidHandleClasses=[];this.applyConfig();},applyConfig:function(){this.events={mouseDown:true,b4MouseDown:true,mouseUp:true,b4StartDrag:true,startDrag:true,b4EndDrag:true,endDrag:true,drag:true,b4Drag:true,invalidDrop:true,b4DragOut:true,dragOut:true,dragEnter:true,b4DragOver:true,dragOver:true,b4DragDrop:true,dragDrop:true};if(this.config.events){for(var C in this.config.events){if(this.config.events[C]===false){this.events[C]=false;}}}this.padding=this.config.padding||[0,0,0,0];this.isTarget=(this.config.isTarget!==false);this.maintainOffset=(this.config.maintainOffset);this.primaryButtonOnly=(this.config.primaryButtonOnly!==false);this.dragOnly=((this.config.dragOnly===true)?true:false);this.useShim=((this.config.useShim===true)?true:false);},handleOnAvailable:function(){this.available=true;this.resetConstraints();this.onAvailable();},setPadding:function(E,C,F,D){if(!C&&0!==C){this.padding=[E,E,E,E];}else{if(!F&&0!==F){this.padding=[E,C,E,C];}else{this.padding=[E,C,F,D];}}},setInitPosition:function(F,E){var G=this.getEl();if(!this.DDM.verifyEl(G)){if(G&&G.style&&(G.style.display=="none")){}else{}return;}var D=F||0;var C=E||0;var H=B.getXY(G);this.initPageX=H[0]-D;this.initPageY=H[1]-C;this.lastPageX=H[0];this.lastPageY=H[1];this.setStartPosition(H);},setStartPosition:function(D){var C=D||B.getXY(this.getEl());this.deltaSetXY=null;this.startPageX=C[0];this.startPageY=C[1];},addToGroup:function(C){this.groups[C]=true;this.DDM.regDragDrop(this,C);},removeFromGroup:function(C){if(this.groups[C]){delete this.groups[C];}this.DDM.removeDDFromGroup(this,C);},setDragElId:function(C){this.dragElId=C;},setHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.handleElId=C;this.DDM.regHandle(this.id,C);},setOuterHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}A.on(C,"mousedown",this.handleMouseDown,this,true);this.setHandleElId(C);this.hasOuterHandles=true;},unreg:function(){A.removeListener(this.id,"mousedown",this.handleMouseDown);this._domRef=null;this.DDM._remove(this);},isLocked:function(){return(this.DDM.isLocked()||this.locked);},handleMouseDown:function(J,I){var D=J.which||J.button;if(this.primaryButtonOnly&&D>1){return;}if(this.isLocked()){return;}var C=this.b4MouseDown(J),F=true;if(this.events.b4MouseDown){F=this.fireEvent("b4MouseDownEvent",J);}var E=this.onMouseDown(J),H=true;if(this.events.mouseDown){H=this.fireEvent("mouseDownEvent",J);}if((C===false)||(E===false)||(F===false)||(H===false)){return;}this.DDM.refreshCache(this.groups);var G=new YAHOO.util.Point(A.getPageX(J),A.getPageY(J));if(!this.hasOuterHandles&&!this.DDM.isOverTarget(G,this)){}else{if(this.clickValidator(J)){this.setStartPosition();this.DDM.handleMouseDown(J,this);this.DDM.stopEvent(J);}else{}}},clickValidator:function(D){var C=YAHOO.util.Event.getTarget(D);return(this.isValidHandleChild(C)&&(this.id==this.handleElId||this.DDM.handleWasClicked(C,this.id)));},getTargetCoord:function(E,D){var C=E-this.deltaX;var F=D-this.deltaY;if(this.constrainX){if(C<this.minX){C=this.minX;}if(C>this.maxX){C=this.maxX;}}if(this.constrainY){if(F<this.minY){F=this.minY;}if(F>this.maxY){F=this.maxY;}}C=this.getTick(C,this.xTicks);F=this.getTick(F,this.yTicks);return{x:C,y:F};},addInvalidHandleType:function(C){var D=C.toUpperCase();this.invalidHandleTypes[D]=D;},addInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.invalidHandleIds[C]=C;},addInvalidHandleClass:function(C){this.invalidHandleClasses.push(C);},removeInvalidHandleType:function(C){var D=C.toUpperCase();delete this.invalidHandleTypes[D];},removeInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}delete this.invalidHandleIds[C];},removeInvalidHandleClass:function(D){for(var E=0,C=this.invalidHandleClasses.length;E<C;++E){if(this.invalidHandleClasses[E]==D){delete this.invalidHandleClasses[E];}}},isValidHandleChild:function(F){var E=true;var H;try{H=F.nodeName.toUpperCase();}catch(G){H=F.nodeName;}E=E&&!this.invalidHandleTypes[H];E=E&&!this.invalidHandleIds[F.id];for(var D=0,C=this.invalidHandleClasses.length;E&&D<C;++D){E=!B.hasClass(F,this.invalidHandleClasses[D]);}return E;},setXTicks:function(F,C){this.xTicks=[];this.xTickSize=C;var E={};for(var D=this.initPageX;D>=this.minX;D=D-C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}for(D=this.initPageX;D<=this.maxX;D=D+C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}this.xTicks.sort(this.DDM.numericSort);},setYTicks:function(F,C){this.yTicks=[];this.yTickSize=C;var E={};for(var D=this.initPageY;D>=this.minY;D=D-C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}for(D=this.initPageY;D<=this.maxY;D=D+C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}this.yTicks.sort(this.DDM.numericSort);},setXConstraint:function(E,D,C){this.leftConstraint=parseInt(E,10);this.rightConstraint=parseInt(D,10);this.minX=this.initPageX-this.leftConstraint;this.maxX=this.initPageX+this.rightConstraint;if(C){this.setXTicks(this.initPageX,C);}this.constrainX=true;},clearConstraints:function(){this.constrainX=false;this.constrainY=false;this.clearTicks();},clearTicks:function(){this.xTicks=null;this.yTicks=null;this.xTickSize=0;this.yTickSize=0;},setYConstraint:function(C,E,D){this.topConstraint=parseInt(C,10);this.bottomConstraint=parseInt(E,10);this.minY=this.initPageY-this.topConstraint;this.maxY=this.initPageY+this.bottomConstraint;if(D){this.setYTicks(this.initPageY,D);
-}this.constrainY=true;},resetConstraints:function(){if(this.initPageX||this.initPageX===0){var D=(this.maintainOffset)?this.lastPageX-this.initPageX:0;var C=(this.maintainOffset)?this.lastPageY-this.initPageY:0;this.setInitPosition(D,C);}else{this.setInitPosition();}if(this.constrainX){this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);}if(this.constrainY){this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize);}},getTick:function(I,F){if(!F){return I;}else{if(F[0]>=I){return F[0];}else{for(var D=0,C=F.length;D<C;++D){var E=D+1;if(F[E]&&F[E]>=I){var H=I-F[D];var G=F[E]-I;return(G>H)?F[D]:F[E];}}return F[F.length-1];}}},toString:function(){return("DragDrop "+this.id);}};YAHOO.augment(YAHOO.util.DragDrop,YAHOO.util.EventProvider);})();YAHOO.util.DD=function(C,A,B){if(C){this.init(C,A,B);}};YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop,{scroll:true,autoOffset:function(C,B){var A=C-this.startPageX;var D=B-this.startPageY;this.setDelta(A,D);},setDelta:function(B,A){this.deltaX=B;this.deltaY=A;},setDragElPos:function(C,B){var A=this.getDragEl();this.alignElWithMouse(A,C,B);},alignElWithMouse:function(C,G,F){var E=this.getTargetCoord(G,F);if(!this.deltaSetXY){var H=[E.x,E.y];YAHOO.util.Dom.setXY(C,H);var D=parseInt(YAHOO.util.Dom.getStyle(C,"left"),10);var B=parseInt(YAHOO.util.Dom.getStyle(C,"top"),10);this.deltaSetXY=[D-E.x,B-E.y];}else{YAHOO.util.Dom.setStyle(C,"left",(E.x+this.deltaSetXY[0])+"px");YAHOO.util.Dom.setStyle(C,"top",(E.y+this.deltaSetXY[1])+"px");}this.cachePosition(E.x,E.y);var A=this;setTimeout(function(){A.autoScroll.call(A,E.x,E.y,C.offsetHeight,C.offsetWidth);},0);},cachePosition:function(B,A){if(B){this.lastPageX=B;this.lastPageY=A;}else{var C=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=C[0];this.lastPageY=C[1];}},autoScroll:function(J,I,E,K){if(this.scroll){var L=this.DDM.getClientHeight();var B=this.DDM.getClientWidth();var N=this.DDM.getScrollTop();var D=this.DDM.getScrollLeft();var H=E+I;var M=K+J;var G=(L+N-I-this.deltaY);var F=(B+D-J-this.deltaX);var C=40;var A=(document.all)?80:30;if(H>L&&G<C){window.scrollTo(D,N+A);}if(I<N&&N>0&&I-N<C){window.scrollTo(D,N-A);}if(M>B&&F<C){window.scrollTo(D+A,N);}if(J<D&&D>0&&J-D<C){window.scrollTo(D-A,N);}}},applyConfig:function(){YAHOO.util.DD.superclass.applyConfig.call(this);this.scroll=(this.config.scroll!==false);},b4MouseDown:function(A){this.setStartPosition();this.autoOffset(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},b4Drag:function(A){this.setDragElPos(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},toString:function(){return("DD "+this.id);}});YAHOO.util.DDProxy=function(C,A,B){if(C){this.init(C,A,B);this.initFrame();}};YAHOO.util.DDProxy.dragElId="ygddfdiv";YAHOO.extend(YAHOO.util.DDProxy,YAHOO.util.DD,{resizeFrame:true,centerFrame:false,createFrame:function(){var B=this,A=document.body;if(!A||!A.firstChild){setTimeout(function(){B.createFrame();},50);return;}var F=this.getDragEl(),E=YAHOO.util.Dom;if(!F){F=document.createElement("div");F.id=this.dragElId;var D=F.style;D.position="absolute";D.visibility="hidden";D.cursor="move";D.border="2px solid #aaa";D.zIndex=999;D.height="25px";D.width="25px";var C=document.createElement("div");E.setStyle(C,"height","100%");E.setStyle(C,"width","100%");E.setStyle(C,"background-color","#ccc");E.setStyle(C,"opacity","0");F.appendChild(C);A.insertBefore(F,A.firstChild);}},initFrame:function(){this.createFrame();},applyConfig:function(){YAHOO.util.DDProxy.superclass.applyConfig.call(this);this.resizeFrame=(this.config.resizeFrame!==false);this.centerFrame=(this.config.centerFrame);this.setDragElId(this.config.dragElId||YAHOO.util.DDProxy.dragElId);},showFrame:function(E,D){var C=this.getEl();var A=this.getDragEl();var B=A.style;this._resizeProxy();if(this.centerFrame){this.setDelta(Math.round(parseInt(B.width,10)/2),Math.round(parseInt(B.height,10)/2));}this.setDragElPos(E,D);YAHOO.util.Dom.setStyle(A,"visibility","visible");},_resizeProxy:function(){if(this.resizeFrame){var H=YAHOO.util.Dom;var B=this.getEl();var C=this.getDragEl();var G=parseInt(H.getStyle(C,"borderTopWidth"),10);var I=parseInt(H.getStyle(C,"borderRightWidth"),10);var F=parseInt(H.getStyle(C,"borderBottomWidth"),10);var D=parseInt(H.getStyle(C,"borderLeftWidth"),10);if(isNaN(G)){G=0;}if(isNaN(I)){I=0;}if(isNaN(F)){F=0;}if(isNaN(D)){D=0;}var E=Math.max(0,B.offsetWidth-I-D);var A=Math.max(0,B.offsetHeight-G-F);H.setStyle(C,"width",E+"px");H.setStyle(C,"height",A+"px");}},b4MouseDown:function(B){this.setStartPosition();var A=YAHOO.util.Event.getPageX(B);var C=YAHOO.util.Event.getPageY(B);this.autoOffset(A,C);},b4StartDrag:function(A,B){this.showFrame(A,B);},b4EndDrag:function(A){YAHOO.util.Dom.setStyle(this.getDragEl(),"visibility","hidden");},endDrag:function(D){var C=YAHOO.util.Dom;var B=this.getEl();var A=this.getDragEl();C.setStyle(A,"visibility","");C.setStyle(B,"visibility","hidden");YAHOO.util.DDM.moveToEl(B,A);C.setStyle(A,"visibility","hidden");C.setStyle(B,"visibility","");},toString:function(){return("DDProxy "+this.id);}});YAHOO.util.DDTarget=function(C,A,B){if(C){this.initTarget(C,A,B);}};YAHOO.extend(YAHOO.util.DDTarget,YAHOO.util.DragDrop,{toString:function(){return("DDTarget "+this.id);}});YAHOO.register("dragdrop",YAHOO.util.DragDropMgr,{version:"2.8.1",build:"19"});YAHOO.util.Attribute=function(B,A){if(A){this.owner=A;this.configure(B,true);}};YAHOO.util.Attribute.prototype={name:undefined,value:null,owner:null,readOnly:false,writeOnce:false,_initialConfig:null,_written:false,method:null,setter:null,getter:null,validator:null,getValue:function(){var A=this.value;if(this.getter){A=this.getter.call(this.owner,this.name,A);}return A;},setValue:function(F,B){var E,A=this.owner,C=this.name;var D={type:C,prevValue:this.getValue(),newValue:F};if(this.readOnly||(this.writeOnce&&this._written)){return false;}if(this.validator&&!this.validator.call(A,F)){return false;}if(!B){E=A.fireBeforeChangeEvent(D);if(E===false){return false;}}if(this.setter){F=this.setter.call(A,F,this.name);if(F===undefined){}}if(this.method){this.method.call(A,F,this.name);}this.value=F;this._written=true;D.type=C;if(!B){this.owner.fireChangeEvent(D);}return true;},configure:function(B,C){B=B||{};if(C){this._written=false;}this._initialConfig=this._initialConfig||{};for(var A in B){if(B.hasOwnProperty(A)){this[A]=B[A];if(C){this._initialConfig[A]=B[A];}}}},resetValue:function(){return this.setValue(this._initialConfig.value);},resetConfig:function(){this.configure(this._initialConfig,true);},refresh:function(A){this.setValue(this.value,A);}};(function(){var A=YAHOO.util.Lang;YAHOO.util.AttributeProvider=function(){};YAHOO.util.AttributeProvider.prototype={_configs:null,get:function(C){this._configs=this._configs||{};var B=this._configs[C];if(!B||!this._configs.hasOwnProperty(C)){return null;}return B.getValue();},set:function(D,E,B){this._configs=this._configs||{};var C=this._configs[D];if(!C){return false;}return C.setValue(E,B);},getAttributeKeys:function(){this._configs=this._configs;var C=[],B;for(B in this._configs){if(A.hasOwnProperty(this._configs,B)&&!A.isUndefined(this._configs[B])){C[C.length]=B;}}return C;},setAttributes:function(D,B){for(var C in D){if(A.hasOwnProperty(D,C)){this.set(C,D[C],B);}}},resetValue:function(C,B){this._configs=this._configs||{};if(this._configs[C]){this.set(C,this._configs[C]._initialConfig.value,B);return true;}return false;},refresh:function(E,C){this._configs=this._configs||{};var F=this._configs;E=((A.isString(E))?[E]:E)||this.getAttributeKeys();for(var D=0,B=E.length;D<B;++D){if(F.hasOwnProperty(E[D])){this._configs[E[D]].refresh(C);}}},register:function(B,C){this.setAttributeConfig(B,C);},getAttributeConfig:function(C){this._configs=this._configs||{};var B=this._configs[C]||{};var D={};for(C in B){if(A.hasOwnProperty(B,C)){D[C]=B[C];}}return D;},setAttributeConfig:function(B,C,D){this._configs=this._configs||{};C=C||{};if(!this._configs[B]){C.name=B;this._configs[B]=this.createAttribute(C);}else{this._configs[B].configure(C,D);}},configureAttribute:function(B,C,D){this.setAttributeConfig(B,C,D);},resetAttributeConfig:function(B){this._configs=this._configs||{};this._configs[B].resetConfig();},subscribe:function(B,C){this._events=this._events||{};if(!(B in this._events)){this._events[B]=this.createEvent(B);}YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){this.subscribe.apply(this,arguments);},addListener:function(){this.subscribe.apply(this,arguments);},fireBeforeChangeEvent:function(C){var B="before";B+=C.type.charAt(0).toUpperCase()+C.type.substr(1)+"Change";C.type=B;return this.fireEvent(C.type,C);},fireChangeEvent:function(B){B.type+="Change";return this.fireEvent(B.type,B);},createAttribute:function(B){return new YAHOO.util.Attribute(B,this);}};YAHOO.augment(YAHOO.util.AttributeProvider,YAHOO.util.EventProvider);})();(function(){var B=YAHOO.util.Dom,D=YAHOO.util.AttributeProvider,C={mouseenter:true,mouseleave:true};var A=function(E,F){this.init.apply(this,arguments);};A.DOM_EVENTS={"click":true,"dblclick":true,"keydown":true,"keypress":true,"keyup":true,"mousedown":true,"mousemove":true,"mouseout":true,"mouseover":true,"mouseup":true,"mouseenter":true,"mouseleave":true,"focus":true,"blur":true,"submit":true,"change":true};A.prototype={DOM_EVENTS:null,DEFAULT_HTML_SETTER:function(G,E){var F=this.get("element");if(F){F[E]=G;}return G;},DEFAULT_HTML_GETTER:function(E){var F=this.get("element"),G;if(F){G=F[E];}return G;},appendChild:function(E){E=E.get?E.get("element"):E;return this.get("element").appendChild(E);},getElementsByTagName:function(E){return this.get("element").getElementsByTagName(E);},hasChildNodes:function(){return this.get("element").hasChildNodes();},insertBefore:function(E,F){E=E.get?E.get("element"):E;F=(F&&F.get)?F.get("element"):F;return this.get("element").insertBefore(E,F);},removeChild:function(E){E=E.get?E.get("element"):E;return this.get("element").removeChild(E);},replaceChild:function(E,F){E=E.get?E.get("element"):E;F=F.get?F.get("element"):F;return this.get("element").replaceChild(E,F);},initAttributes:function(E){},addListener:function(J,I,K,H){H=H||this;var E=YAHOO.util.Event,G=this.get("element")||this.get("id"),F=this;if(C[J]&&!E._createMouseDelegate){return false;}if(!this._events[J]){if(G&&this.DOM_EVENTS[J]){E.on(G,J,function(M,L){if(M.srcElement&&!M.target){M.target=M.srcElement;}if((M.toElement&&!M.relatedTarget)||(M.fromElement&&!M.relatedTarget)){M.relatedTarget=E.getRelatedTarget(M);}if(!M.currentTarget){M.currentTarget=G;}F.fireEvent(J,M,L);},K,H);}this.createEvent(J,{scope:this});}return YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){return this.addListener.apply(this,arguments);},subscribe:function(){return this.addListener.apply(this,arguments);},removeListener:function(F,E){return this.unsubscribe.apply(this,arguments);},addClass:function(E){B.addClass(this.get("element"),E);},getElementsByClassName:function(F,E){return B.getElementsByClassName(F,E,this.get("element"));},hasClass:function(E){return B.hasClass(this.get("element"),E);},removeClass:function(E){return B.removeClass(this.get("element"),E);},replaceClass:function(F,E){return B.replaceClass(this.get("element"),F,E);},setStyle:function(F,E){return B.setStyle(this.get("element"),F,E);
-},getStyle:function(E){return B.getStyle(this.get("element"),E);},fireQueue:function(){var F=this._queue;for(var G=0,E=F.length;G<E;++G){this[F[G][0]].apply(this,F[G][1]);}},appendTo:function(F,G){F=(F.get)?F.get("element"):B.get(F);this.fireEvent("beforeAppendTo",{type:"beforeAppendTo",target:F});G=(G&&G.get)?G.get("element"):B.get(G);var E=this.get("element");if(!E){return false;}if(!F){return false;}if(E.parent!=F){if(G){F.insertBefore(E,G);}else{F.appendChild(E);}}this.fireEvent("appendTo",{type:"appendTo",target:F});return E;},get:function(E){var G=this._configs||{},F=G.element;if(F&&!G[E]&&!YAHOO.lang.isUndefined(F.value[E])){this._setHTMLAttrConfig(E);}return D.prototype.get.call(this,E);},setAttributes:function(K,H){var F={},I=this._configOrder;for(var J=0,E=I.length;J<E;++J){if(K[I[J]]!==undefined){F[I[J]]=true;this.set(I[J],K[I[J]],H);}}for(var G in K){if(K.hasOwnProperty(G)&&!F[G]){this.set(G,K[G],H);}}},set:function(F,H,E){var G=this.get("element");if(!G){this._queue[this._queue.length]=["set",arguments];if(this._configs[F]){this._configs[F].value=H;}return;}if(!this._configs[F]&&!YAHOO.lang.isUndefined(G[F])){this._setHTMLAttrConfig(F);}return D.prototype.set.apply(this,arguments);},setAttributeConfig:function(E,F,G){this._configOrder.push(E);D.prototype.setAttributeConfig.apply(this,arguments);},createEvent:function(F,E){this._events[F]=true;return D.prototype.createEvent.apply(this,arguments);},init:function(F,E){this._initElement(F,E);},destroy:function(){var E=this.get("element");YAHOO.util.Event.purgeElement(E,true);this.unsubscribeAll();if(E&&E.parentNode){E.parentNode.removeChild(E);}this._queue=[];this._events={};this._configs={};this._configOrder=[];},_initElement:function(G,F){this._queue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};this._configOrder=[];F=F||{};F.element=F.element||G||null;var I=false;var E=A.DOM_EVENTS;this.DOM_EVENTS=this.DOM_EVENTS||{};for(var H in E){if(E.hasOwnProperty(H)){this.DOM_EVENTS[H]=E[H];}}if(typeof F.element==="string"){this._setHTMLAttrConfig("id",{value:F.element});}if(B.get(F.element)){I=true;this._initHTMLElement(F);this._initContent(F);}YAHOO.util.Event.onAvailable(F.element,function(){if(!I){this._initHTMLElement(F);}this.fireEvent("available",{type:"available",target:B.get(F.element)});},this,true);YAHOO.util.Event.onContentReady(F.element,function(){if(!I){this._initContent(F);}this.fireEvent("contentReady",{type:"contentReady",target:B.get(F.element)});},this,true);},_initHTMLElement:function(E){this.setAttributeConfig("element",{value:B.get(E.element),readOnly:true});},_initContent:function(E){this.initAttributes(E);this.setAttributes(E,true);this.fireQueue();},_setHTMLAttrConfig:function(E,G){var F=this.get("element");G=G||{};G.name=E;G.setter=G.setter||this.DEFAULT_HTML_SETTER;G.getter=G.getter||this.DEFAULT_HTML_GETTER;G.value=G.value||F[E];this._configs[E]=new YAHOO.util.Attribute(G,this);}};YAHOO.augment(A,D);YAHOO.util.Element=A;})();YAHOO.register("element",YAHOO.util.Element,{version:"2.8.1",build:"19"});YAHOO.register("utilities", YAHOO, {version: "2.8.1", build: "19"});/*
-Copyright (c) 2010, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.8.1
-*/
-(function(){var lang=YAHOO.lang,util=YAHOO.util,Ev=util.Event;util.DataSourceBase=function(oLiveData,oConfigs){if(oLiveData===null||oLiveData===undefined){return;}this.liveData=oLiveData;this._oQueue={interval:null,conn:null,requests:[]};this.responseSchema={};if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){if(sConfig){this[sConfig]=oConfigs[sConfig];}}}var maxCacheEntries=this.maxCacheEntries;if(!lang.isNumber(maxCacheEntries)||(maxCacheEntries<0)){maxCacheEntries=0;}this._aIntervals=[];this.createEvent("cacheRequestEvent");this.createEvent("cacheResponseEvent");this.createEvent("requestEvent");this.createEvent("responseEvent");this.createEvent("responseParseEvent");this.createEvent("responseCacheEvent");this.createEvent("dataErrorEvent");this.createEvent("cacheFlushEvent");var DS=util.DataSourceBase;this._sName="DataSource instance"+DS._nIndex;DS._nIndex++;};var DS=util.DataSourceBase;lang.augmentObject(DS,{TYPE_UNKNOWN:-1,TYPE_JSARRAY:0,TYPE_JSFUNCTION:1,TYPE_XHR:2,TYPE_JSON:3,TYPE_XML:4,TYPE_TEXT:5,TYPE_HTMLTABLE:6,TYPE_SCRIPTNODE:7,TYPE_LOCAL:8,ERROR_DATAINVALID:"Invalid data",ERROR_DATANULL:"Null data",_nIndex:0,_nTransactionId:0,_getLocationValue:function(field,context){var locator=field.locator||field.key||field,xmldoc=context.ownerDocument||context,result,res,value=null;try{if(!lang.isUndefined(xmldoc.evaluate)){result=xmldoc.evaluate(locator,context,xmldoc.createNSResolver(!context.ownerDocument?context.documentElement:context.ownerDocument.documentElement),0,null);while(res=result.iterateNext()){value=res.textContent;}}else{xmldoc.setProperty("SelectionLanguage","XPath");result=context.selectNodes(locator)[0];value=result.value||result.text||null;}return value;}catch(e){}},issueCallback:function(callback,params,error,scope){if(lang.isFunction(callback)){callback.apply(scope,params);}else{if(lang.isObject(callback)){scope=callback.scope||scope||window;var callbackFunc=callback.success;if(error){callbackFunc=callback.failure;}if(callbackFunc){callbackFunc.apply(scope,params.concat([callback.argument]));}}}},parseString:function(oData){if(!lang.isValue(oData)){return null;}var string=oData+"";if(lang.isString(string)){return string;}else{return null;}},parseNumber:function(oData){if(!lang.isValue(oData)||(oData==="")){return null;}var number=oData*1;if(lang.isNumber(number)){return number;}else{return null;}},convertNumber:function(oData){return DS.parseNumber(oData);},parseDate:function(oData){var date=null;if(!(oData instanceof Date)){date=new Date(oData);}else{return oData;}if(date instanceof Date){return date;}else{return null;}},convertDate:function(oData){return DS.parseDate(oData);}});DS.Parser={string:DS.parseString,number:DS.parseNumber,date:DS.parseDate};DS.prototype={_sName:null,_aCache:null,_oQueue:null,_aIntervals:null,maxCacheEntries:0,liveData:null,dataType:DS.TYPE_UNKNOWN,responseType:DS.TYPE_UNKNOWN,responseSchema:null,useXPath:false,toString:function(){return this._sName;},getCachedResponse:function(oRequest,oCallback,oCaller){var aCache=this._aCache;if(this.maxCacheEntries>0){if(!aCache){this._aCache=[];}else{var nCacheLength=aCache.length;if(nCacheLength>0){var oResponse=null;this.fireEvent("cacheRequestEvent",{request:oRequest,callback:oCallback,caller:oCaller});for(var i=nCacheLength-1;i>=0;i--){var oCacheElem=aCache[i];if(this.isCacheHit(oRequest,oCacheElem.request)){oResponse=oCacheElem.response;this.fireEvent("cacheResponseEvent",{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller});if(i<nCacheLength-1){aCache.splice(i,1);this.addToCache(oRequest,oResponse);}oResponse.cached=true;break;}}return oResponse;}}}else{if(aCache){this._aCache=null;}}return null;},isCacheHit:function(oRequest,oCachedRequest){return(oRequest===oCachedRequest);},addToCache:function(oRequest,oResponse){var aCache=this._aCache;if(!aCache){return;}while(aCache.length>=this.maxCacheEntries){aCache.shift();}var oCacheElem={request:oRequest,response:oResponse};aCache[aCache.length]=oCacheElem;this.fireEvent("responseCacheEvent",{request:oRequest,response:oResponse});},flushCache:function(){if(this._aCache){this._aCache=[];this.fireEvent("cacheFlushEvent");}},setInterval:function(nMsec,oRequest,oCallback,oCaller){if(lang.isNumber(nMsec)&&(nMsec>=0)){var oSelf=this;var nId=setInterval(function(){oSelf.makeConnection(oRequest,oCallback,oCaller);},nMsec);this._aIntervals.push(nId);return nId;}else{}},clearInterval:function(nId){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i>-1;i--){if(tracker[i]===nId){tracker.splice(i,1);clearInterval(nId);}}},clearAllIntervals:function(){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i>-1;i--){clearInterval(tracker[i]);}tracker=[];},sendRequest:function(oRequest,oCallback,oCaller){var oCachedResponse=this.getCachedResponse(oRequest,oCallback,oCaller);if(oCachedResponse){DS.issueCallback(oCallback,[oRequest,oCachedResponse],false,oCaller);return null;}return this.makeConnection(oRequest,oCallback,oCaller);},makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=this.liveData;this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;},handleResponse:function(oRequest,oRawResponse,oCallback,oCaller,tId){this.fireEvent("responseEvent",{tId:tId,request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller});var xhr=(this.dataType==DS.TYPE_XHR)?true:false;var oParsedResponse=null;var oFullResponse=oRawResponse;if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oRawResponse&&oRawResponse.getResponseHeader)?oRawResponse.getResponseHeader["Content-Type"]:null;if(ctype){if(ctype.indexOf("text/xml")>-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf("application/json")>-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf("text/plain")>-1){this.responseType=DS.TYPE_TEXT;}}}}else{if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY;
-}else{if(oRawResponse&&oRawResponse.nodeType&&(oRawResponse.nodeType===9||oRawResponse.nodeType===1||oRawResponse.nodeType===11)){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&&oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.responseType=DS.TYPE_TEXT;}}}}}}}switch(this.responseType){case DS.TYPE_JSARRAY:if(xhr&&oRawResponse&&oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&&JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length>0&&(oFullResponse.charAt(0)!="{")&&(oFullResponse.charAt(0)!="[")){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length>0){var arrayEnd=Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}"));oFullResponse=oFullResponse.substring(0,arrayEnd+1);oFullResponse=eval("("+oFullResponse+")");}}}}}}catch(e1){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseArrayData(oRequest,oFullResponse);break;case DS.TYPE_JSON:if(xhr&&oRawResponse&&oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&&JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length>0&&(oFullResponse.charAt(0)!="{")&&(oFullResponse.charAt(0)!="[")){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length>0){var objEnd=Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}"));oFullResponse=oFullResponse.substring(0,objEnd+1);oFullResponse=eval("("+oFullResponse+")");}}}}}}catch(e){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseJSONData(oRequest,oFullResponse);break;case DS.TYPE_HTMLTABLE:if(xhr&&oRawResponse.responseText){var el=document.createElement("div");el.innerHTML=oRawResponse.responseText;oFullResponse=el.getElementsByTagName("table")[0];}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseHTMLTableData(oRequest,oFullResponse);break;case DS.TYPE_XML:if(xhr&&oRawResponse.responseXML){oFullResponse=oRawResponse.responseXML;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseXMLData(oRequest,oFullResponse);break;case DS.TYPE_TEXT:if(xhr&&lang.isString(oRawResponse.responseText)){oFullResponse=oRawResponse.responseText;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseTextData(oRequest,oFullResponse);break;default:oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseData(oRequest,oFullResponse);break;}oParsedResponse=oParsedResponse||{};if(!oParsedResponse.results){oParsedResponse.results=[];}if(!oParsedResponse.meta){oParsedResponse.meta={};}if(!oParsedResponse.error){oParsedResponse=this.doBeforeCallback(oRequest,oFullResponse,oParsedResponse,oCallback);this.fireEvent("responseParseEvent",{request:oRequest,response:oParsedResponse,callback:oCallback,caller:oCaller});this.addToCache(oRequest,oParsedResponse);}else{oParsedResponse.error=true;this.fireEvent("dataErrorEvent",{request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});}oParsedResponse.tId=tId;DS.issueCallback(oCallback,[oRequest,oParsedResponse],oParsedResponse.error,oCaller);},doBeforeParseData:function(oRequest,oFullResponse,oCallback){return oFullResponse;},doBeforeCallback:function(oRequest,oFullResponse,oParsedResponse,oCallback){return oParsedResponse;},parseData:function(oRequest,oFullResponse){if(lang.isValue(oFullResponse)){var oParsedResponse={results:oFullResponse,meta:{}};return oParsedResponse;}return null;},parseArrayData:function(oRequest,oFullResponse){if(lang.isArray(oFullResponse)){var results=[],i,j,rec,field,data;if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;for(i=fields.length-1;i>=0;--i){if(typeof fields[i]!=="object"){fields[i]={key:fields[i]};}}var parsers={},p;for(i=fields.length-1;i>=0;--i){p=(typeof fields[i].parser==="function"?fields[i].parser:DS.Parser[fields[i].parser+""])||fields[i].converter;if(p){parsers[fields[i].key]=p;}}var arrType=lang.isArray(oFullResponse[0]);for(i=oFullResponse.length-1;i>-1;i--){var oResult={};rec=oFullResponse[i];if(typeof rec==="object"){for(j=fields.length-1;j>-1;j--){field=fields[j];data=arrType?rec[j]:rec[field.key];if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;}}else{if(lang.isString(rec)){for(j=fields.length-1;j>-1;j--){field=fields[j];data=rec;if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;}}}results[i]=oResult;}}else{results=oFullResponse;}var oParsedResponse={results:results};return oParsedResponse;}return null;},parseTextData:function(oRequest,oFullResponse){if(lang.isString(oFullResponse)){if(lang.isString(this.responseSchema.recordDelim)&&lang.isString(this.responseSchema.fieldDelim)){var oParsedResponse={results:[]};var recDelim=this.responseSchema.recordDelim;var fieldDelim=this.responseSchema.fieldDelim;if(oFullResponse.length>0){var newLength=oFullResponse.length-recDelim.length;if(oFullResponse.substr(newLength)==recDelim){oFullResponse=oFullResponse.substr(0,newLength);
-}if(oFullResponse.length>0){var recordsarray=oFullResponse.split(recDelim);for(var i=0,len=recordsarray.length,recIdx=0;i<len;++i){var bError=false,sRecord=recordsarray[i];if(lang.isString(sRecord)&&(sRecord.length>0)){var fielddataarray=recordsarray[i].split(fieldDelim);var oResult={};if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;for(var j=fields.length-1;j>-1;j--){try{var data=fielddataarray[j];if(lang.isString(data)){if(data.charAt(0)=='"'){data=data.substr(1);}if(data.charAt(data.length-1)=='"'){data=data.substr(0,data.length-1);}var field=fields[j];var key=(lang.isValue(field.key))?field.key:field;if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}else{bError=true;}}catch(e){bError=true;}}}else{oResult=fielddataarray;}if(!bError){oParsedResponse.results[recIdx++]=oResult;}}}}}return oParsedResponse;}}return null;},parseXMLResult:function(result){var oResult={},schema=this.responseSchema;try{for(var m=schema.fields.length-1;m>=0;m--){var field=schema.fields[m];var key=(lang.isValue(field.key))?field.key:field;var data=null;if(this.useXPath){data=YAHOO.util.DataSource._getLocationValue(field,result);}else{var xmlAttr=result.attributes.getNamedItem(key);if(xmlAttr){data=xmlAttr.value;}else{var xmlNode=result.getElementsByTagName(key);if(xmlNode&&xmlNode.item(0)){var item=xmlNode.item(0);data=(item)?((item.text)?item.text:(item.textContent)?item.textContent:null):null;if(!data){var datapieces=[];for(var j=0,len=item.childNodes.length;j<len;j++){if(item.childNodes[j].nodeValue){datapieces[datapieces.length]=item.childNodes[j].nodeValue;}}if(datapieces.length>0){data=datapieces.join("");}}}}}if(data===null){data="";}if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}}catch(e){}return oResult;},parseXMLData:function(oRequest,oFullResponse){var bError=false,schema=this.responseSchema,oParsedResponse={meta:{}},xmlList=null,metaNode=schema.metaNode,metaLocators=schema.metaFields||{},i,k,loc,v;try{if(this.useXPath){for(k in metaLocators){oParsedResponse.meta[k]=YAHOO.util.DataSource._getLocationValue(metaLocators[k],oFullResponse);}}else{metaNode=metaNode?oFullResponse.getElementsByTagName(metaNode)[0]:oFullResponse;if(metaNode){for(k in metaLocators){if(lang.hasOwnProperty(metaLocators,k)){loc=metaLocators[k];v=metaNode.getElementsByTagName(loc)[0];if(v){v=v.firstChild.nodeValue;}else{v=metaNode.attributes.getNamedItem(loc);if(v){v=v.value;}}if(lang.isValue(v)){oParsedResponse.meta[k]=v;}}}}}xmlList=(schema.resultNode)?oFullResponse.getElementsByTagName(schema.resultNode):null;}catch(e){}if(!xmlList||!lang.isArray(schema.fields)){bError=true;}else{oParsedResponse.results=[];for(i=xmlList.length-1;i>=0;--i){var oResult=this.parseXMLResult(xmlList.item(i));oParsedResponse.results[i]=oResult;}}if(bError){oParsedResponse.error=true;}else{}return oParsedResponse;},parseJSONData:function(oRequest,oFullResponse){var oParsedResponse={results:[],meta:{}};if(lang.isObject(oFullResponse)&&this.responseSchema.resultsList){var schema=this.responseSchema,fields=schema.fields,resultsList=oFullResponse,results=[],metaFields=schema.metaFields||{},fieldParsers=[],fieldPaths=[],simpleFields=[],bError=false,i,len,j,v,key,parser,path;var buildPath=function(needle){var path=null,keys=[],i=0;if(needle){needle=needle.replace(/\[(['"])(.*?)\1\]/g,function(x,$1,$2){keys[i]=$2;return".@"+(i++);}).replace(/\[(\d+)\]/g,function(x,$1){keys[i]=parseInt($1,10)|0;return".@"+(i++);}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(needle)){path=needle.split(".");for(i=path.length-1;i>=0;--i){if(path[i].charAt(0)==="@"){path[i]=keys[parseInt(path[i].substr(1),10)];}}}else{}}return path;};var walkPath=function(path,origin){var v=origin,i=0,len=path.length;for(;i<len&&v;++i){v=v[path[i]];}return v;};path=buildPath(schema.resultsList);if(path){resultsList=walkPath(path,oFullResponse);if(resultsList===undefined){bError=true;}}else{bError=true;}if(!resultsList){resultsList=[];}if(!lang.isArray(resultsList)){resultsList=[resultsList];}if(!bError){if(schema.fields){var field;for(i=0,len=fields.length;i<len;i++){field=fields[i];key=field.key||field;parser=((typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""])||field.converter;path=buildPath(key);if(parser){fieldParsers[fieldParsers.length]={key:key,parser:parser};}if(path){if(path.length>1){fieldPaths[fieldPaths.length]={key:key,path:path};}else{simpleFields[simpleFields.length]={key:key,path:path[0]};}}else{}}for(i=resultsList.length-1;i>=0;--i){var r=resultsList[i],rec={};if(r){for(j=simpleFields.length-1;j>=0;--j){rec[simpleFields[j].key]=(r[simpleFields[j].path]!==undefined)?r[simpleFields[j].path]:r[j];}for(j=fieldPaths.length-1;j>=0;--j){rec[fieldPaths[j].key]=walkPath(fieldPaths[j].path,r);}for(j=fieldParsers.length-1;j>=0;--j){var p=fieldParsers[j].key;rec[p]=fieldParsers[j].parser(rec[p]);if(rec[p]===undefined){rec[p]=null;}}}results[i]=rec;}}else{results=resultsList;}for(key in metaFields){if(lang.hasOwnProperty(metaFields,key)){path=buildPath(metaFields[key]);if(path){v=walkPath(path,oFullResponse);oParsedResponse.meta[key]=v;}}}}else{oParsedResponse.error=true;}oParsedResponse.results=results;}else{oParsedResponse.error=true;}return oParsedResponse;},parseHTMLTableData:function(oRequest,oFullResponse){var bError=false;var elTable=oFullResponse;var fields=this.responseSchema.fields;var oParsedResponse={results:[]};if(lang.isArray(fields)){for(var i=0;i<elTable.tBodies.length;i++){var elTbody=elTable.tBodies[i];for(var j=elTbody.rows.length-1;j>-1;j--){var elRow=elTbody.rows[j];var oResult={};for(var k=fields.length-1;k>-1;k--){var field=fields[k];var key=(lang.isValue(field.key))?field.key:field;
-var data=elRow.cells[k].innerHTML;if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}oParsedResponse.results[j]=oResult;}}}else{bError=true;}if(bError){oParsedResponse.error=true;}else{}return oParsedResponse;}};lang.augmentProto(DS,util.EventProvider);util.LocalDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_LOCAL;if(oLiveData){if(YAHOO.lang.isArray(oLiveData)){this.responseType=DS.TYPE_JSARRAY;}else{if(oLiveData.nodeType&&oLiveData.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oLiveData.nodeName&&(oLiveData.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;oLiveData=oLiveData.cloneNode(true);}else{if(YAHOO.lang.isString(oLiveData)){this.responseType=DS.TYPE_TEXT;}else{if(YAHOO.lang.isObject(oLiveData)){this.responseType=DS.TYPE_JSON;}}}}}}else{oLiveData=[];this.responseType=DS.TYPE_JSARRAY;}util.LocalDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.LocalDataSource,DS);lang.augmentObject(util.LocalDataSource,DS);util.FunctionDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_JSFUNCTION;oLiveData=oLiveData||function(){};util.FunctionDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.FunctionDataSource,DS,{scope:null,makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=(this.scope)?this.liveData.call(this.scope,oRequest,this):this.liveData(oRequest);if(this.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse&&oRawResponse.nodeType&&oRawResponse.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&&oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.responseType=DS.TYPE_TEXT;}}}}}}this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;}});lang.augmentObject(util.FunctionDataSource,DS);util.ScriptNodeDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_SCRIPTNODE;oLiveData=oLiveData||"";util.ScriptNodeDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.ScriptNodeDataSource,DS,{getUtility:util.Get,asyncMode:"allowAll",scriptCallbackParam:"callback",generateRequestCallback:function(id){return"&"+this.scriptCallbackParam+"=YAHOO.util.ScriptNodeDataSource.callbacks["+id+"]";},doBeforeGetScriptNode:function(sUri){return sUri;},makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});if(util.ScriptNodeDataSource._nPending===0){util.ScriptNodeDataSource.callbacks=[];util.ScriptNodeDataSource._nId=0;}var id=util.ScriptNodeDataSource._nId;util.ScriptNodeDataSource._nId++;var oSelf=this;util.ScriptNodeDataSource.callbacks[id]=function(oRawResponse){if((oSelf.asyncMode!=="ignoreStaleResponses")||(id===util.ScriptNodeDataSource.callbacks.length-1)){if(oSelf.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){oSelf.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse.nodeType&&oRawResponse.nodeType==9){oSelf.responseType=DS.TYPE_XML;}else{if(oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){oSelf.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){oSelf.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){oSelf.responseType=DS.TYPE_TEXT;}}}}}}oSelf.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);}else{}delete util.ScriptNodeDataSource.callbacks[id];};util.ScriptNodeDataSource._nPending++;var sUri=this.liveData+oRequest+this.generateRequestCallback(id);sUri=this.doBeforeGetScriptNode(sUri);this.getUtility.script(sUri,{autopurge:true,onsuccess:util.ScriptNodeDataSource._bumpPendingDown,onfail:util.ScriptNodeDataSource._bumpPendingDown});return tId;}});lang.augmentObject(util.ScriptNodeDataSource,DS);lang.augmentObject(util.ScriptNodeDataSource,{_nId:0,_nPending:0,callbacks:[]});util.XHRDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_XHR;this.connMgr=this.connMgr||util.Connect;oLiveData=oLiveData||"";util.XHRDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.XHRDataSource,DS,{connMgr:null,connXhrMode:"allowAll",connMethodPost:false,connTimeout:0,makeConnection:function(oRequest,oCallback,oCaller){var oRawResponse=null;var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oSelf=this;var oConnMgr=this.connMgr;var oQueue=this._oQueue;var _xhrSuccess=function(oResponse){if(oResponse&&(this.connXhrMode=="ignoreStaleResponses")&&(oResponse.tId!=oQueue.conn.tId)){return null;}else{if(!oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,response:null,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);return null;}else{if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oResponse.getResponseHeader)?oResponse.getResponseHeader["Content-Type"]:null;if(ctype){if(ctype.indexOf("text/xml")>-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf("application/json")>-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf("text/plain")>-1){this.responseType=DS.TYPE_TEXT;}}}}}this.handleResponse(oRequest,oResponse,oCallback,oCaller,tId);}}};var _xhrFailure=function(oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATAINVALID});if(lang.isString(this.liveData)&&lang.isString(oRequest)&&(this.liveData.lastIndexOf("?")!==this.liveData.length-1)&&(oRequest.indexOf("?")!==0)){}oResponse=oResponse||{};
-oResponse.error=true;DS.issueCallback(oCallback,[oRequest,oResponse],true,oCaller);return null;};var _xhrCallback={success:_xhrSuccess,failure:_xhrFailure,scope:this};if(lang.isNumber(this.connTimeout)){_xhrCallback.timeout=this.connTimeout;}if(this.connXhrMode=="cancelStaleRequests"){if(oQueue.conn){if(oConnMgr.abort){oConnMgr.abort(oQueue.conn);oQueue.conn=null;}else{}}}if(oConnMgr&&oConnMgr.asyncRequest){var sLiveData=this.liveData;var isPost=this.connMethodPost;var sMethod=(isPost)?"POST":"GET";var sUri=(isPost||!lang.isValue(oRequest))?sLiveData:sLiveData+oRequest;var sRequest=(isPost)?oRequest:null;if(this.connXhrMode!="queueRequests"){oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}else{if(oQueue.conn){var allRequests=oQueue.requests;allRequests.push({request:oRequest,callback:_xhrCallback});if(!oQueue.interval){oQueue.interval=setInterval(function(){if(oConnMgr.isCallInProgress(oQueue.conn)){return;}else{if(allRequests.length>0){sUri=(isPost||!lang.isValue(allRequests[0].request))?sLiveData:sLiveData+allRequests[0].request;sRequest=(isPost)?allRequests[0].request:null;oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,allRequests[0].callback,sRequest);allRequests.shift();}else{clearInterval(oQueue.interval);oQueue.interval=null;}}},50);}}else{oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}}}else{DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);}return tId;}});lang.augmentObject(util.XHRDataSource,DS);util.DataSource=function(oLiveData,oConfigs){oConfigs=oConfigs||{};var dataType=oConfigs.dataType;if(dataType){if(dataType==DS.TYPE_LOCAL){lang.augmentObject(util.DataSource,util.LocalDataSource);return new util.LocalDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_XHR){lang.augmentObject(util.DataSource,util.XHRDataSource);return new util.XHRDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_SCRIPTNODE){lang.augmentObject(util.DataSource,util.ScriptNodeDataSource);return new util.ScriptNodeDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_JSFUNCTION){lang.augmentObject(util.DataSource,util.FunctionDataSource);return new util.FunctionDataSource(oLiveData,oConfigs);}}}}}if(YAHOO.lang.isString(oLiveData)){lang.augmentObject(util.DataSource,util.XHRDataSource);return new util.XHRDataSource(oLiveData,oConfigs);}else{if(YAHOO.lang.isFunction(oLiveData)){lang.augmentObject(util.DataSource,util.FunctionDataSource);return new util.FunctionDataSource(oLiveData,oConfigs);}else{lang.augmentObject(util.DataSource,util.LocalDataSource);return new util.LocalDataSource(oLiveData,oConfigs);}}};lang.augmentObject(util.DataSource,DS);})();YAHOO.util.Number={format:function(B,E){if(!isFinite(+B)){return"";}B=!isFinite(+B)?0:+B;E=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,(E||{}));var C=B<0,F=Math.abs(B),A=E.decimalPlaces,I=E.thousandsSeparator,H,G,D;if(A<0){H=F-(F%1)+"";D=H.length+A;if(D>0){H=Number("."+H).toFixed(D).slice(2)+new Array(H.length-D+1).join("0");}else{H="0";}}else{H=F<1&&F>=0.5&&!A?"1":F.toFixed(A);}if(F>1000){G=H.split(/\D/);D=G[0].length%3||3;G[0]=G[0].slice(0,D)+G[0].slice(D).replace(/(\d{3})/g,I+"$1");H=G.join(E.decimalSeparator);}H=E.prefix+H+E.suffix;return C?E.negativeFormat.replace(/#/,H):H;}};YAHOO.util.Number.format.defaults={decimalSeparator:".",decimalPlaces:null,thousandsSeparator:"",prefix:"",suffix:"",negativeFormat:"-#"};(function(){var A=function(C,E,D){if(typeof D==="undefined"){D=10;}for(;parseInt(C,10)<D&&D>1;D/=10){C=E.toString()+C;}return C.toString();};var B={formats:{a:function(D,C){return C.a[D.getDay()];},A:function(D,C){return C.A[D.getDay()];},b:function(D,C){return C.b[D.getMonth()];},B:function(D,C){return C.B[D.getMonth()];},C:function(C){return A(parseInt(C.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(C){return A(parseInt(B.formats.G(C)%100,10),0);},G:function(E){var F=E.getFullYear();var D=parseInt(B.formats.V(E),10);var C=parseInt(B.formats.W(E),10);if(C>D){F++;}else{if(C===0&&D>=52){F--;}}return F;},H:["getHours","0"],I:function(D){var C=D.getHours()%12;return A(C===0?12:C,0);},j:function(G){var F=new Date(""+G.getFullYear()+"/1/1 GMT");var D=new Date(""+G.getFullYear()+"/"+(G.getMonth()+1)+"/"+G.getDate()+" GMT");var C=D-F;var E=parseInt(C/60000/60/24,10)+1;return A(E,0,100);},k:["getHours"," "],l:function(D){var C=D.getHours()%12;return A(C===0?12:C," ");},m:function(C){return A(C.getMonth()+1,0);},M:["getMinutes","0"],p:function(D,C){return C.p[D.getHours()>=12?1:0];},P:function(D,C){return C.P[D.getHours()>=12?1:0];},s:function(D,C){return parseInt(D.getTime()/1000,10);},S:["getSeconds","0"],u:function(C){var D=C.getDay();return D===0?7:D;},U:function(F){var C=parseInt(B.formats.j(F),10);var E=6-F.getDay();var D=parseInt((C+E)/7,10);return A(D,0);},V:function(F){var E=parseInt(B.formats.W(F),10);var C=(new Date(""+F.getFullYear()+"/1/1")).getDay();var D=E+(C>4||C<=1?0:1);if(D===53&&(new Date(""+F.getFullYear()+"/12/31")).getDay()<4){D=1;}else{if(D===0){D=B.formats.V(new Date(""+(F.getFullYear()-1)+"/12/31"));}}return A(D,0);},w:"getDay",W:function(F){var C=parseInt(B.formats.j(F),10);var E=7-B.formats.u(F);var D=parseInt((C+E)/7,10);return A(D,0,10);},y:function(C){return A(C.getFullYear()%100,0);},Y:"getFullYear",z:function(E){var D=E.getTimezoneOffset();var C=A(parseInt(Math.abs(D/60),10),0);var F=A(Math.abs(D%60),0);return(D>0?"-":"+")+C+F;},Z:function(C){var D=C.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(D.length>4){D=B.formats.z(C);}return D;},"%":function(C){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(G,F,D){F=F||{};if(!(G instanceof Date)){return YAHOO.lang.isValue(G)?G:"";}var H=F.format||"%m/%d/%Y";if(H==="YYYY/MM/DD"){H="%Y/%m/%d";}else{if(H==="DD/MM/YYYY"){H="%d/%m/%Y";}else{if(H==="MM/DD/YYYY"){H="%m/%d/%Y";}}}D=D||"en";if(!(D in YAHOO.util.DateLocale)){if(D.replace(/-[a-zA-Z]+$/,"") in YAHOO.util.DateLocale){D=D.replace(/-[a-zA-Z]+$/,"");
-}else{D="en";}}var J=YAHOO.util.DateLocale[D];var C=function(L,K){var M=B.aggregates[K];return(M==="locale"?J[K]:M);};var E=function(L,K){var M=B.formats[K];if(typeof M==="string"){return G[M]();}else{if(typeof M==="function"){return M.call(G,G,J);}else{if(typeof M==="object"&&typeof M[0]==="string"){return A(G[M[0]](),M[1]);}else{return K;}}}};while(H.match(/%[cDFhnrRtTxX]/)){H=H.replace(/%([cDFhnrRtTxX])/g,C);}var I=H.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,E);C=E=undefined;return I;}};YAHOO.namespace("YAHOO.util");YAHOO.util.Date=B;YAHOO.util.DateLocale={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};YAHOO.util.DateLocale["en"]=YAHOO.lang.merge(YAHOO.util.DateLocale,{});YAHOO.util.DateLocale["en-US"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"],{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});YAHOO.util.DateLocale["en-GB"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"],{r:"%l:%M:%S %P %Z"});YAHOO.util.DateLocale["en-AU"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"]);})();YAHOO.register("datasource",YAHOO.util.DataSource,{version:"2.8.1",build:"19"});/*
-Copyright (c) 2010, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.8.1
-*/
-YAHOO.widget.DS_JSArray=YAHOO.util.LocalDataSource;YAHOO.widget.DS_JSFunction=YAHOO.util.FunctionDataSource;YAHOO.widget.DS_XHR=function(B,A,D){var C=new YAHOO.util.XHRDataSource(B,D);C._aDeprecatedSchema=A;return C;};YAHOO.widget.DS_ScriptNode=function(B,A,D){var C=new YAHOO.util.ScriptNodeDataSource(B,D);C._aDeprecatedSchema=A;return C;};YAHOO.widget.DS_XHR.TYPE_JSON=YAHOO.util.DataSourceBase.TYPE_JSON;YAHOO.widget.DS_XHR.TYPE_XML=YAHOO.util.DataSourceBase.TYPE_XML;YAHOO.widget.DS_XHR.TYPE_FLAT=YAHOO.util.DataSourceBase.TYPE_TEXT;YAHOO.widget.AutoComplete=function(G,B,J,C){if(G&&B&&J){if(J&&YAHOO.lang.isFunction(J.sendRequest)){this.dataSource=J;}else{return;}this.key=0;var D=J.responseSchema;if(J._aDeprecatedSchema){var K=J._aDeprecatedSchema;if(YAHOO.lang.isArray(K)){if((J.responseType===YAHOO.util.DataSourceBase.TYPE_JSON)||(J.responseType===YAHOO.util.DataSourceBase.TYPE_UNKNOWN)){D.resultsList=K[0];this.key=K[1];D.fields=(K.length<3)?null:K.slice(1);}else{if(J.responseType===YAHOO.util.DataSourceBase.TYPE_XML){D.resultNode=K[0];this.key=K[1];D.fields=K.slice(1);}else{if(J.responseType===YAHOO.util.DataSourceBase.TYPE_TEXT){D.recordDelim=K[0];D.fieldDelim=K[1];}}}J.responseSchema=D;}}if(YAHOO.util.Dom.inDocument(G)){if(YAHOO.lang.isString(G)){this._sName="instance"+YAHOO.widget.AutoComplete._nIndex+" "+G;this._elTextbox=document.getElementById(G);}else{this._sName=(G.id)?"instance"+YAHOO.widget.AutoComplete._nIndex+" "+G.id:"instance"+YAHOO.widget.AutoComplete._nIndex;this._elTextbox=G;}YAHOO.util.Dom.addClass(this._elTextbox,"yui-ac-input");}else{return;}if(YAHOO.util.Dom.inDocument(B)){if(YAHOO.lang.isString(B)){this._elContainer=document.getElementById(B);}else{this._elContainer=B;}if(this._elContainer.style.display=="none"){}var E=this._elContainer.parentNode;var A=E.tagName.toLowerCase();if(A=="div"){YAHOO.util.Dom.addClass(E,"yui-ac");}else{}}else{return;}if(this.dataSource.dataType===YAHOO.util.DataSourceBase.TYPE_LOCAL){this.applyLocalFilter=true;}if(C&&(C.constructor==Object)){for(var I in C){if(I){this[I]=C[I];}}}this._initContainerEl();this._initProps();this._initListEl();this._initContainerHelperEls();var H=this;var F=this._elTextbox;YAHOO.util.Event.addListener(F,"keyup",H._onTextboxKeyUp,H);YAHOO.util.Event.addListener(F,"keydown",H._onTextboxKeyDown,H);YAHOO.util.Event.addListener(F,"focus",H._onTextboxFocus,H);YAHOO.util.Event.addListener(F,"blur",H._onTextboxBlur,H);YAHOO.util.Event.addListener(B,"mouseover",H._onContainerMouseover,H);YAHOO.util.Event.addListener(B,"mouseout",H._onContainerMouseout,H);YAHOO.util.Event.addListener(B,"click",H._onContainerClick,H);YAHOO.util.Event.addListener(B,"scroll",H._onContainerScroll,H);YAHOO.util.Event.addListener(B,"resize",H._onContainerResize,H);YAHOO.util.Event.addListener(F,"keypress",H._onTextboxKeyPress,H);YAHOO.util.Event.addListener(window,"unload",H._onWindowUnload,H);this.textboxFocusEvent=new YAHOO.util.CustomEvent("textboxFocus",this);this.textboxKeyEvent=new YAHOO.util.CustomEvent("textboxKey",this);this.dataRequestEvent=new YAHOO.util.CustomEvent("dataRequest",this);this.dataReturnEvent=new YAHOO.util.CustomEvent("dataReturn",this);this.dataErrorEvent=new YAHOO.util.CustomEvent("dataError",this);this.containerPopulateEvent=new YAHOO.util.CustomEvent("containerPopulate",this);this.containerExpandEvent=new YAHOO.util.CustomEvent("containerExpand",this);this.typeAheadEvent=new YAHOO.util.CustomEvent("typeAhead",this);this.itemMouseOverEvent=new YAHOO.util.CustomEvent("itemMouseOver",this);this.itemMouseOutEvent=new YAHOO.util.CustomEvent("itemMouseOut",this);this.itemArrowToEvent=new YAHOO.util.CustomEvent("itemArrowTo",this);this.itemArrowFromEvent=new YAHOO.util.CustomEvent("itemArrowFrom",this);this.itemSelectEvent=new YAHOO.util.CustomEvent("itemSelect",this);this.unmatchedItemSelectEvent=new YAHOO.util.CustomEvent("unmatchedItemSelect",this);this.selectionEnforceEvent=new YAHOO.util.CustomEvent("selectionEnforce",this);this.containerCollapseEvent=new YAHOO.util.CustomEvent("containerCollapse",this);this.textboxBlurEvent=new YAHOO.util.CustomEvent("textboxBlur",this);this.textboxChangeEvent=new YAHOO.util.CustomEvent("textboxChange",this);F.setAttribute("autocomplete","off");YAHOO.widget.AutoComplete._nIndex++;}else{}};YAHOO.widget.AutoComplete.prototype.dataSource=null;YAHOO.widget.AutoComplete.prototype.applyLocalFilter=null;YAHOO.widget.AutoComplete.prototype.queryMatchCase=false;YAHOO.widget.AutoComplete.prototype.queryMatchContains=false;YAHOO.widget.AutoComplete.prototype.queryMatchSubset=false;YAHOO.widget.AutoComplete.prototype.minQueryLength=1;YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed=10;YAHOO.widget.AutoComplete.prototype.queryDelay=0.2;YAHOO.widget.AutoComplete.prototype.typeAheadDelay=0.5;YAHOO.widget.AutoComplete.prototype.queryInterval=500;YAHOO.widget.AutoComplete.prototype.highlightClassName="yui-ac-highlight";YAHOO.widget.AutoComplete.prototype.prehighlightClassName=null;YAHOO.widget.AutoComplete.prototype.delimChar=null;YAHOO.widget.AutoComplete.prototype.autoHighlight=true;YAHOO.widget.AutoComplete.prototype.typeAhead=false;YAHOO.widget.AutoComplete.prototype.animHoriz=false;YAHOO.widget.AutoComplete.prototype.animVert=true;YAHOO.widget.AutoComplete.prototype.animSpeed=0.3;YAHOO.widget.AutoComplete.prototype.forceSelection=false;YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete=true;YAHOO.widget.AutoComplete.prototype.alwaysShowContainer=false;YAHOO.widget.AutoComplete.prototype.useIFrame=false;YAHOO.widget.AutoComplete.prototype.useShadow=false;YAHOO.widget.AutoComplete.prototype.suppressInputUpdate=false;YAHOO.widget.AutoComplete.prototype.resultTypeList=true;YAHOO.widget.AutoComplete.prototype.queryQuestionMark=true;YAHOO.widget.AutoComplete.prototype.autoSnapContainer=true;YAHOO.widget.AutoComplete.prototype.toString=function(){return"AutoComplete "+this._sName;};YAHOO.widget.AutoComplete.prototype.getInputEl=function(){return this._elTextbox;};YAHOO.widget.AutoComplete.prototype.getContainerEl=function(){return this._elContainer;
-};YAHOO.widget.AutoComplete.prototype.isFocused=function(){return this._bFocused;};YAHOO.widget.AutoComplete.prototype.isContainerOpen=function(){return this._bContainerOpen;};YAHOO.widget.AutoComplete.prototype.getListEl=function(){return this._elList;};YAHOO.widget.AutoComplete.prototype.getListItemMatch=function(A){if(A._sResultMatch){return A._sResultMatch;}else{return null;}};YAHOO.widget.AutoComplete.prototype.getListItemData=function(A){if(A._oResultData){return A._oResultData;}else{return null;}};YAHOO.widget.AutoComplete.prototype.getListItemIndex=function(A){if(YAHOO.lang.isNumber(A._nItemIndex)){return A._nItemIndex;}else{return null;}};YAHOO.widget.AutoComplete.prototype.setHeader=function(B){if(this._elHeader){var A=this._elHeader;if(B){A.innerHTML=B;A.style.display="";}else{A.innerHTML="";A.style.display="none";}}};YAHOO.widget.AutoComplete.prototype.setFooter=function(B){if(this._elFooter){var A=this._elFooter;if(B){A.innerHTML=B;A.style.display="";}else{A.innerHTML="";A.style.display="none";}}};YAHOO.widget.AutoComplete.prototype.setBody=function(A){if(this._elBody){var B=this._elBody;YAHOO.util.Event.purgeElement(B,true);if(A){B.innerHTML=A;B.style.display="";}else{B.innerHTML="";B.style.display="none";}this._elList=null;}};YAHOO.widget.AutoComplete.prototype.generateRequest=function(B){var A=this.dataSource.dataType;if(A===YAHOO.util.DataSourceBase.TYPE_XHR){if(!this.dataSource.connMethodPost){B=(this.queryQuestionMark?"?":"")+(this.dataSource.scriptQueryParam||"query")+"="+B+(this.dataSource.scriptQueryAppend?("&"+this.dataSource.scriptQueryAppend):"");}else{B=(this.dataSource.scriptQueryParam||"query")+"="+B+(this.dataSource.scriptQueryAppend?("&"+this.dataSource.scriptQueryAppend):"");}}else{if(A===YAHOO.util.DataSourceBase.TYPE_SCRIPTNODE){B="&"+(this.dataSource.scriptQueryParam||"query")+"="+B+(this.dataSource.scriptQueryAppend?("&"+this.dataSource.scriptQueryAppend):"");}}return B;};YAHOO.widget.AutoComplete.prototype.sendQuery=function(B){this._bFocused=true;var A=(this.delimChar)?this._elTextbox.value+B:B;this._sendQuery(A);};YAHOO.widget.AutoComplete.prototype.snapContainer=function(){var A=this._elTextbox,B=YAHOO.util.Dom.getXY(A);B[1]+=YAHOO.util.Dom.get(A).offsetHeight+2;YAHOO.util.Dom.setXY(this._elContainer,B);};YAHOO.widget.AutoComplete.prototype.expandContainer=function(){this._toggleContainer(true);};YAHOO.widget.AutoComplete.prototype.collapseContainer=function(){this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype.clearList=function(){var B=this._elList.childNodes,A=B.length-1;for(;A>-1;A--){B[A].style.display="none";}};YAHOO.widget.AutoComplete.prototype.getSubsetMatches=function(E){var D,C,A;for(var B=E.length;B>=this.minQueryLength;B--){A=this.generateRequest(E.substr(0,B));this.dataRequestEvent.fire(this,D,A);C=this.dataSource.getCachedResponse(A);if(C){return this.filterResults.apply(this.dataSource,[E,C,C,{scope:this}]);}}return null;};YAHOO.widget.AutoComplete.prototype.preparseRawResponse=function(C,B,A){var D=((this.responseStripAfter!=="")&&(B.indexOf))?B.indexOf(this.responseStripAfter):-1;if(D!=-1){B=B.substring(0,D);}return B;};YAHOO.widget.AutoComplete.prototype.filterResults=function(K,M,Q,L){if(L&&L.argument&&L.argument.query){K=L.argument.query;}if(K&&K!==""){Q=YAHOO.widget.AutoComplete._cloneObject(Q);var I=L.scope,P=this,C=Q.results,N=[],B=I.maxResultsDisplayed,J=(P.queryMatchCase||I.queryMatchCase),A=(P.queryMatchContains||I.queryMatchContains);for(var D=0,H=C.length;D<H;D++){var F=C[D];var E=null;if(YAHOO.lang.isString(F)){E=F;}else{if(YAHOO.lang.isArray(F)){E=F[0];}else{if(this.responseSchema.fields){var O=this.responseSchema.fields[0].key||this.responseSchema.fields[0];E=F[O];}else{if(this.key){E=F[this.key];}}}}if(YAHOO.lang.isString(E)){var G=(J)?E.indexOf(decodeURIComponent(K)):E.toLowerCase().indexOf(decodeURIComponent(K).toLowerCase());if((!A&&(G===0))||(A&&(G>-1))){N.push(F);}}if(H>B&&N.length===B){break;}}Q.results=N;}else{}return Q;};YAHOO.widget.AutoComplete.prototype.handleResponse=function(C,A,B){if((this instanceof YAHOO.widget.AutoComplete)&&this._sName){this._populateList(C,A,B);}};YAHOO.widget.AutoComplete.prototype.doBeforeLoadData=function(C,A,B){return true;};YAHOO.widget.AutoComplete.prototype.formatResult=function(B,D,A){var C=(A)?A:"";return C;};YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer=function(D,A,C,B){return true;};YAHOO.widget.AutoComplete.prototype.destroy=function(){var B=this.toString();var A=this._elTextbox;var D=this._elContainer;this.textboxFocusEvent.unsubscribeAll();this.textboxKeyEvent.unsubscribeAll();this.dataRequestEvent.unsubscribeAll();this.dataReturnEvent.unsubscribeAll();this.dataErrorEvent.unsubscribeAll();this.containerPopulateEvent.unsubscribeAll();this.containerExpandEvent.unsubscribeAll();this.typeAheadEvent.unsubscribeAll();this.itemMouseOverEvent.unsubscribeAll();this.itemMouseOutEvent.unsubscribeAll();this.itemArrowToEvent.unsubscribeAll();this.itemArrowFromEvent.unsubscribeAll();this.itemSelectEvent.unsubscribeAll();this.unmatchedItemSelectEvent.unsubscribeAll();this.selectionEnforceEvent.unsubscribeAll();this.containerCollapseEvent.unsubscribeAll();this.textboxBlurEvent.unsubscribeAll();this.textboxChangeEvent.unsubscribeAll();YAHOO.util.Event.purgeElement(A,true);YAHOO.util.Event.purgeElement(D,true);D.innerHTML="";for(var C in this){if(YAHOO.lang.hasOwnProperty(this,C)){this[C]=null;}}};YAHOO.widget.AutoComplete.prototype.textboxFocusEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestEvent=null;YAHOO.widget.AutoComplete.prototype.dataReturnEvent=null;YAHOO.widget.AutoComplete.prototype.dataErrorEvent=null;YAHOO.widget.AutoComplete.prototype.containerPopulateEvent=null;YAHOO.widget.AutoComplete.prototype.containerExpandEvent=null;YAHOO.widget.AutoComplete.prototype.typeAheadEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent=null;
-YAHOO.widget.AutoComplete.prototype.itemArrowToEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent=null;YAHOO.widget.AutoComplete.prototype.itemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent=null;YAHOO.widget.AutoComplete.prototype.containerCollapseEvent=null;YAHOO.widget.AutoComplete.prototype.textboxBlurEvent=null;YAHOO.widget.AutoComplete.prototype.textboxChangeEvent=null;YAHOO.widget.AutoComplete._nIndex=0;YAHOO.widget.AutoComplete.prototype._sName=null;YAHOO.widget.AutoComplete.prototype._elTextbox=null;YAHOO.widget.AutoComplete.prototype._elContainer=null;YAHOO.widget.AutoComplete.prototype._elContent=null;YAHOO.widget.AutoComplete.prototype._elHeader=null;YAHOO.widget.AutoComplete.prototype._elBody=null;YAHOO.widget.AutoComplete.prototype._elFooter=null;YAHOO.widget.AutoComplete.prototype._elShadow=null;YAHOO.widget.AutoComplete.prototype._elIFrame=null;YAHOO.widget.AutoComplete.prototype._bFocused=false;YAHOO.widget.AutoComplete.prototype._oAnim=null;YAHOO.widget.AutoComplete.prototype._bContainerOpen=false;YAHOO.widget.AutoComplete.prototype._bOverContainer=false;YAHOO.widget.AutoComplete.prototype._elList=null;YAHOO.widget.AutoComplete.prototype._nDisplayedItems=0;YAHOO.widget.AutoComplete.prototype._sCurQuery=null;YAHOO.widget.AutoComplete.prototype._sPastSelections="";YAHOO.widget.AutoComplete.prototype._sInitInputValue=null;YAHOO.widget.AutoComplete.prototype._elCurListItem=null;YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem=null;YAHOO.widget.AutoComplete.prototype._bItemSelected=false;YAHOO.widget.AutoComplete.prototype._nKeyCode=null;YAHOO.widget.AutoComplete.prototype._nDelayID=-1;YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID=-1;YAHOO.widget.AutoComplete.prototype._iFrameSrc="javascript:false;";YAHOO.widget.AutoComplete.prototype._queryInterval=null;YAHOO.widget.AutoComplete.prototype._sLastTextboxValue=null;YAHOO.widget.AutoComplete.prototype._initProps=function(){var B=this.minQueryLength;if(!YAHOO.lang.isNumber(B)){this.minQueryLength=1;}var E=this.maxResultsDisplayed;if(!YAHOO.lang.isNumber(E)||(E<1)){this.maxResultsDisplayed=10;}var F=this.queryDelay;if(!YAHOO.lang.isNumber(F)||(F<0)){this.queryDelay=0.2;}var C=this.typeAheadDelay;if(!YAHOO.lang.isNumber(C)||(C<0)){this.typeAheadDelay=0.2;}var A=this.delimChar;if(YAHOO.lang.isString(A)&&(A.length>0)){this.delimChar=[A];}else{if(!YAHOO.lang.isArray(A)){this.delimChar=null;}}var D=this.animSpeed;if((this.animHoriz||this.animVert)&&YAHOO.util.Anim){if(!YAHOO.lang.isNumber(D)||(D<0)){this.animSpeed=0.3;}if(!this._oAnim){this._oAnim=new YAHOO.util.Anim(this._elContent,{},this.animSpeed);}else{this._oAnim.duration=this.animSpeed;}}if(this.forceSelection&&A){}};YAHOO.widget.AutoComplete.prototype._initContainerHelperEls=function(){if(this.useShadow&&!this._elShadow){var A=document.createElement("div");A.className="yui-ac-shadow";A.style.width=0;A.style.height=0;this._elShadow=this._elContainer.appendChild(A);}if(this.useIFrame&&!this._elIFrame){var B=document.createElement("iframe");B.src=this._iFrameSrc;B.frameBorder=0;B.scrolling="no";B.style.position="absolute";B.style.width=0;B.style.height=0;B.style.padding=0;B.tabIndex=-1;B.role="presentation";B.title="Presentational iframe shim";this._elIFrame=this._elContainer.appendChild(B);}};YAHOO.widget.AutoComplete.prototype._initContainerEl=function(){YAHOO.util.Dom.addClass(this._elContainer,"yui-ac-container");if(!this._elContent){var C=document.createElement("div");C.className="yui-ac-content";C.style.display="none";this._elContent=this._elContainer.appendChild(C);var B=document.createElement("div");B.className="yui-ac-hd";B.style.display="none";this._elHeader=this._elContent.appendChild(B);var D=document.createElement("div");D.className="yui-ac-bd";this._elBody=this._elContent.appendChild(D);var A=document.createElement("div");A.className="yui-ac-ft";A.style.display="none";this._elFooter=this._elContent.appendChild(A);}else{}};YAHOO.widget.AutoComplete.prototype._initListEl=function(){var C=this.maxResultsDisplayed,A=this._elList||document.createElement("ul"),B;while(A.childNodes.length<C){B=document.createElement("li");B.style.display="none";B._nItemIndex=A.childNodes.length;A.appendChild(B);}if(!this._elList){var D=this._elBody;YAHOO.util.Event.purgeElement(D,true);D.innerHTML="";this._elList=D.appendChild(A);}this._elBody.style.display="";};YAHOO.widget.AutoComplete.prototype._focus=function(){var A=this;setTimeout(function(){try{A._elTextbox.focus();}catch(B){}},0);};YAHOO.widget.AutoComplete.prototype._enableIntervalDetection=function(){var A=this;if(!A._queryInterval&&A.queryInterval){A._queryInterval=setInterval(function(){A._onInterval();},A.queryInterval);}};YAHOO.widget.AutoComplete.prototype.enableIntervalDetection=YAHOO.widget.AutoComplete.prototype._enableIntervalDetection;YAHOO.widget.AutoComplete.prototype._onInterval=function(){var A=this._elTextbox.value;var B=this._sLastTextboxValue;if(A!=B){this._sLastTextboxValue=A;this._sendQuery(A);}};YAHOO.widget.AutoComplete.prototype._clearInterval=function(){if(this._queryInterval){clearInterval(this._queryInterval);this._queryInterval=null;}};YAHOO.widget.AutoComplete.prototype._isIgnoreKey=function(A){if((A==9)||(A==13)||(A==16)||(A==17)||(A>=18&&A<=20)||(A==27)||(A>=33&&A<=35)||(A>=36&&A<=40)||(A>=44&&A<=45)||(A==229)){return true;}return false;};YAHOO.widget.AutoComplete.prototype._sendQuery=function(D){if(this.minQueryLength<0){this._toggleContainer(false);return;}if(this.delimChar){var A=this._extractQuery(D);D=A.query;this._sPastSelections=A.previous;}if((D&&(D.length<this.minQueryLength))||(!D&&this.minQueryLength>0)){if(this._nDelayID!=-1){clearTimeout(this._nDelayID);}this._toggleContainer(false);return;}D=encodeURIComponent(D);this._nDelayID=-1;if(this.dataSource.queryMatchSubset||this.queryMatchSubset){var C=this.getSubsetMatches(D);if(C){this.handleResponse(D,C,{query:D});return;
-}}if(this.dataSource.responseStripAfter){this.dataSource.doBeforeParseData=this.preparseRawResponse;}if(this.applyLocalFilter){this.dataSource.doBeforeCallback=this.filterResults;}var B=this.generateRequest(D);this.dataRequestEvent.fire(this,D,B);this.dataSource.sendRequest(B,{success:this.handleResponse,failure:this.handleResponse,scope:this,argument:{query:D}});};YAHOO.widget.AutoComplete.prototype._populateListItem=function(B,A,C){B.innerHTML=this.formatResult(A,C,B._sResultMatch);};YAHOO.widget.AutoComplete.prototype._populateList=function(K,F,C){if(this._nTypeAheadDelayID!=-1){clearTimeout(this._nTypeAheadDelayID);}K=(C&&C.query)?C.query:K;var H=this.doBeforeLoadData(K,F,C);if(H&&!F.error){this.dataReturnEvent.fire(this,K,F.results);if(this._bFocused){var M=decodeURIComponent(K);this._sCurQuery=M;this._bItemSelected=false;var R=F.results,A=Math.min(R.length,this.maxResultsDisplayed),J=(this.dataSource.responseSchema.fields)?(this.dataSource.responseSchema.fields[0].key||this.dataSource.responseSchema.fields[0]):0;if(A>0){if(!this._elList||(this._elList.childNodes.length<A)){this._initListEl();}this._initContainerHelperEls();var I=this._elList.childNodes;for(var Q=A-1;Q>=0;Q--){var P=I[Q],E=R[Q];if(this.resultTypeList){var B=[];B[0]=(YAHOO.lang.isString(E))?E:E[J]||E[this.key];var L=this.dataSource.responseSchema.fields;if(YAHOO.lang.isArray(L)&&(L.length>1)){for(var N=1,S=L.length;N<S;N++){B[B.length]=E[L[N].key||L[N]];}}else{if(YAHOO.lang.isArray(E)){B=E;}else{if(YAHOO.lang.isString(E)){B=[E];}else{B[1]=E;}}}E=B;}P._sResultMatch=(YAHOO.lang.isString(E))?E:(YAHOO.lang.isArray(E))?E[0]:(E[J]||"");P._oResultData=E;this._populateListItem(P,E,M);P.style.display="";}if(A<I.length){var G;for(var O=I.length-1;O>=A;O--){G=I[O];G.style.display="none";}}this._nDisplayedItems=A;this.containerPopulateEvent.fire(this,K,R);if(this.autoHighlight){var D=this._elList.firstChild;this._toggleHighlight(D,"to");this.itemArrowToEvent.fire(this,D);this._typeAhead(D,K);}else{this._toggleHighlight(this._elCurListItem,"from");}H=this._doBeforeExpandContainer(this._elTextbox,this._elContainer,K,R);this._toggleContainer(H);}else{this._toggleContainer(false);}return;}}else{this.dataErrorEvent.fire(this,K,F);}};YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer=function(D,A,C,B){if(this.autoSnapContainer){this.snapContainer();}return this.doBeforeExpandContainer(D,A,C,B);};YAHOO.widget.AutoComplete.prototype._clearSelection=function(){var A=(this.delimChar)?this._extractQuery(this._elTextbox.value):{previous:"",query:this._elTextbox.value};this._elTextbox.value=A.previous;this.selectionEnforceEvent.fire(this,A.query);};YAHOO.widget.AutoComplete.prototype._textMatchesOption=function(){var A=null;for(var B=0;B<this._nDisplayedItems;B++){var C=this._elList.childNodes[B];var D=(""+C._sResultMatch).toLowerCase();if(D==this._sCurQuery.toLowerCase()){A=C;break;}}return(A);};YAHOO.widget.AutoComplete.prototype._typeAhead=function(B,D){if(!this.typeAhead||(this._nKeyCode==8)){return;}var A=this,C=this._elTextbox;if(C.setSelectionRange||C.createTextRange){this._nTypeAheadDelayID=setTimeout(function(){var F=C.value.length;A._updateValue(B);var G=C.value.length;A._selectText(C,F,G);var E=C.value.substr(F,G);A.typeAheadEvent.fire(A,D,E);},(this.typeAheadDelay*1000));}};YAHOO.widget.AutoComplete.prototype._selectText=function(D,A,B){if(D.setSelectionRange){D.setSelectionRange(A,B);}else{if(D.createTextRange){var C=D.createTextRange();C.moveStart("character",A);C.moveEnd("character",B-D.value.length);C.select();}else{D.select();}}};YAHOO.widget.AutoComplete.prototype._extractQuery=function(H){var C=this.delimChar,F=-1,G,E,B=C.length-1,D;for(;B>=0;B--){G=H.lastIndexOf(C[B]);if(G>F){F=G;}}if(C[B]==" "){for(var A=C.length-1;A>=0;A--){if(H[F-1]==C[A]){F--;break;}}}if(F>-1){E=F+1;while(H.charAt(E)==" "){E+=1;}D=H.substring(0,E);H=H.substr(E);}else{D="";}return{previous:D,query:H};};YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers=function(D){var E=this._elContent.offsetWidth+"px";var B=this._elContent.offsetHeight+"px";if(this.useIFrame&&this._elIFrame){var C=this._elIFrame;if(D){C.style.width=E;C.style.height=B;C.style.padding="";}else{C.style.width=0;C.style.height=0;C.style.padding=0;}}if(this.useShadow&&this._elShadow){var A=this._elShadow;if(D){A.style.width=E;A.style.height=B;}else{A.style.width=0;A.style.height=0;}}};YAHOO.widget.AutoComplete.prototype._toggleContainer=function(I){var D=this._elContainer;if(this.alwaysShowContainer&&this._bContainerOpen){return;}if(!I){this._toggleHighlight(this._elCurListItem,"from");this._nDisplayedItems=0;this._sCurQuery=null;if(this._elContent.style.display=="none"){return;}}var A=this._oAnim;if(A&&A.getEl()&&(this.animHoriz||this.animVert)){if(A.isAnimated()){A.stop(true);}var G=this._elContent.cloneNode(true);D.appendChild(G);G.style.top="-9000px";G.style.width="";G.style.height="";G.style.display="";var F=G.offsetWidth;var C=G.offsetHeight;var B=(this.animHoriz)?0:F;var E=(this.animVert)?0:C;A.attributes=(I)?{width:{to:F},height:{to:C}}:{width:{to:B},height:{to:E}};if(I&&!this._bContainerOpen){this._elContent.style.width=B+"px";this._elContent.style.height=E+"px";}else{this._elContent.style.width=F+"px";this._elContent.style.height=C+"px";}D.removeChild(G);G=null;var H=this;var J=function(){A.onComplete.unsubscribeAll();if(I){H._toggleContainerHelpers(true);H._bContainerOpen=I;H.containerExpandEvent.fire(H);}else{H._elContent.style.display="none";H._bContainerOpen=I;H.containerCollapseEvent.fire(H);}};this._toggleContainerHelpers(false);this._elContent.style.display="";A.onComplete.subscribe(J);A.animate();}else{if(I){this._elContent.style.display="";this._toggleContainerHelpers(true);this._bContainerOpen=I;this.containerExpandEvent.fire(this);}else{this._toggleContainerHelpers(false);this._elContent.style.display="none";this._bContainerOpen=I;this.containerCollapseEvent.fire(this);}}};YAHOO.widget.AutoComplete.prototype._toggleHighlight=function(A,C){if(A){var B=this.highlightClassName;
-if(this._elCurListItem){YAHOO.util.Dom.removeClass(this._elCurListItem,B);this._elCurListItem=null;}if((C=="to")&&B){YAHOO.util.Dom.addClass(A,B);this._elCurListItem=A;}}};YAHOO.widget.AutoComplete.prototype._togglePrehighlight=function(B,C){var A=this.prehighlightClassName;if(this._elCurPrehighlightItem){YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem,A);}if(B==this._elCurListItem){return;}if((C=="mouseover")&&A){YAHOO.util.Dom.addClass(B,A);this._elCurPrehighlightItem=B;}else{YAHOO.util.Dom.removeClass(B,A);}};YAHOO.widget.AutoComplete.prototype._updateValue=function(C){if(!this.suppressInputUpdate){var F=this._elTextbox;var E=(this.delimChar)?(this.delimChar[0]||this.delimChar):null;var B=C._sResultMatch;var D="";if(E){D=this._sPastSelections;D+=B+E;if(E!=" "){D+=" ";}}else{D=B;}F.value=D;if(F.type=="textarea"){F.scrollTop=F.scrollHeight;}var A=F.value.length;this._selectText(F,A,A);this._elCurListItem=C;}};YAHOO.widget.AutoComplete.prototype._selectItem=function(A){this._bItemSelected=true;this._updateValue(A);this._sPastSelections=this._elTextbox.value;this._clearInterval();this.itemSelectEvent.fire(this,A,A._oResultData);this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype._jumpSelection=function(){if(this._elCurListItem){this._selectItem(this._elCurListItem);}else{this._toggleContainer(false);}};YAHOO.widget.AutoComplete.prototype._moveSelection=function(G){if(this._bContainerOpen){var H=this._elCurListItem,D=-1;if(H){D=H._nItemIndex;}var E=(G==40)?(D+1):(D-1);if(E<-2||E>=this._nDisplayedItems){return;}if(H){this._toggleHighlight(H,"from");this.itemArrowFromEvent.fire(this,H);}if(E==-1){if(this.delimChar){this._elTextbox.value=this._sPastSelections+this._sCurQuery;}else{this._elTextbox.value=this._sCurQuery;}return;}if(E==-2){this._toggleContainer(false);return;}var F=this._elList.childNodes[E],B=this._elContent,C=YAHOO.util.Dom.getStyle(B,"overflow"),I=YAHOO.util.Dom.getStyle(B,"overflowY"),A=((C=="auto")||(C=="scroll")||(I=="auto")||(I=="scroll"));if(A&&(E>-1)&&(E<this._nDisplayedItems)){if(G==40){if((F.offsetTop+F.offsetHeight)>(B.scrollTop+B.offsetHeight)){B.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}else{if((F.offsetTop+F.offsetHeight)<B.scrollTop){B.scrollTop=F.offsetTop;}}}else{if(F.offsetTop<B.scrollTop){this._elContent.scrollTop=F.offsetTop;}else{if(F.offsetTop>(B.scrollTop+B.offsetHeight)){this._elContent.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}}}}this._toggleHighlight(F,"to");this.itemArrowToEvent.fire(this,F);if(this.typeAhead){this._updateValue(F);}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseover=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseover");}else{C._toggleHighlight(D,"to");}C.itemMouseOverEvent.fire(C,D);break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=true;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseout=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseout");}else{C._toggleHighlight(D,"from");}C.itemMouseOutEvent.fire(C,D);break;case"ul":C._toggleHighlight(C._elCurListItem,"to");break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=false;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerClick=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":C._toggleHighlight(D,"to");C._selectItem(D);return;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerScroll=function(A,B){B._focus();};YAHOO.widget.AutoComplete.prototype._onContainerResize=function(A,B){B._toggleContainerHelpers(B._bContainerOpen);};YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown=function(A,B){var C=A.keyCode;if(B._nTypeAheadDelayID!=-1){clearTimeout(B._nTypeAheadDelayID);}switch(C){case 9:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B.delimChar&&(B._nKeyCode!=C)){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B._nKeyCode!=C){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 27:B._toggleContainer(false);return;case 39:B._jumpSelection();break;case 38:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;case 40:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;default:B._bItemSelected=false;B._toggleHighlight(B._elCurListItem,"from");B.textboxKeyEvent.fire(B,C);break;}if(C===18){B._enableIntervalDetection();}B._nKeyCode=C;};YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress=function(A,B){var C=A.keyCode;if(YAHOO.env.ua.opera||(navigator.userAgent.toLowerCase().indexOf("mac")!=-1)&&(YAHOO.env.ua.webkit<420)){switch(C){case 9:if(B._bContainerOpen){if(B.delimChar){YAHOO.util.Event.stopEvent(A);}if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;default:break;}}else{if(C==229){B._enableIntervalDetection();}}};YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp=function(A,C){var B=this.value;C._initProps();var D=A.keyCode;if(C._isIgnoreKey(D)){return;
-}if(C._nDelayID!=-1){clearTimeout(C._nDelayID);}C._nDelayID=setTimeout(function(){C._sendQuery(B);},(C.queryDelay*1000));};YAHOO.widget.AutoComplete.prototype._onTextboxFocus=function(A,B){if(!B._bFocused){B._elTextbox.setAttribute("autocomplete","off");B._bFocused=true;B._sInitInputValue=B._elTextbox.value;B.textboxFocusEvent.fire(B);}};YAHOO.widget.AutoComplete.prototype._onTextboxBlur=function(A,C){if(!C._bOverContainer||(C._nKeyCode==9)){if(!C._bItemSelected){var B=C._textMatchesOption();if(!C._bContainerOpen||(C._bContainerOpen&&(B===null))){if(C.forceSelection){C._clearSelection();}else{C.unmatchedItemSelectEvent.fire(C,C._sCurQuery);}}else{if(C.forceSelection){C._selectItem(B);}}}C._clearInterval();C._bFocused=false;if(C._sInitInputValue!==C._elTextbox.value){C.textboxChangeEvent.fire(C);}C.textboxBlurEvent.fire(C);C._toggleContainer(false);}else{C._focus();}};YAHOO.widget.AutoComplete.prototype._onWindowUnload=function(A,B){if(B&&B._elTextbox&&B.allowBrowserAutocomplete){B._elTextbox.setAttribute("autocomplete","on");}};YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery=function(A){return this.generateRequest(A);};YAHOO.widget.AutoComplete.prototype.getListItems=function(){var C=[],B=this._elList.childNodes;for(var A=B.length-1;A>=0;A--){C[A]=B[A];}return C;};YAHOO.widget.AutoComplete._cloneObject=function(D){if(!YAHOO.lang.isValue(D)){return D;}var F={};if(YAHOO.lang.isFunction(D)){F=D;}else{if(YAHOO.lang.isArray(D)){var E=[];for(var C=0,B=D.length;C<B;C++){E[C]=YAHOO.widget.AutoComplete._cloneObject(D[C]);}F=E;}else{if(YAHOO.lang.isObject(D)){for(var A in D){if(YAHOO.lang.hasOwnProperty(D,A)){if(YAHOO.lang.isValue(D[A])&&YAHOO.lang.isObject(D[A])||YAHOO.lang.isArray(D[A])){F[A]=YAHOO.widget.AutoComplete._cloneObject(D[A]);}else{F[A]=D[A];}}}}else{F=D;}}}return F;};YAHOO.register("autocomplete",YAHOO.widget.AutoComplete,{version:"2.8.1",build:"19"});/*
-Copyright (c) 2010, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.8.1
-*/
-(function(){YAHOO.util.Config=function(D){if(D){this.init(D);}};var B=YAHOO.lang,C=YAHOO.util.CustomEvent,A=YAHOO.util.Config;A.CONFIG_CHANGED_EVENT="configChanged";A.BOOLEAN_TYPE="boolean";A.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(D){this.owner=D;this.configChangedEvent=this.createEvent(A.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=C.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(D){return(typeof D==A.BOOLEAN_TYPE);},checkNumber:function(D){return(!isNaN(D));},fireEvent:function(D,F){var E=this.config[D];if(E&&E.event){E.event.fire(F);}},addProperty:function(E,D){E=E.toLowerCase();this.config[E]=D;D.event=this.createEvent(E,{scope:this.owner});D.event.signature=C.LIST;D.key=E;if(D.handler){D.event.subscribe(D.handler,this.owner);}this.setProperty(E,D.value,true);if(!D.suppressEvent){this.queueProperty(E,D.value);}},getConfig:function(){var D={},F=this.config,G,E;for(G in F){if(B.hasOwnProperty(F,G)){E=F[G];if(E&&E.event){D[G]=E.value;}}}return D;},getProperty:function(D){var E=this.config[D.toLowerCase()];if(E&&E.event){return E.value;}else{return undefined;}},resetProperty:function(D){D=D.toLowerCase();var E=this.config[D];if(E&&E.event){if(this.initialConfig[D]&&!B.isUndefined(this.initialConfig[D])){this.setProperty(D,this.initialConfig[D]);return true;}}else{return false;}},setProperty:function(E,G,D){var F;E=E.toLowerCase();if(this.queueInProgress&&!D){this.queueProperty(E,G);return true;}else{F=this.config[E];if(F&&F.event){if(F.validator&&!F.validator(G)){return false;}else{F.value=G;if(!D){this.fireEvent(E,G);this.configChangedEvent.fire([E,G]);}return true;}}else{return false;}}},queueProperty:function(S,P){S=S.toLowerCase();var R=this.config[S],K=false,J,G,H,I,O,Q,F,M,N,D,L,T,E;if(R&&R.event){if(!B.isUndefined(P)&&R.validator&&!R.validator(P)){return false;}else{if(!B.isUndefined(P)){R.value=P;}else{P=R.value;}K=false;J=this.eventQueue.length;for(L=0;L<J;L++){G=this.eventQueue[L];if(G){H=G[0];I=G[1];if(H==S){this.eventQueue[L]=null;this.eventQueue.push([S,(!B.isUndefined(P)?P:I)]);K=true;break;}}}if(!K&&!B.isUndefined(P)){this.eventQueue.push([S,P]);}}if(R.supercedes){O=R.supercedes.length;for(T=0;T<O;T++){Q=R.supercedes[T];F=this.eventQueue.length;for(E=0;E<F;E++){M=this.eventQueue[E];if(M){N=M[0];D=M[1];if(N==Q.toLowerCase()){this.eventQueue.push([N,D]);this.eventQueue[E]=null;break;}}}}}return true;}else{return false;}},refireEvent:function(D){D=D.toLowerCase();var E=this.config[D];if(E&&E.event&&!B.isUndefined(E.value)){if(this.queueInProgress){this.queueProperty(D);}else{this.fireEvent(D,E.value);}}},applyConfig:function(D,G){var F,E;if(G){E={};for(F in D){if(B.hasOwnProperty(D,F)){E[F.toLowerCase()]=D[F];}}this.initialConfig=E;}for(F in D){if(B.hasOwnProperty(D,F)){this.queueProperty(F,D[F]);}}},refresh:function(){var D;for(D in this.config){if(B.hasOwnProperty(this.config,D)){this.refireEvent(D);}}},fireQueue:function(){var E,H,D,G,F;this.queueInProgress=true;for(E=0;E<this.eventQueue.length;E++){H=this.eventQueue[E];if(H){D=H[0];G=H[1];F=this.config[D];F.value=G;this.eventQueue[E]=null;this.fireEvent(D,G);}}this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(D,E,G,H){var F=this.config[D.toLowerCase()];if(F&&F.event){if(!A.alreadySubscribed(F.event,E,G)){F.event.subscribe(E,G,H);}return true;}else{return false;}},unsubscribeFromConfigEvent:function(D,E,G){var F=this.config[D.toLowerCase()];if(F&&F.event){return F.event.unsubscribe(E,G);}else{return false;}},toString:function(){var D="Config";if(this.owner){D+=" ["+this.owner.toString()+"]";}return D;},outputEventQueue:function(){var D="",G,E,F=this.eventQueue.length;for(E=0;E<F;E++){G=this.eventQueue[E];if(G){D+=G[0]+"="+G[1]+", ";}}return D;},destroy:function(){var E=this.config,D,F;for(D in E){if(B.hasOwnProperty(E,D)){F=E[D];F.event.unsubscribeAll();F.event=null;}}this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};A.alreadySubscribed=function(E,H,I){var F=E.subscribers.length,D,G;if(F>0){G=F-1;do{D=E.subscribers[G];if(D&&D.obj==I&&D.fn==H){return true;}}while(G--);}return false;};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(R,Q){if(R){this.init(R,Q);}else{}};var F=YAHOO.util.Dom,D=YAHOO.util.Config,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,I=YAHOO.env.ua,H,P,O,E,A={"BEFORE_INIT":"beforeInit","INIT":"init","APPEND":"append","BEFORE_RENDER":"beforeRender","RENDER":"render","CHANGE_HEADER":"changeHeader","CHANGE_BODY":"changeBody","CHANGE_FOOTER":"changeFooter","CHANGE_CONTENT":"changeContent","DESTROY":"destroy","BEFORE_SHOW":"beforeShow","SHOW":"show","BEFORE_HIDE":"beforeHide","HIDE":"hide"},J={"VISIBLE":{key:"visible",value:true,validator:YAHOO.lang.isBoolean},"EFFECT":{key:"effect",suppressEvent:true,supercedes:["visible"]},"MONITOR_RESIZE":{key:"monitorresize",value:true},"APPEND_TO_DOCUMENT_BODY":{key:"appendtodocumentbody",value:false}};G.IMG_ROOT=null;G.IMG_ROOT_SSL=null;G.CSS_MODULE="yui-module";G.CSS_HEADER="hd";G.CSS_BODY="bd";G.CSS_FOOTER="ft";G.RESIZE_MONITOR_SECURE_URL="javascript:false;";G.RESIZE_MONITOR_BUFFER=1;G.textResizeEvent=new M("textResize");G.forceDocumentRedraw=function(){var Q=document.documentElement;if(Q){Q.className+=" ";Q.className=YAHOO.lang.trim(Q.className);}};function L(){if(!H){H=document.createElement("div");H.innerHTML=('<div class="'+G.CSS_HEADER+'"></div>'+'<div class="'+G.CSS_BODY+'"></div><div class="'+G.CSS_FOOTER+'"></div>');P=H.firstChild;O=P.nextSibling;E=O.nextSibling;}return H;}function K(){if(!P){L();}return(P.cloneNode(false));}function B(){if(!O){L();}return(O.cloneNode(false));}function C(){if(!E){L();}return(E.cloneNode(false));}G.prototype={constructor:G,element:null,header:null,body:null,footer:null,id:null,imageRoot:G.IMG_ROOT,initEvents:function(){var Q=M.LIST;
-this.beforeInitEvent=this.createEvent(A.BEFORE_INIT);this.beforeInitEvent.signature=Q;this.initEvent=this.createEvent(A.INIT);this.initEvent.signature=Q;this.appendEvent=this.createEvent(A.APPEND);this.appendEvent.signature=Q;this.beforeRenderEvent=this.createEvent(A.BEFORE_RENDER);this.beforeRenderEvent.signature=Q;this.renderEvent=this.createEvent(A.RENDER);this.renderEvent.signature=Q;this.changeHeaderEvent=this.createEvent(A.CHANGE_HEADER);this.changeHeaderEvent.signature=Q;this.changeBodyEvent=this.createEvent(A.CHANGE_BODY);this.changeBodyEvent.signature=Q;this.changeFooterEvent=this.createEvent(A.CHANGE_FOOTER);this.changeFooterEvent.signature=Q;this.changeContentEvent=this.createEvent(A.CHANGE_CONTENT);this.changeContentEvent.signature=Q;this.destroyEvent=this.createEvent(A.DESTROY);this.destroyEvent.signature=Q;this.beforeShowEvent=this.createEvent(A.BEFORE_SHOW);this.beforeShowEvent.signature=Q;this.showEvent=this.createEvent(A.SHOW);this.showEvent.signature=Q;this.beforeHideEvent=this.createEvent(A.BEFORE_HIDE);this.beforeHideEvent.signature=Q;this.hideEvent=this.createEvent(A.HIDE);this.hideEvent.signature=Q;},platform:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("windows")!=-1||Q.indexOf("win32")!=-1){return"windows";}else{if(Q.indexOf("macintosh")!=-1){return"mac";}else{return false;}}}(),browser:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("opera")!=-1){return"opera";}else{if(Q.indexOf("msie 7")!=-1){return"ie7";}else{if(Q.indexOf("msie")!=-1){return"ie";}else{if(Q.indexOf("safari")!=-1){return"safari";}else{if(Q.indexOf("gecko")!=-1){return"gecko";}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf("https")===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addProperty(J.VISIBLE.key,{handler:this.configVisible,value:J.VISIBLE.value,validator:J.VISIBLE.validator});this.cfg.addProperty(J.EFFECT.key,{suppressEvent:J.EFFECT.suppressEvent,supercedes:J.EFFECT.supercedes});this.cfg.addProperty(J.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:J.MONITOR_RESIZE.value});this.cfg.addProperty(J.APPEND_TO_DOCUMENT_BODY.key,{value:J.APPEND_TO_DOCUMENT_BODY.value});},init:function(V,U){var S,W;this.initEvents();this.beforeInitEvent.fire(G);this.cfg=new D(this);if(this.isSecure){this.imageRoot=G.IMG_ROOT_SSL;}if(typeof V=="string"){S=V;V=document.getElementById(V);if(!V){V=(L()).cloneNode(false);V.id=S;}}this.id=F.generateId(V);this.element=V;W=this.element.firstChild;if(W){var R=false,Q=false,T=false;do{if(1==W.nodeType){if(!R&&F.hasClass(W,G.CSS_HEADER)){this.header=W;R=true;}else{if(!Q&&F.hasClass(W,G.CSS_BODY)){this.body=W;Q=true;}else{if(!T&&F.hasClass(W,G.CSS_FOOTER)){this.footer=W;T=true;}}}}}while((W=W.nextSibling));}this.initDefaultConfig();F.addClass(this.element,G.CSS_MODULE);if(U){this.cfg.applyConfig(U,true);}if(!D.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(G);},initResizeMonitor:function(){var R=(I.gecko&&this.platform=="windows");if(R){var Q=this;setTimeout(function(){Q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var Q,S,U;function W(){G.textResizeEvent.fire();}if(!I.opera){S=F.get("_yuiResizeMonitor");var V=this._supportsCWResize();if(!S){S=document.createElement("iframe");if(this.isSecure&&G.RESIZE_MONITOR_SECURE_URL&&I.ie){S.src=G.RESIZE_MONITOR_SECURE_URL;}if(!V){U=["<html><head><script ",'type="text/javascript">',"window.onresize=function(){window.parent.","YAHOO.widget.Module.textResizeEvent.","fire();};<","/script></head>","<body></body></html>"].join("");S.src="data:text/html;charset=utf-8,"+encodeURIComponent(U);}S.id="_yuiResizeMonitor";S.title="Text Resize Monitor";S.style.position="absolute";S.style.visibility="hidden";var R=document.body,T=R.firstChild;if(T){R.insertBefore(S,T);}else{R.appendChild(S);}S.style.backgroundColor="transparent";S.style.borderWidth="0";S.style.width="2em";S.style.height="2em";S.style.left="0";S.style.top=(-1*(S.offsetHeight+G.RESIZE_MONITOR_BUFFER))+"px";S.style.visibility="visible";if(I.webkit){Q=S.contentWindow.document;Q.open();Q.close();}}if(S&&S.contentWindow){G.textResizeEvent.subscribe(this.onDomResize,this,true);if(!G.textResizeInitialized){if(V){if(!N.on(S.contentWindow,"resize",W)){N.on(S,"resize",W);}}G.textResizeInitialized=true;}this.resizeMonitor=S;}}},_supportsCWResize:function(){var Q=true;if(I.gecko&&I.gecko<=1.8){Q=false;}return Q;},onDomResize:function(S,R){var Q=-1*(this.resizeMonitor.offsetHeight+G.RESIZE_MONITOR_BUFFER);this.resizeMonitor.style.top=Q+"px";this.resizeMonitor.style.left="0";},setHeader:function(R){var Q=this.header||(this.header=K());if(R.nodeName){Q.innerHTML="";Q.appendChild(R);}else{Q.innerHTML=R;}if(this._rendered){this._renderHeader();}this.changeHeaderEvent.fire(R);this.changeContentEvent.fire();},appendToHeader:function(R){var Q=this.header||(this.header=K());Q.appendChild(R);this.changeHeaderEvent.fire(R);this.changeContentEvent.fire();},setBody:function(R){var Q=this.body||(this.body=B());if(R.nodeName){Q.innerHTML="";Q.appendChild(R);}else{Q.innerHTML=R;}if(this._rendered){this._renderBody();}this.changeBodyEvent.fire(R);this.changeContentEvent.fire();},appendToBody:function(R){var Q=this.body||(this.body=B());Q.appendChild(R);this.changeBodyEvent.fire(R);this.changeContentEvent.fire();},setFooter:function(R){var Q=this.footer||(this.footer=C());if(R.nodeName){Q.innerHTML="";Q.appendChild(R);}else{Q.innerHTML=R;}if(this._rendered){this._renderFooter();}this.changeFooterEvent.fire(R);this.changeContentEvent.fire();},appendToFooter:function(R){var Q=this.footer||(this.footer=C());Q.appendChild(R);this.changeFooterEvent.fire(R);this.changeContentEvent.fire();},render:function(S,Q){var T=this;function R(U){if(typeof U=="string"){U=document.getElementById(U);}if(U){T._addToParent(U,T.element);T.appendEvent.fire();}}this.beforeRenderEvent.fire();
-if(!Q){Q=this.element;}if(S){R(S);}else{if(!F.inDocument(this.element)){return false;}}this._renderHeader(Q);this._renderBody(Q);this._renderFooter(Q);this._rendered=true;this.renderEvent.fire();return true;},_renderHeader:function(Q){Q=Q||this.element;if(this.header&&!F.inDocument(this.header)){var R=Q.firstChild;if(R){Q.insertBefore(this.header,R);}else{Q.appendChild(this.header);}}},_renderBody:function(Q){Q=Q||this.element;if(this.body&&!F.inDocument(this.body)){if(this.footer&&F.isAncestor(Q,this.footer)){Q.insertBefore(this.body,this.footer);}else{Q.appendChild(this.body);}}},_renderFooter:function(Q){Q=Q||this.element;if(this.footer&&!F.inDocument(this.footer)){Q.appendChild(this.footer);}},destroy:function(){var Q;if(this.element){N.purgeElement(this.element,true);Q=this.element.parentNode;}if(Q){Q.removeChild(this.element);}this.element=null;this.header=null;this.body=null;this.footer=null;G.textResizeEvent.unsubscribe(this.onDomResize,this);this.cfg.destroy();this.cfg=null;this.destroyEvent.fire();},show:function(){this.cfg.setProperty("visible",true);},hide:function(){this.cfg.setProperty("visible",false);},configVisible:function(R,Q,S){var T=Q[0];if(T){this.beforeShowEvent.fire();F.setStyle(this.element,"display","block");this.showEvent.fire();}else{this.beforeHideEvent.fire();F.setStyle(this.element,"display","none");this.hideEvent.fire();}},configMonitorResize:function(S,R,T){var Q=R[0];if(Q){this.initResizeMonitor();}else{G.textResizeEvent.unsubscribe(this.onDomResize,this,true);this.resizeMonitor=null;}},_addToParent:function(Q,R){if(!this.cfg.getProperty("appendtodocumentbody")&&Q===document.body&&Q.firstChild){Q.insertBefore(R,Q.firstChild);}else{Q.appendChild(R);}},toString:function(){return"Module "+this.id;}};YAHOO.lang.augmentProto(G,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Overlay=function(P,O){YAHOO.widget.Overlay.superclass.constructor.call(this,P,O);};var I=YAHOO.lang,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,N=YAHOO.util.Event,F=YAHOO.util.Dom,D=YAHOO.util.Config,K=YAHOO.env.ua,B=YAHOO.widget.Overlay,H="subscribe",E="unsubscribe",C="contained",J,A={"BEFORE_MOVE":"beforeMove","MOVE":"move"},L={"X":{key:"x",validator:I.isNumber,suppressEvent:true,supercedes:["iframe"]},"Y":{key:"y",validator:I.isNumber,suppressEvent:true,supercedes:["iframe"]},"XY":{key:"xy",suppressEvent:true,supercedes:["iframe"]},"CONTEXT":{key:"context",suppressEvent:true,supercedes:["iframe"]},"FIXED_CENTER":{key:"fixedcenter",value:false,supercedes:["iframe","visible"]},"WIDTH":{key:"width",suppressEvent:true,supercedes:["context","fixedcenter","iframe"]},"HEIGHT":{key:"height",suppressEvent:true,supercedes:["context","fixedcenter","iframe"]},"AUTO_FILL_HEIGHT":{key:"autofillheight",supercedes:["height"],value:"body"},"ZINDEX":{key:"zindex",value:null},"CONSTRAIN_TO_VIEWPORT":{key:"constraintoviewport",value:false,validator:I.isBoolean,supercedes:["iframe","x","y","xy"]},"IFRAME":{key:"iframe",value:(K.ie==6?true:false),validator:I.isBoolean,supercedes:["zindex"]},"PREVENT_CONTEXT_OVERLAP":{key:"preventcontextoverlap",value:false,validator:I.isBoolean,supercedes:["constraintoviewport"]}};B.IFRAME_SRC="javascript:false;";B.IFRAME_OFFSET=3;B.VIEWPORT_OFFSET=10;B.TOP_LEFT="tl";B.TOP_RIGHT="tr";B.BOTTOM_LEFT="bl";B.BOTTOM_RIGHT="br";B.PREVENT_OVERLAP_X={"tltr":true,"blbr":true,"brbl":true,"trtl":true};B.PREVENT_OVERLAP_Y={"trbr":true,"tlbl":true,"bltl":true,"brtr":true};B.CSS_OVERLAY="yui-overlay";B.CSS_HIDDEN="yui-overlay-hidden";B.CSS_IFRAME="yui-overlay-iframe";B.STD_MOD_RE=/^\s*?(body|footer|header)\s*?$/i;B.windowScrollEvent=new M("windowScroll");B.windowResizeEvent=new M("windowResize");B.windowScrollHandler=function(P){var O=N.getTarget(P);if(!O||O===window||O===window.document){if(K.ie){if(!window.scrollEnd){window.scrollEnd=-1;}clearTimeout(window.scrollEnd);window.scrollEnd=setTimeout(function(){B.windowScrollEvent.fire();},1);}else{B.windowScrollEvent.fire();}}};B.windowResizeHandler=function(O){if(K.ie){if(!window.resizeEnd){window.resizeEnd=-1;}clearTimeout(window.resizeEnd);window.resizeEnd=setTimeout(function(){B.windowResizeEvent.fire();},100);}else{B.windowResizeEvent.fire();}};B._initialized=null;if(B._initialized===null){N.on(window,"scroll",B.windowScrollHandler);N.on(window,"resize",B.windowResizeHandler);B._initialized=true;}B._TRIGGER_MAP={"windowScroll":B.windowScrollEvent,"windowResize":B.windowResizeEvent,"textResize":G.textResizeEvent};YAHOO.extend(B,G,{CONTEXT_TRIGGERS:[],init:function(P,O){B.superclass.init.call(this,P);this.beforeInitEvent.fire(B);F.addClass(this.element,B.CSS_OVERLAY);if(O){this.cfg.applyConfig(O,true);}if(this.platform=="mac"&&K.gecko){if(!D.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)){this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);}if(!D.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)){this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true);}}this.initEvent.fire(B);},initEvents:function(){B.superclass.initEvents.call(this);var O=M.LIST;this.beforeMoveEvent=this.createEvent(A.BEFORE_MOVE);this.beforeMoveEvent.signature=O;this.moveEvent=this.createEvent(A.MOVE);this.moveEvent.signature=O;},initDefaultConfig:function(){B.superclass.initDefaultConfig.call(this);var O=this.cfg;O.addProperty(L.X.key,{handler:this.configX,validator:L.X.validator,suppressEvent:L.X.suppressEvent,supercedes:L.X.supercedes});O.addProperty(L.Y.key,{handler:this.configY,validator:L.Y.validator,suppressEvent:L.Y.suppressEvent,supercedes:L.Y.supercedes});O.addProperty(L.XY.key,{handler:this.configXY,suppressEvent:L.XY.suppressEvent,supercedes:L.XY.supercedes});O.addProperty(L.CONTEXT.key,{handler:this.configContext,suppressEvent:L.CONTEXT.suppressEvent,supercedes:L.CONTEXT.supercedes});O.addProperty(L.FIXED_CENTER.key,{handler:this.configFixedCenter,value:L.FIXED_CENTER.value,validator:L.FIXED_CENTER.validator,supercedes:L.FIXED_CENTER.supercedes});O.addProperty(L.WIDTH.key,{handler:this.configWidth,suppressEvent:L.WIDTH.suppressEvent,supercedes:L.WIDTH.supercedes});
-O.addProperty(L.HEIGHT.key,{handler:this.configHeight,suppressEvent:L.HEIGHT.suppressEvent,supercedes:L.HEIGHT.supercedes});O.addProperty(L.AUTO_FILL_HEIGHT.key,{handler:this.configAutoFillHeight,value:L.AUTO_FILL_HEIGHT.value,validator:this._validateAutoFill,supercedes:L.AUTO_FILL_HEIGHT.supercedes});O.addProperty(L.ZINDEX.key,{handler:this.configzIndex,value:L.ZINDEX.value});O.addProperty(L.CONSTRAIN_TO_VIEWPORT.key,{handler:this.configConstrainToViewport,value:L.CONSTRAIN_TO_VIEWPORT.value,validator:L.CONSTRAIN_TO_VIEWPORT.validator,supercedes:L.CONSTRAIN_TO_VIEWPORT.supercedes});O.addProperty(L.IFRAME.key,{handler:this.configIframe,value:L.IFRAME.value,validator:L.IFRAME.validator,supercedes:L.IFRAME.supercedes});O.addProperty(L.PREVENT_CONTEXT_OVERLAP.key,{value:L.PREVENT_CONTEXT_OVERLAP.value,validator:L.PREVENT_CONTEXT_OVERLAP.validator,supercedes:L.PREVENT_CONTEXT_OVERLAP.supercedes});},moveTo:function(O,P){this.cfg.setProperty("xy",[O,P]);},hideMacGeckoScrollbars:function(){F.replaceClass(this.element,"show-scrollbars","hide-scrollbars");},showMacGeckoScrollbars:function(){F.replaceClass(this.element,"hide-scrollbars","show-scrollbars");},_setDomVisibility:function(O){F.setStyle(this.element,"visibility",(O)?"visible":"hidden");var P=B.CSS_HIDDEN;if(O){F.removeClass(this.element,P);}else{F.addClass(this.element,P);}},configVisible:function(R,O,X){var Q=O[0],S=F.getStyle(this.element,"visibility"),Y=this.cfg.getProperty("effect"),V=[],U=(this.platform=="mac"&&K.gecko),g=D.alreadySubscribed,W,P,f,c,b,a,d,Z,T;if(S=="inherit"){f=this.element.parentNode;while(f.nodeType!=9&&f.nodeType!=11){S=F.getStyle(f,"visibility");if(S!="inherit"){break;}f=f.parentNode;}if(S=="inherit"){S="visible";}}if(Y){if(Y instanceof Array){Z=Y.length;for(c=0;c<Z;c++){W=Y[c];V[V.length]=W.effect(this,W.duration);}}else{V[V.length]=Y.effect(this,Y.duration);}}if(Q){if(U){this.showMacGeckoScrollbars();}if(Y){if(Q){if(S!="visible"||S===""){this.beforeShowEvent.fire();T=V.length;for(b=0;b<T;b++){P=V[b];if(b===0&&!g(P.animateInCompleteEvent,this.showEvent.fire,this.showEvent)){P.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true);}P.animateIn();}}}}else{if(S!="visible"||S===""){this.beforeShowEvent.fire();this._setDomVisibility(true);this.cfg.refireEvent("iframe");this.showEvent.fire();}else{this._setDomVisibility(true);}}}else{if(U){this.hideMacGeckoScrollbars();}if(Y){if(S=="visible"){this.beforeHideEvent.fire();T=V.length;for(a=0;a<T;a++){d=V[a];if(a===0&&!g(d.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)){d.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true);}d.animateOut();}}else{if(S===""){this._setDomVisibility(false);}}}else{if(S=="visible"||S===""){this.beforeHideEvent.fire();this._setDomVisibility(false);this.hideEvent.fire();}else{this._setDomVisibility(false);}}}},doCenterOnDOMEvent:function(){var O=this.cfg,P=O.getProperty("fixedcenter");if(O.getProperty("visible")){if(P&&(P!==C||this.fitsInViewport())){this.center();}}},fitsInViewport:function(){var S=B.VIEWPORT_OFFSET,Q=this.element,T=Q.offsetWidth,R=Q.offsetHeight,O=F.getViewportWidth(),P=F.getViewportHeight();return((T+S<O)&&(R+S<P));},configFixedCenter:function(S,Q,T){var U=Q[0],P=D.alreadySubscribed,R=B.windowResizeEvent,O=B.windowScrollEvent;if(U){this.center();if(!P(this.beforeShowEvent,this.center)){this.beforeShowEvent.subscribe(this.center);}if(!P(R,this.doCenterOnDOMEvent,this)){R.subscribe(this.doCenterOnDOMEvent,this,true);}if(!P(O,this.doCenterOnDOMEvent,this)){O.subscribe(this.doCenterOnDOMEvent,this,true);}}else{this.beforeShowEvent.unsubscribe(this.center);R.unsubscribe(this.doCenterOnDOMEvent,this);O.unsubscribe(this.doCenterOnDOMEvent,this);}},configHeight:function(R,P,S){var O=P[0],Q=this.element;F.setStyle(Q,"height",O);this.cfg.refireEvent("iframe");},configAutoFillHeight:function(T,S,P){var V=S[0],Q=this.cfg,U="autofillheight",W="height",R=Q.getProperty(U),O=this._autoFillOnHeightChange;Q.unsubscribeFromConfigEvent(W,O);G.textResizeEvent.unsubscribe(O);this.changeContentEvent.unsubscribe(O);if(R&&V!==R&&this[R]){F.setStyle(this[R],W,"");}if(V){V=I.trim(V.toLowerCase());Q.subscribeToConfigEvent(W,O,this[V],this);G.textResizeEvent.subscribe(O,this[V],this);this.changeContentEvent.subscribe(O,this[V],this);Q.setProperty(U,V,true);}},configWidth:function(R,O,S){var Q=O[0],P=this.element;F.setStyle(P,"width",Q);this.cfg.refireEvent("iframe");},configzIndex:function(Q,O,R){var S=O[0],P=this.element;if(!S){S=F.getStyle(P,"zIndex");if(!S||isNaN(S)){S=0;}}if(this.iframe||this.cfg.getProperty("iframe")===true){if(S<=0){S=1;}}F.setStyle(P,"zIndex",S);this.cfg.setProperty("zIndex",S,true);if(this.iframe){this.stackIframe();}},configXY:function(Q,P,R){var T=P[0],O=T[0],S=T[1];this.cfg.setProperty("x",O);this.cfg.setProperty("y",S);this.beforeMoveEvent.fire([O,S]);O=this.cfg.getProperty("x");S=this.cfg.getProperty("y");this.cfg.refireEvent("iframe");this.moveEvent.fire([O,S]);},configX:function(Q,P,R){var O=P[0],S=this.cfg.getProperty("y");this.cfg.setProperty("x",O,true);this.cfg.setProperty("y",S,true);this.beforeMoveEvent.fire([O,S]);O=this.cfg.getProperty("x");S=this.cfg.getProperty("y");F.setX(this.element,O,true);this.cfg.setProperty("xy",[O,S],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([O,S]);},configY:function(Q,P,R){var O=this.cfg.getProperty("x"),S=P[0];this.cfg.setProperty("x",O,true);this.cfg.setProperty("y",S,true);this.beforeMoveEvent.fire([O,S]);O=this.cfg.getProperty("x");S=this.cfg.getProperty("y");F.setY(this.element,S,true);this.cfg.setProperty("xy",[O,S],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([O,S]);},showIframe:function(){var P=this.iframe,O;if(P){O=this.element.parentNode;if(O!=P.parentNode){this._addToParent(O,P);}P.style.display="block";}},hideIframe:function(){if(this.iframe){this.iframe.style.display="none";}},syncIframe:function(){var O=this.iframe,Q=this.element,S=B.IFRAME_OFFSET,P=(S*2),R;if(O){O.style.width=(Q.offsetWidth+P+"px");
-O.style.height=(Q.offsetHeight+P+"px");R=this.cfg.getProperty("xy");if(!I.isArray(R)||(isNaN(R[0])||isNaN(R[1]))){this.syncPosition();R=this.cfg.getProperty("xy");}F.setXY(O,[(R[0]-S),(R[1]-S)]);}},stackIframe:function(){if(this.iframe){var O=F.getStyle(this.element,"zIndex");if(!YAHOO.lang.isUndefined(O)&&!isNaN(O)){F.setStyle(this.iframe,"zIndex",(O-1));}}},configIframe:function(R,Q,S){var O=Q[0];function T(){var V=this.iframe,W=this.element,X;if(!V){if(!J){J=document.createElement("iframe");if(this.isSecure){J.src=B.IFRAME_SRC;}if(K.ie){J.style.filter="alpha(opacity=0)";J.frameBorder=0;}else{J.style.opacity="0";}J.style.position="absolute";J.style.border="none";J.style.margin="0";J.style.padding="0";J.style.display="none";J.tabIndex=-1;J.className=B.CSS_IFRAME;}V=J.cloneNode(false);V.id=this.id+"_f";X=W.parentNode;var U=X||document.body;this._addToParent(U,V);this.iframe=V;}this.showIframe();this.syncIframe();this.stackIframe();if(!this._hasIframeEventListeners){this.showEvent.subscribe(this.showIframe);this.hideEvent.subscribe(this.hideIframe);this.changeContentEvent.subscribe(this.syncIframe);this._hasIframeEventListeners=true;}}function P(){T.call(this);this.beforeShowEvent.unsubscribe(P);this._iframeDeferred=false;}if(O){if(this.cfg.getProperty("visible")){T.call(this);}else{if(!this._iframeDeferred){this.beforeShowEvent.subscribe(P);this._iframeDeferred=true;}}}else{this.hideIframe();if(this._hasIframeEventListeners){this.showEvent.unsubscribe(this.showIframe);this.hideEvent.unsubscribe(this.hideIframe);this.changeContentEvent.unsubscribe(this.syncIframe);this._hasIframeEventListeners=false;}}},_primeXYFromDOM:function(){if(YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))){this.syncPosition();this.cfg.refireEvent("xy");this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);}},configConstrainToViewport:function(P,O,Q){var R=O[0];if(R){if(!D.alreadySubscribed(this.beforeMoveEvent,this.enforceConstraints,this)){this.beforeMoveEvent.subscribe(this.enforceConstraints,this,true);}if(!D.alreadySubscribed(this.beforeShowEvent,this._primeXYFromDOM)){this.beforeShowEvent.subscribe(this._primeXYFromDOM);}}else{this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);this.beforeMoveEvent.unsubscribe(this.enforceConstraints,this);}},configContext:function(U,T,Q){var X=T[0],R,O,V,S,P,W=this.CONTEXT_TRIGGERS;if(X){R=X[0];O=X[1];V=X[2];S=X[3];P=X[4];if(W&&W.length>0){S=(S||[]).concat(W);}if(R){if(typeof R=="string"){this.cfg.setProperty("context",[document.getElementById(R),O,V,S,P],true);}if(O&&V){this.align(O,V,P);}if(this._contextTriggers){this._processTriggers(this._contextTriggers,E,this._alignOnTrigger);}if(S){this._processTriggers(S,H,this._alignOnTrigger);this._contextTriggers=S;}}}},_alignOnTrigger:function(P,O){this.align();},_findTriggerCE:function(O){var P=null;if(O instanceof M){P=O;}else{if(B._TRIGGER_MAP[O]){P=B._TRIGGER_MAP[O];}}return P;},_processTriggers:function(S,U,R){var Q,T;for(var P=0,O=S.length;P<O;++P){Q=S[P];T=this._findTriggerCE(Q);if(T){T[U](R,this,true);}else{this[U](Q,R);}}},align:function(P,W,S){var V=this.cfg.getProperty("context"),T=this,O,Q,U;function R(Z,a){var Y=null,X=null;switch(P){case B.TOP_LEFT:Y=a;X=Z;break;case B.TOP_RIGHT:Y=a-Q.offsetWidth;X=Z;break;case B.BOTTOM_LEFT:Y=a;X=Z-Q.offsetHeight;break;case B.BOTTOM_RIGHT:Y=a-Q.offsetWidth;X=Z-Q.offsetHeight;break;}if(Y!==null&&X!==null){if(S){Y+=S[0];X+=S[1];}T.moveTo(Y,X);}}if(V){O=V[0];Q=this.element;T=this;if(!P){P=V[1];}if(!W){W=V[2];}if(!S&&V[4]){S=V[4];}if(Q&&O){U=F.getRegion(O);switch(W){case B.TOP_LEFT:R(U.top,U.left);break;case B.TOP_RIGHT:R(U.top,U.right);break;case B.BOTTOM_LEFT:R(U.bottom,U.left);break;case B.BOTTOM_RIGHT:R(U.bottom,U.right);break;}}}},enforceConstraints:function(P,O,Q){var S=O[0];var R=this.getConstrainedXY(S[0],S[1]);this.cfg.setProperty("x",R[0],true);this.cfg.setProperty("y",R[1],true);this.cfg.setProperty("xy",R,true);},_getConstrainedPos:function(X,P){var T=this.element,R=B.VIEWPORT_OFFSET,Z=(X=="x"),Y=(Z)?T.offsetWidth:T.offsetHeight,S=(Z)?F.getViewportWidth():F.getViewportHeight(),c=(Z)?F.getDocumentScrollLeft():F.getDocumentScrollTop(),b=(Z)?B.PREVENT_OVERLAP_X:B.PREVENT_OVERLAP_Y,O=this.cfg.getProperty("context"),U=(Y+R<S),W=this.cfg.getProperty("preventcontextoverlap")&&O&&b[(O[1]+O[2])],V=c+R,a=c+S-Y-R,Q=P;if(P<V||P>a){if(W){Q=this._preventOverlap(X,O[0],Y,S,c);}else{if(U){if(P<V){Q=V;}else{if(P>a){Q=a;}}}else{Q=V;}}}return Q;},_preventOverlap:function(X,W,Y,U,b){var Z=(X=="x"),T=B.VIEWPORT_OFFSET,S=this,Q=((Z)?F.getX(W):F.getY(W))-b,O=(Z)?W.offsetWidth:W.offsetHeight,P=Q-T,R=(U-(Q+O))-T,c=false,V=function(){var d;if((S.cfg.getProperty(X)-b)>Q){d=(Q-Y);}else{d=(Q+O);}S.cfg.setProperty(X,(d+b),true);return d;},a=function(){var e=((S.cfg.getProperty(X)-b)>Q)?R:P,d;if(Y>e){if(c){V();}else{V();c=true;d=a();}}return d;};a();return this.cfg.getProperty(X);},getConstrainedX:function(O){return this._getConstrainedPos("x",O);},getConstrainedY:function(O){return this._getConstrainedPos("y",O);},getConstrainedXY:function(O,P){return[this.getConstrainedX(O),this.getConstrainedY(P)];},center:function(){var R=B.VIEWPORT_OFFSET,S=this.element.offsetWidth,Q=this.element.offsetHeight,P=F.getViewportWidth(),T=F.getViewportHeight(),O,U;if(S<P){O=(P/2)-(S/2)+F.getDocumentScrollLeft();}else{O=R+F.getDocumentScrollLeft();}if(Q<T){U=(T/2)-(Q/2)+F.getDocumentScrollTop();}else{U=R+F.getDocumentScrollTop();}this.cfg.setProperty("xy",[parseInt(O,10),parseInt(U,10)]);this.cfg.refireEvent("iframe");if(K.webkit){this.forceContainerRedraw();}},syncPosition:function(){var O=F.getXY(this.element);this.cfg.setProperty("x",O[0],true);this.cfg.setProperty("y",O[1],true);this.cfg.setProperty("xy",O,true);},onDomResize:function(Q,P){var O=this;B.superclass.onDomResize.call(this,Q,P);setTimeout(function(){O.syncPosition();O.cfg.refireEvent("iframe");O.cfg.refireEvent("context");},0);},_getComputedHeight:(function(){if(document.defaultView&&document.defaultView.getComputedStyle){return function(P){var O=null;
-if(P.ownerDocument&&P.ownerDocument.defaultView){var Q=P.ownerDocument.defaultView.getComputedStyle(P,"");if(Q){O=parseInt(Q.height,10);}}return(I.isNumber(O))?O:null;};}else{return function(P){var O=null;if(P.style.pixelHeight){O=P.style.pixelHeight;}return(I.isNumber(O))?O:null;};}})(),_validateAutoFillHeight:function(O){return(!O)||(I.isString(O)&&B.STD_MOD_RE.test(O));},_autoFillOnHeightChange:function(R,P,Q){var O=this.cfg.getProperty("height");if((O&&O!=="auto")||(O===0)){this.fillHeight(Q);}},_getPreciseHeight:function(P){var O=P.offsetHeight;if(P.getBoundingClientRect){var Q=P.getBoundingClientRect();O=Q.bottom-Q.top;}return O;},fillHeight:function(R){if(R){var P=this.innerElement||this.element,O=[this.header,this.body,this.footer],V,W=0,X=0,T=0,Q=false;for(var U=0,S=O.length;U<S;U++){V=O[U];if(V){if(R!==V){X+=this._getPreciseHeight(V);}else{Q=true;}}}if(Q){if(K.ie||K.opera){F.setStyle(R,"height",0+"px");}W=this._getComputedHeight(P);if(W===null){F.addClass(P,"yui-override-padding");W=P.clientHeight;F.removeClass(P,"yui-override-padding");}T=Math.max(W-X,0);F.setStyle(R,"height",T+"px");if(R.offsetHeight!=T){T=Math.max(T-(R.offsetHeight-T),0);}F.setStyle(R,"height",T+"px");}}},bringToTop:function(){var S=[],R=this.element;function V(Z,Y){var b=F.getStyle(Z,"zIndex"),a=F.getStyle(Y,"zIndex"),X=(!b||isNaN(b))?0:parseInt(b,10),W=(!a||isNaN(a))?0:parseInt(a,10);if(X>W){return -1;}else{if(X<W){return 1;}else{return 0;}}}function Q(Y){var X=F.hasClass(Y,B.CSS_OVERLAY),W=YAHOO.widget.Panel;if(X&&!F.isAncestor(R,Y)){if(W&&F.hasClass(Y,W.CSS_PANEL)){S[S.length]=Y.parentNode;}else{S[S.length]=Y;}}}F.getElementsBy(Q,"DIV",document.body);S.sort(V);var O=S[0],U;if(O){U=F.getStyle(O,"zIndex");if(!isNaN(U)){var T=false;if(O!=R){T=true;}else{if(S.length>1){var P=F.getStyle(S[1],"zIndex");if(!isNaN(P)&&(U==P)){T=true;}}}if(T){this.cfg.setProperty("zindex",(parseInt(U,10)+2));}}}},destroy:function(){if(this.iframe){this.iframe.parentNode.removeChild(this.iframe);}this.iframe=null;B.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent,this);B.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent,this);G.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);if(this._contextTriggers){this._processTriggers(this._contextTriggers,E,this._alignOnTrigger);}B.superclass.destroy.call(this);},forceContainerRedraw:function(){var O=this;F.addClass(O.element,"yui-force-redraw");setTimeout(function(){F.removeClass(O.element,"yui-force-redraw");},0);},toString:function(){return"Overlay "+this.id;}});}());(function(){YAHOO.widget.OverlayManager=function(G){this.init(G);};var D=YAHOO.widget.Overlay,C=YAHOO.util.Event,E=YAHOO.util.Dom,B=YAHOO.util.Config,F=YAHOO.util.CustomEvent,A=YAHOO.widget.OverlayManager;A.CSS_FOCUSED="focused";A.prototype={constructor:A,overlays:null,initDefaultConfig:function(){this.cfg.addProperty("overlays",{suppressEvent:true});this.cfg.addProperty("focusevent",{value:"mousedown"});},init:function(I){this.cfg=new B(this);this.initDefaultConfig();if(I){this.cfg.applyConfig(I,true);}this.cfg.fireQueue();var H=null;this.getActive=function(){return H;};this.focus=function(J){var K=this.find(J);if(K){K.focus();}};this.remove=function(K){var M=this.find(K),J;if(M){if(H==M){H=null;}var L=(M.element===null&&M.cfg===null)?true:false;if(!L){J=E.getStyle(M.element,"zIndex");M.cfg.setProperty("zIndex",-1000,true);}this.overlays.sort(this.compareZIndexDesc);this.overlays=this.overlays.slice(0,(this.overlays.length-1));M.hideEvent.unsubscribe(M.blur);M.destroyEvent.unsubscribe(this._onOverlayDestroy,M);M.focusEvent.unsubscribe(this._onOverlayFocusHandler,M);M.blurEvent.unsubscribe(this._onOverlayBlurHandler,M);if(!L){C.removeListener(M.element,this.cfg.getProperty("focusevent"),this._onOverlayElementFocus);M.cfg.setProperty("zIndex",J,true);M.cfg.setProperty("manager",null);}if(M.focusEvent._managed){M.focusEvent=null;}if(M.blurEvent._managed){M.blurEvent=null;}if(M.focus._managed){M.focus=null;}if(M.blur._managed){M.blur=null;}}};this.blurAll=function(){var K=this.overlays.length,J;if(K>0){J=K-1;do{this.overlays[J].blur();}while(J--);}};this._manageBlur=function(J){var K=false;if(H==J){E.removeClass(H.element,A.CSS_FOCUSED);H=null;K=true;}return K;};this._manageFocus=function(J){var K=false;if(H!=J){if(H){H.blur();}H=J;this.bringToTop(H);E.addClass(H.element,A.CSS_FOCUSED);K=true;}return K;};var G=this.cfg.getProperty("overlays");if(!this.overlays){this.overlays=[];}if(G){this.register(G);this.overlays.sort(this.compareZIndexDesc);}},_onOverlayElementFocus:function(I){var G=C.getTarget(I),H=this.close;if(H&&(G==H||E.isAncestor(H,G))){this.blur();}else{this.focus();}},_onOverlayDestroy:function(H,G,I){this.remove(I);},_onOverlayFocusHandler:function(H,G,I){this._manageFocus(I);},_onOverlayBlurHandler:function(H,G,I){this._manageBlur(I);},_bindFocus:function(G){var H=this;if(!G.focusEvent){G.focusEvent=G.createEvent("focus");G.focusEvent.signature=F.LIST;G.focusEvent._managed=true;}else{G.focusEvent.subscribe(H._onOverlayFocusHandler,G,H);}if(!G.focus){C.on(G.element,H.cfg.getProperty("focusevent"),H._onOverlayElementFocus,null,G);G.focus=function(){if(H._manageFocus(this)){if(this.cfg.getProperty("visible")&&this.focusFirst){this.focusFirst();}this.focusEvent.fire();}};G.focus._managed=true;}},_bindBlur:function(G){var H=this;if(!G.blurEvent){G.blurEvent=G.createEvent("blur");G.blurEvent.signature=F.LIST;G.focusEvent._managed=true;}else{G.blurEvent.subscribe(H._onOverlayBlurHandler,G,H);}if(!G.blur){G.blur=function(){if(H._manageBlur(this)){this.blurEvent.fire();}};G.blur._managed=true;}G.hideEvent.subscribe(G.blur);},_bindDestroy:function(G){var H=this;G.destroyEvent.subscribe(H._onOverlayDestroy,G,H);},_syncZIndex:function(G){var H=E.getStyle(G.element,"zIndex");if(!isNaN(H)){G.cfg.setProperty("zIndex",parseInt(H,10));}else{G.cfg.setProperty("zIndex",0);}},register:function(G){var J=false,H,I;if(G instanceof D){G.cfg.addProperty("manager",{value:this});this._bindFocus(G);this._bindBlur(G);this._bindDestroy(G);
-this._syncZIndex(G);this.overlays.push(G);this.bringToTop(G);J=true;}else{if(G instanceof Array){for(H=0,I=G.length;H<I;H++){J=this.register(G[H])||J;}}}return J;},bringToTop:function(M){var I=this.find(M),L,G,J;if(I){J=this.overlays;J.sort(this.compareZIndexDesc);G=J[0];if(G){L=E.getStyle(G.element,"zIndex");if(!isNaN(L)){var K=false;if(G!==I){K=true;}else{if(J.length>1){var H=E.getStyle(J[1].element,"zIndex");if(!isNaN(H)&&(L==H)){K=true;}}}if(K){I.cfg.setProperty("zindex",(parseInt(L,10)+2));}}J.sort(this.compareZIndexDesc);}}},find:function(G){var K=G instanceof D,I=this.overlays,M=I.length,J=null,L,H;if(K||typeof G=="string"){for(H=M-1;H>=0;H--){L=I[H];if((K&&(L===G))||(L.id==G)){J=L;break;}}}return J;},compareZIndexDesc:function(J,I){var H=(J.cfg)?J.cfg.getProperty("zIndex"):null,G=(I.cfg)?I.cfg.getProperty("zIndex"):null;if(H===null&&G===null){return 0;}else{if(H===null){return 1;}else{if(G===null){return -1;}else{if(H>G){return -1;}else{if(H<G){return 1;}else{return 0;}}}}}},showAll:function(){var H=this.overlays,I=H.length,G;for(G=I-1;G>=0;G--){H[G].show();}},hideAll:function(){var H=this.overlays,I=H.length,G;for(G=I-1;G>=0;G--){H[G].hide();}},toString:function(){return"OverlayManager";}};}());(function(){YAHOO.widget.Tooltip=function(P,O){YAHOO.widget.Tooltip.superclass.constructor.call(this,P,O);};var E=YAHOO.lang,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,C=YAHOO.util.Dom,J=YAHOO.widget.Tooltip,H=YAHOO.env.ua,G=(H.ie&&(H.ie<=6||document.compatMode=="BackCompat")),F,I={"PREVENT_OVERLAP":{key:"preventoverlap",value:true,validator:E.isBoolean,supercedes:["x","y","xy"]},"SHOW_DELAY":{key:"showdelay",value:200,validator:E.isNumber},"AUTO_DISMISS_DELAY":{key:"autodismissdelay",value:5000,validator:E.isNumber},"HIDE_DELAY":{key:"hidedelay",value:250,validator:E.isNumber},"TEXT":{key:"text",suppressEvent:true},"CONTAINER":{key:"container"},"DISABLED":{key:"disabled",value:false,suppressEvent:true},"XY_OFFSET":{key:"xyoffset",value:[0,25],suppressEvent:true}},A={"CONTEXT_MOUSE_OVER":"contextMouseOver","CONTEXT_MOUSE_OUT":"contextMouseOut","CONTEXT_TRIGGER":"contextTrigger"};J.CSS_TOOLTIP="yui-tt";function K(Q,O){var P=this.cfg,R=P.getProperty("width");if(R==O){P.setProperty("width",Q);}}function D(P,O){if("_originalWidth" in this){K.call(this,this._originalWidth,this._forcedWidth);}var Q=document.body,U=this.cfg,T=U.getProperty("width"),R,S;if((!T||T=="auto")&&(U.getProperty("container")!=Q||U.getProperty("x")>=C.getViewportWidth()||U.getProperty("y")>=C.getViewportHeight())){S=this.element.cloneNode(true);S.style.visibility="hidden";S.style.top="0px";S.style.left="0px";Q.appendChild(S);R=(S.offsetWidth+"px");Q.removeChild(S);S=null;U.setProperty("width",R);U.refireEvent("xy");this._originalWidth=T||"";this._forcedWidth=R;}}function B(P,O,Q){this.render(Q);}function L(){N.onDOMReady(B,this.cfg.getProperty("container"),this);}YAHOO.extend(J,YAHOO.widget.Overlay,{init:function(P,O){J.superclass.init.call(this,P);this.beforeInitEvent.fire(J);C.addClass(this.element,J.CSS_TOOLTIP);if(O){this.cfg.applyConfig(O,true);}this.cfg.queueProperty("visible",false);this.cfg.queueProperty("constraintoviewport",true);this.setBody("");this.subscribe("changeContent",D);this.subscribe("init",L);this.subscribe("render",this.onRender);this.initEvent.fire(J);},initEvents:function(){J.superclass.initEvents.call(this);var O=M.LIST;this.contextMouseOverEvent=this.createEvent(A.CONTEXT_MOUSE_OVER);this.contextMouseOverEvent.signature=O;this.contextMouseOutEvent=this.createEvent(A.CONTEXT_MOUSE_OUT);this.contextMouseOutEvent.signature=O;this.contextTriggerEvent=this.createEvent(A.CONTEXT_TRIGGER);this.contextTriggerEvent.signature=O;},initDefaultConfig:function(){J.superclass.initDefaultConfig.call(this);this.cfg.addProperty(I.PREVENT_OVERLAP.key,{value:I.PREVENT_OVERLAP.value,validator:I.PREVENT_OVERLAP.validator,supercedes:I.PREVENT_OVERLAP.supercedes});this.cfg.addProperty(I.SHOW_DELAY.key,{handler:this.configShowDelay,value:200,validator:I.SHOW_DELAY.validator});this.cfg.addProperty(I.AUTO_DISMISS_DELAY.key,{handler:this.configAutoDismissDelay,value:I.AUTO_DISMISS_DELAY.value,validator:I.AUTO_DISMISS_DELAY.validator});this.cfg.addProperty(I.HIDE_DELAY.key,{handler:this.configHideDelay,value:I.HIDE_DELAY.value,validator:I.HIDE_DELAY.validator});this.cfg.addProperty(I.TEXT.key,{handler:this.configText,suppressEvent:I.TEXT.suppressEvent});this.cfg.addProperty(I.CONTAINER.key,{handler:this.configContainer,value:document.body});this.cfg.addProperty(I.DISABLED.key,{handler:this.configContainer,value:I.DISABLED.value,supressEvent:I.DISABLED.suppressEvent});this.cfg.addProperty(I.XY_OFFSET.key,{value:I.XY_OFFSET.value.concat(),supressEvent:I.XY_OFFSET.suppressEvent});},configText:function(P,O,Q){var R=O[0];if(R){this.setBody(R);}},configContainer:function(Q,P,R){var O=P[0];if(typeof O=="string"){this.cfg.setProperty("container",document.getElementById(O),true);}},_removeEventListeners:function(){var R=this._context,O,Q,P;if(R){O=R.length;if(O>0){P=O-1;do{Q=R[P];N.removeListener(Q,"mouseover",this.onContextMouseOver);N.removeListener(Q,"mousemove",this.onContextMouseMove);N.removeListener(Q,"mouseout",this.onContextMouseOut);}while(P--);}}},configContext:function(T,P,U){var S=P[0],V,O,R,Q;if(S){if(!(S instanceof Array)){if(typeof S=="string"){this.cfg.setProperty("context",[document.getElementById(S)],true);}else{this.cfg.setProperty("context",[S],true);}S=this.cfg.getProperty("context");}this._removeEventListeners();this._context=S;V=this._context;if(V){O=V.length;if(O>0){Q=O-1;do{R=V[Q];N.on(R,"mouseover",this.onContextMouseOver,this);N.on(R,"mousemove",this.onContextMouseMove,this);N.on(R,"mouseout",this.onContextMouseOut,this);}while(Q--);}}}},onContextMouseMove:function(P,O){O.pageX=N.getPageX(P);O.pageY=N.getPageY(P);},onContextMouseOver:function(Q,P){var O=this;if(O.title){P._tempTitle=O.title;O.title="";}if(P.fireEvent("contextMouseOver",O,Q)!==false&&!P.cfg.getProperty("disabled")){if(P.hideProcId){clearTimeout(P.hideProcId);
-P.hideProcId=null;}N.on(O,"mousemove",P.onContextMouseMove,P);P.showProcId=P.doShow(Q,O);}},onContextMouseOut:function(Q,P){var O=this;if(P._tempTitle){O.title=P._tempTitle;P._tempTitle=null;}if(P.showProcId){clearTimeout(P.showProcId);P.showProcId=null;}if(P.hideProcId){clearTimeout(P.hideProcId);P.hideProcId=null;}P.fireEvent("contextMouseOut",O,Q);P.hideProcId=setTimeout(function(){P.hide();},P.cfg.getProperty("hidedelay"));},doShow:function(R,O){var T=this.cfg.getProperty("xyoffset"),P=T[0],S=T[1],Q=this;if(H.opera&&O.tagName&&O.tagName.toUpperCase()=="A"){S+=12;}return setTimeout(function(){var U=Q.cfg.getProperty("text");if(Q._tempTitle&&(U===""||YAHOO.lang.isUndefined(U)||YAHOO.lang.isNull(U))){Q.setBody(Q._tempTitle);}else{Q.cfg.refireEvent("text");}Q.moveTo(Q.pageX+P,Q.pageY+S);if(Q.cfg.getProperty("preventoverlap")){Q.preventOverlap(Q.pageX,Q.pageY);}N.removeListener(O,"mousemove",Q.onContextMouseMove);Q.contextTriggerEvent.fire(O);Q.show();Q.hideProcId=Q.doHide();},this.cfg.getProperty("showdelay"));},doHide:function(){var O=this;return setTimeout(function(){O.hide();},this.cfg.getProperty("autodismissdelay"));},preventOverlap:function(S,R){var O=this.element.offsetHeight,Q=new YAHOO.util.Point(S,R),P=C.getRegion(this.element);P.top-=5;P.left-=5;P.right+=5;P.bottom+=5;if(P.contains(Q)){this.cfg.setProperty("y",(R-O-5));}},onRender:function(S,R){function T(){var W=this.element,V=this.underlay;if(V){V.style.width=(W.offsetWidth+6)+"px";V.style.height=(W.offsetHeight+1)+"px";}}function P(){C.addClass(this.underlay,"yui-tt-shadow-visible");if(H.ie){this.forceUnderlayRedraw();}}function O(){C.removeClass(this.underlay,"yui-tt-shadow-visible");}function U(){var X=this.underlay,W,V,Z,Y;if(!X){W=this.element;V=YAHOO.widget.Module;Z=H.ie;Y=this;if(!F){F=document.createElement("div");F.className="yui-tt-shadow";}X=F.cloneNode(false);W.appendChild(X);this.underlay=X;this._shadow=this.underlay;P.call(this);this.subscribe("beforeShow",P);this.subscribe("hide",O);if(G){window.setTimeout(function(){T.call(Y);},0);this.cfg.subscribeToConfigEvent("width",T);this.cfg.subscribeToConfigEvent("height",T);this.subscribe("changeContent",T);V.textResizeEvent.subscribe(T,this,true);this.subscribe("destroy",function(){V.textResizeEvent.unsubscribe(T,this);});}}}function Q(){U.call(this);this.unsubscribe("beforeShow",Q);}if(this.cfg.getProperty("visible")){U.call(this);}else{this.subscribe("beforeShow",Q);}},forceUnderlayRedraw:function(){var O=this;C.addClass(O.underlay,"yui-force-redraw");setTimeout(function(){C.removeClass(O.underlay,"yui-force-redraw");},0);},destroy:function(){this._removeEventListeners();J.superclass.destroy.call(this);},toString:function(){return"Tooltip "+this.id;}});}());(function(){YAHOO.widget.Panel=function(V,U){YAHOO.widget.Panel.superclass.constructor.call(this,V,U);};var S=null;var E=YAHOO.lang,F=YAHOO.util,A=F.Dom,T=F.Event,M=F.CustomEvent,K=YAHOO.util.KeyListener,I=F.Config,H=YAHOO.widget.Overlay,O=YAHOO.widget.Panel,L=YAHOO.env.ua,P=(L.ie&&(L.ie<=6||document.compatMode=="BackCompat")),G,Q,C,D={"SHOW_MASK":"showMask","HIDE_MASK":"hideMask","DRAG":"drag"},N={"CLOSE":{key:"close",value:true,validator:E.isBoolean,supercedes:["visible"]},"DRAGGABLE":{key:"draggable",value:(F.DD?true:false),validator:E.isBoolean,supercedes:["visible"]},"DRAG_ONLY":{key:"dragonly",value:false,validator:E.isBoolean,supercedes:["draggable"]},"UNDERLAY":{key:"underlay",value:"shadow",supercedes:["visible"]},"MODAL":{key:"modal",value:false,validator:E.isBoolean,supercedes:["visible","zindex"]},"KEY_LISTENERS":{key:"keylisteners",suppressEvent:true,supercedes:["visible"]},"STRINGS":{key:"strings",supercedes:["close"],validator:E.isObject,value:{close:"Close"}}};O.CSS_PANEL="yui-panel";O.CSS_PANEL_CONTAINER="yui-panel-container";O.FOCUSABLE=["a","button","select","textarea","input","iframe"];function J(V,U){if(!this.header&&this.cfg.getProperty("draggable")){this.setHeader("&#160;");}}function R(V,U,W){var Z=W[0],X=W[1],Y=this.cfg,a=Y.getProperty("width");if(a==X){Y.setProperty("width",Z);}this.unsubscribe("hide",R,W);}function B(V,U){var Y,X,W;if(P){Y=this.cfg;X=Y.getProperty("width");if(!X||X=="auto"){W=(this.element.offsetWidth+"px");Y.setProperty("width",W);this.subscribe("hide",R,[(X||""),W]);}}}YAHOO.extend(O,H,{init:function(V,U){O.superclass.init.call(this,V);this.beforeInitEvent.fire(O);A.addClass(this.element,O.CSS_PANEL);this.buildWrapper();if(U){this.cfg.applyConfig(U,true);}this.subscribe("showMask",this._addFocusHandlers);this.subscribe("hideMask",this._removeFocusHandlers);this.subscribe("beforeRender",J);this.subscribe("render",function(){this.setFirstLastFocusable();this.subscribe("changeContent",this.setFirstLastFocusable);});this.subscribe("show",this.focusFirst);this.initEvent.fire(O);},_onElementFocus:function(Z){if(S===this){var Y=T.getTarget(Z),X=document.documentElement,V=(Y!==X&&Y!==window);if(V&&Y!==this.element&&Y!==this.mask&&!A.isAncestor(this.element,Y)){try{if(this.firstElement){this.firstElement.focus();}else{if(this._modalFocus){this._modalFocus.focus();}else{this.innerElement.focus();}}}catch(W){try{if(V&&Y!==document.body){Y.blur();}}catch(U){}}}}},_addFocusHandlers:function(V,U){if(!this.firstElement){if(L.webkit||L.opera){if(!this._modalFocus){this._createHiddenFocusElement();}}else{this.innerElement.tabIndex=0;}}this.setTabLoop(this.firstElement,this.lastElement);T.onFocus(document.documentElement,this._onElementFocus,this,true);S=this;},_createHiddenFocusElement:function(){var U=document.createElement("button");U.style.height="1px";U.style.width="1px";U.style.position="absolute";U.style.left="-10000em";U.style.opacity=0;U.tabIndex=-1;this.innerElement.appendChild(U);this._modalFocus=U;},_removeFocusHandlers:function(V,U){T.removeFocusListener(document.documentElement,this._onElementFocus,this);if(S==this){S=null;}},focusFirst:function(W,U,Y){var V=this.firstElement;if(U&&U[1]){T.stopEvent(U[1]);}if(V){try{V.focus();}catch(X){}}},focusLast:function(W,U,Y){var V=this.lastElement;
-if(U&&U[1]){T.stopEvent(U[1]);}if(V){try{V.focus();}catch(X){}}},setTabLoop:function(X,Z){var V=this.preventBackTab,W=this.preventTabOut,U=this.showEvent,Y=this.hideEvent;if(V){V.disable();U.unsubscribe(V.enable,V);Y.unsubscribe(V.disable,V);V=this.preventBackTab=null;}if(W){W.disable();U.unsubscribe(W.enable,W);Y.unsubscribe(W.disable,W);W=this.preventTabOut=null;}if(X){this.preventBackTab=new K(X,{shift:true,keys:9},{fn:this.focusLast,scope:this,correctScope:true});V=this.preventBackTab;U.subscribe(V.enable,V,true);Y.subscribe(V.disable,V,true);}if(Z){this.preventTabOut=new K(Z,{shift:false,keys:9},{fn:this.focusFirst,scope:this,correctScope:true});W=this.preventTabOut;U.subscribe(W.enable,W,true);Y.subscribe(W.disable,W,true);}},getFocusableElements:function(U){U=U||this.innerElement;var X={};for(var W=0;W<O.FOCUSABLE.length;W++){X[O.FOCUSABLE[W]]=true;}function V(Y){if(Y.focus&&Y.type!=="hidden"&&!Y.disabled&&X[Y.tagName.toLowerCase()]){return true;}return false;}return A.getElementsBy(V,null,U);},setFirstLastFocusable:function(){this.firstElement=null;this.lastElement=null;var U=this.getFocusableElements();this.focusableElements=U;if(U.length>0){this.firstElement=U[0];this.lastElement=U[U.length-1];}if(this.cfg.getProperty("modal")){this.setTabLoop(this.firstElement,this.lastElement);}},initEvents:function(){O.superclass.initEvents.call(this);var U=M.LIST;this.showMaskEvent=this.createEvent(D.SHOW_MASK);this.showMaskEvent.signature=U;this.hideMaskEvent=this.createEvent(D.HIDE_MASK);this.hideMaskEvent.signature=U;this.dragEvent=this.createEvent(D.DRAG);this.dragEvent.signature=U;},initDefaultConfig:function(){O.superclass.initDefaultConfig.call(this);this.cfg.addProperty(N.CLOSE.key,{handler:this.configClose,value:N.CLOSE.value,validator:N.CLOSE.validator,supercedes:N.CLOSE.supercedes});this.cfg.addProperty(N.DRAGGABLE.key,{handler:this.configDraggable,value:(F.DD)?true:false,validator:N.DRAGGABLE.validator,supercedes:N.DRAGGABLE.supercedes});this.cfg.addProperty(N.DRAG_ONLY.key,{value:N.DRAG_ONLY.value,validator:N.DRAG_ONLY.validator,supercedes:N.DRAG_ONLY.supercedes});this.cfg.addProperty(N.UNDERLAY.key,{handler:this.configUnderlay,value:N.UNDERLAY.value,supercedes:N.UNDERLAY.supercedes});this.cfg.addProperty(N.MODAL.key,{handler:this.configModal,value:N.MODAL.value,validator:N.MODAL.validator,supercedes:N.MODAL.supercedes});this.cfg.addProperty(N.KEY_LISTENERS.key,{handler:this.configKeyListeners,suppressEvent:N.KEY_LISTENERS.suppressEvent,supercedes:N.KEY_LISTENERS.supercedes});this.cfg.addProperty(N.STRINGS.key,{value:N.STRINGS.value,handler:this.configStrings,validator:N.STRINGS.validator,supercedes:N.STRINGS.supercedes});},configClose:function(X,V,Y){var Z=V[0],W=this.close,U=this.cfg.getProperty("strings");if(Z){if(!W){if(!C){C=document.createElement("a");C.className="container-close";C.href="#";}W=C.cloneNode(true);this.innerElement.appendChild(W);W.innerHTML=(U&&U.close)?U.close:"&#160;";T.on(W,"click",this._doClose,this,true);this.close=W;}else{W.style.display="block";}}else{if(W){W.style.display="none";}}},_doClose:function(U){T.preventDefault(U);this.hide();},configDraggable:function(V,U,W){var X=U[0];if(X){if(!F.DD){this.cfg.setProperty("draggable",false);return;}if(this.header){A.setStyle(this.header,"cursor","move");this.registerDragDrop();}this.subscribe("beforeShow",B);}else{if(this.dd){this.dd.unreg();}if(this.header){A.setStyle(this.header,"cursor","auto");}this.unsubscribe("beforeShow",B);}},configUnderlay:function(d,c,Z){var b=(this.platform=="mac"&&L.gecko),e=c[0].toLowerCase(),V=this.underlay,W=this.element;function X(){var f=false;if(!V){if(!Q){Q=document.createElement("div");Q.className="underlay";}V=Q.cloneNode(false);this.element.appendChild(V);this.underlay=V;if(P){this.sizeUnderlay();this.cfg.subscribeToConfigEvent("width",this.sizeUnderlay);this.cfg.subscribeToConfigEvent("height",this.sizeUnderlay);this.changeContentEvent.subscribe(this.sizeUnderlay);YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay,this,true);}if(L.webkit&&L.webkit<420){this.changeContentEvent.subscribe(this.forceUnderlayRedraw);}f=true;}}function a(){var f=X.call(this);if(!f&&P){this.sizeUnderlay();}this._underlayDeferred=false;this.beforeShowEvent.unsubscribe(a);}function Y(){if(this._underlayDeferred){this.beforeShowEvent.unsubscribe(a);this._underlayDeferred=false;}if(V){this.cfg.unsubscribeFromConfigEvent("width",this.sizeUnderlay);this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);this.changeContentEvent.unsubscribe(this.sizeUnderlay);this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay,this,true);this.element.removeChild(V);this.underlay=null;}}switch(e){case"shadow":A.removeClass(W,"matte");A.addClass(W,"shadow");break;case"matte":if(!b){Y.call(this);}A.removeClass(W,"shadow");A.addClass(W,"matte");break;default:if(!b){Y.call(this);}A.removeClass(W,"shadow");A.removeClass(W,"matte");break;}if((e=="shadow")||(b&&!V)){if(this.cfg.getProperty("visible")){var U=X.call(this);if(!U&&P){this.sizeUnderlay();}}else{if(!this._underlayDeferred){this.beforeShowEvent.subscribe(a);this._underlayDeferred=true;}}}},configModal:function(V,U,X){var W=U[0];if(W){if(!this._hasModalityEventListeners){this.subscribe("beforeShow",this.buildMask);this.subscribe("beforeShow",this.bringToTop);this.subscribe("beforeShow",this.showMask);this.subscribe("hide",this.hideMask);H.windowResizeEvent.subscribe(this.sizeMask,this,true);this._hasModalityEventListeners=true;}}else{if(this._hasModalityEventListeners){if(this.cfg.getProperty("visible")){this.hideMask();this.removeMask();}this.unsubscribe("beforeShow",this.buildMask);this.unsubscribe("beforeShow",this.bringToTop);this.unsubscribe("beforeShow",this.showMask);this.unsubscribe("hide",this.hideMask);H.windowResizeEvent.unsubscribe(this.sizeMask,this);this._hasModalityEventListeners=false;}}},removeMask:function(){var V=this.mask,U;if(V){this.hideMask();U=V.parentNode;
-if(U){U.removeChild(V);}this.mask=null;}},configKeyListeners:function(X,U,a){var W=U[0],Z,Y,V;if(W){if(W instanceof Array){Y=W.length;for(V=0;V<Y;V++){Z=W[V];if(!I.alreadySubscribed(this.showEvent,Z.enable,Z)){this.showEvent.subscribe(Z.enable,Z,true);}if(!I.alreadySubscribed(this.hideEvent,Z.disable,Z)){this.hideEvent.subscribe(Z.disable,Z,true);this.destroyEvent.subscribe(Z.disable,Z,true);}}}else{if(!I.alreadySubscribed(this.showEvent,W.enable,W)){this.showEvent.subscribe(W.enable,W,true);}if(!I.alreadySubscribed(this.hideEvent,W.disable,W)){this.hideEvent.subscribe(W.disable,W,true);this.destroyEvent.subscribe(W.disable,W,true);}}}},configStrings:function(V,U,W){var X=E.merge(N.STRINGS.value,U[0]);this.cfg.setProperty(N.STRINGS.key,X,true);},configHeight:function(X,V,Y){var U=V[0],W=this.innerElement;A.setStyle(W,"height",U);this.cfg.refireEvent("iframe");},_autoFillOnHeightChange:function(X,V,W){O.superclass._autoFillOnHeightChange.apply(this,arguments);if(P){var U=this;setTimeout(function(){U.sizeUnderlay();},0);}},configWidth:function(X,U,Y){var W=U[0],V=this.innerElement;A.setStyle(V,"width",W);this.cfg.refireEvent("iframe");},configzIndex:function(V,U,X){O.superclass.configzIndex.call(this,V,U,X);if(this.mask||this.cfg.getProperty("modal")===true){var W=A.getStyle(this.element,"zIndex");if(!W||isNaN(W)){W=0;}if(W===0){this.cfg.setProperty("zIndex",1);}else{this.stackMask();}}},buildWrapper:function(){var W=this.element.parentNode,U=this.element,V=document.createElement("div");V.className=O.CSS_PANEL_CONTAINER;V.id=U.id+"_c";if(W){W.insertBefore(V,U);}V.appendChild(U);this.element=V;this.innerElement=U;A.setStyle(this.innerElement,"visibility","inherit");},sizeUnderlay:function(){var V=this.underlay,U;if(V){U=this.element;V.style.width=U.offsetWidth+"px";V.style.height=U.offsetHeight+"px";}},registerDragDrop:function(){var V=this;if(this.header){if(!F.DD){return;}var U=(this.cfg.getProperty("dragonly")===true);this.dd=new F.DD(this.element.id,this.id,{dragOnly:U});if(!this.header.id){this.header.id=this.id+"_h";}this.dd.startDrag=function(){var X,Z,W,c,b,a;if(YAHOO.env.ua.ie==6){A.addClass(V.element,"drag");}if(V.cfg.getProperty("constraintoviewport")){var Y=H.VIEWPORT_OFFSET;X=V.element.offsetHeight;Z=V.element.offsetWidth;W=A.getViewportWidth();c=A.getViewportHeight();b=A.getDocumentScrollLeft();a=A.getDocumentScrollTop();if(X+Y<c){this.minY=a+Y;this.maxY=a+c-X-Y;}else{this.minY=a+Y;this.maxY=a+Y;}if(Z+Y<W){this.minX=b+Y;this.maxX=b+W-Z-Y;}else{this.minX=b+Y;this.maxX=b+Y;}this.constrainX=true;this.constrainY=true;}else{this.constrainX=false;this.constrainY=false;}V.dragEvent.fire("startDrag",arguments);};this.dd.onDrag=function(){V.syncPosition();V.cfg.refireEvent("iframe");if(this.platform=="mac"&&YAHOO.env.ua.gecko){this.showMacGeckoScrollbars();}V.dragEvent.fire("onDrag",arguments);};this.dd.endDrag=function(){if(YAHOO.env.ua.ie==6){A.removeClass(V.element,"drag");}V.dragEvent.fire("endDrag",arguments);V.moveEvent.fire(V.cfg.getProperty("xy"));};this.dd.setHandleElId(this.header.id);this.dd.addInvalidHandleType("INPUT");this.dd.addInvalidHandleType("SELECT");this.dd.addInvalidHandleType("TEXTAREA");}},buildMask:function(){var U=this.mask;if(!U){if(!G){G=document.createElement("div");G.className="mask";G.innerHTML="&#160;";}U=G.cloneNode(true);U.id=this.id+"_mask";document.body.insertBefore(U,document.body.firstChild);this.mask=U;if(YAHOO.env.ua.gecko&&this.platform=="mac"){A.addClass(this.mask,"block-scrollbars");}this.stackMask();}},hideMask:function(){if(this.cfg.getProperty("modal")&&this.mask){this.mask.style.display="none";A.removeClass(document.body,"masked");this.hideMaskEvent.fire();}},showMask:function(){if(this.cfg.getProperty("modal")&&this.mask){A.addClass(document.body,"masked");this.sizeMask();this.mask.style.display="block";this.showMaskEvent.fire();}},sizeMask:function(){if(this.mask){var V=this.mask,W=A.getViewportWidth(),U=A.getViewportHeight();if(V.offsetHeight>U){V.style.height=U+"px";}if(V.offsetWidth>W){V.style.width=W+"px";}V.style.height=A.getDocumentHeight()+"px";V.style.width=A.getDocumentWidth()+"px";}},stackMask:function(){if(this.mask){var U=A.getStyle(this.element,"zIndex");if(!YAHOO.lang.isUndefined(U)&&!isNaN(U)){A.setStyle(this.mask,"zIndex",U-1);}}},render:function(U){return O.superclass.render.call(this,U,this.innerElement);},_renderHeader:function(U){U=U||this.innerElement;O.superclass._renderHeader.call(this,U);},_renderBody:function(U){U=U||this.innerElement;O.superclass._renderBody.call(this,U);},_renderFooter:function(U){U=U||this.innerElement;O.superclass._renderFooter.call(this,U);},destroy:function(){H.windowResizeEvent.unsubscribe(this.sizeMask,this);this.removeMask();if(this.close){T.purgeElement(this.close);}O.superclass.destroy.call(this);},forceUnderlayRedraw:function(){var U=this.underlay;A.addClass(U,"yui-force-redraw");setTimeout(function(){A.removeClass(U,"yui-force-redraw");},0);},toString:function(){return"Panel "+this.id;}});}());(function(){YAHOO.widget.Dialog=function(J,I){YAHOO.widget.Dialog.superclass.constructor.call(this,J,I);};var B=YAHOO.util.Event,G=YAHOO.util.CustomEvent,E=YAHOO.util.Dom,A=YAHOO.widget.Dialog,F=YAHOO.lang,H={"BEFORE_SUBMIT":"beforeSubmit","SUBMIT":"submit","MANUAL_SUBMIT":"manualSubmit","ASYNC_SUBMIT":"asyncSubmit","FORM_SUBMIT":"formSubmit","CANCEL":"cancel"},C={"POST_METHOD":{key:"postmethod",value:"async"},"POST_DATA":{key:"postdata",value:null},"BUTTONS":{key:"buttons",value:"none",supercedes:["visible"]},"HIDEAFTERSUBMIT":{key:"hideaftersubmit",value:true}};A.CSS_DIALOG="yui-dialog";function D(){var L=this._aButtons,J,K,I;if(F.isArray(L)){J=L.length;if(J>0){I=J-1;do{K=L[I];if(YAHOO.widget.Button&&K instanceof YAHOO.widget.Button){K.destroy();}else{if(K.tagName.toUpperCase()=="BUTTON"){B.purgeElement(K);B.purgeElement(K,false);}}}while(I--);}}}YAHOO.extend(A,YAHOO.widget.Panel,{form:null,initDefaultConfig:function(){A.superclass.initDefaultConfig.call(this);this.callback={success:null,failure:null,argument:null};
-this.cfg.addProperty(C.POST_METHOD.key,{handler:this.configPostMethod,value:C.POST_METHOD.value,validator:function(I){if(I!="form"&&I!="async"&&I!="none"&&I!="manual"){return false;}else{return true;}}});this.cfg.addProperty(C.POST_DATA.key,{value:C.POST_DATA.value});this.cfg.addProperty(C.HIDEAFTERSUBMIT.key,{value:C.HIDEAFTERSUBMIT.value});this.cfg.addProperty(C.BUTTONS.key,{handler:this.configButtons,value:C.BUTTONS.value,supercedes:C.BUTTONS.supercedes});},initEvents:function(){A.superclass.initEvents.call(this);var I=G.LIST;this.beforeSubmitEvent=this.createEvent(H.BEFORE_SUBMIT);this.beforeSubmitEvent.signature=I;this.submitEvent=this.createEvent(H.SUBMIT);this.submitEvent.signature=I;this.manualSubmitEvent=this.createEvent(H.MANUAL_SUBMIT);this.manualSubmitEvent.signature=I;this.asyncSubmitEvent=this.createEvent(H.ASYNC_SUBMIT);this.asyncSubmitEvent.signature=I;this.formSubmitEvent=this.createEvent(H.FORM_SUBMIT);this.formSubmitEvent.signature=I;this.cancelEvent=this.createEvent(H.CANCEL);this.cancelEvent.signature=I;},init:function(J,I){A.superclass.init.call(this,J);this.beforeInitEvent.fire(A);E.addClass(this.element,A.CSS_DIALOG);this.cfg.setProperty("visible",false);if(I){this.cfg.applyConfig(I,true);}this.showEvent.subscribe(this.focusFirst,this,true);this.beforeHideEvent.subscribe(this.blurButtons,this,true);this.subscribe("changeBody",this.registerForm);this.initEvent.fire(A);},doSubmit:function(){var P=YAHOO.util.Connect,Q=this.form,K=false,N=false,R,M,L,I;switch(this.cfg.getProperty("postmethod")){case"async":R=Q.elements;M=R.length;if(M>0){L=M-1;do{if(R[L].type=="file"){K=true;break;}}while(L--);}if(K&&YAHOO.env.ua.ie&&this.isSecure){N=true;}I=this._getFormAttributes(Q);P.setForm(Q,K,N);var J=this.cfg.getProperty("postdata");var O=P.asyncRequest(I.method,I.action,this.callback,J);this.asyncSubmitEvent.fire(O);break;case"form":Q.submit();this.formSubmitEvent.fire();break;case"none":case"manual":this.manualSubmitEvent.fire();break;}},_getFormAttributes:function(K){var I={method:null,action:null};if(K){if(K.getAttributeNode){var J=K.getAttributeNode("action");var L=K.getAttributeNode("method");if(J){I.action=J.value;}if(L){I.method=L.value;}}else{I.action=K.getAttribute("action");I.method=K.getAttribute("method");}}I.method=(F.isString(I.method)?I.method:"POST").toUpperCase();I.action=F.isString(I.action)?I.action:"";return I;},registerForm:function(){var I=this.element.getElementsByTagName("form")[0];if(this.form){if(this.form==I&&E.isAncestor(this.element,this.form)){return;}else{B.purgeElement(this.form);this.form=null;}}if(!I){I=document.createElement("form");I.name="frm_"+this.id;this.body.appendChild(I);}if(I){this.form=I;B.on(I,"submit",this._submitHandler,this,true);}},_submitHandler:function(I){B.stopEvent(I);this.submit();this.form.blur();},setTabLoop:function(I,J){I=I||this.firstButton;J=this.lastButton||J;A.superclass.setTabLoop.call(this,I,J);},setFirstLastFocusable:function(){A.superclass.setFirstLastFocusable.call(this);var J,I,K,L=this.focusableElements;this.firstFormElement=null;this.lastFormElement=null;if(this.form&&L&&L.length>0){I=L.length;for(J=0;J<I;++J){K=L[J];if(this.form===K.form){this.firstFormElement=K;break;}}for(J=I-1;J>=0;--J){K=L[J];if(this.form===K.form){this.lastFormElement=K;break;}}}},configClose:function(J,I,K){A.superclass.configClose.apply(this,arguments);},_doClose:function(I){B.preventDefault(I);this.cancel();},configButtons:function(S,R,M){var N=YAHOO.widget.Button,U=R[0],K=this.innerElement,T,P,J,Q,O,I,L;D.call(this);this._aButtons=null;if(F.isArray(U)){O=document.createElement("span");O.className="button-group";Q=U.length;this._aButtons=[];this.defaultHtmlButton=null;for(L=0;L<Q;L++){T=U[L];if(N){J=new N({label:T.text});J.appendTo(O);P=J.get("element");if(T.isDefault){J.addClass("default");this.defaultHtmlButton=P;}if(F.isFunction(T.handler)){J.set("onclick",{fn:T.handler,obj:this,scope:this});}else{if(F.isObject(T.handler)&&F.isFunction(T.handler.fn)){J.set("onclick",{fn:T.handler.fn,obj:((!F.isUndefined(T.handler.obj))?T.handler.obj:this),scope:(T.handler.scope||this)});}}this._aButtons[this._aButtons.length]=J;}else{P=document.createElement("button");P.setAttribute("type","button");if(T.isDefault){P.className="default";this.defaultHtmlButton=P;}P.innerHTML=T.text;if(F.isFunction(T.handler)){B.on(P,"click",T.handler,this,true);}else{if(F.isObject(T.handler)&&F.isFunction(T.handler.fn)){B.on(P,"click",T.handler.fn,((!F.isUndefined(T.handler.obj))?T.handler.obj:this),(T.handler.scope||this));}}O.appendChild(P);this._aButtons[this._aButtons.length]=P;}T.htmlButton=P;if(L===0){this.firstButton=P;}if(L==(Q-1)){this.lastButton=P;}}this.setFooter(O);I=this.footer;if(E.inDocument(this.element)&&!E.isAncestor(K,I)){K.appendChild(I);}this.buttonSpan=O;}else{O=this.buttonSpan;I=this.footer;if(O&&I){I.removeChild(O);this.buttonSpan=null;this.firstButton=null;this.lastButton=null;this.defaultHtmlButton=null;}}this.changeContentEvent.fire();},getButtons:function(){return this._aButtons||null;},focusFirst:function(K,I,M){var J=this.firstFormElement;if(I&&I[1]){B.stopEvent(I[1]);}if(J){try{J.focus();}catch(L){}}else{if(this.defaultHtmlButton){this.focusDefaultButton();}else{this.focusFirstButton();}}},focusLast:function(K,I,M){var N=this.cfg.getProperty("buttons"),J=this.lastFormElement;if(I&&I[1]){B.stopEvent(I[1]);}if(N&&F.isArray(N)){this.focusLastButton();}else{if(J){try{J.focus();}catch(L){}}}},_getButton:function(J){var I=YAHOO.widget.Button;if(I&&J&&J.nodeName&&J.id){J=I.getButton(J.id)||J;}return J;},focusDefaultButton:function(){var I=this._getButton(this.defaultHtmlButton);if(I){try{I.focus();}catch(J){}}},blurButtons:function(){var N=this.cfg.getProperty("buttons"),K,M,J,I;if(N&&F.isArray(N)){K=N.length;if(K>0){I=(K-1);do{M=N[I];if(M){J=this._getButton(M.htmlButton);if(J){try{J.blur();}catch(L){}}}}while(I--);}}},focusFirstButton:function(){var L=this.cfg.getProperty("buttons"),K,I;if(L&&F.isArray(L)){K=L[0];if(K){I=this._getButton(K.htmlButton);
-if(I){try{I.focus();}catch(J){}}}}},focusLastButton:function(){var M=this.cfg.getProperty("buttons"),J,L,I;if(M&&F.isArray(M)){J=M.length;if(J>0){L=M[(J-1)];if(L){I=this._getButton(L.htmlButton);if(I){try{I.focus();}catch(K){}}}}}},configPostMethod:function(J,I,K){this.registerForm();},validate:function(){return true;},submit:function(){if(this.validate()){if(this.beforeSubmitEvent.fire()){this.doSubmit();this.submitEvent.fire();if(this.cfg.getProperty("hideaftersubmit")){this.hide();}return true;}else{return false;}}else{return false;}},cancel:function(){this.cancelEvent.fire();this.hide();},getData:function(){var Y=this.form,J,R,U,L,S,P,O,I,V,K,W,Z,N,a,M,X,T;function Q(c){var b=c.tagName.toUpperCase();return((b=="INPUT"||b=="TEXTAREA"||b=="SELECT")&&c.name==L);}if(Y){J=Y.elements;R=J.length;U={};for(X=0;X<R;X++){L=J[X].name;S=E.getElementsBy(Q,"*",Y);P=S.length;if(P>0){if(P==1){S=S[0];O=S.type;I=S.tagName.toUpperCase();switch(I){case"INPUT":if(O=="checkbox"){U[L]=S.checked;}else{if(O!="radio"){U[L]=S.value;}}break;case"TEXTAREA":U[L]=S.value;break;case"SELECT":V=S.options;K=V.length;W=[];for(T=0;T<K;T++){Z=V[T];if(Z.selected){M=Z.attributes.value;W[W.length]=(M&&M.specified)?Z.value:Z.text;}}U[L]=W;break;}}else{O=S[0].type;switch(O){case"radio":for(T=0;T<P;T++){N=S[T];if(N.checked){U[L]=N.value;break;}}break;case"checkbox":W=[];for(T=0;T<P;T++){a=S[T];if(a.checked){W[W.length]=a.value;}}U[L]=W;break;}}}}}return U;},destroy:function(){D.call(this);this._aButtons=null;var I=this.element.getElementsByTagName("form"),J;if(I.length>0){J=I[0];if(J){B.purgeElement(J);if(J.parentNode){J.parentNode.removeChild(J);}this.form=null;}}A.superclass.destroy.call(this);},toString:function(){return"Dialog "+this.id;}});}());(function(){YAHOO.widget.SimpleDialog=function(E,D){YAHOO.widget.SimpleDialog.superclass.constructor.call(this,E,D);};var C=YAHOO.util.Dom,B=YAHOO.widget.SimpleDialog,A={"ICON":{key:"icon",value:"none",suppressEvent:true},"TEXT":{key:"text",value:"",suppressEvent:true,supercedes:["icon"]}};B.ICON_BLOCK="blckicon";B.ICON_ALARM="alrticon";B.ICON_HELP="hlpicon";B.ICON_INFO="infoicon";B.ICON_WARN="warnicon";B.ICON_TIP="tipicon";B.ICON_CSS_CLASSNAME="yui-icon";B.CSS_SIMPLEDIALOG="yui-simple-dialog";YAHOO.extend(B,YAHOO.widget.Dialog,{initDefaultConfig:function(){B.superclass.initDefaultConfig.call(this);this.cfg.addProperty(A.ICON.key,{handler:this.configIcon,value:A.ICON.value,suppressEvent:A.ICON.suppressEvent});this.cfg.addProperty(A.TEXT.key,{handler:this.configText,value:A.TEXT.value,suppressEvent:A.TEXT.suppressEvent,supercedes:A.TEXT.supercedes});},init:function(E,D){B.superclass.init.call(this,E);this.beforeInitEvent.fire(B);C.addClass(this.element,B.CSS_SIMPLEDIALOG);this.cfg.queueProperty("postmethod","manual");if(D){this.cfg.applyConfig(D,true);}this.beforeRenderEvent.subscribe(function(){if(!this.body){this.setBody("");}},this,true);this.initEvent.fire(B);},registerForm:function(){B.superclass.registerForm.call(this);this.form.innerHTML+='<input type="hidden" name="'+this.id+'" value=""/>';},configIcon:function(K,J,H){var D=J[0],E=this.body,F=B.ICON_CSS_CLASSNAME,L,I,G;if(D&&D!="none"){L=C.getElementsByClassName(F,"*",E);if(L.length===1){I=L[0];G=I.parentNode;if(G){G.removeChild(I);I=null;}}if(D.indexOf(".")==-1){I=document.createElement("span");I.className=(F+" "+D);I.innerHTML="&#160;";}else{I=document.createElement("img");I.src=(this.imageRoot+D);I.className=F;}if(I){E.insertBefore(I,E.firstChild);}}},configText:function(E,D,F){var G=D[0];if(G){this.setBody(G);this.cfg.refireEvent("icon");}},toString:function(){return"SimpleDialog "+this.id;}});}());(function(){YAHOO.widget.ContainerEffect=function(E,H,G,D,F){if(!F){F=YAHOO.util.Anim;}this.overlay=E;this.attrIn=H;this.attrOut=G;this.targetElement=D||E.element;this.animClass=F;};var B=YAHOO.util.Dom,C=YAHOO.util.CustomEvent,A=YAHOO.widget.ContainerEffect;A.FADE=function(D,F){var G=YAHOO.util.Easing,I={attributes:{opacity:{from:0,to:1}},duration:F,method:G.easeIn},E={attributes:{opacity:{to:0}},duration:F,method:G.easeOut},H=new A(D,I,E,D.element);H.handleUnderlayStart=function(){var K=this.overlay.underlay;if(K&&YAHOO.env.ua.ie){var J=(K.filters&&K.filters.length>0);if(J){B.addClass(D.element,"yui-effect-fade");}}};H.handleUnderlayComplete=function(){var J=this.overlay.underlay;if(J&&YAHOO.env.ua.ie){B.removeClass(D.element,"yui-effect-fade");}};H.handleStartAnimateIn=function(K,J,L){B.addClass(L.overlay.element,"hide-select");if(!L.overlay.underlay){L.overlay.cfg.refireEvent("underlay");}L.handleUnderlayStart();L.overlay._setDomVisibility(true);B.setStyle(L.overlay.element,"opacity",0);};H.handleCompleteAnimateIn=function(K,J,L){B.removeClass(L.overlay.element,"hide-select");if(L.overlay.element.style.filter){L.overlay.element.style.filter=null;}L.handleUnderlayComplete();L.overlay.cfg.refireEvent("iframe");L.animateInCompleteEvent.fire();};H.handleStartAnimateOut=function(K,J,L){B.addClass(L.overlay.element,"hide-select");L.handleUnderlayStart();};H.handleCompleteAnimateOut=function(K,J,L){B.removeClass(L.overlay.element,"hide-select");if(L.overlay.element.style.filter){L.overlay.element.style.filter=null;}L.overlay._setDomVisibility(false);B.setStyle(L.overlay.element,"opacity",1);L.handleUnderlayComplete();L.overlay.cfg.refireEvent("iframe");L.animateOutCompleteEvent.fire();};H.init();return H;};A.SLIDE=function(F,D){var I=YAHOO.util.Easing,L=F.cfg.getProperty("x")||B.getX(F.element),K=F.cfg.getProperty("y")||B.getY(F.element),M=B.getClientWidth(),H=F.element.offsetWidth,J={attributes:{points:{to:[L,K]}},duration:D,method:I.easeIn},E={attributes:{points:{to:[(M+25),K]}},duration:D,method:I.easeOut},G=new A(F,J,E,F.element,YAHOO.util.Motion);G.handleStartAnimateIn=function(O,N,P){P.overlay.element.style.left=((-25)-H)+"px";P.overlay.element.style.top=K+"px";};G.handleTweenAnimateIn=function(Q,P,R){var S=B.getXY(R.overlay.element),O=S[0],N=S[1];if(B.getStyle(R.overlay.element,"visibility")=="hidden"&&O<L){R.overlay._setDomVisibility(true);
-}R.overlay.cfg.setProperty("xy",[O,N],true);R.overlay.cfg.refireEvent("iframe");};G.handleCompleteAnimateIn=function(O,N,P){P.overlay.cfg.setProperty("xy",[L,K],true);P.startX=L;P.startY=K;P.overlay.cfg.refireEvent("iframe");P.animateInCompleteEvent.fire();};G.handleStartAnimateOut=function(O,N,R){var P=B.getViewportWidth(),S=B.getXY(R.overlay.element),Q=S[1];R.animOut.attributes.points.to=[(P+25),Q];};G.handleTweenAnimateOut=function(P,O,Q){var S=B.getXY(Q.overlay.element),N=S[0],R=S[1];Q.overlay.cfg.setProperty("xy",[N,R],true);Q.overlay.cfg.refireEvent("iframe");};G.handleCompleteAnimateOut=function(O,N,P){P.overlay._setDomVisibility(false);P.overlay.cfg.setProperty("xy",[L,K]);P.animateOutCompleteEvent.fire();};G.init();return G;};A.prototype={init:function(){this.beforeAnimateInEvent=this.createEvent("beforeAnimateIn");this.beforeAnimateInEvent.signature=C.LIST;this.beforeAnimateOutEvent=this.createEvent("beforeAnimateOut");this.beforeAnimateOutEvent.signature=C.LIST;this.animateInCompleteEvent=this.createEvent("animateInComplete");this.animateInCompleteEvent.signature=C.LIST;this.animateOutCompleteEvent=this.createEvent("animateOutComplete");this.animateOutCompleteEvent.signature=C.LIST;this.animIn=new this.animClass(this.targetElement,this.attrIn.attributes,this.attrIn.duration,this.attrIn.method);this.animIn.onStart.subscribe(this.handleStartAnimateIn,this);this.animIn.onTween.subscribe(this.handleTweenAnimateIn,this);this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);this.animOut=new this.animClass(this.targetElement,this.attrOut.attributes,this.attrOut.duration,this.attrOut.method);this.animOut.onStart.subscribe(this.handleStartAnimateOut,this);this.animOut.onTween.subscribe(this.handleTweenAnimateOut,this);this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,this);},animateIn:function(){this.beforeAnimateInEvent.fire();this.animIn.animate();},animateOut:function(){this.beforeAnimateOutEvent.fire();this.animOut.animate();},handleStartAnimateIn:function(E,D,F){},handleTweenAnimateIn:function(E,D,F){},handleCompleteAnimateIn:function(E,D,F){},handleStartAnimateOut:function(E,D,F){},handleTweenAnimateOut:function(E,D,F){},handleCompleteAnimateOut:function(E,D,F){},toString:function(){var D="ContainerEffect";if(this.overlay){D+=" ["+this.overlay.toString()+"]";}return D;}};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);})();YAHOO.register("container",YAHOO.widget.Module,{version:"2.8.1",build:"19"});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/public/js/yui2a.js	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+*/
+if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C<A.length;C=C+1){D=(""+A[C]).split(".");E=YAHOO;for(B=(D[0]=="YAHOO")?1:0;B<D.length;B=B+1){E[D[B]]=E[D[B]]||{};E=E[D[B]];}}return E;};YAHOO.log=function(D,A,C){var B=YAHOO.widget.Logger;if(B&&B.log){return B.log(D,A,C);}else{return false;}};YAHOO.register=function(A,E,D){var I=YAHOO.env.modules,B,H,G,F,C;if(!I[A]){I[A]={versions:[],builds:[]};}B=I[A];H=D.version;G=D.build;F=YAHOO.env.listeners;B.name=A;B.version=H;B.build=G;B.versions.push(H);B.builds.push(G);B.mainClass=E;for(C=0;C<F.length;C=C+1){F[C](B);}if(E){E.VERSION=H;E.BUILD=G;}else{YAHOO.log("mainClass is undefined for module "+A,"warn");}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(A){return YAHOO.env.modules[A]||null;};YAHOO.env.ua=function(){var D=function(H){var I=0;return parseFloat(H.replace(/\./g,function(){return(I++==1)?"":".";}));},G=navigator,F={ie:0,opera:0,gecko:0,webkit:0,mobile:null,air:0,caja:G.cajaVersion,secure:false,os:null},C=navigator&&navigator.userAgent,E=window&&window.location,B=E&&E.href,A;F.secure=B&&(B.toLowerCase().indexOf("https")===0);if(C){if((/windows|win32/i).test(C)){F.os="windows";}else{if((/macintosh/i).test(C)){F.os="macintosh";}}if((/KHTML/).test(C)){F.webkit=1;}A=C.match(/AppleWebKit\/([^\s]*)/);if(A&&A[1]){F.webkit=D(A[1]);if(/ Mobile\//.test(C)){F.mobile="Apple";}else{A=C.match(/NokiaN[^\/]*/);if(A){F.mobile=A[0];}}A=C.match(/AdobeAIR\/([^\s]*)/);if(A){F.air=A[0];}}if(!F.webkit){A=C.match(/Opera[\s\/]([^\s]*)/);if(A&&A[1]){F.opera=D(A[1]);A=C.match(/Opera Mini[^;]*/);if(A){F.mobile=A[0];}}else{A=C.match(/MSIE\s([^;]*)/);if(A&&A[1]){F.ie=D(A[1]);}else{A=C.match(/Gecko\/([^\s]*)/);if(A){F.gecko=1;A=C.match(/rv:([^\s\)]*)/);if(A&&A[1]){F.gecko=D(A[1]);}}}}}}return F;}();(function(){YAHOO.namespace("util","widget","example");if("undefined"!==typeof YAHOO_config){var B=YAHOO_config.listener,A=YAHOO.env.listeners,D=true,C;if(B){for(C=0;C<A.length;C++){if(A[C]==B){D=false;break;}}if(D){A.push(B);}}}})();YAHOO.lang=YAHOO.lang||{};(function(){var B=YAHOO.lang,A=Object.prototype,H="[object Array]",C="[object Function]",G="[object Object]",E=[],F=["toString","valueOf"],D={isArray:function(I){return A.toString.apply(I)===H;},isBoolean:function(I){return typeof I==="boolean";},isFunction:function(I){return(typeof I==="function")||A.toString.apply(I)===C;},isNull:function(I){return I===null;},isNumber:function(I){return typeof I==="number"&&isFinite(I);},isObject:function(I){return(I&&(typeof I==="object"||B.isFunction(I)))||false;},isString:function(I){return typeof I==="string";},isUndefined:function(I){return typeof I==="undefined";},_IEEnumFix:(YAHOO.env.ua.ie)?function(K,J){var I,M,L;for(I=0;I<F.length;I=I+1){M=F[I];L=J[M];if(B.isFunction(L)&&L!=A[M]){K[M]=L;}}}:function(){},extend:function(L,M,K){if(!M||!L){throw new Error("extend failed, please check that "+"all dependencies are included.");}var J=function(){},I;J.prototype=M.prototype;L.prototype=new J();L.prototype.constructor=L;L.superclass=M.prototype;if(M.prototype.constructor==A.constructor){M.prototype.constructor=M;}if(K){for(I in K){if(B.hasOwnProperty(K,I)){L.prototype[I]=K[I];}}B._IEEnumFix(L.prototype,K);}},augmentObject:function(M,L){if(!L||!M){throw new Error("Absorb failed, verify dependencies.");}var I=arguments,K,N,J=I[2];if(J&&J!==true){for(K=2;K<I.length;K=K+1){M[I[K]]=L[I[K]];}}else{for(N in L){if(J||!(N in M)){M[N]=L[N];}}B._IEEnumFix(M,L);}},augmentProto:function(L,K){if(!K||!L){throw new Error("Augment failed, verify dependencies.");}var I=[L.prototype,K.prototype],J;for(J=2;J<arguments.length;J=J+1){I.push(arguments[J]);}B.augmentObject.apply(this,I);},dump:function(I,N){var K,M,P=[],Q="{...}",J="f(){...}",O=", ",L=" => ";if(!B.isObject(I)){return I+"";}else{if(I instanceof Date||("nodeType" in I&&"tagName" in I)){return I;}else{if(B.isFunction(I)){return J;}}}N=(B.isNumber(N))?N:3;if(B.isArray(I)){P.push("[");for(K=0,M=I.length;K<M;K=K+1){if(B.isObject(I[K])){P.push((N>0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}if(P.length>1){P.pop();}P.push("]");}else{P.push("{");for(K in I){if(B.hasOwnProperty(I,K)){P.push(K+L);if(B.isObject(I[K])){P.push((N>0)?B.dump(I[K],N-1):Q);}else{P.push(I[K]);}P.push(O);}}if(P.length>1){P.pop();}P.push("}");}return P.join("");},substitute:function(Y,J,R){var N,M,L,U,V,X,T=[],K,O="dump",S=" ",I="{",W="}",Q,P;for(;;){N=Y.lastIndexOf(I);if(N<0){break;}M=Y.indexOf(W,N);if(N+1>=M){break;}K=Y.substring(N+1,M);U=K;X=null;L=U.indexOf(S);if(L>-1){X=U.substring(L+1);U=U.substring(0,L);}V=J[U];if(R){V=R(U,V,X);}if(B.isObject(V)){if(B.isArray(V)){V=B.dump(V,parseInt(X,10));}else{X=X||"";Q=X.indexOf(O);if(Q>-1){X=X.substring(4);}P=V.toString();if(P===G||Q>-1){V=B.dump(V,parseInt(X,10));}else{V=P;}}}else{if(!B.isString(V)&&!B.isNumber(V)){V="~-"+T.length+"-~";T[T.length]=K;}}Y=Y.substring(0,N)+V+Y.substring(M+1);}for(N=T.length-1;N>=0;N=N-1){Y=Y.replace(new RegExp("~-"+N+"-~"),"{"+T[N]+"}","g");}return Y;},trim:function(I){try{return I.replace(/^\s+|\s+$/g,"");}catch(J){return I;}},merge:function(){var L={},J=arguments,I=J.length,K;for(K=0;K<I;K=K+1){B.augmentObject(L,J[K],true);}return L;},later:function(P,J,Q,L,M){P=P||0;J=J||{};var K=Q,O=L,N,I;if(B.isString(Q)){K=J[Q];}if(!K){throw new TypeError("method undefined");}if(O&&!B.isArray(O)){O=[L];}N=function(){K.apply(J,O||E);};I=(M)?setInterval(N,P):setTimeout(N,P);return{interval:M,cancel:function(){if(this.interval){clearInterval(I);}else{clearTimeout(I);}}};},isValue:function(I){return(B.isObject(I)||B.isString(I)||B.isNumber(I)||B.isBoolean(I));}};B.hasOwnProperty=(A.hasOwnProperty)?function(I,J){return I&&I.hasOwnProperty(J);}:function(I,J){return !B.isUndefined(I[J])&&I.constructor.prototype[J]!==I[J];};D.augmentObject(B,D,true);YAHOO.util.Lang=B;B.augment=B.augmentProto;YAHOO.augment=B.augmentProto;YAHOO.extend=B.extend;})();YAHOO.register("yahoo",YAHOO,{version:"2.8.2r1",build:"7"});
+YAHOO.util.Get=function(){var M={},L=0,R=0,E=false,N=YAHOO.env.ua,S=YAHOO.lang;var J=function(W,T,X){var U=X||window,Y=U.document,Z=Y.createElement(W);for(var V in T){if(T[V]&&YAHOO.lang.hasOwnProperty(T,V)){Z.setAttribute(V,T[V]);}}return Z;};var I=function(U,V,T){var W={id:"yui__dyn_"+(R++),type:"text/css",rel:"stylesheet",href:U};if(T){S.augmentObject(W,T);}return J("link",W,V);};var P=function(U,V,T){var W={id:"yui__dyn_"+(R++),type:"text/javascript",src:U};if(T){S.augmentObject(W,T);}return J("script",W,V);};var A=function(T,U){return{tId:T.tId,win:T.win,data:T.data,nodes:T.nodes,msg:U,purge:function(){D(this.tId);}};};var B=function(T,W){var U=M[W],V=(S.isString(T))?U.win.document.getElementById(T):T;if(!V){Q(W,"target node not found: "+T);}return V;};var Q=function(W,V){var T=M[W];if(T.onFailure){var U=T.scope||T.win;T.onFailure.call(U,A(T,V));}};var C=function(W){var T=M[W];T.finished=true;if(T.aborted){var V="transaction "+W+" was aborted";Q(W,V);return;}if(T.onSuccess){var U=T.scope||T.win;T.onSuccess.call(U,A(T));}};var O=function(V){var T=M[V];if(T.onTimeout){var U=T.scope||T;T.onTimeout.call(U,A(T));}};var G=function(V,Z){var U=M[V];if(U.timer){U.timer.cancel();}if(U.aborted){var X="transaction "+V+" was aborted";Q(V,X);return;}if(Z){U.url.shift();if(U.varName){U.varName.shift();}}else{U.url=(S.isString(U.url))?[U.url]:U.url;if(U.varName){U.varName=(S.isString(U.varName))?[U.varName]:U.varName;}}var c=U.win,b=c.document,a=b.getElementsByTagName("head")[0],W;if(U.url.length===0){if(U.type==="script"&&N.webkit&&N.webkit<420&&!U.finalpass&&!U.varName){var Y=P(null,U.win,U.attributes);Y.innerHTML='YAHOO.util.Get._finalize("'+V+'");';U.nodes.push(Y);a.appendChild(Y);}else{C(V);}return;}var T=U.url[0];if(!T){U.url.shift();return G(V);}if(U.timeout){U.timer=S.later(U.timeout,U,O,V);}if(U.type==="script"){W=P(T,c,U.attributes);}else{W=I(T,c,U.attributes);}F(U.type,W,V,T,c,U.url.length);U.nodes.push(W);if(U.insertBefore){var e=B(U.insertBefore,V);if(e){e.parentNode.insertBefore(W,e);}}else{a.appendChild(W);}if((N.webkit||N.gecko)&&U.type==="css"){G(V,T);}};var K=function(){if(E){return;}E=true;for(var T in M){var U=M[T];if(U.autopurge&&U.finished){D(U.tId);delete M[T];}}E=false;};var D=function(Z){if(M[Z]){var T=M[Z],U=T.nodes,X=U.length,c=T.win.document,a=c.getElementsByTagName("head")[0],V,Y,W,b;if(T.insertBefore){V=B(T.insertBefore,Z);if(V){a=V.parentNode;}}for(Y=0;Y<X;Y=Y+1){W=U[Y];if(W.clearAttributes){W.clearAttributes();}else{for(b in W){delete W[b];}}a.removeChild(W);}T.nodes=[];}};var H=function(U,T,V){var X="q"+(L++);V=V||{};if(L%YAHOO.util.Get.PURGE_THRESH===0){K();}M[X]=S.merge(V,{tId:X,type:U,url:T,finished:false,aborted:false,nodes:[]});var W=M[X];W.win=W.win||window;W.scope=W.scope||W.win;W.autopurge=("autopurge" in W)?W.autopurge:(U==="script")?true:false;if(V.charset){W.attributes=W.attributes||{};W.attributes.charset=V.charset;}S.later(0,W,G,X);return{tId:X};};var F=function(c,X,W,U,Y,Z,b){var a=b||G;if(N.ie){X.onreadystatechange=function(){var d=this.readyState;if("loaded"===d||"complete"===d){X.onreadystatechange=null;a(W,U);}};}else{if(N.webkit){if(c==="script"){if(N.webkit>=420){X.addEventListener("load",function(){a(W,U);});}else{var T=M[W];if(T.varName){var V=YAHOO.util.Get.POLL_FREQ;T.maxattempts=YAHOO.util.Get.TIMEOUT/V;T.attempts=0;T._cache=T.varName[0].split(".");T.timer=S.later(V,T,function(j){var f=this._cache,e=f.length,d=this.win,g;for(g=0;g<e;g=g+1){d=d[f[g]];if(!d){this.attempts++;if(this.attempts++>this.maxattempts){var h="Over retry limit, giving up";T.timer.cancel();Q(W,h);}else{}return;}}T.timer.cancel();a(W,U);},null,true);}else{S.later(YAHOO.util.Get.POLL_FREQ,null,a,[W,U]);}}}}else{X.onload=function(){a(W,U);};}}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(T){S.later(0,null,C,T);},abort:function(U){var V=(S.isString(U))?U:U.tId;var T=M[V];if(T){T.aborted=true;}},script:function(T,U){return H("script",T,U);},css:function(T,U){return H("css",T,U);}};}();YAHOO.register("get",YAHOO.util.Get,{version:"2.8.2r1",build:"7"});(function(){var Y=YAHOO,util=Y.util,lang=Y.lang,env=Y.env,PROV="_provides",SUPER="_supersedes",REQ="expanded",AFTER="_after";var YUI={dupsAllowed:{"yahoo":true,"get":true},info:{"root":"2.8.2r1/build/","base":"http://yui.yahooapis.com/2.8.2r1/build/","comboBase":"http://yui.yahooapis.com/combo?","skin":{"defaultSkin":"sam","base":"assets/skins/","path":"skin.css","after":["reset","fonts","grids","base"],"rollup":3},dupsAllowed:["yahoo","get"],"moduleInfo":{"animation":{"type":"js","path":"animation/animation-min.js","requires":["dom","event"]},"autocomplete":{"type":"js","path":"autocomplete/autocomplete-min.js","requires":["dom","event","datasource"],"optional":["connection","animation"],"skinnable":true},"base":{"type":"css","path":"base/base-min.css","after":["reset","fonts","grids"]},"button":{"type":"js","path":"button/button-min.js","requires":["element"],"optional":["menu"],"skinnable":true},"calendar":{"type":"js","path":"calendar/calendar-min.js","requires":["event","dom"],supersedes:["datemeth"],"skinnable":true},"carousel":{"type":"js","path":"carousel/carousel-min.js","requires":["element"],"optional":["animation"],"skinnable":true},"charts":{"type":"js","path":"charts/charts-min.js","requires":["element","json","datasource","swf"]},"colorpicker":{"type":"js","path":"colorpicker/colorpicker-min.js","requires":["slider","element"],"optional":["animation"],"skinnable":true},"connection":{"type":"js","path":"connection/connection-min.js","requires":["event"],"supersedes":["connectioncore"]},"connectioncore":{"type":"js","path":"connection/connection_core-min.js","requires":["event"],"pkg":"connection"},"container":{"type":"js","path":"container/container-min.js","requires":["dom","event"],"optional":["dragdrop","animation","connection"],"supersedes":["containercore"],"skinnable":true},"containercore":{"type":"js","path":"container/container_core-min.js","requires":["dom","event"],"pkg":"container"},"cookie":{"type":"js","path":"cookie/cookie-min.js","requires":["yahoo"]},"datasource":{"type":"js","path":"datasource/datasource-min.js","requires":["event"],"optional":["connection"]},"datatable":{"type":"js","path":"datatable/datatable-min.js","requires":["element","datasource"],"optional":["calendar","dragdrop","paginator"],"skinnable":true},datemath:{"type":"js","path":"datemath/datemath-min.js","requires":["yahoo"]},"dom":{"type":"js","path":"dom/dom-min.js","requires":["yahoo"]},"dragdrop":{"type":"js","path":"dragdrop/dragdrop-min.js","requires":["dom","event"]},"editor":{"type":"js","path":"editor/editor-min.js","requires":["menu","element","button"],"optional":["animation","dragdrop"],"supersedes":["simpleeditor"],"skinnable":true},"element":{"type":"js","path":"element/element-min.js","requires":["dom","event"],"optional":["event-mouseenter","event-delegate"]},"element-delegate":{"type":"js","path":"element-delegate/element-delegate-min.js","requires":["element"]},"event":{"type":"js","path":"event/event-min.js","requires":["yahoo"]},"event-simulate":{"type":"js","path":"event-simulate/event-simulate-min.js","requires":["event"]},"event-delegate":{"type":"js","path":"event-delegate/event-delegate-min.js","requires":["event"],"optional":["selector"]},"event-mouseenter":{"type":"js","path":"event-mouseenter/event-mouseenter-min.js","requires":["dom","event"]},"fonts":{"type":"css","path":"fonts/fonts-min.css"},"get":{"type":"js","path":"get/get-min.js","requires":["yahoo"]},"grids":{"type":"css","path":"grids/grids-min.css","requires":["fonts"],"optional":["reset"]},"history":{"type":"js","path":"history/history-min.js","requires":["event"]},"imagecropper":{"type":"js","path":"imagecropper/imagecropper-min.js","requires":["dragdrop","element","resize"],"skinnable":true},"imageloader":{"type":"js","path":"imageloader/imageloader-min.js","requires":["event","dom"]},"json":{"type":"js","path":"json/json-min.js","requires":["yahoo"]},"layout":{"type":"js","path":"layout/layout-min.js","requires":["element"],"optional":["animation","dragdrop","resize","selector"],"skinnable":true},"logger":{"type":"js","path":"logger/logger-min.js","requires":["event","dom"],"optional":["dragdrop"],"skinnable":true},"menu":{"type":"js","path":"menu/menu-min.js","requires":["containercore"],"skinnable":true},"paginator":{"type":"js","path":"paginator/paginator-min.js","requires":["element"],"skinnable":true},"profiler":{"type":"js","path":"profiler/profiler-min.js","requires":["yahoo"]},"profilerviewer":{"type":"js","path":"profilerviewer/profilerviewer-min.js","requires":["profiler","yuiloader","element"],"skinnable":true},"progressbar":{"type":"js","path":"progressbar/progressbar-min.js","requires":["element"],"optional":["animation"],"skinnable":true},"reset":{"type":"css","path":"reset/reset-min.css"},"reset-fonts-grids":{"type":"css","path":"reset-fonts-grids/reset-fonts-grids.css","supersedes":["reset","fonts","grids","reset-fonts"],"rollup":4},"reset-fonts":{"type":"css","path":"reset-fonts/reset-fonts.css","supersedes":["reset","fonts"],"rollup":2},"resize":{"type":"js","path":"resize/resize-min.js","requires":["dragdrop","element"],"optional":["animation"],"skinnable":true},"selector":{"type":"js","path":"selector/selector-min.js","requires":["yahoo","dom"]},"simpleeditor":{"type":"js","path":"editor/simpleeditor-min.js","requires":["element"],"optional":["containercore","menu","button","animation","dragdrop"],"skinnable":true,"pkg":"editor"},"slider":{"type":"js","path":"slider/slider-min.js","requires":["dragdrop"],"optional":["animation"],"skinnable":true},"storage":{"type":"js","path":"storage/storage-min.js","requires":["yahoo","event","cookie"],"optional":["swfstore"]},"stylesheet":{"type":"js","path":"stylesheet/stylesheet-min.js","requires":["yahoo"]},"swf":{"type":"js","path":"swf/swf-min.js","requires":["element"],"supersedes":["swfdetect"]},"swfdetect":{"type":"js","path":"swfdetect/swfdetect-min.js","requires":["yahoo"]},"swfstore":{"type":"js","path":"swfstore/swfstore-min.js","requires":["element","cookie","swf"]},"tabview":{"type":"js","path":"tabview/tabview-min.js","requires":["element"],"optional":["connection"],"skinnable":true},"treeview":{"type":"js","path":"treeview/treeview-min.js","requires":["event","dom"],"optional":["json","animation","calendar"],"skinnable":true},"uploader":{"type":"js","path":"uploader/uploader-min.js","requires":["element"]},"utilities":{"type":"js","path":"utilities/utilities.js","supersedes":["yahoo","event","dragdrop","animation","dom","connection","element","yahoo-dom-event","get","yuiloader","yuiloader-dom-event"],"rollup":8},"yahoo":{"type":"js","path":"yahoo/yahoo-min.js"},"yahoo-dom-event":{"type":"js","path":"yahoo-dom-event/yahoo-dom-event.js","supersedes":["yahoo","event","dom"],"rollup":3},"yuiloader":{"type":"js","path":"yuiloader/yuiloader-min.js","supersedes":["yahoo","get"]},"yuiloader-dom-event":{"type":"js","path":"yuiloader-dom-event/yuiloader-dom-event.js","supersedes":["yahoo","dom","event","get","yuiloader","yahoo-dom-event"],"rollup":5},"yuitest":{"type":"js","path":"yuitest/yuitest-min.js","requires":["logger"],"optional":["event-simulate"],"skinnable":true}}},ObjectUtil:{appendArray:function(o,a){if(a){for(var i=0;
+i<a.length;i=i+1){o[a[i]]=true;}}},keys:function(o,ordered){var a=[],i;for(i in o){if(lang.hasOwnProperty(o,i)){a.push(i);}}return a;}},ArrayUtil:{appendArray:function(a1,a2){Array.prototype.push.apply(a1,a2);},indexOf:function(a,val){for(var i=0;i<a.length;i=i+1){if(a[i]===val){return i;}}return -1;},toObject:function(a){var o={};for(var i=0;i<a.length;i=i+1){o[a[i]]=true;}return o;},uniq:function(a){return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));}}};YAHOO.util.YUILoader=function(o){this._internalCallback=null;this._useYahooListener=false;this.onSuccess=null;this.onFailure=Y.log;this.onProgress=null;this.onTimeout=null;this.scope=this;this.data=null;this.insertBefore=null;this.charset=null;this.varName=null;this.base=YUI.info.base;this.comboBase=YUI.info.comboBase;this.combine=false;this.root=YUI.info.root;this.timeout=0;this.ignore=null;this.force=null;this.allowRollup=true;this.filter=null;this.required={};this.moduleInfo=lang.merge(YUI.info.moduleInfo);this.rollups=null;this.loadOptional=false;this.sorted=[];this.loaded={};this.dirty=true;this.inserted={};var self=this;env.listeners.push(function(m){if(self._useYahooListener){self.loadNext(m.name);}});this.skin=lang.merge(YUI.info.skin);this._config(o);};Y.util.YUILoader.prototype={FILTERS:{RAW:{"searchExp":"-min\\.js","replaceStr":".js"},DEBUG:{"searchExp":"-min\\.js","replaceStr":"-debug.js"}},SKIN_PREFIX:"skin-",_config:function(o){if(o){for(var i in o){if(lang.hasOwnProperty(o,i)){if(i=="require"){this.require(o[i]);}else{this[i]=o[i];}}}}var f=this.filter;if(lang.isString(f)){f=f.toUpperCase();if(f==="DEBUG"){this.require("logger");}if(!Y.widget.LogWriter){Y.widget.LogWriter=function(){return Y;};}this.filter=this.FILTERS[f];}},addModule:function(o){if(!o||!o.name||!o.type||(!o.path&&!o.fullpath)){return false;}o.ext=("ext" in o)?o.ext:true;o.requires=o.requires||[];this.moduleInfo[o.name]=o;this.dirty=true;return true;},require:function(what){var a=(typeof what==="string")?arguments:what;this.dirty=true;YUI.ObjectUtil.appendArray(this.required,a);},_addSkin:function(skin,mod){var name=this.formatSkin(skin),info=this.moduleInfo,sinf=this.skin,ext=info[mod]&&info[mod].ext;if(!info[name]){this.addModule({"name":name,"type":"css","path":sinf.base+skin+"/"+sinf.path,"after":sinf.after,"rollup":sinf.rollup,"ext":ext});}if(mod){name=this.formatSkin(skin,mod);if(!info[name]){var mdef=info[mod],pkg=mdef.pkg||mod;this.addModule({"name":name,"type":"css","after":sinf.after,"path":pkg+"/"+sinf.base+skin+"/"+mod+".css","ext":ext});}}return name;},getRequires:function(mod){if(!mod){return[];}if(!this.dirty&&mod.expanded){return mod.expanded;}mod.requires=mod.requires||[];var i,d=[],r=mod.requires,o=mod.optional,info=this.moduleInfo,m;for(i=0;i<r.length;i=i+1){d.push(r[i]);m=info[r[i]];YUI.ArrayUtil.appendArray(d,this.getRequires(m));}if(o&&this.loadOptional){for(i=0;i<o.length;i=i+1){d.push(o[i]);YUI.ArrayUtil.appendArray(d,this.getRequires(info[o[i]]));}}mod.expanded=YUI.ArrayUtil.uniq(d);return mod.expanded;},getProvides:function(name,notMe){var addMe=!(notMe),ckey=(addMe)?PROV:SUPER,m=this.moduleInfo[name],o={};if(!m){return o;}if(m[ckey]){return m[ckey];}var s=m.supersedes,done={},me=this;var add=function(mm){if(!done[mm]){done[mm]=true;lang.augmentObject(o,me.getProvides(mm));}};if(s){for(var i=0;i<s.length;i=i+1){add(s[i]);}}m[SUPER]=o;m[PROV]=lang.merge(o);m[PROV][name]=true;return m[ckey];},calculate:function(o){if(o||this.dirty){this._config(o);this._setup();this._explode();if(this.allowRollup){this._rollup();}this._reduce();this._sort();this.dirty=false;}},_setup:function(){var info=this.moduleInfo,name,i,j;for(name in info){if(lang.hasOwnProperty(info,name)){var m=info[name];if(m&&m.skinnable){var o=this.skin.overrides,smod;if(o&&o[name]){for(i=0;i<o[name].length;i=i+1){smod=this._addSkin(o[name][i],name);}}else{smod=this._addSkin(this.skin.defaultSkin,name);}m.requires.push(smod);}}}var l=lang.merge(this.inserted);if(!this._sandbox){l=lang.merge(l,env.modules);}if(this.ignore){YUI.ObjectUtil.appendArray(l,this.ignore);}if(this.force){for(i=0;i<this.force.length;i=i+1){if(this.force[i] in l){delete l[this.force[i]];}}}for(j in l){if(lang.hasOwnProperty(l,j)){lang.augmentObject(l,this.getProvides(j));}}this.loaded=l;},_explode:function(){var r=this.required,i,mod;for(i in r){if(lang.hasOwnProperty(r,i)){mod=this.moduleInfo[i];if(mod){var req=this.getRequires(mod);if(req){YUI.ObjectUtil.appendArray(r,req);}}}}},_skin:function(){},formatSkin:function(skin,mod){var s=this.SKIN_PREFIX+skin;if(mod){s=s+"-"+mod;}return s;},parseSkin:function(mod){if(mod.indexOf(this.SKIN_PREFIX)===0){var a=mod.split("-");return{skin:a[1],module:a[2]};}return null;},_rollup:function(){var i,j,m,s,rollups={},r=this.required,roll,info=this.moduleInfo;if(this.dirty||!this.rollups){for(i in info){if(lang.hasOwnProperty(info,i)){m=info[i];if(m&&m.rollup){rollups[i]=m;}}}this.rollups=rollups;}for(;;){var rolled=false;for(i in rollups){if(!r[i]&&!this.loaded[i]){m=info[i];s=m.supersedes;roll=false;if(!m.rollup){continue;}var skin=(m.ext)?false:this.parseSkin(i),c=0;if(skin){for(j in r){if(lang.hasOwnProperty(r,j)){if(i!==j&&this.parseSkin(j)){c++;roll=(c>=m.rollup);if(roll){break;}}}}}else{for(j=0;j<s.length;j=j+1){if(this.loaded[s[j]]&&(!YUI.dupsAllowed[s[j]])){roll=false;break;}else{if(r[s[j]]){c++;roll=(c>=m.rollup);if(roll){break;}}}}}if(roll){r[i]=true;rolled=true;this.getRequires(m);}}}if(!rolled){break;}}},_reduce:function(){var i,j,s,m,r=this.required;for(i in r){if(i in this.loaded){delete r[i];}else{var skinDef=this.parseSkin(i);if(skinDef){if(!skinDef.module){var skin_pre=this.SKIN_PREFIX+skinDef.skin;for(j in r){if(lang.hasOwnProperty(r,j)){m=this.moduleInfo[j];var ext=m&&m.ext;if(!ext&&j!==i&&j.indexOf(skin_pre)>-1){delete r[j];}}}}}else{m=this.moduleInfo[i];s=m&&m.supersedes;if(s){for(j=0;j<s.length;j=j+1){if(s[j] in r){delete r[s[j]];}}}}}}},_onFailure:function(msg){YAHOO.log("Failure","info","loader");var f=this.onFailure;if(f){f.call(this.scope,{msg:"failure: "+msg,data:this.data,success:false});
+}},_onTimeout:function(){YAHOO.log("Timeout","info","loader");var f=this.onTimeout;if(f){f.call(this.scope,{msg:"timeout",data:this.data,success:false});}},_sort:function(){var s=[],info=this.moduleInfo,loaded=this.loaded,checkOptional=!this.loadOptional,me=this;var requires=function(aa,bb){var mm=info[aa];if(loaded[bb]||!mm){return false;}var ii,rr=mm.expanded,after=mm.after,other=info[bb],optional=mm.optional;if(rr&&YUI.ArrayUtil.indexOf(rr,bb)>-1){return true;}if(after&&YUI.ArrayUtil.indexOf(after,bb)>-1){return true;}if(checkOptional&&optional&&YUI.ArrayUtil.indexOf(optional,bb)>-1){return true;}var ss=info[bb]&&info[bb].supersedes;if(ss){for(ii=0;ii<ss.length;ii=ii+1){if(requires(aa,ss[ii])){return true;}}}if(mm.ext&&mm.type=="css"&&!other.ext&&other.type=="css"){return true;}return false;};for(var i in this.required){if(lang.hasOwnProperty(this.required,i)){s.push(i);}}var p=0;for(;;){var l=s.length,a,b,j,k,moved=false;for(j=p;j<l;j=j+1){a=s[j];for(k=j+1;k<l;k=k+1){if(requires(a,s[k])){b=s.splice(k,1);s.splice(j,0,b[0]);moved=true;break;}}if(moved){break;}else{p=p+1;}}if(!moved){break;}}this.sorted=s;},toString:function(){var o={type:"YUILoader",base:this.base,filter:this.filter,required:this.required,loaded:this.loaded,inserted:this.inserted};lang.dump(o,1);},_combine:function(){this._combining=[];var self=this,s=this.sorted,len=s.length,js=this.comboBase,css=this.comboBase,target,startLen=js.length,i,m,type=this.loadType;YAHOO.log("type "+type);for(i=0;i<len;i=i+1){m=this.moduleInfo[s[i]];if(m&&!m.ext&&(!type||type===m.type)){target=this.root+m.path;target+="&";if(m.type=="js"){js+=target;}else{css+=target;}this._combining.push(s[i]);}}if(this._combining.length){YAHOO.log("Attempting to combine: "+this._combining,"info","loader");var callback=function(o){var c=this._combining,len=c.length,i,m;for(i=0;i<len;i=i+1){this.inserted[c[i]]=true;}this.loadNext(o.data);},loadScript=function(){if(js.length>startLen){YAHOO.util.Get.script(self._filter(js),{data:self._loading,onSuccess:callback,onFailure:self._onFailure,onTimeout:self._onTimeout,insertBefore:self.insertBefore,charset:self.charset,timeout:self.timeout,scope:self});}};if(css.length>startLen){YAHOO.util.Get.css(this._filter(css),{data:this._loading,onSuccess:loadScript,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,scope:self});}else{loadScript();}return;}else{this.loadNext(this._loading);}},insert:function(o,type){this.calculate(o);this._loading=true;this.loadType=type;if(this.combine){return this._combine();}if(!type){var self=this;this._internalCallback=function(){self._internalCallback=null;self.insert(null,"js");};this.insert(null,"css");return;}this.loadNext();},sandbox:function(o,type){this._config(o);if(!this.onSuccess){throw new Error("You must supply an onSuccess handler for your sandbox");}this._sandbox=true;var self=this;if(!type||type!=="js"){this._internalCallback=function(){self._internalCallback=null;self.sandbox(null,"js");};this.insert(null,"css");return;}if(!util.Connect){var ld=new YAHOO.util.YUILoader();ld.insert({base:this.base,filter:this.filter,require:"connection",insertBefore:this.insertBefore,charset:this.charset,onSuccess:function(){this.sandbox(null,"js");},scope:this},"js");return;}this._scriptText=[];this._loadCount=0;this._stopCount=this.sorted.length;this._xhr=[];this.calculate();var s=this.sorted,l=s.length,i,m,url;for(i=0;i<l;i=i+1){m=this.moduleInfo[s[i]];if(!m){this._onFailure("undefined module "+m);for(var j=0;j<this._xhr.length;j=j+1){this._xhr[j].abort();}return;}if(m.type!=="js"){this._loadCount++;continue;}url=m.fullpath;url=(url)?this._filter(url):this._url(m.path);var xhrData={success:function(o){var idx=o.argument[0],name=o.argument[2];this._scriptText[idx]=o.responseText;if(this.onProgress){this.onProgress.call(this.scope,{name:name,scriptText:o.responseText,xhrResponse:o,data:this.data});}this._loadCount++;if(this._loadCount>=this._stopCount){var v=this.varName||"YAHOO";var t="(function() {\n";var b="\nreturn "+v+";\n})();";var ref=eval(t+this._scriptText.join("\n")+b);this._pushEvents(ref);if(ref){this.onSuccess.call(this.scope,{reference:ref,data:this.data});}else{this._onFailure.call(this.varName+" reference failure");}}},failure:function(o){this.onFailure.call(this.scope,{msg:"XHR failure",xhrResponse:o,data:this.data});},scope:this,argument:[i,url,s[i]]};this._xhr.push(util.Connect.asyncRequest("GET",url,xhrData));}},loadNext:function(mname){if(!this._loading){return;}if(mname){if(mname!==this._loading){return;}this.inserted[mname]=true;if(this.onProgress){this.onProgress.call(this.scope,{name:mname,data:this.data});}}var s=this.sorted,len=s.length,i,m;for(i=0;i<len;i=i+1){if(s[i] in this.inserted){continue;}if(s[i]===this._loading){return;}m=this.moduleInfo[s[i]];if(!m){this.onFailure.call(this.scope,{msg:"undefined module "+m,data:this.data});return;}if(!this.loadType||this.loadType===m.type){this._loading=s[i];var fn=(m.type==="css")?util.Get.css:util.Get.script,url=m.fullpath,self=this,c=function(o){self.loadNext(o.data);};url=(url)?this._filter(url):this._url(m.path);if(env.ua.webkit&&env.ua.webkit<420&&m.type==="js"&&!m.varName){c=null;this._useYahooListener=true;}fn(url,{data:s[i],onSuccess:c,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,varName:m.varName,scope:self});return;}}this._loading=null;if(this._internalCallback){var f=this._internalCallback;this._internalCallback=null;f.call(this);}else{if(this.onSuccess){this._pushEvents();this.onSuccess.call(this.scope,{data:this.data});}}},_pushEvents:function(ref){var r=ref||YAHOO;if(r.util&&r.util.Event){r.util.Event._load();}},_filter:function(str){var f=this.filter;return(f)?str.replace(new RegExp(f.searchExp,"g"),f.replaceStr):str;},_url:function(path){return this._filter((this.base||"")+path);}};})();YAHOO.register("yuiloader",YAHOO.util.YUILoader,{version:"2.8.2r1",build:"7"});
+(function(){YAHOO.env._id_counter=YAHOO.env._id_counter||0;var E=YAHOO.util,L=YAHOO.lang,m=YAHOO.env.ua,A=YAHOO.lang.trim,d={},h={},N=/^t(?:able|d|h)$/i,X=/color$/i,K=window.document,W=K.documentElement,e="ownerDocument",n="defaultView",v="documentElement",t="compatMode",b="offsetLeft",P="offsetTop",u="offsetParent",Z="parentNode",l="nodeType",C="tagName",O="scrollLeft",i="scrollTop",Q="getBoundingClientRect",w="getComputedStyle",a="currentStyle",M="CSS1Compat",c="BackCompat",g="class",F="className",J="",B=" ",s="(?:^|\\s)",k="(?= |$)",U="g",p="position",f="fixed",V="relative",j="left",o="top",r="medium",q="borderLeftWidth",R="borderTopWidth",D=m.opera,I=m.webkit,H=m.gecko,T=m.ie;E.Dom={CUSTOM_ATTRIBUTES:(!W.hasAttribute)?{"for":"htmlFor","class":F}:{"htmlFor":"for","className":g},DOT_ATTRIBUTES:{},get:function(z){var AB,x,AA,y,Y,G;if(z){if(z[l]||z.item){return z;}if(typeof z==="string"){AB=z;z=K.getElementById(z);G=(z)?z.attributes:null;if(z&&G&&G.id&&G.id.value===AB){return z;}else{if(z&&K.all){z=null;x=K.all[AB];for(y=0,Y=x.length;y<Y;++y){if(x[y].id===AB){return x[y];}}}}return z;}if(YAHOO.util.Element&&z instanceof YAHOO.util.Element){z=z.get("element");}if("length" in z){AA=[];for(y=0,Y=z.length;y<Y;++y){AA[AA.length]=E.Dom.get(z[y]);}return AA;}return z;}return null;},getComputedStyle:function(G,Y){if(window[w]){return G[e][n][w](G,null)[Y];}else{if(G[a]){return E.Dom.IE_ComputedStyle.get(G,Y);}}},getStyle:function(G,Y){return E.Dom.batch(G,E.Dom._getStyle,Y);},_getStyle:function(){if(window[w]){return function(G,y){y=(y==="float")?y="cssFloat":E.Dom._toCamel(y);var x=G.style[y],Y;if(!x){Y=G[e][n][w](G,null);if(Y){x=Y[y];}}return x;};}else{if(W[a]){return function(G,y){var x;switch(y){case"opacity":x=100;try{x=G.filters["DXImageTransform.Microsoft.Alpha"].opacity;}catch(z){try{x=G.filters("alpha").opacity;}catch(Y){}}return x/100;case"float":y="styleFloat";default:y=E.Dom._toCamel(y);x=G[a]?G[a][y]:null;return(G.style[y]||x);}};}}}(),setStyle:function(G,Y,x){E.Dom.batch(G,E.Dom._setStyle,{prop:Y,val:x});},_setStyle:function(){if(T){return function(Y,G){var x=E.Dom._toCamel(G.prop),y=G.val;if(Y){switch(x){case"opacity":if(L.isString(Y.style.filter)){Y.style.filter="alpha(opacity="+y*100+")";if(!Y[a]||!Y[a].hasLayout){Y.style.zoom=1;}}break;case"float":x="styleFloat";default:Y.style[x]=y;}}else{}};}else{return function(Y,G){var x=E.Dom._toCamel(G.prop),y=G.val;if(Y){if(x=="float"){x="cssFloat";}Y.style[x]=y;}else{}};}}(),getXY:function(G){return E.Dom.batch(G,E.Dom._getXY);},_canPosition:function(G){return(E.Dom._getStyle(G,"display")!=="none"&&E.Dom._inDoc(G));},_getXY:function(){if(K[v][Q]){return function(y){var z,Y,AA,AF,AE,AD,AC,G,x,AB=Math.floor,AG=false;if(E.Dom._canPosition(y)){AA=y[Q]();AF=y[e];z=E.Dom.getDocumentScrollLeft(AF);Y=E.Dom.getDocumentScrollTop(AF);AG=[AB(AA[j]),AB(AA[o])];if(T&&m.ie<8){AE=2;AD=2;AC=AF[t];if(m.ie===6){if(AC!==c){AE=0;AD=0;}}if((AC===c)){G=S(AF[v],q);x=S(AF[v],R);if(G!==r){AE=parseInt(G,10);}if(x!==r){AD=parseInt(x,10);}}AG[0]-=AE;AG[1]-=AD;}if((Y||z)){AG[0]+=z;AG[1]+=Y;}AG[0]=AB(AG[0]);AG[1]=AB(AG[1]);}else{}return AG;};}else{return function(y){var x,Y,AA,AB,AC,z=false,G=y;if(E.Dom._canPosition(y)){z=[y[b],y[P]];x=E.Dom.getDocumentScrollLeft(y[e]);Y=E.Dom.getDocumentScrollTop(y[e]);AC=((H||m.webkit>519)?true:false);while((G=G[u])){z[0]+=G[b];z[1]+=G[P];if(AC){z=E.Dom._calcBorders(G,z);}}if(E.Dom._getStyle(y,p)!==f){G=y;while((G=G[Z])&&G[C]){AA=G[i];AB=G[O];if(H&&(E.Dom._getStyle(G,"overflow")!=="visible")){z=E.Dom._calcBorders(G,z);}if(AA||AB){z[0]-=AB;z[1]-=AA;}}z[0]+=x;z[1]+=Y;}else{if(D){z[0]-=x;z[1]-=Y;}else{if(I||H){z[0]+=x;z[1]+=Y;}}}z[0]=Math.floor(z[0]);z[1]=Math.floor(z[1]);}else{}return z;};}}(),getX:function(G){var Y=function(x){return E.Dom.getXY(x)[0];};return E.Dom.batch(G,Y,E.Dom,true);},getY:function(G){var Y=function(x){return E.Dom.getXY(x)[1];};return E.Dom.batch(G,Y,E.Dom,true);},setXY:function(G,x,Y){E.Dom.batch(G,E.Dom._setXY,{pos:x,noRetry:Y});},_setXY:function(G,z){var AA=E.Dom._getStyle(G,p),y=E.Dom.setStyle,AD=z.pos,Y=z.noRetry,AB=[parseInt(E.Dom.getComputedStyle(G,j),10),parseInt(E.Dom.getComputedStyle(G,o),10)],AC,x;if(AA=="static"){AA=V;y(G,p,AA);}AC=E.Dom._getXY(G);if(!AD||AC===false){return false;}if(isNaN(AB[0])){AB[0]=(AA==V)?0:G[b];}if(isNaN(AB[1])){AB[1]=(AA==V)?0:G[P];}if(AD[0]!==null){y(G,j,AD[0]-AC[0]+AB[0]+"px");}if(AD[1]!==null){y(G,o,AD[1]-AC[1]+AB[1]+"px");}if(!Y){x=E.Dom._getXY(G);if((AD[0]!==null&&x[0]!=AD[0])||(AD[1]!==null&&x[1]!=AD[1])){E.Dom._setXY(G,{pos:AD,noRetry:true});}}},setX:function(Y,G){E.Dom.setXY(Y,[G,null]);},setY:function(G,Y){E.Dom.setXY(G,[null,Y]);},getRegion:function(G){var Y=function(x){var y=false;if(E.Dom._canPosition(x)){y=E.Region.getRegion(x);}else{}return y;};return E.Dom.batch(G,Y,E.Dom,true);},getClientWidth:function(){return E.Dom.getViewportWidth();},getClientHeight:function(){return E.Dom.getViewportHeight();},getElementsByClassName:function(AB,AF,AC,AE,x,AD){AF=AF||"*";AC=(AC)?E.Dom.get(AC):null||K;if(!AC){return[];}var Y=[],G=AC.getElementsByTagName(AF),z=E.Dom.hasClass;for(var y=0,AA=G.length;y<AA;++y){if(z(G[y],AB)){Y[Y.length]=G[y];}}if(AE){E.Dom.batch(Y,AE,x,AD);}return Y;},hasClass:function(Y,G){return E.Dom.batch(Y,E.Dom._hasClass,G);},_hasClass:function(x,Y){var G=false,y;if(x&&Y){y=E.Dom._getAttribute(x,F)||J;if(Y.exec){G=Y.test(y);}else{G=Y&&(B+y+B).indexOf(B+Y+B)>-1;}}else{}return G;},addClass:function(Y,G){return E.Dom.batch(Y,E.Dom._addClass,G);},_addClass:function(x,Y){var G=false,y;if(x&&Y){y=E.Dom._getAttribute(x,F)||J;if(!E.Dom._hasClass(x,Y)){E.Dom.setAttribute(x,F,A(y+B+Y));G=true;}}else{}return G;},removeClass:function(Y,G){return E.Dom.batch(Y,E.Dom._removeClass,G);},_removeClass:function(y,x){var Y=false,AA,z,G;if(y&&x){AA=E.Dom._getAttribute(y,F)||J;E.Dom.setAttribute(y,F,AA.replace(E.Dom._getClassRegex(x),J));z=E.Dom._getAttribute(y,F);if(AA!==z){E.Dom.setAttribute(y,F,A(z));Y=true;if(E.Dom._getAttribute(y,F)===""){G=(y.hasAttribute&&y.hasAttribute(g))?g:F;
+y.removeAttribute(G);}}}else{}return Y;},replaceClass:function(x,Y,G){return E.Dom.batch(x,E.Dom._replaceClass,{from:Y,to:G});},_replaceClass:function(y,x){var Y,AB,AA,G=false,z;if(y&&x){AB=x.from;AA=x.to;if(!AA){G=false;}else{if(!AB){G=E.Dom._addClass(y,x.to);}else{if(AB!==AA){z=E.Dom._getAttribute(y,F)||J;Y=(B+z.replace(E.Dom._getClassRegex(AB),B+AA)).split(E.Dom._getClassRegex(AA));Y.splice(1,0,B+AA);E.Dom.setAttribute(y,F,A(Y.join(J)));G=true;}}}}else{}return G;},generateId:function(G,x){x=x||"yui-gen";var Y=function(y){if(y&&y.id){return y.id;}var z=x+YAHOO.env._id_counter++;if(y){if(y[e]&&y[e].getElementById(z)){return E.Dom.generateId(y,z+x);}y.id=z;}return z;};return E.Dom.batch(G,Y,E.Dom,true)||Y.apply(E.Dom,arguments);},isAncestor:function(Y,x){Y=E.Dom.get(Y);x=E.Dom.get(x);var G=false;if((Y&&x)&&(Y[l]&&x[l])){if(Y.contains&&Y!==x){G=Y.contains(x);}else{if(Y.compareDocumentPosition){G=!!(Y.compareDocumentPosition(x)&16);}}}else{}return G;},inDocument:function(G,Y){return E.Dom._inDoc(E.Dom.get(G),Y);},_inDoc:function(Y,x){var G=false;if(Y&&Y[C]){x=x||Y[e];G=E.Dom.isAncestor(x[v],Y);}else{}return G;},getElementsBy:function(Y,AF,AB,AD,y,AC,AE){AF=AF||"*";AB=(AB)?E.Dom.get(AB):null||K;if(!AB){return[];}var x=[],G=AB.getElementsByTagName(AF);for(var z=0,AA=G.length;z<AA;++z){if(Y(G[z])){if(AE){x=G[z];break;}else{x[x.length]=G[z];}}}if(AD){E.Dom.batch(x,AD,y,AC);}return x;},getElementBy:function(x,G,Y){return E.Dom.getElementsBy(x,G,Y,null,null,null,true);},batch:function(x,AB,AA,z){var y=[],Y=(z)?AA:window;x=(x&&(x[C]||x.item))?x:E.Dom.get(x);if(x&&AB){if(x[C]||x.length===undefined){return AB.call(Y,x,AA);}for(var G=0;G<x.length;++G){y[y.length]=AB.call(Y,x[G],AA);}}else{return false;}return y;},getDocumentHeight:function(){var Y=(K[t]!=M||I)?K.body.scrollHeight:W.scrollHeight,G=Math.max(Y,E.Dom.getViewportHeight());return G;},getDocumentWidth:function(){var Y=(K[t]!=M||I)?K.body.scrollWidth:W.scrollWidth,G=Math.max(Y,E.Dom.getViewportWidth());return G;},getViewportHeight:function(){var G=self.innerHeight,Y=K[t];if((Y||T)&&!D){G=(Y==M)?W.clientHeight:K.body.clientHeight;}return G;},getViewportWidth:function(){var G=self.innerWidth,Y=K[t];if(Y||T){G=(Y==M)?W.clientWidth:K.body.clientWidth;}return G;},getAncestorBy:function(G,Y){while((G=G[Z])){if(E.Dom._testElement(G,Y)){return G;}}return null;},getAncestorByClassName:function(Y,G){Y=E.Dom.get(Y);if(!Y){return null;}var x=function(y){return E.Dom.hasClass(y,G);};return E.Dom.getAncestorBy(Y,x);},getAncestorByTagName:function(Y,G){Y=E.Dom.get(Y);if(!Y){return null;}var x=function(y){return y[C]&&y[C].toUpperCase()==G.toUpperCase();};return E.Dom.getAncestorBy(Y,x);},getPreviousSiblingBy:function(G,Y){while(G){G=G.previousSibling;if(E.Dom._testElement(G,Y)){return G;}}return null;},getPreviousSibling:function(G){G=E.Dom.get(G);if(!G){return null;}return E.Dom.getPreviousSiblingBy(G);},getNextSiblingBy:function(G,Y){while(G){G=G.nextSibling;if(E.Dom._testElement(G,Y)){return G;}}return null;},getNextSibling:function(G){G=E.Dom.get(G);if(!G){return null;}return E.Dom.getNextSiblingBy(G);},getFirstChildBy:function(G,x){var Y=(E.Dom._testElement(G.firstChild,x))?G.firstChild:null;return Y||E.Dom.getNextSiblingBy(G.firstChild,x);},getFirstChild:function(G,Y){G=E.Dom.get(G);if(!G){return null;}return E.Dom.getFirstChildBy(G);},getLastChildBy:function(G,x){if(!G){return null;}var Y=(E.Dom._testElement(G.lastChild,x))?G.lastChild:null;return Y||E.Dom.getPreviousSiblingBy(G.lastChild,x);},getLastChild:function(G){G=E.Dom.get(G);return E.Dom.getLastChildBy(G);},getChildrenBy:function(Y,y){var x=E.Dom.getFirstChildBy(Y,y),G=x?[x]:[];E.Dom.getNextSiblingBy(x,function(z){if(!y||y(z)){G[G.length]=z;}return false;});return G;},getChildren:function(G){G=E.Dom.get(G);if(!G){}return E.Dom.getChildrenBy(G);},getDocumentScrollLeft:function(G){G=G||K;return Math.max(G[v].scrollLeft,G.body.scrollLeft);},getDocumentScrollTop:function(G){G=G||K;return Math.max(G[v].scrollTop,G.body.scrollTop);},insertBefore:function(Y,G){Y=E.Dom.get(Y);G=E.Dom.get(G);if(!Y||!G||!G[Z]){return null;}return G[Z].insertBefore(Y,G);},insertAfter:function(Y,G){Y=E.Dom.get(Y);G=E.Dom.get(G);if(!Y||!G||!G[Z]){return null;}if(G.nextSibling){return G[Z].insertBefore(Y,G.nextSibling);}else{return G[Z].appendChild(Y);}},getClientRegion:function(){var x=E.Dom.getDocumentScrollTop(),Y=E.Dom.getDocumentScrollLeft(),y=E.Dom.getViewportWidth()+Y,G=E.Dom.getViewportHeight()+x;return new E.Region(x,y,G,Y);},setAttribute:function(Y,G,x){E.Dom.batch(Y,E.Dom._setAttribute,{attr:G,val:x});},_setAttribute:function(x,Y){var G=E.Dom._toCamel(Y.attr),y=Y.val;if(x&&x.setAttribute){if(E.Dom.DOT_ATTRIBUTES[G]){x[G]=y;}else{G=E.Dom.CUSTOM_ATTRIBUTES[G]||G;x.setAttribute(G,y);}}else{}},getAttribute:function(Y,G){return E.Dom.batch(Y,E.Dom._getAttribute,G);},_getAttribute:function(Y,G){var x;G=E.Dom.CUSTOM_ATTRIBUTES[G]||G;if(Y&&Y.getAttribute){x=Y.getAttribute(G,2);}else{}return x;},_toCamel:function(Y){var x=d;function G(y,z){return z.toUpperCase();}return x[Y]||(x[Y]=Y.indexOf("-")===-1?Y:Y.replace(/-([a-z])/gi,G));},_getClassRegex:function(Y){var G;if(Y!==undefined){if(Y.exec){G=Y;}else{G=h[Y];if(!G){Y=Y.replace(E.Dom._patterns.CLASS_RE_TOKENS,"\\$1");G=h[Y]=new RegExp(s+Y+k,U);}}}return G;},_patterns:{ROOT_TAG:/^body|html$/i,CLASS_RE_TOKENS:/([\.\(\)\^\$\*\+\?\|\[\]\{\}\\])/g},_testElement:function(G,Y){return G&&G[l]==1&&(!Y||Y(G));},_calcBorders:function(x,y){var Y=parseInt(E.Dom[w](x,R),10)||0,G=parseInt(E.Dom[w](x,q),10)||0;if(H){if(N.test(x[C])){Y=0;G=0;}}y[0]+=G;y[1]+=Y;return y;}};var S=E.Dom[w];if(m.opera){E.Dom[w]=function(Y,G){var x=S(Y,G);if(X.test(G)){x=E.Dom.Color.toRGB(x);}return x;};}if(m.webkit){E.Dom[w]=function(Y,G){var x=S(Y,G);if(x==="rgba(0, 0, 0, 0)"){x="transparent";}return x;};}if(m.ie&&m.ie>=8&&K.documentElement.hasAttribute){E.Dom.DOT_ATTRIBUTES.type=true;}})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this.y=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this.x=B;this[0]=B;
+this.width=this.right-this.left;this.height=this.bottom-this.top;};YAHOO.util.Region.prototype.contains=function(A){return(A.left>=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top),D=Math.min(this.right,E.right),A=Math.min(this.bottom,E.bottom),B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top),D=Math.max(this.right,E.right),A=Math.max(this.bottom,E.bottom),B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+", height: "+this.height+", width: "+this.width+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D),C=F[1],E=F[0]+D.offsetWidth,A=F[1]+D.offsetHeight,B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}YAHOO.util.Point.superclass.constructor.call(this,B,A,B,A);};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var B=YAHOO.util,A="clientTop",F="clientLeft",J="parentNode",K="right",W="hasLayout",I="px",U="opacity",L="auto",D="borderLeftWidth",G="borderTopWidth",P="borderRightWidth",V="borderBottomWidth",S="visible",Q="transparent",N="height",E="width",H="style",T="currentStyle",R=/^width|height$/,O=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,M={get:function(X,Z){var Y="",a=X[T][Z];if(Z===U){Y=B.Dom.getStyle(X,U);}else{if(!a||(a.indexOf&&a.indexOf(I)>-1)){Y=a;}else{if(B.Dom.IE_COMPUTED[Z]){Y=B.Dom.IE_COMPUTED[Z](X,Z);}else{if(O.test(a)){Y=B.Dom.IE.ComputedStyle.getPixel(X,Z);}else{Y=a;}}}}return Y;},getOffset:function(Z,e){var b=Z[T][e],X=e.charAt(0).toUpperCase()+e.substr(1),c="offset"+X,Y="pixel"+X,a="",d;if(b==L){d=Z[c];if(d===undefined){a=0;}a=d;if(R.test(e)){Z[H][e]=d;if(Z[c]>d){a=d-(Z[c]-d);}Z[H][e]=L;}}else{if(!Z[H][Y]&&!Z[H][e]){Z[H][e]=b;}a=Z[H][Y];}return a+I;},getBorderWidth:function(X,Z){var Y=null;if(!X[T][W]){X[H].zoom=1;}switch(Z){case G:Y=X[A];break;case V:Y=X.offsetHeight-X.clientHeight-X[A];break;case D:Y=X[F];break;case P:Y=X.offsetWidth-X.clientWidth-X[F];break;}return Y+I;},getPixel:function(Y,X){var a=null,b=Y[T][K],Z=Y[T][X];Y[H][K]=Z;a=Y[H].pixelRight;Y[H][K]=b;return a+I;},getMargin:function(Y,X){var Z;if(Y[T][X]==L){Z=0+I;}else{Z=B.Dom.IE.ComputedStyle.getPixel(Y,X);}return Z;},getVisibility:function(Y,X){var Z;while((Z=Y[T])&&Z[X]=="inherit"){Y=Y[J];}return(Z)?Z[X]:S;},getColor:function(Y,X){return B.Dom.Color.toRGB(Y[T][X])||Q;},getBorderColor:function(Y,X){var Z=Y[T],a=Z[X]||Z.color;return B.Dom.Color.toRGB(B.Dom.Color.toHex(a));}},C={};C.top=C.right=C.bottom=C.left=C[E]=C[N]=M.getOffset;C.color=M.getColor;C[G]=C[P]=C[V]=C[D]=M.getBorderWidth;C.marginTop=C.marginRight=C.marginBottom=C.marginLeft=M.getMargin;C.visibility=M.getVisibility;C.borderColor=C.borderTopColor=C.borderRightColor=C.borderBottomColor=C.borderLeftColor=M.getBorderColor;B.Dom.IE_COMPUTED=C;B.Dom.IE_ComputedStyle=M;})();(function(){var C="toString",A=parseInt,B=RegExp,D=YAHOO.util;D.Dom.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Dom.Color.re_RGB.test(E)){E=D.Dom.Color.toHex(E);}if(D.Dom.Color.re_hex.exec(E)){E="rgb("+[A(B.$1,16),A(B.$2,16),A(B.$3,16)].join(", ")+")";}return E;},toHex:function(H){H=D.Dom.Color.KEYWORDS[H]||H;if(D.Dom.Color.re_RGB.exec(H)){var G=(B.$1.length===1)?"0"+B.$1:Number(B.$1),F=(B.$2.length===1)?"0"+B.$2:Number(B.$2),E=(B.$3.length===1)?"0"+B.$3:Number(B.$3);H=[G[C](16),F[C](16),E[C](16)].join("");}if(H.length<6){H=H.replace(D.Dom.Color.re_hex3,"$1$1");}if(H!=="transparent"&&H.indexOf("#")<0){H="#"+H;}return H.toLowerCase();}};}());YAHOO.register("dom",YAHOO.util.Dom,{version:"2.8.2r1",build:"7"});YAHOO.util.CustomEvent=function(D,C,B,A,E){this.type=D;this.scope=C||window;this.silent=B;this.fireOnce=E;this.fired=false;this.firedWith=null;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var F="_YUICEOnSubscribe";if(D!==F){this.subscribeEvent=new YAHOO.util.CustomEvent(F,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,D){if(!B){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,D);}var A=new YAHOO.util.Subscriber(B,C,D);if(this.fireOnce&&this.fired){this.notify(A,this.firedWith);}else{this.subscribers.push(A);}},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B<A;++B){var C=this.subscribers[B];if(C&&C.contains(D,F)){this._delete(B);E=true;}}return E;},fire:function(){this.lastError=null;var H=[],A=this.subscribers.length;var D=[].slice.call(arguments,0),C=true,F,B=false;if(this.fireOnce){if(this.fired){return true;}else{this.firedWith=D;}}this.fired=true;if(!A&&this.silent){return true;}if(!this.silent){}var E=this.subscribers.slice();for(F=0;F<A;++F){var G=E[F];if(!G){B=true;}else{C=this.notify(G,D);if(false===C){if(!this.silent){}break;}}}return(C!==false);},notify:function(F,C){var B,H=null,E=F.getScope(this.scope),A=YAHOO.util.Event.throwErrors;if(!this.silent){}if(this.signature==YAHOO.util.CustomEvent.FLAT){if(C.length>0){H=C[0];}try{B=F.fn.call(E,H,F.obj);}catch(G){this.lastError=G;if(A){throw G;}}}else{try{B=F.fn.call(E,this.type,C,F.obj);}catch(D){this.lastError=D;if(A){throw D;}}}return B;},unsubscribeAll:function(){var A=this.subscribers.length,B;for(B=A-1;B>-1;B--){this._delete(B);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"context: "+this.scope;}};YAHOO.util.Subscriber=function(A,B,C){this.fn=A;this.obj=YAHOO.lang.isUndefined(B)?null:B;this.overrideContext=C;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.overrideContext){if(this.overrideContext===true){return this.obj;}else{return this.overrideContext;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", overrideContext: "+(this.overrideContext||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var G=false,H=[],J=[],A=0,E=[],B=0,C={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9},D=YAHOO.env.ua.ie,F="focusin",I="focusout";return{POLL_RETRYS:500,POLL_INTERVAL:40,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,CAPTURE:7,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:D,_interval:null,_dri:null,_specialTypes:{focusin:(D?"focusin":"focus"),focusout:(D?"focusout":"blur")},DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){this._interval=YAHOO.lang.later(this.POLL_INTERVAL,this,this._tryPreloadAttach,null,true);}},onAvailable:function(Q,M,O,P,N){var K=(YAHOO.lang.isString(Q))?[Q]:Q;for(var L=0;L<K.length;L=L+1){E.push({id:K[L],fn:M,obj:O,overrideContext:P,checkReady:N});}A=this.POLL_RETRYS;this.startInterval();},onContentReady:function(N,K,L,M){this.onAvailable(N,K,L,M,true);},onDOMReady:function(){this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent,arguments);},_addListener:function(M,K,V,P,T,Y){if(!V||!V.call){return false;}if(this._isValidCollection(M)){var W=true;for(var Q=0,S=M.length;Q<S;++Q){W=this.on(M[Q],K,V,P,T)&&W;}return W;}else{if(YAHOO.lang.isString(M)){var O=this.getEl(M);if(O){M=O;}else{this.onAvailable(M,function(){YAHOO.util.Event._addListener(M,K,V,P,T,Y);});return true;}}}if(!M){return false;}if("unload"==K&&P!==this){J[J.length]=[M,K,V,P,T];return true;}var L=M;if(T){if(T===true){L=P;}else{L=T;}}var N=function(Z){return V.call(L,YAHOO.util.Event.getEvent(Z,M),P);};var X=[M,K,V,N,L,P,T,Y];var R=H.length;H[R]=X;try{this._simpleAdd(M,K,N,Y);}catch(U){this.lastError=U;this.removeListener(M,K,V);return false;}return true;},_getType:function(K){return this._specialTypes[K]||K;},addListener:function(M,P,L,N,O){var K=((P==F||P==I)&&!YAHOO.env.ua.ie)?true:false;return this._addListener(M,this._getType(P),L,N,O,K);},addFocusListener:function(L,K,M,N){return this.on(L,F,K,M,N);},removeFocusListener:function(L,K){return this.removeListener(L,F,K);},addBlurListener:function(L,K,M,N){return this.on(L,I,K,M,N);},removeBlurListener:function(L,K){return this.removeListener(L,I,K);},removeListener:function(L,K,R){var M,P,U;K=this._getType(K);if(typeof L=="string"){L=this.getEl(L);}else{if(this._isValidCollection(L)){var S=true;for(M=L.length-1;M>-1;M--){S=(this.removeListener(L[M],K,R)&&S);}return S;}}if(!R||!R.call){return this.purgeElement(L,false,K);}if("unload"==K){for(M=J.length-1;M>-1;M--){U=J[M];if(U&&U[0]==L&&U[1]==K&&U[2]==R){J.splice(M,1);return true;}}return false;}var N=null;var O=arguments[3];if("undefined"===typeof O){O=this._getCacheIndex(H,L,K,R);}if(O>=0){N=H[O];}if(!L||!N){return false;}var T=N[this.CAPTURE]===true?true:false;try{this._simpleRemove(L,K,N[this.WFN],T);}catch(Q){this.lastError=Q;return false;}delete H[O][this.WFN];delete H[O][this.FN];H.splice(O,1);return true;},getTarget:function(M,L){var K=M.target||M.srcElement;return this.resolveTextNode(K);},resolveTextNode:function(L){try{if(L&&3==L.nodeType){return L.parentNode;}}catch(K){}return L;},getPageX:function(L){var K=L.pageX;if(!K&&0!==K){K=L.clientX||0;if(this.isIE){K+=this._getScrollLeft();}}return K;},getPageY:function(K){var L=K.pageY;if(!L&&0!==L){L=K.clientY||0;if(this.isIE){L+=this._getScrollTop();}}return L;},getXY:function(K){return[this.getPageX(K),this.getPageY(K)];},getRelatedTarget:function(L){var K=L.relatedTarget;if(!K){if(L.type=="mouseout"){K=L.toElement;
+}else{if(L.type=="mouseover"){K=L.fromElement;}}}return this.resolveTextNode(K);},getTime:function(M){if(!M.time){var L=new Date().getTime();try{M.time=L;}catch(K){this.lastError=K;return L;}}return M.time;},stopEvent:function(K){this.stopPropagation(K);this.preventDefault(K);},stopPropagation:function(K){if(K.stopPropagation){K.stopPropagation();}else{K.cancelBubble=true;}},preventDefault:function(K){if(K.preventDefault){K.preventDefault();}else{K.returnValue=false;}},getEvent:function(M,K){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break;}N=N.caller;}}return L;},getCharCode:function(L){var K=L.keyCode||L.charCode||0;if(YAHOO.env.ua.webkit&&(K in C)){K=C[K];}return K;},_getCacheIndex:function(M,P,Q,O){for(var N=0,L=M.length;N<L;N=N+1){var K=M[N];if(K&&K[this.FN]==O&&K[this.EL]==P&&K[this.TYPE]==Q){return N;}}return -1;},generateId:function(K){var L=K.id;if(!L){L="yuievtautoid-"+B;++B;K.id=L;}return L;},_isValidCollection:function(L){try{return(L&&typeof L!=="string"&&L.length&&!L.tagName&&!L.alert&&typeof L[0]!=="undefined");}catch(K){return false;}},elCache:{},getEl:function(K){return(typeof K==="string")?document.getElementById(K):K;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent("DOMReady",YAHOO,0,0,1),_load:function(L){if(!G){G=true;var K=YAHOO.util.Event;K._ready();K._tryPreloadAttach();}},_ready:function(L){var K=YAHOO.util.Event;if(!K.DOMReady){K.DOMReady=true;K.DOMReadyEvent.fire();K._simpleRemove(document,"DOMContentLoaded",K._ready);}},_tryPreloadAttach:function(){if(E.length===0){A=0;if(this._interval){this._interval.cancel();this._interval=null;}return;}if(this.locked){return;}if(this.isIE){if(!this.DOMReady){this.startInterval();return;}}this.locked=true;var Q=!G;if(!Q){Q=(A>0&&E.length>0);}var P=[];var R=function(T,U){var S=T;if(U.overrideContext){if(U.overrideContext===true){S=U.obj;}else{S=U.overrideContext;}}U.fn.call(S,U.obj);};var L,K,O,N,M=[];for(L=0,K=E.length;L<K;L=L+1){O=E[L];if(O){N=this.getEl(O.id);if(N){if(O.checkReady){if(G||N.nextSibling||!Q){M.push(O);E[L]=null;}}else{R(N,O);E[L]=null;}}else{P.push(O);}}}for(L=0,K=M.length;L<K;L=L+1){O=M[L];R(this.getEl(O.id),O);}A--;if(Q){for(L=E.length-1;L>-1;L--){O=E[L];if(!O||!O.id){E.splice(L,1);}}this.startInterval();}else{if(this._interval){this._interval.cancel();this._interval=null;}}this.locked=false;},purgeElement:function(O,P,R){var M=(YAHOO.lang.isString(O))?this.getEl(O):O;var Q=this.getListeners(M,R),N,K;if(Q){for(N=Q.length-1;N>-1;N--){var L=Q[N];this.removeListener(M,L.type,L.fn);}}if(P&&M&&M.childNodes){for(N=0,K=M.childNodes.length;N<K;++N){this.purgeElement(M.childNodes[N],P,R);}}},getListeners:function(M,K){var P=[],L;if(!K){L=[H,J];}else{if(K==="unload"){L=[J];}else{K=this._getType(K);L=[H];}}var R=(YAHOO.lang.isString(M))?this.getEl(M):M;for(var O=0;O<L.length;O=O+1){var T=L[O];if(T){for(var Q=0,S=T.length;Q<S;++Q){var N=T[Q];if(N&&N[this.EL]===R&&(!K||K===N[this.TYPE])){P.push({type:N[this.TYPE],fn:N[this.FN],obj:N[this.OBJ],adjust:N[this.OVERRIDE],scope:N[this.ADJ_SCOPE],index:Q});}}}}return(P.length)?P:null;},_unload:function(R){var L=YAHOO.util.Event,O,N,M,Q,P,S=J.slice(),K;for(O=0,Q=J.length;O<Q;++O){M=S[O];if(M){K=window;if(M[L.ADJ_SCOPE]){if(M[L.ADJ_SCOPE]===true){K=M[L.UNLOAD_OBJ];}else{K=M[L.ADJ_SCOPE];}}M[L.FN].call(K,L.getEvent(R,M[L.EL]),M[L.UNLOAD_OBJ]);S[O]=null;}}M=null;K=null;J=null;if(H){for(N=H.length-1;N>-1;N--){M=H[N];if(M){L.removeListener(M[L.EL],M[L.TYPE],M[L.FN],N);}}M=null;}L._simpleRemove(window,"unload",L._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var K=document.documentElement,L=document.body;if(K&&(K.scrollTop||K.scrollLeft)){return[K.scrollTop,K.scrollLeft];}else{if(L){return[L.scrollTop,L.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(M,N,L,K){M.addEventListener(N,L,(K));};}else{if(window.attachEvent){return function(M,N,L,K){M.attachEvent("on"+N,L);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(M,N,L,K){M.removeEventListener(N,L,(K));};}else{if(window.detachEvent){return function(L,M,K){L.detachEvent("on"+M,K);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;EU.onFocus=EU.addFocusListener;EU.onBlur=EU.addBlurListener;
+/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+if(EU.isIE){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;EU._ready();}};}else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,overrideContext:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A);
+},createEvent:function(B,G){this.__yui_events=this.__yui_events||{};var E=G||{},D=this.__yui_events,F;if(D[B]){}else{F=new YAHOO.util.CustomEvent(B,E.scope||this,E.silent,YAHOO.util.CustomEvent.FLAT,E.fireOnce);D[B]=F;if(E.onSubscribeCallback){F.subscribeEvent.subscribe(E.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var A=this.__yui_subscribers[B];if(A){for(var C=0;C<A.length;++C){F.subscribe(A[C].fn,A[C].obj,A[C].overrideContext);}}}return D[B];},fireEvent:function(B){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[B];if(!D){return null;}var A=[];for(var C=1;C<arguments.length;++C){A.push(arguments[C]);}return D.fire.apply(D,A);},hasEvent:function(A){if(this.__yui_events){if(this.__yui_events[A]){return true;}}return false;}};(function(){var A=YAHOO.util.Event,C=YAHOO.lang;YAHOO.util.KeyListener=function(D,I,E,F){if(!D){}else{if(!I){}else{if(!E){}}}if(!F){F=YAHOO.util.KeyListener.KEYDOWN;}var G=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");if(C.isString(D)){D=document.getElementById(D);}if(C.isFunction(E)){G.subscribe(E);}else{G.subscribe(E.fn,E.scope,E.correctScope);}function H(O,N){if(!I.shift){I.shift=false;}if(!I.alt){I.alt=false;}if(!I.ctrl){I.ctrl=false;}if(O.shiftKey==I.shift&&O.altKey==I.alt&&O.ctrlKey==I.ctrl){var J,M=I.keys,L;if(YAHOO.lang.isArray(M)){for(var K=0;K<M.length;K++){J=M[K];L=A.getCharCode(O);if(J==L){G.fire(L,O);break;}}}else{L=A.getCharCode(O);if(M==L){G.fire(L,O);}}}}this.enable=function(){if(!this.enabled){A.on(D,F,H);this.enabledEvent.fire(I);}this.enabled=true;};this.disable=function(){if(this.enabled){A.removeListener(D,F,H);this.disabledEvent.fire(I);}this.enabled=false;};this.toString=function(){return"KeyListener ["+I.keys+"] "+D.tagName+(D.id?"["+D.id+"]":"");};};var B=YAHOO.util.KeyListener;B.KEYDOWN="keydown";B.KEYUP="keyup";B.KEY={ALT:18,BACK_SPACE:8,CAPS_LOCK:20,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,META:224,NUM_LOCK:144,PAGE_DOWN:34,PAGE_UP:33,PAUSE:19,PRINTSCREEN:44,RIGHT:39,SCROLL_LOCK:145,SHIFT:16,SPACE:32,TAB:9,UP:38};})();YAHOO.register("event",YAHOO.util.Event,{version:"2.8.2r1",build:"7"});YAHOO.util.Connect={_msxml_progid:["Microsoft.XMLHTTP","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP"],_http_headers:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:"application/x-www-form-urlencoded; charset=UTF-8",_default_form_header:"application/x-www-form-urlencoded",_use_default_xhr_header:true,_default_xhr_header:"XMLHttpRequest",_has_default_headers:true,_default_headers:{},_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,startEvent:new YAHOO.util.CustomEvent("start"),completeEvent:new YAHOO.util.CustomEvent("complete"),successEvent:new YAHOO.util.CustomEvent("success"),failureEvent:new YAHOO.util.CustomEvent("failure"),abortEvent:new YAHOO.util.CustomEvent("abort"),_customEvents:{onStart:["startEvent","start"],onComplete:["completeEvent","complete"],onSuccess:["successEvent","success"],onFailure:["failureEvent","failure"],onUpload:["uploadEvent","upload"],onAbort:["abortEvent","abort"]},setProgId:function(A){this._msxml_progid.unshift(A);},setDefaultPostHeader:function(A){if(typeof A=="string"){this._default_post_header=A;}else{if(typeof A=="boolean"){this._use_default_post_header=A;}}},setDefaultXhrHeader:function(A){if(typeof A=="string"){this._default_xhr_header=A;}else{this._use_default_xhr_header=A;}},setPollingInterval:function(A){if(typeof A=="number"&&isFinite(A)){this._polling_interval=A;}},createXhrObject:function(F){var D,A,B;try{A=new XMLHttpRequest();D={conn:A,tId:F,xhr:true};}catch(C){for(B=0;B<this._msxml_progid.length;++B){try{A=new ActiveXObject(this._msxml_progid[B]);D={conn:A,tId:F,xhr:true};break;}catch(E){}}}finally{return D;}},getConnectionObject:function(A){var C,D=this._transaction_id;try{if(!A){C=this.createXhrObject(D);}else{C={tId:D};if(A==="xdr"){C.conn=this._transport;C.xdr=true;}else{if(A==="upload"){C.upload=true;}}}if(C){this._transaction_id++;}}catch(B){}return C;},asyncRequest:function(G,D,F,A){var E,C,B=(F&&F.argument)?F.argument:null;if(this._isFileUpload){C="upload";}else{if(F.xdr){C="xdr";}}E=this.getConnectionObject(C);if(!E){return null;}else{if(F&&F.customevents){this.initCustomEvents(E,F);}if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(E,F,D,A);return E;}if(G.toUpperCase()=="GET"){if(this._sFormData.length!==0){D+=((D.indexOf("?")==-1)?"?":"&")+this._sFormData;}}else{if(G.toUpperCase()=="POST"){A=A?this._sFormData+"&"+A:this._sFormData;}}}if(G.toUpperCase()=="GET"&&(F&&F.cache===false)){D+=((D.indexOf("?")==-1)?"?":"&")+"rnd="+new Date().valueOf().toString();}if(this._use_default_xhr_header){if(!this._default_headers["X-Requested-With"]){this.initHeader("X-Requested-With",this._default_xhr_header,true);}}if((G.toUpperCase()==="POST"&&this._use_default_post_header)&&this._isFormSubmit===false){this.initHeader("Content-Type",this._default_post_header);}if(E.xdr){this.xdr(E,G,D,F,A);return E;}E.conn.open(G,D,true);if(this._has_default_headers||this._has_http_headers){this.setHeader(E);}this.handleReadyState(E,F);E.conn.send(A||"");if(this._isFormSubmit===true){this.resetFormState();}this.startEvent.fire(E,B);if(E.startEvent){E.startEvent.fire(E,B);}return E;}},initCustomEvents:function(A,C){var B;for(B in C.customevents){if(this._customEvents[B][0]){A[this._customEvents[B][0]]=new YAHOO.util.CustomEvent(this._customEvents[B][1],(C.scope)?C.scope:null);A[this._customEvents[B][0]].subscribe(C.customevents[B]);}}},handleReadyState:function(C,D){var B=this,A=(D&&D.argument)?D.argument:null;if(D&&D.timeout){this._timeOut[C.tId]=window.setTimeout(function(){B.abort(C,D,true);},D.timeout);}this._poll[C.tId]=window.setInterval(function(){if(C.conn&&C.conn.readyState===4){window.clearInterval(B._poll[C.tId]);delete B._poll[C.tId];if(D&&D.timeout){window.clearTimeout(B._timeOut[C.tId]);delete B._timeOut[C.tId];}B.completeEvent.fire(C,A);if(C.completeEvent){C.completeEvent.fire(C,A);}B.handleTransactionResponse(C,D);}},this._polling_interval);},handleTransactionResponse:function(B,I,D){var E,A,G=(I&&I.argument)?I.argument:null,C=(B.r&&B.r.statusText==="xdr:success")?true:false,H=(B.r&&B.r.statusText==="xdr:failure")?true:false,J=D;try{if((B.conn.status!==undefined&&B.conn.status!==0)||C){E=B.conn.status;}else{if(H&&!J){E=0;}else{E=13030;}}}catch(F){E=13030;}if((E>=200&&E<300)||E===1223||C){A=B.xdr?B.r:this.createResponseObject(B,G);if(I&&I.success){if(!I.scope){I.success(A);}else{I.success.apply(I.scope,[A]);}}this.successEvent.fire(A);if(B.successEvent){B.successEvent.fire(A);}}else{switch(E){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:A=this.createExceptionObject(B.tId,G,(D?D:false));if(I&&I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}break;default:A=(B.xdr)?B.response:this.createResponseObject(B,G);if(I&&I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}}this.failureEvent.fire(A);if(B.failureEvent){B.failureEvent.fire(A);}}this.releaseObject(B);A=null;},createResponseObject:function(A,G){var D={},I={},E,C,F,B;try{C=A.conn.getAllResponseHeaders();F=C.split("\n");for(E=0;E<F.length;E++){B=F[E].indexOf(":");if(B!=-1){I[F[E].substring(0,B)]=YAHOO.lang.trim(F[E].substring(B+2));}}}catch(H){}D.tId=A.tId;D.status=(A.conn.status==1223)?204:A.conn.status;D.statusText=(A.conn.status==1223)?"No Content":A.conn.statusText;D.getResponseHeader=I;D.getAllResponseHeaders=C;D.responseText=A.conn.responseText;D.responseXML=A.conn.responseXML;if(G){D.argument=G;}return D;},createExceptionObject:function(H,D,A){var F=0,G="communication failure",C=-1,B="transaction aborted",E={};E.tId=H;if(A){E.status=C;E.statusText=B;}else{E.status=F;E.statusText=G;}if(D){E.argument=D;}return E;},initHeader:function(A,D,C){var B=(C)?this._default_headers:this._http_headers;B[A]=D;if(C){this._has_default_headers=true;}else{this._has_http_headers=true;}},setHeader:function(A){var B;if(this._has_default_headers){for(B in this._default_headers){if(YAHOO.lang.hasOwnProperty(this._default_headers,B)){A.conn.setRequestHeader(B,this._default_headers[B]);}}}if(this._has_http_headers){for(B in this._http_headers){if(YAHOO.lang.hasOwnProperty(this._http_headers,B)){A.conn.setRequestHeader(B,this._http_headers[B]);
+}}this._http_headers={};this._has_http_headers=false;}},resetDefaultHeaders:function(){this._default_headers={};this._has_default_headers=false;},abort:function(E,G,A){var D,B=(G&&G.argument)?G.argument:null;E=E||{};if(E.conn){if(E.xhr){if(this.isCallInProgress(E)){E.conn.abort();window.clearInterval(this._poll[E.tId]);delete this._poll[E.tId];if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{if(E.xdr){E.conn.abort(E.tId);D=true;}}}else{if(E.upload){var C="yuiIO"+E.tId;var F=document.getElementById(C);if(F){YAHOO.util.Event.removeListener(F,"load");document.body.removeChild(F);if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{D=false;}}if(D===true){this.abortEvent.fire(E,B);if(E.abortEvent){E.abortEvent.fire(E,B);}this.handleTransactionResponse(E,G,true);}return D;},isCallInProgress:function(A){A=A||{};if(A.xhr&&A.conn){return A.conn.readyState!==4&&A.conn.readyState!==0;}else{if(A.xdr&&A.conn){return A.conn.isCallInProgress(A.tId);}else{if(A.upload===true){return document.getElementById("yuiIO"+A.tId)?true:false;}else{return false;}}}},releaseObject:function(A){if(A&&A.conn){A.conn=null;A=null;}}};(function(){var G=YAHOO.util.Connect,H={};function D(I){var J='<object id="YUIConnectionSwf" type="application/x-shockwave-flash" data="'+I+'" width="0" height="0">'+'<param name="movie" value="'+I+'">'+'<param name="allowScriptAccess" value="always">'+"</object>",K=document.createElement("div");document.body.appendChild(K);K.innerHTML=J;}function B(L,I,J,M,K){H[parseInt(L.tId)]={"o":L,"c":M};if(K){M.method=I;M.data=K;}L.conn.send(J,M,L.tId);}function E(I){D(I);G._transport=document.getElementById("YUIConnectionSwf");}function C(){G.xdrReadyEvent.fire();}function A(J,I){if(J){G.startEvent.fire(J,I.argument);if(J.startEvent){J.startEvent.fire(J,I.argument);}}}function F(J){var K=H[J.tId].o,I=H[J.tId].c;if(J.statusText==="xdr:start"){A(K,I);return;}J.responseText=decodeURI(J.responseText);K.r=J;if(I.argument){K.r.argument=I.argument;}this.handleTransactionResponse(K,I,J.statusText==="xdr:abort"?true:false);delete H[J.tId];}G.xdr=B;G.swf=D;G.transport=E;G.xdrReadyEvent=new YAHOO.util.CustomEvent("xdrReady");G.xdrReady=C;G.handleXdrResponse=F;})();(function(){var D=YAHOO.util.Connect,F=YAHOO.util.Event;D._isFormSubmit=false;D._isFileUpload=false;D._formNode=null;D._sFormData=null;D._submitElementValue=null;D.uploadEvent=new YAHOO.util.CustomEvent("upload"),D._hasSubmitListener=function(){if(F){F.addListener(document,"click",function(J){var I=F.getTarget(J),H=I.nodeName.toLowerCase();if((H==="input"||H==="button")&&(I.type&&I.type.toLowerCase()=="submit")){D._submitElementValue=encodeURIComponent(I.name)+"="+encodeURIComponent(I.value);}});return true;}return false;}();function G(T,O,J){var S,I,R,P,W,Q=false,M=[],V=0,L,N,K,U,H;this.resetFormState();if(typeof T=="string"){S=(document.getElementById(T)||document.forms[T]);}else{if(typeof T=="object"){S=T;}else{return;}}if(O){this.createFrame(J?J:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=S;return;}for(L=0,N=S.elements.length;L<N;++L){I=S.elements[L];W=I.disabled;R=I.name;if(!W&&R){R=encodeURIComponent(R)+"=";P=encodeURIComponent(I.value);switch(I.type){case"select-one":if(I.selectedIndex>-1){H=I.options[I.selectedIndex];M[V++]=R+encodeURIComponent((H.attributes.value&&H.attributes.value.specified)?H.value:H.text);}break;case"select-multiple":if(I.selectedIndex>-1){for(K=I.selectedIndex,U=I.options.length;K<U;++K){H=I.options[K];if(H.selected){M[V++]=R+encodeURIComponent((H.attributes.value&&H.attributes.value.specified)?H.value:H.text);}}}break;case"radio":case"checkbox":if(I.checked){M[V++]=R+P;}break;case"file":case undefined:case"reset":case"button":break;case"submit":if(Q===false){if(this._hasSubmitListener&&this._submitElementValue){M[V++]=this._submitElementValue;}Q=true;}break;default:M[V++]=R+P;}}}this._isFormSubmit=true;this._sFormData=M.join("&");this.initHeader("Content-Type",this._default_form_header);return this._sFormData;}function C(){this._isFormSubmit=false;this._isFileUpload=false;this._formNode=null;this._sFormData="";}function B(H){var I="yuiIO"+this._transaction_id,J;if(YAHOO.env.ua.ie){J=document.createElement('<iframe id="'+I+'" name="'+I+'" />');if(typeof H=="boolean"){J.src="javascript:false";}}else{J=document.createElement("iframe");J.id=I;J.name=I;}J.style.position="absolute";J.style.top="-1000px";J.style.left="-1000px";document.body.appendChild(J);}function E(H){var K=[],I=H.split("&"),J,L;for(J=0;J<I.length;J++){L=I[J].indexOf("=");if(L!=-1){K[J]=document.createElement("input");K[J].type="hidden";K[J].name=decodeURIComponent(I[J].substring(0,L));K[J].value=decodeURIComponent(I[J].substring(L+1));this._formNode.appendChild(K[J]);}}return K;}function A(K,V,L,J){var Q="yuiIO"+K.tId,R="multipart/form-data",T=document.getElementById(Q),M=(document.documentMode&&document.documentMode===8)?true:false,W=this,S=(V&&V.argument)?V.argument:null,U,P,I,O,H,N;H={action:this._formNode.getAttribute("action"),method:this._formNode.getAttribute("method"),target:this._formNode.getAttribute("target")};this._formNode.setAttribute("action",L);this._formNode.setAttribute("method","POST");this._formNode.setAttribute("target",Q);if(YAHOO.env.ua.ie&&!M){this._formNode.setAttribute("encoding",R);}else{this._formNode.setAttribute("enctype",R);}if(J){U=this.appendPostData(J);}this._formNode.submit();this.startEvent.fire(K,S);if(K.startEvent){K.startEvent.fire(K,S);}if(V&&V.timeout){this._timeOut[K.tId]=window.setTimeout(function(){W.abort(K,V,true);},V.timeout);}if(U&&U.length>0){for(P=0;P<U.length;P++){this._formNode.removeChild(U[P]);}}for(I in H){if(YAHOO.lang.hasOwnProperty(H,I)){if(H[I]){this._formNode.setAttribute(I,H[I]);}else{this._formNode.removeAttribute(I);}}}this.resetFormState();N=function(){if(V&&V.timeout){window.clearTimeout(W._timeOut[K.tId]);delete W._timeOut[K.tId];}W.completeEvent.fire(K,S);if(K.completeEvent){K.completeEvent.fire(K,S);
+}O={tId:K.tId,argument:V.argument};try{O.responseText=T.contentWindow.document.body?T.contentWindow.document.body.innerHTML:T.contentWindow.document.documentElement.textContent;O.responseXML=T.contentWindow.document.XMLDocument?T.contentWindow.document.XMLDocument:T.contentWindow.document;}catch(X){}if(V&&V.upload){if(!V.scope){V.upload(O);}else{V.upload.apply(V.scope,[O]);}}W.uploadEvent.fire(O);if(K.uploadEvent){K.uploadEvent.fire(O);}F.removeListener(T,"load",N);setTimeout(function(){document.body.removeChild(T);W.releaseObject(K);},100);};F.addListener(T,"load",N);}D.setForm=G;D.resetFormState=C;D.createFrame=B;D.appendPostData=E;D.uploadFile=A;})();YAHOO.register("connection",YAHOO.util.Connect,{version:"2.8.2r1",build:"7"});(function(){var B=YAHOO.util;var A=function(D,C,E,F){if(!D){}this.init(D,C,E,F);};A.NAME="Anim";A.prototype={toString:function(){var C=this.getEl()||{};var D=C.id||C.tagName;return(this.constructor.NAME+": "+D);},patterns:{noNegatives:/width|height|opacity|padding/i,offsetAttribute:/^((width|height)|(top|left))$/,defaultUnit:/width|height|top$|bottom$|left$|right$/i,offsetUnit:/\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i},doMethod:function(C,E,D){return this.method(this.currentFrame,E,D-E,this.totalFrames);},setAttribute:function(C,F,E){var D=this.getEl();if(this.patterns.noNegatives.test(C)){F=(F>0)?F:0;}if(C in D&&!("style" in D&&C in D.style)){D[C]=F;}else{B.Dom.setStyle(D,C,F+E);}},getAttribute:function(C){var E=this.getEl();var G=B.Dom.getStyle(E,C);if(G!=="auto"&&!this.patterns.offsetUnit.test(G)){return parseFloat(G);}var D=this.patterns.offsetAttribute.exec(C)||[];var H=!!(D[3]);var F=!!(D[2]);if("style" in E){if(F||(B.Dom.getStyle(E,"position")=="absolute"&&H)){G=E["offset"+D[0].charAt(0).toUpperCase()+D[0].substr(1)];}else{G=0;}}else{if(C in E){G=E[C];}}return G;},getDefaultUnit:function(C){if(this.patterns.defaultUnit.test(C)){return"px";}return"";},setRuntimeAttribute:function(D){var I;var E;var F=this.attributes;this.runtimeAttributes[D]={};var H=function(J){return(typeof J!=="undefined");};if(!H(F[D]["to"])&&!H(F[D]["by"])){return false;}I=(H(F[D]["from"]))?F[D]["from"]:this.getAttribute(D);if(H(F[D]["to"])){E=F[D]["to"];}else{if(H(F[D]["by"])){if(I.constructor==Array){E=[];for(var G=0,C=I.length;G<C;++G){E[G]=I[G]+F[D]["by"][G]*1;}}else{E=I+F[D]["by"]*1;}}}this.runtimeAttributes[D].start=I;this.runtimeAttributes[D].end=E;this.runtimeAttributes[D].unit=(H(F[D].unit))?F[D]["unit"]:this.getDefaultUnit(D);return true;},init:function(E,J,I,C){var D=false;var F=null;var H=0;E=B.Dom.get(E);this.attributes=J||{};this.duration=!YAHOO.lang.isUndefined(I)?I:1;this.method=C||B.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=B.AnimMgr.fps;this.setEl=function(M){E=B.Dom.get(M);};this.getEl=function(){return E;};this.isAnimated=function(){return D;};this.getStartTime=function(){return F;};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated()){return false;}this.currentFrame=0;this.totalFrames=(this.useSeconds)?Math.ceil(B.AnimMgr.fps*this.duration):this.duration;if(this.duration===0&&this.useSeconds){this.totalFrames=1;}B.AnimMgr.registerElement(this);return true;};this.stop=function(M){if(!this.isAnimated()){return false;}if(M){this.currentFrame=this.totalFrames;this._onTween.fire();}B.AnimMgr.stop(this);};var L=function(){this.onStart.fire();this.runtimeAttributes={};for(var M in this.attributes){this.setRuntimeAttribute(M);}D=true;H=0;F=new Date();};var K=function(){var O={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};O.toString=function(){return("duration: "+O.duration+", currentFrame: "+O.currentFrame);};this.onTween.fire(O);var N=this.runtimeAttributes;for(var M in N){this.setAttribute(M,this.doMethod(M,N[M].start,N[M].end),N[M].unit);}H+=1;};var G=function(){var M=(new Date()-F)/1000;var N={duration:M,frames:H,fps:H/M};N.toString=function(){return("duration: "+N.duration+", frames: "+N.frames+", fps: "+N.fps);};D=false;H=0;this.onComplete.fire(N);};this._onStart=new B.CustomEvent("_start",this,true);this.onStart=new B.CustomEvent("start",this);this.onTween=new B.CustomEvent("tween",this);this._onTween=new B.CustomEvent("_tween",this,true);this.onComplete=new B.CustomEvent("complete",this);this._onComplete=new B.CustomEvent("_complete",this,true);this._onStart.subscribe(L);this._onTween.subscribe(K);this._onComplete.subscribe(G);}};B.Anim=A;})();YAHOO.util.AnimMgr=new function(){var C=null;var B=[];var A=0;this.fps=1000;this.delay=1;this.registerElement=function(F){B[B.length]=F;A+=1;F._onStart.fire();this.start();};this.unRegister=function(G,F){F=F||E(G);if(!G.isAnimated()||F===-1){return false;}G._onComplete.fire();B.splice(F,1);A-=1;if(A<=0){this.stop();}return true;};this.start=function(){if(C===null){C=setInterval(this.run,this.delay);}};this.stop=function(H){if(!H){clearInterval(C);for(var G=0,F=B.length;G<F;++G){this.unRegister(B[0],0);}B=[];C=null;A=0;}else{this.unRegister(H);}};this.run=function(){for(var H=0,F=B.length;H<F;++H){var G=B[H];if(!G||!G.isAnimated()){continue;}if(G.currentFrame<G.totalFrames||G.totalFrames===null){G.currentFrame+=1;if(G.useSeconds){D(G);}G._onTween.fire();}else{YAHOO.util.AnimMgr.stop(G,H);}}};var E=function(H){for(var G=0,F=B.length;G<F;++G){if(B[G]===H){return G;}}return -1;};var D=function(G){var J=G.totalFrames;var I=G.currentFrame;var H=(G.currentFrame*G.duration*1000/G.totalFrames);var F=(new Date()-G.getStartTime());var K=0;if(F<G.duration*1000){K=Math.round((F/H-1)*G.currentFrame);}else{K=J-(I+1);}if(K>0&&isFinite(K)){if(G.currentFrame+K>=J){K=J-(I+1);}G.currentFrame+=K;}};this._queue=B;this._getIndex=E;};YAHOO.util.Bezier=new function(){this.getPosition=function(E,D){var F=E.length;var C=[];for(var B=0;B<F;++B){C[B]=[E[B][0],E[B][1]];}for(var A=1;A<F;++A){for(B=0;B<F-A;++B){C[B][0]=(1-D)*C[B][0]+D*C[parseInt(B+1,10)][0];C[B][1]=(1-D)*C[B][1]+D*C[parseInt(B+1,10)][1];}}return[C[0][0],C[0][1]];};};(function(){var A=function(F,E,G,H){A.superclass.constructor.call(this,F,E,G,H);};A.NAME="ColorAnim";A.DEFAULT_BGCOLOR="#fff";var C=YAHOO.util;YAHOO.extend(A,C.Anim);var D=A.superclass;var B=A.prototype;B.patterns.color=/color$/i;B.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;B.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;B.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;B.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;B.parseColor=function(E){if(E.length==3){return E;}var F=this.patterns.hex.exec(E);if(F&&F.length==4){return[parseInt(F[1],16),parseInt(F[2],16),parseInt(F[3],16)];}F=this.patterns.rgb.exec(E);if(F&&F.length==4){return[parseInt(F[1],10),parseInt(F[2],10),parseInt(F[3],10)];}F=this.patterns.hex3.exec(E);if(F&&F.length==4){return[parseInt(F[1]+F[1],16),parseInt(F[2]+F[2],16),parseInt(F[3]+F[3],16)];
+}return null;};B.getAttribute=function(E){var G=this.getEl();if(this.patterns.color.test(E)){var I=YAHOO.util.Dom.getStyle(G,E);var H=this;if(this.patterns.transparent.test(I)){var F=YAHOO.util.Dom.getAncestorBy(G,function(J){return !H.patterns.transparent.test(I);});if(F){I=C.Dom.getStyle(F,E);}else{I=A.DEFAULT_BGCOLOR;}}}else{I=D.getAttribute.call(this,E);}return I;};B.doMethod=function(F,J,G){var I;if(this.patterns.color.test(F)){I=[];for(var H=0,E=J.length;H<E;++H){I[H]=D.doMethod.call(this,F,J[H],G[H]);}I="rgb("+Math.floor(I[0])+","+Math.floor(I[1])+","+Math.floor(I[2])+")";}else{I=D.doMethod.call(this,F,J,G);}return I;};B.setRuntimeAttribute=function(F){D.setRuntimeAttribute.call(this,F);if(this.patterns.color.test(F)){var H=this.attributes;var J=this.parseColor(this.runtimeAttributes[F].start);var G=this.parseColor(this.runtimeAttributes[F].end);if(typeof H[F]["to"]==="undefined"&&typeof H[F]["by"]!=="undefined"){G=this.parseColor(H[F].by);for(var I=0,E=J.length;I<E;++I){G[I]=J[I]+G[I];}}this.runtimeAttributes[F].start=J;this.runtimeAttributes[F].end=G;}};C.ColorAnim=A;})();
+/*
+TERMS OF USE - EASING EQUATIONS
+Open source under the BSD License.
+Copyright 2001 Robert Penner All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+YAHOO.util.Easing={easeNone:function(B,A,D,C){return D*B/C+A;},easeIn:function(B,A,D,C){return D*(B/=C)*B+A;},easeOut:function(B,A,D,C){return -D*(B/=C)*(B-2)+A;},easeBoth:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B+A;}return -D/2*((--B)*(B-2)-1)+A;},easeInStrong:function(B,A,D,C){return D*(B/=C)*B*B*B+A;},easeOutStrong:function(B,A,D,C){return -D*((B=B/C-1)*B*B*B-1)+A;},easeBothStrong:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B*B*B+A;}return -D/2*((B-=2)*B*B*B-2)+A;},elasticIn:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return -(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;},elasticOut:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return B*Math.pow(2,-10*C)*Math.sin((C*F-D)*(2*Math.PI)/E)+G+A;},elasticBoth:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F/2)==2){return A+G;}if(!E){E=F*(0.3*1.5);}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}if(C<1){return -0.5*(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;}return B*Math.pow(2,-10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E)*0.5+G+A;},backIn:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*(B/=D)*B*((C+1)*B-C)+A;},backOut:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*((B=B/D-1)*B*((C+1)*B+C)+1)+A;},backBoth:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}if((B/=D/2)<1){return E/2*(B*B*(((C*=(1.525))+1)*B-C))+A;}return E/2*((B-=2)*B*(((C*=(1.525))+1)*B+C)+2)+A;},bounceIn:function(B,A,D,C){return D-YAHOO.util.Easing.bounceOut(C-B,0,D,C)+A;},bounceOut:function(B,A,D,C){if((B/=C)<(1/2.75)){return D*(7.5625*B*B)+A;}else{if(B<(2/2.75)){return D*(7.5625*(B-=(1.5/2.75))*B+0.75)+A;}else{if(B<(2.5/2.75)){return D*(7.5625*(B-=(2.25/2.75))*B+0.9375)+A;}}}return D*(7.5625*(B-=(2.625/2.75))*B+0.984375)+A;},bounceBoth:function(B,A,D,C){if(B<C/2){return YAHOO.util.Easing.bounceIn(B*2,0,D,C)*0.5+A;}return YAHOO.util.Easing.bounceOut(B*2-C,0,D,C)*0.5+D*0.5+A;}};(function(){var A=function(H,G,I,J){if(H){A.superclass.constructor.call(this,H,G,I,J);}};A.NAME="Motion";var E=YAHOO.util;YAHOO.extend(A,E.ColorAnim);var F=A.superclass;var C=A.prototype;C.patterns.points=/^points$/i;C.setAttribute=function(G,I,H){if(this.patterns.points.test(G)){H=H||"px";F.setAttribute.call(this,"left",I[0],H);F.setAttribute.call(this,"top",I[1],H);}else{F.setAttribute.call(this,G,I,H);}};C.getAttribute=function(G){if(this.patterns.points.test(G)){var H=[F.getAttribute.call(this,"left"),F.getAttribute.call(this,"top")];}else{H=F.getAttribute.call(this,G);}return H;};C.doMethod=function(G,K,H){var J=null;if(this.patterns.points.test(G)){var I=this.method(this.currentFrame,0,100,this.totalFrames)/100;J=E.Bezier.getPosition(this.runtimeAttributes[G],I);}else{J=F.doMethod.call(this,G,K,H);}return J;};C.setRuntimeAttribute=function(P){if(this.patterns.points.test(P)){var H=this.getEl();var J=this.attributes;var G;var L=J["points"]["control"]||[];var I;var M,O;if(L.length>0&&!(L[0] instanceof Array)){L=[L];}else{var K=[];for(M=0,O=L.length;M<O;++M){K[M]=L[M];}L=K;}if(E.Dom.getStyle(H,"position")=="static"){E.Dom.setStyle(H,"position","relative");}if(D(J["points"]["from"])){E.Dom.setXY(H,J["points"]["from"]);
+}else{E.Dom.setXY(H,E.Dom.getXY(H));}G=this.getAttribute("points");if(D(J["points"]["to"])){I=B.call(this,J["points"]["to"],G);var N=E.Dom.getXY(this.getEl());for(M=0,O=L.length;M<O;++M){L[M]=B.call(this,L[M],G);}}else{if(D(J["points"]["by"])){I=[G[0]+J["points"]["by"][0],G[1]+J["points"]["by"][1]];for(M=0,O=L.length;M<O;++M){L[M]=[G[0]+L[M][0],G[1]+L[M][1]];}}}this.runtimeAttributes[P]=[G];if(L.length>0){this.runtimeAttributes[P]=this.runtimeAttributes[P].concat(L);}this.runtimeAttributes[P][this.runtimeAttributes[P].length]=I;}else{F.setRuntimeAttribute.call(this,P);}};var B=function(G,I){var H=E.Dom.getXY(this.getEl());G=[G[0]-H[0]+I[0],G[1]-H[1]+I[1]];return G;};var D=function(G){return(typeof G!=="undefined");};E.Motion=A;})();(function(){var D=function(F,E,G,H){if(F){D.superclass.constructor.call(this,F,E,G,H);}};D.NAME="Scroll";var B=YAHOO.util;YAHOO.extend(D,B.ColorAnim);var C=D.superclass;var A=D.prototype;A.doMethod=function(E,H,F){var G=null;if(E=="scroll"){G=[this.method(this.currentFrame,H[0],F[0]-H[0],this.totalFrames),this.method(this.currentFrame,H[1],F[1]-H[1],this.totalFrames)];}else{G=C.doMethod.call(this,E,H,F);}return G;};A.getAttribute=function(E){var G=null;var F=this.getEl();if(E=="scroll"){G=[F.scrollLeft,F.scrollTop];}else{G=C.getAttribute.call(this,E);}return G;};A.setAttribute=function(E,H,G){var F=this.getEl();if(E=="scroll"){F.scrollLeft=H[0];F.scrollTop=H[1];}else{C.setAttribute.call(this,E,H,G);}};B.Scroll=D;})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.8.2r1",build:"7"});if(!YAHOO.util.DragDropMgr){YAHOO.util.DragDropMgr=function(){var A=YAHOO.util.Event,B=YAHOO.util.Dom;return{useShim:false,_shimActive:false,_shimState:false,_debugShim:false,_createShim:function(){var C=document.createElement("div");C.id="yui-ddm-shim";if(document.body.firstChild){document.body.insertBefore(C,document.body.firstChild);}else{document.body.appendChild(C);}C.style.display="none";C.style.backgroundColor="red";C.style.position="absolute";C.style.zIndex="99999";B.setStyle(C,"opacity","0");this._shim=C;A.on(C,"mouseup",this.handleMouseUp,this,true);A.on(C,"mousemove",this.handleMouseMove,this,true);A.on(window,"scroll",this._sizeShim,this,true);},_sizeShim:function(){if(this._shimActive){var C=this._shim;C.style.height=B.getDocumentHeight()+"px";C.style.width=B.getDocumentWidth()+"px";C.style.top="0";C.style.left="0";}},_activateShim:function(){if(this.useShim){if(!this._shim){this._createShim();}this._shimActive=true;var C=this._shim,D="0";if(this._debugShim){D=".5";}B.setStyle(C,"opacity",D);this._sizeShim();C.style.display="block";}},_deactivateShim:function(){this._shim.style.display="none";this._shimActive=false;},_shim:null,ids:{},handleIds:{},dragCurrent:null,dragOvers:{},deltaX:0,deltaY:0,preventDefault:true,stopPropagation:true,initialized:false,locked:false,interactionInfo:null,init:function(){this.initialized=true;},POINT:0,INTERSECT:1,STRICT_INTERSECT:2,mode:0,_execOnAll:function(E,D){for(var F in this.ids){for(var C in this.ids[F]){var G=this.ids[F][C];if(!this.isTypeOfDD(G)){continue;}G[E].apply(G,D);}}},_onLoad:function(){this.init();A.on(document,"mouseup",this.handleMouseUp,this,true);A.on(document,"mousemove",this.handleMouseMove,this,true);A.on(window,"unload",this._onUnload,this,true);A.on(window,"resize",this._onResize,this,true);},_onResize:function(C){this._execOnAll("resetConstraints",[]);},lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isLocked:function(){return this.locked;},locationCache:{},useCache:true,clickPixelThresh:3,clickTimeThresh:1000,dragThreshMet:false,clickTimeout:null,startX:0,startY:0,fromTimeout:false,regDragDrop:function(D,C){if(!this.initialized){this.init();}if(!this.ids[C]){this.ids[C]={};}this.ids[C][D.id]=D;},removeDDFromGroup:function(E,C){if(!this.ids[C]){this.ids[C]={};}var D=this.ids[C];if(D&&D[E.id]){delete D[E.id];}},_remove:function(E){for(var D in E.groups){if(D){var C=this.ids[D];if(C&&C[E.id]){delete C[E.id];}}}delete this.handleIds[E.id];},regHandle:function(D,C){if(!this.handleIds[D]){this.handleIds[D]={};}this.handleIds[D][C]=C;},isDragDrop:function(C){return(this.getDDById(C))?true:false;},getRelated:function(H,D){var G=[];for(var F in H.groups){for(var E in this.ids[F]){var C=this.ids[F][E];if(!this.isTypeOfDD(C)){continue;}if(!D||C.isTarget){G[G.length]=C;}}}return G;},isLegalTarget:function(G,F){var D=this.getRelated(G,true);for(var E=0,C=D.length;E<C;++E){if(D[E].id==F.id){return true;}}return false;},isTypeOfDD:function(C){return(C&&C.__ygDragDrop);},isHandle:function(D,C){return(this.handleIds[D]&&this.handleIds[D][C]);},getDDById:function(D){for(var C in this.ids){if(this.ids[C][D]){return this.ids[C][D];}}return null;},handleMouseDown:function(E,D){this.currentTarget=YAHOO.util.Event.getTarget(E);this.dragCurrent=D;var C=D.getEl();this.startX=YAHOO.util.Event.getPageX(E);this.startY=YAHOO.util.Event.getPageY(E);this.deltaX=this.startX-C.offsetLeft;this.deltaY=this.startY-C.offsetTop;this.dragThreshMet=false;this.clickTimeout=setTimeout(function(){var F=YAHOO.util.DDM;F.startDrag(F.startX,F.startY);F.fromTimeout=true;},this.clickTimeThresh);},startDrag:function(C,E){if(this.dragCurrent&&this.dragCurrent.useShim){this._shimState=this.useShim;this.useShim=true;}this._activateShim();clearTimeout(this.clickTimeout);var D=this.dragCurrent;if(D&&D.events.b4StartDrag){D.b4StartDrag(C,E);D.fireEvent("b4StartDragEvent",{x:C,y:E});}if(D&&D.events.startDrag){D.startDrag(C,E);D.fireEvent("startDragEvent",{x:C,y:E});}this.dragThreshMet=true;},handleMouseUp:function(C){if(this.dragCurrent){clearTimeout(this.clickTimeout);if(this.dragThreshMet){if(this.fromTimeout){this.fromTimeout=false;this.handleMouseMove(C);}this.fromTimeout=false;this.fireEvents(C,true);}else{}this.stopDrag(C);this.stopEvent(C);}},stopEvent:function(C){if(this.stopPropagation){YAHOO.util.Event.stopPropagation(C);}if(this.preventDefault){YAHOO.util.Event.preventDefault(C);}},stopDrag:function(E,D){var C=this.dragCurrent;if(C&&!D){if(this.dragThreshMet){if(C.events.b4EndDrag){C.b4EndDrag(E);C.fireEvent("b4EndDragEvent",{e:E});}if(C.events.endDrag){C.endDrag(E);C.fireEvent("endDragEvent",{e:E});}}if(C.events.mouseUp){C.onMouseUp(E);C.fireEvent("mouseUpEvent",{e:E});}}if(this._shimActive){this._deactivateShim();if(this.dragCurrent&&this.dragCurrent.useShim){this.useShim=this._shimState;this._shimState=false;}}this.dragCurrent=null;this.dragOvers={};},handleMouseMove:function(F){var C=this.dragCurrent;if(C){if(YAHOO.util.Event.isIE&&!F.button){this.stopEvent(F);return this.handleMouseUp(F);}else{if(F.clientX<0||F.clientY<0){}}if(!this.dragThreshMet){var E=Math.abs(this.startX-YAHOO.util.Event.getPageX(F));var D=Math.abs(this.startY-YAHOO.util.Event.getPageY(F));if(E>this.clickPixelThresh||D>this.clickPixelThresh){this.startDrag(this.startX,this.startY);}}if(this.dragThreshMet){if(C&&C.events.b4Drag){C.b4Drag(F);C.fireEvent("b4DragEvent",{e:F});}if(C&&C.events.drag){C.onDrag(F);C.fireEvent("dragEvent",{e:F});}if(C){this.fireEvents(F,false);}}this.stopEvent(F);}},fireEvents:function(V,L){var a=this.dragCurrent;if(!a||a.isLocked()||a.dragOnly){return;}var N=YAHOO.util.Event.getPageX(V),M=YAHOO.util.Event.getPageY(V),P=new YAHOO.util.Point(N,M),K=a.getTargetCoord(P.x,P.y),F=a.getDragEl(),E=["out","over","drop","enter"],U=new YAHOO.util.Region(K.y,K.x+F.offsetWidth,K.y+F.offsetHeight,K.x),I=[],D={},Q=[],c={outEvts:[],overEvts:[],dropEvts:[],enterEvts:[]};for(var S in this.dragOvers){var d=this.dragOvers[S];if(!this.isTypeOfDD(d)){continue;
+}if(!this.isOverTarget(P,d,this.mode,U)){c.outEvts.push(d);}I[S]=true;delete this.dragOvers[S];}for(var R in a.groups){if("string"!=typeof R){continue;}for(S in this.ids[R]){var G=this.ids[R][S];if(!this.isTypeOfDD(G)){continue;}if(G.isTarget&&!G.isLocked()&&G!=a){if(this.isOverTarget(P,G,this.mode,U)){D[R]=true;if(L){c.dropEvts.push(G);}else{if(!I[G.id]){c.enterEvts.push(G);}else{c.overEvts.push(G);}this.dragOvers[G.id]=G;}}}}}this.interactionInfo={out:c.outEvts,enter:c.enterEvts,over:c.overEvts,drop:c.dropEvts,point:P,draggedRegion:U,sourceRegion:this.locationCache[a.id],validDrop:L};for(var C in D){Q.push(C);}if(L&&!c.dropEvts.length){this.interactionInfo.validDrop=false;if(a.events.invalidDrop){a.onInvalidDrop(V);a.fireEvent("invalidDropEvent",{e:V});}}for(S=0;S<E.length;S++){var Y=null;if(c[E[S]+"Evts"]){Y=c[E[S]+"Evts"];}if(Y&&Y.length){var H=E[S].charAt(0).toUpperCase()+E[S].substr(1),X="onDrag"+H,J="b4Drag"+H,O="drag"+H+"Event",W="drag"+H;if(this.mode){if(a.events[J]){a[J](V,Y,Q);a.fireEvent(J+"Event",{event:V,info:Y,group:Q});}if(a.events[W]){a[X](V,Y,Q);a.fireEvent(O,{event:V,info:Y,group:Q});}}else{for(var Z=0,T=Y.length;Z<T;++Z){if(a.events[J]){a[J](V,Y[Z].id,Q[0]);a.fireEvent(J+"Event",{event:V,info:Y[Z].id,group:Q[0]});}if(a.events[W]){a[X](V,Y[Z].id,Q[0]);a.fireEvent(O,{event:V,info:Y[Z].id,group:Q[0]});}}}}}},getBestMatch:function(E){var G=null;var D=E.length;if(D==1){G=E[0];}else{for(var F=0;F<D;++F){var C=E[F];if(this.mode==this.INTERSECT&&C.cursorIsOver){G=C;break;}else{if(!G||!G.overlap||(C.overlap&&G.overlap.getArea()<C.overlap.getArea())){G=C;}}}}return G;},refreshCache:function(D){var F=D||this.ids;for(var C in F){if("string"!=typeof C){continue;}for(var E in this.ids[C]){var G=this.ids[C][E];if(this.isTypeOfDD(G)){var H=this.getLocation(G);if(H){this.locationCache[G.id]=H;}else{delete this.locationCache[G.id];}}}}},verifyEl:function(D){try{if(D){var C=D.offsetParent;if(C){return true;}}}catch(E){}return false;},getLocation:function(H){if(!this.isTypeOfDD(H)){return null;}var F=H.getEl(),K,E,D,M,L,N,C,J,G;try{K=YAHOO.util.Dom.getXY(F);}catch(I){}if(!K){return null;}E=K[0];D=E+F.offsetWidth;M=K[1];L=M+F.offsetHeight;N=M-H.padding[0];C=D+H.padding[1];J=L+H.padding[2];G=E-H.padding[3];return new YAHOO.util.Region(N,C,J,G);},isOverTarget:function(K,C,E,F){var G=this.locationCache[C.id];if(!G||!this.useCache){G=this.getLocation(C);this.locationCache[C.id]=G;}if(!G){return false;}C.cursorIsOver=G.contains(K);var J=this.dragCurrent;if(!J||(!E&&!J.constrainX&&!J.constrainY)){return C.cursorIsOver;}C.overlap=null;if(!F){var H=J.getTargetCoord(K.x,K.y);var D=J.getDragEl();F=new YAHOO.util.Region(H.y,H.x+D.offsetWidth,H.y+D.offsetHeight,H.x);}var I=F.intersect(G);if(I){C.overlap=I;return(E)?true:C.cursorIsOver;}else{return false;}},_onUnload:function(D,C){this.unregAll();},unregAll:function(){if(this.dragCurrent){this.stopDrag();this.dragCurrent=null;}this._execOnAll("unreg",[]);this.ids={};},elementCache:{},getElWrapper:function(D){var C=this.elementCache[D];if(!C||!C.el){C=this.elementCache[D]=new this.ElementWrapper(YAHOO.util.Dom.get(D));}return C;},getElement:function(C){return YAHOO.util.Dom.get(C);},getCss:function(D){var C=YAHOO.util.Dom.get(D);return(C)?C.style:null;},ElementWrapper:function(C){this.el=C||null;this.id=this.el&&C.id;this.css=this.el&&C.style;},getPosX:function(C){return YAHOO.util.Dom.getX(C);},getPosY:function(C){return YAHOO.util.Dom.getY(C);},swapNode:function(E,C){if(E.swapNode){E.swapNode(C);}else{var F=C.parentNode;var D=C.nextSibling;if(D==E){F.insertBefore(E,C);}else{if(C==E.nextSibling){F.insertBefore(C,E);}else{E.parentNode.replaceChild(C,E);F.insertBefore(E,D);}}}},getScroll:function(){var E,C,F=document.documentElement,D=document.body;if(F&&(F.scrollTop||F.scrollLeft)){E=F.scrollTop;C=F.scrollLeft;}else{if(D){E=D.scrollTop;C=D.scrollLeft;}else{}}return{top:E,left:C};},getStyle:function(D,C){return YAHOO.util.Dom.getStyle(D,C);},getScrollTop:function(){return this.getScroll().top;},getScrollLeft:function(){return this.getScroll().left;},moveToEl:function(C,E){var D=YAHOO.util.Dom.getXY(E);YAHOO.util.Dom.setXY(C,D);},getClientHeight:function(){return YAHOO.util.Dom.getViewportHeight();},getClientWidth:function(){return YAHOO.util.Dom.getViewportWidth();},numericSort:function(D,C){return(D-C);},_timeoutCount:0,_addListeners:function(){var C=YAHOO.util.DDM;if(YAHOO.util.Event&&document){C._onLoad();}else{if(C._timeoutCount>2000){}else{setTimeout(C._addListeners,10);if(document&&document.body){C._timeoutCount+=1;}}}},handleWasClicked:function(C,E){if(this.isHandle(E,C.id)){return true;}else{var D=C.parentNode;while(D){if(this.isHandle(E,D.id)){return true;}else{D=D.parentNode;}}}return false;}};}();YAHOO.util.DDM=YAHOO.util.DragDropMgr;YAHOO.util.DDM._addListeners();}(function(){var A=YAHOO.util.Event;var B=YAHOO.util.Dom;YAHOO.util.DragDrop=function(E,C,D){if(E){this.init(E,C,D);}};YAHOO.util.DragDrop.prototype={events:null,on:function(){this.subscribe.apply(this,arguments);},id:null,config:null,dragElId:null,handleElId:null,invalidHandleTypes:null,invalidHandleIds:null,invalidHandleClasses:null,startPageX:0,startPageY:0,groups:null,locked:false,lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isTarget:true,padding:null,dragOnly:false,useShim:false,_domRef:null,__ygDragDrop:true,constrainX:false,constrainY:false,minX:0,maxX:0,minY:0,maxY:0,deltaX:0,deltaY:0,maintainOffset:false,xTicks:null,yTicks:null,primaryButtonOnly:true,available:false,hasOuterHandles:false,cursorIsOver:false,overlap:null,b4StartDrag:function(C,D){},startDrag:function(C,D){},b4Drag:function(C){},onDrag:function(C){},onDragEnter:function(C,D){},b4DragOver:function(C){},onDragOver:function(C,D){},b4DragOut:function(C){},onDragOut:function(C,D){},b4DragDrop:function(C){},onDragDrop:function(C,D){},onInvalidDrop:function(C){},b4EndDrag:function(C){},endDrag:function(C){},b4MouseDown:function(C){},onMouseDown:function(C){},onMouseUp:function(C){},onAvailable:function(){},getEl:function(){if(!this._domRef){this._domRef=B.get(this.id);
+}return this._domRef;},getDragEl:function(){return B.get(this.dragElId);},init:function(F,C,D){this.initTarget(F,C,D);A.on(this._domRef||this.id,"mousedown",this.handleMouseDown,this,true);for(var E in this.events){this.createEvent(E+"Event");}},initTarget:function(E,C,D){this.config=D||{};this.events={};this.DDM=YAHOO.util.DDM;this.groups={};if(typeof E!=="string"){this._domRef=E;E=B.generateId(E);}this.id=E;this.addToGroup((C)?C:"default");this.handleElId=E;A.onAvailable(E,this.handleOnAvailable,this,true);this.setDragElId(E);this.invalidHandleTypes={A:"A"};this.invalidHandleIds={};this.invalidHandleClasses=[];this.applyConfig();},applyConfig:function(){this.events={mouseDown:true,b4MouseDown:true,mouseUp:true,b4StartDrag:true,startDrag:true,b4EndDrag:true,endDrag:true,drag:true,b4Drag:true,invalidDrop:true,b4DragOut:true,dragOut:true,dragEnter:true,b4DragOver:true,dragOver:true,b4DragDrop:true,dragDrop:true};if(this.config.events){for(var C in this.config.events){if(this.config.events[C]===false){this.events[C]=false;}}}this.padding=this.config.padding||[0,0,0,0];this.isTarget=(this.config.isTarget!==false);this.maintainOffset=(this.config.maintainOffset);this.primaryButtonOnly=(this.config.primaryButtonOnly!==false);this.dragOnly=((this.config.dragOnly===true)?true:false);this.useShim=((this.config.useShim===true)?true:false);},handleOnAvailable:function(){this.available=true;this.resetConstraints();this.onAvailable();},setPadding:function(E,C,F,D){if(!C&&0!==C){this.padding=[E,E,E,E];}else{if(!F&&0!==F){this.padding=[E,C,E,C];}else{this.padding=[E,C,F,D];}}},setInitPosition:function(F,E){var G=this.getEl();if(!this.DDM.verifyEl(G)){if(G&&G.style&&(G.style.display=="none")){}else{}return;}var D=F||0;var C=E||0;var H=B.getXY(G);this.initPageX=H[0]-D;this.initPageY=H[1]-C;this.lastPageX=H[0];this.lastPageY=H[1];this.setStartPosition(H);},setStartPosition:function(D){var C=D||B.getXY(this.getEl());this.deltaSetXY=null;this.startPageX=C[0];this.startPageY=C[1];},addToGroup:function(C){this.groups[C]=true;this.DDM.regDragDrop(this,C);},removeFromGroup:function(C){if(this.groups[C]){delete this.groups[C];}this.DDM.removeDDFromGroup(this,C);},setDragElId:function(C){this.dragElId=C;},setHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.handleElId=C;this.DDM.regHandle(this.id,C);},setOuterHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}A.on(C,"mousedown",this.handleMouseDown,this,true);this.setHandleElId(C);this.hasOuterHandles=true;},unreg:function(){A.removeListener(this.id,"mousedown",this.handleMouseDown);this._domRef=null;this.DDM._remove(this);},isLocked:function(){return(this.DDM.isLocked()||this.locked);},handleMouseDown:function(J,I){var D=J.which||J.button;if(this.primaryButtonOnly&&D>1){return;}if(this.isLocked()){return;}var C=this.b4MouseDown(J),F=true;if(this.events.b4MouseDown){F=this.fireEvent("b4MouseDownEvent",J);}var E=this.onMouseDown(J),H=true;if(this.events.mouseDown){H=this.fireEvent("mouseDownEvent",J);}if((C===false)||(E===false)||(F===false)||(H===false)){return;}this.DDM.refreshCache(this.groups);var G=new YAHOO.util.Point(A.getPageX(J),A.getPageY(J));if(!this.hasOuterHandles&&!this.DDM.isOverTarget(G,this)){}else{if(this.clickValidator(J)){this.setStartPosition();this.DDM.handleMouseDown(J,this);this.DDM.stopEvent(J);}else{}}},clickValidator:function(D){var C=YAHOO.util.Event.getTarget(D);return(this.isValidHandleChild(C)&&(this.id==this.handleElId||this.DDM.handleWasClicked(C,this.id)));},getTargetCoord:function(E,D){var C=E-this.deltaX;var F=D-this.deltaY;if(this.constrainX){if(C<this.minX){C=this.minX;}if(C>this.maxX){C=this.maxX;}}if(this.constrainY){if(F<this.minY){F=this.minY;}if(F>this.maxY){F=this.maxY;}}C=this.getTick(C,this.xTicks);F=this.getTick(F,this.yTicks);return{x:C,y:F};},addInvalidHandleType:function(C){var D=C.toUpperCase();this.invalidHandleTypes[D]=D;},addInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.invalidHandleIds[C]=C;},addInvalidHandleClass:function(C){this.invalidHandleClasses.push(C);},removeInvalidHandleType:function(C){var D=C.toUpperCase();delete this.invalidHandleTypes[D];},removeInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}delete this.invalidHandleIds[C];},removeInvalidHandleClass:function(D){for(var E=0,C=this.invalidHandleClasses.length;E<C;++E){if(this.invalidHandleClasses[E]==D){delete this.invalidHandleClasses[E];}}},isValidHandleChild:function(F){var E=true;var H;try{H=F.nodeName.toUpperCase();}catch(G){H=F.nodeName;}E=E&&!this.invalidHandleTypes[H];E=E&&!this.invalidHandleIds[F.id];for(var D=0,C=this.invalidHandleClasses.length;E&&D<C;++D){E=!B.hasClass(F,this.invalidHandleClasses[D]);}return E;},setXTicks:function(F,C){this.xTicks=[];this.xTickSize=C;var E={};for(var D=this.initPageX;D>=this.minX;D=D-C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}for(D=this.initPageX;D<=this.maxX;D=D+C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}this.xTicks.sort(this.DDM.numericSort);},setYTicks:function(F,C){this.yTicks=[];this.yTickSize=C;var E={};for(var D=this.initPageY;D>=this.minY;D=D-C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}for(D=this.initPageY;D<=this.maxY;D=D+C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}this.yTicks.sort(this.DDM.numericSort);},setXConstraint:function(E,D,C){this.leftConstraint=parseInt(E,10);this.rightConstraint=parseInt(D,10);this.minX=this.initPageX-this.leftConstraint;this.maxX=this.initPageX+this.rightConstraint;if(C){this.setXTicks(this.initPageX,C);}this.constrainX=true;},clearConstraints:function(){this.constrainX=false;this.constrainY=false;this.clearTicks();},clearTicks:function(){this.xTicks=null;this.yTicks=null;this.xTickSize=0;this.yTickSize=0;},setYConstraint:function(C,E,D){this.topConstraint=parseInt(C,10);this.bottomConstraint=parseInt(E,10);this.minY=this.initPageY-this.topConstraint;this.maxY=this.initPageY+this.bottomConstraint;if(D){this.setYTicks(this.initPageY,D);
+}this.constrainY=true;},resetConstraints:function(){if(this.initPageX||this.initPageX===0){var D=(this.maintainOffset)?this.lastPageX-this.initPageX:0;var C=(this.maintainOffset)?this.lastPageY-this.initPageY:0;this.setInitPosition(D,C);}else{this.setInitPosition();}if(this.constrainX){this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);}if(this.constrainY){this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize);}},getTick:function(I,F){if(!F){return I;}else{if(F[0]>=I){return F[0];}else{for(var D=0,C=F.length;D<C;++D){var E=D+1;if(F[E]&&F[E]>=I){var H=I-F[D];var G=F[E]-I;return(G>H)?F[D]:F[E];}}return F[F.length-1];}}},toString:function(){return("DragDrop "+this.id);}};YAHOO.augment(YAHOO.util.DragDrop,YAHOO.util.EventProvider);})();YAHOO.util.DD=function(C,A,B){if(C){this.init(C,A,B);}};YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop,{scroll:true,autoOffset:function(C,B){var A=C-this.startPageX;var D=B-this.startPageY;this.setDelta(A,D);},setDelta:function(B,A){this.deltaX=B;this.deltaY=A;},setDragElPos:function(C,B){var A=this.getDragEl();this.alignElWithMouse(A,C,B);},alignElWithMouse:function(C,G,F){var E=this.getTargetCoord(G,F);if(!this.deltaSetXY){var H=[E.x,E.y];YAHOO.util.Dom.setXY(C,H);var D=parseInt(YAHOO.util.Dom.getStyle(C,"left"),10);var B=parseInt(YAHOO.util.Dom.getStyle(C,"top"),10);this.deltaSetXY=[D-E.x,B-E.y];}else{YAHOO.util.Dom.setStyle(C,"left",(E.x+this.deltaSetXY[0])+"px");YAHOO.util.Dom.setStyle(C,"top",(E.y+this.deltaSetXY[1])+"px");}this.cachePosition(E.x,E.y);var A=this;setTimeout(function(){A.autoScroll.call(A,E.x,E.y,C.offsetHeight,C.offsetWidth);},0);},cachePosition:function(B,A){if(B){this.lastPageX=B;this.lastPageY=A;}else{var C=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=C[0];this.lastPageY=C[1];}},autoScroll:function(J,I,E,K){if(this.scroll){var L=this.DDM.getClientHeight();var B=this.DDM.getClientWidth();var N=this.DDM.getScrollTop();var D=this.DDM.getScrollLeft();var H=E+I;var M=K+J;var G=(L+N-I-this.deltaY);var F=(B+D-J-this.deltaX);var C=40;var A=(document.all)?80:30;if(H>L&&G<C){window.scrollTo(D,N+A);}if(I<N&&N>0&&I-N<C){window.scrollTo(D,N-A);}if(M>B&&F<C){window.scrollTo(D+A,N);}if(J<D&&D>0&&J-D<C){window.scrollTo(D-A,N);}}},applyConfig:function(){YAHOO.util.DD.superclass.applyConfig.call(this);this.scroll=(this.config.scroll!==false);},b4MouseDown:function(A){this.setStartPosition();this.autoOffset(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},b4Drag:function(A){this.setDragElPos(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},toString:function(){return("DD "+this.id);}});YAHOO.util.DDProxy=function(C,A,B){if(C){this.init(C,A,B);this.initFrame();}};YAHOO.util.DDProxy.dragElId="ygddfdiv";YAHOO.extend(YAHOO.util.DDProxy,YAHOO.util.DD,{resizeFrame:true,centerFrame:false,createFrame:function(){var B=this,A=document.body;if(!A||!A.firstChild){setTimeout(function(){B.createFrame();},50);return;}var F=this.getDragEl(),E=YAHOO.util.Dom;if(!F){F=document.createElement("div");F.id=this.dragElId;var D=F.style;D.position="absolute";D.visibility="hidden";D.cursor="move";D.border="2px solid #aaa";D.zIndex=999;D.height="25px";D.width="25px";var C=document.createElement("div");E.setStyle(C,"height","100%");E.setStyle(C,"width","100%");E.setStyle(C,"background-color","#ccc");E.setStyle(C,"opacity","0");F.appendChild(C);A.insertBefore(F,A.firstChild);}},initFrame:function(){this.createFrame();},applyConfig:function(){YAHOO.util.DDProxy.superclass.applyConfig.call(this);this.resizeFrame=(this.config.resizeFrame!==false);this.centerFrame=(this.config.centerFrame);this.setDragElId(this.config.dragElId||YAHOO.util.DDProxy.dragElId);},showFrame:function(E,D){var C=this.getEl();var A=this.getDragEl();var B=A.style;this._resizeProxy();if(this.centerFrame){this.setDelta(Math.round(parseInt(B.width,10)/2),Math.round(parseInt(B.height,10)/2));}this.setDragElPos(E,D);YAHOO.util.Dom.setStyle(A,"visibility","visible");},_resizeProxy:function(){if(this.resizeFrame){var H=YAHOO.util.Dom;var B=this.getEl();var C=this.getDragEl();var G=parseInt(H.getStyle(C,"borderTopWidth"),10);var I=parseInt(H.getStyle(C,"borderRightWidth"),10);var F=parseInt(H.getStyle(C,"borderBottomWidth"),10);var D=parseInt(H.getStyle(C,"borderLeftWidth"),10);if(isNaN(G)){G=0;}if(isNaN(I)){I=0;}if(isNaN(F)){F=0;}if(isNaN(D)){D=0;}var E=Math.max(0,B.offsetWidth-I-D);var A=Math.max(0,B.offsetHeight-G-F);H.setStyle(C,"width",E+"px");H.setStyle(C,"height",A+"px");}},b4MouseDown:function(B){this.setStartPosition();var A=YAHOO.util.Event.getPageX(B);var C=YAHOO.util.Event.getPageY(B);this.autoOffset(A,C);},b4StartDrag:function(A,B){this.showFrame(A,B);},b4EndDrag:function(A){YAHOO.util.Dom.setStyle(this.getDragEl(),"visibility","hidden");},endDrag:function(D){var C=YAHOO.util.Dom;var B=this.getEl();var A=this.getDragEl();C.setStyle(A,"visibility","");C.setStyle(B,"visibility","hidden");YAHOO.util.DDM.moveToEl(B,A);C.setStyle(A,"visibility","hidden");C.setStyle(B,"visibility","");},toString:function(){return("DDProxy "+this.id);}});YAHOO.util.DDTarget=function(C,A,B){if(C){this.initTarget(C,A,B);}};YAHOO.extend(YAHOO.util.DDTarget,YAHOO.util.DragDrop,{toString:function(){return("DDTarget "+this.id);}});YAHOO.register("dragdrop",YAHOO.util.DragDropMgr,{version:"2.8.2r1",build:"7"});YAHOO.util.Attribute=function(B,A){if(A){this.owner=A;this.configure(B,true);}};YAHOO.util.Attribute.prototype={name:undefined,value:null,owner:null,readOnly:false,writeOnce:false,_initialConfig:null,_written:false,method:null,setter:null,getter:null,validator:null,getValue:function(){var A=this.value;if(this.getter){A=this.getter.call(this.owner,this.name,A);}return A;},setValue:function(F,B){var E,A=this.owner,C=this.name;var D={type:C,prevValue:this.getValue(),newValue:F};if(this.readOnly||(this.writeOnce&&this._written)){return false;}if(this.validator&&!this.validator.call(A,F)){return false;}if(!B){E=A.fireBeforeChangeEvent(D);if(E===false){return false;}}if(this.setter){F=this.setter.call(A,F,this.name);if(F===undefined){}}if(this.method){this.method.call(A,F,this.name);}this.value=F;this._written=true;D.type=C;if(!B){this.owner.fireChangeEvent(D);}return true;},configure:function(B,C){B=B||{};if(C){this._written=false;}this._initialConfig=this._initialConfig||{};for(var A in B){if(B.hasOwnProperty(A)){this[A]=B[A];if(C){this._initialConfig[A]=B[A];}}}},resetValue:function(){return this.setValue(this._initialConfig.value);},resetConfig:function(){this.configure(this._initialConfig,true);},refresh:function(A){this.setValue(this.value,A);}};(function(){var A=YAHOO.util.Lang;YAHOO.util.AttributeProvider=function(){};YAHOO.util.AttributeProvider.prototype={_configs:null,get:function(C){this._configs=this._configs||{};var B=this._configs[C];if(!B||!this._configs.hasOwnProperty(C)){return null;}return B.getValue();},set:function(D,E,B){this._configs=this._configs||{};var C=this._configs[D];if(!C){return false;}return C.setValue(E,B);},getAttributeKeys:function(){this._configs=this._configs;var C=[],B;for(B in this._configs){if(A.hasOwnProperty(this._configs,B)&&!A.isUndefined(this._configs[B])){C[C.length]=B;}}return C;},setAttributes:function(D,B){for(var C in D){if(A.hasOwnProperty(D,C)){this.set(C,D[C],B);}}},resetValue:function(C,B){this._configs=this._configs||{};if(this._configs[C]){this.set(C,this._configs[C]._initialConfig.value,B);return true;}return false;},refresh:function(E,C){this._configs=this._configs||{};var F=this._configs;E=((A.isString(E))?[E]:E)||this.getAttributeKeys();for(var D=0,B=E.length;D<B;++D){if(F.hasOwnProperty(E[D])){this._configs[E[D]].refresh(C);}}},register:function(B,C){this.setAttributeConfig(B,C);},getAttributeConfig:function(C){this._configs=this._configs||{};var B=this._configs[C]||{};var D={};for(C in B){if(A.hasOwnProperty(B,C)){D[C]=B[C];}}return D;},setAttributeConfig:function(B,C,D){this._configs=this._configs||{};C=C||{};if(!this._configs[B]){C.name=B;this._configs[B]=this.createAttribute(C);}else{this._configs[B].configure(C,D);}},configureAttribute:function(B,C,D){this.setAttributeConfig(B,C,D);},resetAttributeConfig:function(B){this._configs=this._configs||{};this._configs[B].resetConfig();},subscribe:function(B,C){this._events=this._events||{};if(!(B in this._events)){this._events[B]=this.createEvent(B);}YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){this.subscribe.apply(this,arguments);},addListener:function(){this.subscribe.apply(this,arguments);},fireBeforeChangeEvent:function(C){var B="before";B+=C.type.charAt(0).toUpperCase()+C.type.substr(1)+"Change";C.type=B;return this.fireEvent(C.type,C);},fireChangeEvent:function(B){B.type+="Change";return this.fireEvent(B.type,B);},createAttribute:function(B){return new YAHOO.util.Attribute(B,this);}};YAHOO.augment(YAHOO.util.AttributeProvider,YAHOO.util.EventProvider);})();(function(){var B=YAHOO.util.Dom,D=YAHOO.util.AttributeProvider,C={mouseenter:true,mouseleave:true};var A=function(E,F){this.init.apply(this,arguments);};A.DOM_EVENTS={"click":true,"dblclick":true,"keydown":true,"keypress":true,"keyup":true,"mousedown":true,"mousemove":true,"mouseout":true,"mouseover":true,"mouseup":true,"mouseenter":true,"mouseleave":true,"focus":true,"blur":true,"submit":true,"change":true};A.prototype={DOM_EVENTS:null,DEFAULT_HTML_SETTER:function(G,E){var F=this.get("element");if(F){F[E]=G;}return G;},DEFAULT_HTML_GETTER:function(E){var F=this.get("element"),G;if(F){G=F[E];}return G;},appendChild:function(E){E=E.get?E.get("element"):E;return this.get("element").appendChild(E);},getElementsByTagName:function(E){return this.get("element").getElementsByTagName(E);},hasChildNodes:function(){return this.get("element").hasChildNodes();},insertBefore:function(E,F){E=E.get?E.get("element"):E;F=(F&&F.get)?F.get("element"):F;return this.get("element").insertBefore(E,F);},removeChild:function(E){E=E.get?E.get("element"):E;return this.get("element").removeChild(E);},replaceChild:function(E,F){E=E.get?E.get("element"):E;F=F.get?F.get("element"):F;return this.get("element").replaceChild(E,F);},initAttributes:function(E){},addListener:function(J,I,K,H){H=H||this;var E=YAHOO.util.Event,G=this.get("element")||this.get("id"),F=this;if(C[J]&&!E._createMouseDelegate){return false;}if(!this._events[J]){if(G&&this.DOM_EVENTS[J]){E.on(G,J,function(M,L){if(M.srcElement&&!M.target){M.target=M.srcElement;}if((M.toElement&&!M.relatedTarget)||(M.fromElement&&!M.relatedTarget)){M.relatedTarget=E.getRelatedTarget(M);}if(!M.currentTarget){M.currentTarget=G;}F.fireEvent(J,M,L);},K,H);}this.createEvent(J,{scope:this});}return YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){return this.addListener.apply(this,arguments);},subscribe:function(){return this.addListener.apply(this,arguments);},removeListener:function(F,E){return this.unsubscribe.apply(this,arguments);},addClass:function(E){B.addClass(this.get("element"),E);},getElementsByClassName:function(F,E){return B.getElementsByClassName(F,E,this.get("element"));},hasClass:function(E){return B.hasClass(this.get("element"),E);},removeClass:function(E){return B.removeClass(this.get("element"),E);},replaceClass:function(F,E){return B.replaceClass(this.get("element"),F,E);},setStyle:function(F,E){return B.setStyle(this.get("element"),F,E);
+},getStyle:function(E){return B.getStyle(this.get("element"),E);},fireQueue:function(){var F=this._queue;for(var G=0,E=F.length;G<E;++G){this[F[G][0]].apply(this,F[G][1]);}},appendTo:function(F,G){F=(F.get)?F.get("element"):B.get(F);this.fireEvent("beforeAppendTo",{type:"beforeAppendTo",target:F});G=(G&&G.get)?G.get("element"):B.get(G);var E=this.get("element");if(!E){return false;}if(!F){return false;}if(E.parent!=F){if(G){F.insertBefore(E,G);}else{F.appendChild(E);}}this.fireEvent("appendTo",{type:"appendTo",target:F});return E;},get:function(E){var G=this._configs||{},F=G.element;if(F&&!G[E]&&!YAHOO.lang.isUndefined(F.value[E])){this._setHTMLAttrConfig(E);}return D.prototype.get.call(this,E);},setAttributes:function(K,H){var F={},I=this._configOrder;for(var J=0,E=I.length;J<E;++J){if(K[I[J]]!==undefined){F[I[J]]=true;this.set(I[J],K[I[J]],H);}}for(var G in K){if(K.hasOwnProperty(G)&&!F[G]){this.set(G,K[G],H);}}},set:function(F,H,E){var G=this.get("element");if(!G){this._queue[this._queue.length]=["set",arguments];if(this._configs[F]){this._configs[F].value=H;}return;}if(!this._configs[F]&&!YAHOO.lang.isUndefined(G[F])){this._setHTMLAttrConfig(F);}return D.prototype.set.apply(this,arguments);},setAttributeConfig:function(E,F,G){this._configOrder.push(E);D.prototype.setAttributeConfig.apply(this,arguments);},createEvent:function(F,E){this._events[F]=true;return D.prototype.createEvent.apply(this,arguments);},init:function(F,E){this._initElement(F,E);},destroy:function(){var E=this.get("element");YAHOO.util.Event.purgeElement(E,true);this.unsubscribeAll();if(E&&E.parentNode){E.parentNode.removeChild(E);}this._queue=[];this._events={};this._configs={};this._configOrder=[];},_initElement:function(G,F){this._queue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};this._configOrder=[];F=F||{};F.element=F.element||G||null;var I=false;var E=A.DOM_EVENTS;this.DOM_EVENTS=this.DOM_EVENTS||{};for(var H in E){if(E.hasOwnProperty(H)){this.DOM_EVENTS[H]=E[H];}}if(typeof F.element==="string"){this._setHTMLAttrConfig("id",{value:F.element});}if(B.get(F.element)){I=true;this._initHTMLElement(F);this._initContent(F);}YAHOO.util.Event.onAvailable(F.element,function(){if(!I){this._initHTMLElement(F);}this.fireEvent("available",{type:"available",target:B.get(F.element)});},this,true);YAHOO.util.Event.onContentReady(F.element,function(){if(!I){this._initContent(F);}this.fireEvent("contentReady",{type:"contentReady",target:B.get(F.element)});},this,true);},_initHTMLElement:function(E){this.setAttributeConfig("element",{value:B.get(E.element),readOnly:true});},_initContent:function(E){this.initAttributes(E);this.setAttributes(E,true);this.fireQueue();},_setHTMLAttrConfig:function(E,G){var F=this.get("element");G=G||{};G.name=E;G.setter=G.setter||this.DEFAULT_HTML_SETTER;G.getter=G.getter||this.DEFAULT_HTML_GETTER;G.value=G.value||F[E];this._configs[E]=new YAHOO.util.Attribute(G,this);}};YAHOO.augment(A,D);YAHOO.util.Element=A;})();YAHOO.register("element",YAHOO.util.Element,{version:"2.8.2r1",build:"7"});YAHOO.register("utilities", YAHOO, {version: "2.8.2r1", build: "7"});/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+*/
+(function(){var lang=YAHOO.lang,util=YAHOO.util,Ev=util.Event;util.DataSourceBase=function(oLiveData,oConfigs){if(oLiveData===null||oLiveData===undefined){return;}this.liveData=oLiveData;this._oQueue={interval:null,conn:null,requests:[]};this.responseSchema={};if(oConfigs&&(oConfigs.constructor==Object)){for(var sConfig in oConfigs){if(sConfig){this[sConfig]=oConfigs[sConfig];}}}var maxCacheEntries=this.maxCacheEntries;if(!lang.isNumber(maxCacheEntries)||(maxCacheEntries<0)){maxCacheEntries=0;}this._aIntervals=[];this.createEvent("cacheRequestEvent");this.createEvent("cacheResponseEvent");this.createEvent("requestEvent");this.createEvent("responseEvent");this.createEvent("responseParseEvent");this.createEvent("responseCacheEvent");this.createEvent("dataErrorEvent");this.createEvent("cacheFlushEvent");var DS=util.DataSourceBase;this._sName="DataSource instance"+DS._nIndex;DS._nIndex++;};var DS=util.DataSourceBase;lang.augmentObject(DS,{TYPE_UNKNOWN:-1,TYPE_JSARRAY:0,TYPE_JSFUNCTION:1,TYPE_XHR:2,TYPE_JSON:3,TYPE_XML:4,TYPE_TEXT:5,TYPE_HTMLTABLE:6,TYPE_SCRIPTNODE:7,TYPE_LOCAL:8,ERROR_DATAINVALID:"Invalid data",ERROR_DATANULL:"Null data",_nIndex:0,_nTransactionId:0,_getLocationValue:function(field,context){var locator=field.locator||field.key||field,xmldoc=context.ownerDocument||context,result,res,value=null;try{if(!lang.isUndefined(xmldoc.evaluate)){result=xmldoc.evaluate(locator,context,xmldoc.createNSResolver(!context.ownerDocument?context.documentElement:context.ownerDocument.documentElement),0,null);while(res=result.iterateNext()){value=res.textContent;}}else{xmldoc.setProperty("SelectionLanguage","XPath");result=context.selectNodes(locator)[0];value=result.value||result.text||null;}return value;}catch(e){}},issueCallback:function(callback,params,error,scope){if(lang.isFunction(callback)){callback.apply(scope,params);}else{if(lang.isObject(callback)){scope=callback.scope||scope||window;var callbackFunc=callback.success;if(error){callbackFunc=callback.failure;}if(callbackFunc){callbackFunc.apply(scope,params.concat([callback.argument]));}}}},parseString:function(oData){if(!lang.isValue(oData)){return null;}var string=oData+"";if(lang.isString(string)){return string;}else{return null;}},parseNumber:function(oData){if(!lang.isValue(oData)||(oData==="")){return null;}var number=oData*1;if(lang.isNumber(number)){return number;}else{return null;}},convertNumber:function(oData){return DS.parseNumber(oData);},parseDate:function(oData){var date=null;if(!(oData instanceof Date)){date=new Date(oData);}else{return oData;}if(date instanceof Date){return date;}else{return null;}},convertDate:function(oData){return DS.parseDate(oData);}});DS.Parser={string:DS.parseString,number:DS.parseNumber,date:DS.parseDate};DS.prototype={_sName:null,_aCache:null,_oQueue:null,_aIntervals:null,maxCacheEntries:0,liveData:null,dataType:DS.TYPE_UNKNOWN,responseType:DS.TYPE_UNKNOWN,responseSchema:null,useXPath:false,toString:function(){return this._sName;},getCachedResponse:function(oRequest,oCallback,oCaller){var aCache=this._aCache;if(this.maxCacheEntries>0){if(!aCache){this._aCache=[];}else{var nCacheLength=aCache.length;if(nCacheLength>0){var oResponse=null;this.fireEvent("cacheRequestEvent",{request:oRequest,callback:oCallback,caller:oCaller});for(var i=nCacheLength-1;i>=0;i--){var oCacheElem=aCache[i];if(this.isCacheHit(oRequest,oCacheElem.request)){oResponse=oCacheElem.response;this.fireEvent("cacheResponseEvent",{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller});if(i<nCacheLength-1){aCache.splice(i,1);this.addToCache(oRequest,oResponse);}oResponse.cached=true;break;}}return oResponse;}}}else{if(aCache){this._aCache=null;}}return null;},isCacheHit:function(oRequest,oCachedRequest){return(oRequest===oCachedRequest);},addToCache:function(oRequest,oResponse){var aCache=this._aCache;if(!aCache){return;}while(aCache.length>=this.maxCacheEntries){aCache.shift();}var oCacheElem={request:oRequest,response:oResponse};aCache[aCache.length]=oCacheElem;this.fireEvent("responseCacheEvent",{request:oRequest,response:oResponse});},flushCache:function(){if(this._aCache){this._aCache=[];this.fireEvent("cacheFlushEvent");}},setInterval:function(nMsec,oRequest,oCallback,oCaller){if(lang.isNumber(nMsec)&&(nMsec>=0)){var oSelf=this;var nId=setInterval(function(){oSelf.makeConnection(oRequest,oCallback,oCaller);},nMsec);this._aIntervals.push(nId);return nId;}else{}},clearInterval:function(nId){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i>-1;i--){if(tracker[i]===nId){tracker.splice(i,1);clearInterval(nId);}}},clearAllIntervals:function(){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i>-1;i--){clearInterval(tracker[i]);}tracker=[];},sendRequest:function(oRequest,oCallback,oCaller){var oCachedResponse=this.getCachedResponse(oRequest,oCallback,oCaller);if(oCachedResponse){DS.issueCallback(oCallback,[oRequest,oCachedResponse],false,oCaller);return null;}return this.makeConnection(oRequest,oCallback,oCaller);},makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=this.liveData;this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;},handleResponse:function(oRequest,oRawResponse,oCallback,oCaller,tId){this.fireEvent("responseEvent",{tId:tId,request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller});var xhr=(this.dataType==DS.TYPE_XHR)?true:false;var oParsedResponse=null;var oFullResponse=oRawResponse;if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oRawResponse&&oRawResponse.getResponseHeader)?oRawResponse.getResponseHeader["Content-Type"]:null;if(ctype){if(ctype.indexOf("text/xml")>-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf("application/json")>-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf("text/plain")>-1){this.responseType=DS.TYPE_TEXT;}}}}else{if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY;
+}else{if(oRawResponse&&oRawResponse.nodeType&&(oRawResponse.nodeType===9||oRawResponse.nodeType===1||oRawResponse.nodeType===11)){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&&oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.responseType=DS.TYPE_TEXT;}}}}}}}switch(this.responseType){case DS.TYPE_JSARRAY:if(xhr&&oRawResponse&&oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&&JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length>0&&(oFullResponse.charAt(0)!="{")&&(oFullResponse.charAt(0)!="[")){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length>0){var arrayEnd=Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}"));oFullResponse=oFullResponse.substring(0,arrayEnd+1);oFullResponse=eval("("+oFullResponse+")");}}}}}}catch(e1){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseArrayData(oRequest,oFullResponse);break;case DS.TYPE_JSON:if(xhr&&oRawResponse&&oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&&JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length>0&&(oFullResponse.charAt(0)!="{")&&(oFullResponse.charAt(0)!="[")){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length>0){var objEnd=Math.max(oFullResponse.lastIndexOf("]"),oFullResponse.lastIndexOf("}"));oFullResponse=oFullResponse.substring(0,objEnd+1);oFullResponse=eval("("+oFullResponse+")");}}}}}}catch(e){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseJSONData(oRequest,oFullResponse);break;case DS.TYPE_HTMLTABLE:if(xhr&&oRawResponse.responseText){var el=document.createElement("div");el.innerHTML=oRawResponse.responseText;oFullResponse=el.getElementsByTagName("table")[0];}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseHTMLTableData(oRequest,oFullResponse);break;case DS.TYPE_XML:if(xhr&&oRawResponse.responseXML){oFullResponse=oRawResponse.responseXML;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseXMLData(oRequest,oFullResponse);break;case DS.TYPE_TEXT:if(xhr&&lang.isString(oRawResponse.responseText)){oFullResponse=oRawResponse.responseText;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseTextData(oRequest,oFullResponse);break;default:oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseData(oRequest,oFullResponse);break;}oParsedResponse=oParsedResponse||{};if(!oParsedResponse.results){oParsedResponse.results=[];}if(!oParsedResponse.meta){oParsedResponse.meta={};}if(!oParsedResponse.error){oParsedResponse=this.doBeforeCallback(oRequest,oFullResponse,oParsedResponse,oCallback);this.fireEvent("responseParseEvent",{request:oRequest,response:oParsedResponse,callback:oCallback,caller:oCaller});this.addToCache(oRequest,oParsedResponse);}else{oParsedResponse.error=true;this.fireEvent("dataErrorEvent",{request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});}oParsedResponse.tId=tId;DS.issueCallback(oCallback,[oRequest,oParsedResponse],oParsedResponse.error,oCaller);},doBeforeParseData:function(oRequest,oFullResponse,oCallback){return oFullResponse;},doBeforeCallback:function(oRequest,oFullResponse,oParsedResponse,oCallback){return oParsedResponse;},parseData:function(oRequest,oFullResponse){if(lang.isValue(oFullResponse)){var oParsedResponse={results:oFullResponse,meta:{}};return oParsedResponse;}return null;},parseArrayData:function(oRequest,oFullResponse){if(lang.isArray(oFullResponse)){var results=[],i,j,rec,field,data;if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;for(i=fields.length-1;i>=0;--i){if(typeof fields[i]!=="object"){fields[i]={key:fields[i]};}}var parsers={},p;for(i=fields.length-1;i>=0;--i){p=(typeof fields[i].parser==="function"?fields[i].parser:DS.Parser[fields[i].parser+""])||fields[i].converter;if(p){parsers[fields[i].key]=p;}}var arrType=lang.isArray(oFullResponse[0]);for(i=oFullResponse.length-1;i>-1;i--){var oResult={};rec=oFullResponse[i];if(typeof rec==="object"){for(j=fields.length-1;j>-1;j--){field=fields[j];data=arrType?rec[j]:rec[field.key];if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;}}else{if(lang.isString(rec)){for(j=fields.length-1;j>-1;j--){field=fields[j];data=rec;if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;}}}results[i]=oResult;}}else{results=oFullResponse;}var oParsedResponse={results:results};return oParsedResponse;}return null;},parseTextData:function(oRequest,oFullResponse){if(lang.isString(oFullResponse)){if(lang.isString(this.responseSchema.recordDelim)&&lang.isString(this.responseSchema.fieldDelim)){var oParsedResponse={results:[]};var recDelim=this.responseSchema.recordDelim;var fieldDelim=this.responseSchema.fieldDelim;if(oFullResponse.length>0){var newLength=oFullResponse.length-recDelim.length;if(oFullResponse.substr(newLength)==recDelim){oFullResponse=oFullResponse.substr(0,newLength);
+}if(oFullResponse.length>0){var recordsarray=oFullResponse.split(recDelim);for(var i=0,len=recordsarray.length,recIdx=0;i<len;++i){var bError=false,sRecord=recordsarray[i];if(lang.isString(sRecord)&&(sRecord.length>0)){var fielddataarray=recordsarray[i].split(fieldDelim);var oResult={};if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;for(var j=fields.length-1;j>-1;j--){try{var data=fielddataarray[j];if(lang.isString(data)){if(data.charAt(0)=='"'){data=data.substr(1);}if(data.charAt(data.length-1)=='"'){data=data.substr(0,data.length-1);}var field=fields[j];var key=(lang.isValue(field.key))?field.key:field;if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}else{bError=true;}}catch(e){bError=true;}}}else{oResult=fielddataarray;}if(!bError){oParsedResponse.results[recIdx++]=oResult;}}}}}return oParsedResponse;}}return null;},parseXMLResult:function(result){var oResult={},schema=this.responseSchema;try{for(var m=schema.fields.length-1;m>=0;m--){var field=schema.fields[m];var key=(lang.isValue(field.key))?field.key:field;var data=null;if(this.useXPath){data=YAHOO.util.DataSource._getLocationValue(field,result);}else{var xmlAttr=result.attributes.getNamedItem(key);if(xmlAttr){data=xmlAttr.value;}else{var xmlNode=result.getElementsByTagName(key);if(xmlNode&&xmlNode.item(0)){var item=xmlNode.item(0);data=(item)?((item.text)?item.text:(item.textContent)?item.textContent:null):null;if(!data){var datapieces=[];for(var j=0,len=item.childNodes.length;j<len;j++){if(item.childNodes[j].nodeValue){datapieces[datapieces.length]=item.childNodes[j].nodeValue;}}if(datapieces.length>0){data=datapieces.join("");}}}}}if(data===null){data="";}if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}}catch(e){}return oResult;},parseXMLData:function(oRequest,oFullResponse){var bError=false,schema=this.responseSchema,oParsedResponse={meta:{}},xmlList=null,metaNode=schema.metaNode,metaLocators=schema.metaFields||{},i,k,loc,v;try{if(this.useXPath){for(k in metaLocators){oParsedResponse.meta[k]=YAHOO.util.DataSource._getLocationValue(metaLocators[k],oFullResponse);}}else{metaNode=metaNode?oFullResponse.getElementsByTagName(metaNode)[0]:oFullResponse;if(metaNode){for(k in metaLocators){if(lang.hasOwnProperty(metaLocators,k)){loc=metaLocators[k];v=metaNode.getElementsByTagName(loc)[0];if(v){v=v.firstChild.nodeValue;}else{v=metaNode.attributes.getNamedItem(loc);if(v){v=v.value;}}if(lang.isValue(v)){oParsedResponse.meta[k]=v;}}}}}xmlList=(schema.resultNode)?oFullResponse.getElementsByTagName(schema.resultNode):null;}catch(e){}if(!xmlList||!lang.isArray(schema.fields)){bError=true;}else{oParsedResponse.results=[];for(i=xmlList.length-1;i>=0;--i){var oResult=this.parseXMLResult(xmlList.item(i));oParsedResponse.results[i]=oResult;}}if(bError){oParsedResponse.error=true;}else{}return oParsedResponse;},parseJSONData:function(oRequest,oFullResponse){var oParsedResponse={results:[],meta:{}};if(lang.isObject(oFullResponse)&&this.responseSchema.resultsList){var schema=this.responseSchema,fields=schema.fields,resultsList=oFullResponse,results=[],metaFields=schema.metaFields||{},fieldParsers=[],fieldPaths=[],simpleFields=[],bError=false,i,len,j,v,key,parser,path;var buildPath=function(needle){var path=null,keys=[],i=0;if(needle){needle=needle.replace(/\[(['"])(.*?)\1\]/g,function(x,$1,$2){keys[i]=$2;return".@"+(i++);}).replace(/\[(\d+)\]/g,function(x,$1){keys[i]=parseInt($1,10)|0;return".@"+(i++);}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(needle)){path=needle.split(".");for(i=path.length-1;i>=0;--i){if(path[i].charAt(0)==="@"){path[i]=keys[parseInt(path[i].substr(1),10)];}}}else{}}return path;};var walkPath=function(path,origin){var v=origin,i=0,len=path.length;for(;i<len&&v;++i){v=v[path[i]];}return v;};path=buildPath(schema.resultsList);if(path){resultsList=walkPath(path,oFullResponse);if(resultsList===undefined){bError=true;}}else{bError=true;}if(!resultsList){resultsList=[];}if(!lang.isArray(resultsList)){resultsList=[resultsList];}if(!bError){if(schema.fields){var field;for(i=0,len=fields.length;i<len;i++){field=fields[i];key=field.key||field;parser=((typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""])||field.converter;path=buildPath(key);if(parser){fieldParsers[fieldParsers.length]={key:key,parser:parser};}if(path){if(path.length>1){fieldPaths[fieldPaths.length]={key:key,path:path};}else{simpleFields[simpleFields.length]={key:key,path:path[0]};}}else{}}for(i=resultsList.length-1;i>=0;--i){var r=resultsList[i],rec={};if(r){for(j=simpleFields.length-1;j>=0;--j){rec[simpleFields[j].key]=(r[simpleFields[j].path]!==undefined)?r[simpleFields[j].path]:r[j];}for(j=fieldPaths.length-1;j>=0;--j){rec[fieldPaths[j].key]=walkPath(fieldPaths[j].path,r);}for(j=fieldParsers.length-1;j>=0;--j){var p=fieldParsers[j].key;rec[p]=fieldParsers[j].parser(rec[p]);if(rec[p]===undefined){rec[p]=null;}}}results[i]=rec;}}else{results=resultsList;}for(key in metaFields){if(lang.hasOwnProperty(metaFields,key)){path=buildPath(metaFields[key]);if(path){v=walkPath(path,oFullResponse);oParsedResponse.meta[key]=v;}}}}else{oParsedResponse.error=true;}oParsedResponse.results=results;}else{oParsedResponse.error=true;}return oParsedResponse;},parseHTMLTableData:function(oRequest,oFullResponse){var bError=false;var elTable=oFullResponse;var fields=this.responseSchema.fields;var oParsedResponse={results:[]};if(lang.isArray(fields)){for(var i=0;i<elTable.tBodies.length;i++){var elTbody=elTable.tBodies[i];for(var j=elTbody.rows.length-1;j>-1;j--){var elRow=elTbody.rows[j];var oResult={};for(var k=fields.length-1;k>-1;k--){var field=fields[k];var key=(lang.isValue(field.key))?field.key:field;
+var data=elRow.cells[k].innerHTML;if(!field.parser&&field.converter){field.parser=field.converter;}var parser=(typeof field.parser==="function")?field.parser:DS.Parser[field.parser+""];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}oParsedResponse.results[j]=oResult;}}}else{bError=true;}if(bError){oParsedResponse.error=true;}else{}return oParsedResponse;}};lang.augmentProto(DS,util.EventProvider);util.LocalDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_LOCAL;if(oLiveData){if(YAHOO.lang.isArray(oLiveData)){this.responseType=DS.TYPE_JSARRAY;}else{if(oLiveData.nodeType&&oLiveData.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oLiveData.nodeName&&(oLiveData.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;oLiveData=oLiveData.cloneNode(true);}else{if(YAHOO.lang.isString(oLiveData)){this.responseType=DS.TYPE_TEXT;}else{if(YAHOO.lang.isObject(oLiveData)){this.responseType=DS.TYPE_JSON;}}}}}}else{oLiveData=[];this.responseType=DS.TYPE_JSARRAY;}util.LocalDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.LocalDataSource,DS);lang.augmentObject(util.LocalDataSource,DS);util.FunctionDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_JSFUNCTION;oLiveData=oLiveData||function(){};util.FunctionDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.FunctionDataSource,DS,{scope:null,makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=(this.scope)?this.liveData.call(this.scope,oRequest,this):this.liveData(oRequest);if(this.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse&&oRawResponse.nodeType&&oRawResponse.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&&oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.responseType=DS.TYPE_TEXT;}}}}}}this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;}});lang.augmentObject(util.FunctionDataSource,DS);util.ScriptNodeDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_SCRIPTNODE;oLiveData=oLiveData||"";util.ScriptNodeDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.ScriptNodeDataSource,DS,{getUtility:util.Get,asyncMode:"allowAll",scriptCallbackParam:"callback",generateRequestCallback:function(id){return"&"+this.scriptCallbackParam+"=YAHOO.util.ScriptNodeDataSource.callbacks["+id+"]";},doBeforeGetScriptNode:function(sUri){return sUri;},makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});if(util.ScriptNodeDataSource._nPending===0){util.ScriptNodeDataSource.callbacks=[];util.ScriptNodeDataSource._nId=0;}var id=util.ScriptNodeDataSource._nId;util.ScriptNodeDataSource._nId++;var oSelf=this;util.ScriptNodeDataSource.callbacks[id]=function(oRawResponse){if((oSelf.asyncMode!=="ignoreStaleResponses")||(id===util.ScriptNodeDataSource.callbacks.length-1)){if(oSelf.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){oSelf.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse.nodeType&&oRawResponse.nodeType==9){oSelf.responseType=DS.TYPE_XML;}else{if(oRawResponse.nodeName&&(oRawResponse.nodeName.toLowerCase()=="table")){oSelf.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){oSelf.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){oSelf.responseType=DS.TYPE_TEXT;}}}}}}oSelf.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);}else{}delete util.ScriptNodeDataSource.callbacks[id];};util.ScriptNodeDataSource._nPending++;var sUri=this.liveData+oRequest+this.generateRequestCallback(id);sUri=this.doBeforeGetScriptNode(sUri);this.getUtility.script(sUri,{autopurge:true,onsuccess:util.ScriptNodeDataSource._bumpPendingDown,onfail:util.ScriptNodeDataSource._bumpPendingDown});return tId;}});lang.augmentObject(util.ScriptNodeDataSource,DS);lang.augmentObject(util.ScriptNodeDataSource,{_nId:0,_nPending:0,callbacks:[]});util.XHRDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_XHR;this.connMgr=this.connMgr||util.Connect;oLiveData=oLiveData||"";util.XHRDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.XHRDataSource,DS,{connMgr:null,connXhrMode:"allowAll",connMethodPost:false,connTimeout:0,makeConnection:function(oRequest,oCallback,oCaller){var oRawResponse=null;var tId=DS._nTransactionId++;this.fireEvent("requestEvent",{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oSelf=this;var oConnMgr=this.connMgr;var oQueue=this._oQueue;var _xhrSuccess=function(oResponse){if(oResponse&&(this.connXhrMode=="ignoreStaleResponses")&&(oResponse.tId!=oQueue.conn.tId)){return null;}else{if(!oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,response:null,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);return null;}else{if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oResponse.getResponseHeader)?oResponse.getResponseHeader["Content-Type"]:null;if(ctype){if(ctype.indexOf("text/xml")>-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf("application/json")>-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf("text/plain")>-1){this.responseType=DS.TYPE_TEXT;}}}}}this.handleResponse(oRequest,oResponse,oCallback,oCaller,tId);}}};var _xhrFailure=function(oResponse){this.fireEvent("dataErrorEvent",{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATAINVALID});if(lang.isString(this.liveData)&&lang.isString(oRequest)&&(this.liveData.lastIndexOf("?")!==this.liveData.length-1)&&(oRequest.indexOf("?")!==0)){}oResponse=oResponse||{};
+oResponse.error=true;DS.issueCallback(oCallback,[oRequest,oResponse],true,oCaller);return null;};var _xhrCallback={success:_xhrSuccess,failure:_xhrFailure,scope:this};if(lang.isNumber(this.connTimeout)){_xhrCallback.timeout=this.connTimeout;}if(this.connXhrMode=="cancelStaleRequests"){if(oQueue.conn){if(oConnMgr.abort){oConnMgr.abort(oQueue.conn);oQueue.conn=null;}else{}}}if(oConnMgr&&oConnMgr.asyncRequest){var sLiveData=this.liveData;var isPost=this.connMethodPost;var sMethod=(isPost)?"POST":"GET";var sUri=(isPost||!lang.isValue(oRequest))?sLiveData:sLiveData+oRequest;var sRequest=(isPost)?oRequest:null;if(this.connXhrMode!="queueRequests"){oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}else{if(oQueue.conn){var allRequests=oQueue.requests;allRequests.push({request:oRequest,callback:_xhrCallback});if(!oQueue.interval){oQueue.interval=setInterval(function(){if(oConnMgr.isCallInProgress(oQueue.conn)){return;}else{if(allRequests.length>0){sUri=(isPost||!lang.isValue(allRequests[0].request))?sLiveData:sLiveData+allRequests[0].request;sRequest=(isPost)?allRequests[0].request:null;oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,allRequests[0].callback,sRequest);allRequests.shift();}else{clearInterval(oQueue.interval);oQueue.interval=null;}}},50);}}else{oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}}}else{DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);}return tId;}});lang.augmentObject(util.XHRDataSource,DS);util.DataSource=function(oLiveData,oConfigs){oConfigs=oConfigs||{};var dataType=oConfigs.dataType;if(dataType){if(dataType==DS.TYPE_LOCAL){lang.augmentObject(util.DataSource,util.LocalDataSource);return new util.LocalDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_XHR){lang.augmentObject(util.DataSource,util.XHRDataSource);return new util.XHRDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_SCRIPTNODE){lang.augmentObject(util.DataSource,util.ScriptNodeDataSource);return new util.ScriptNodeDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_JSFUNCTION){lang.augmentObject(util.DataSource,util.FunctionDataSource);return new util.FunctionDataSource(oLiveData,oConfigs);}}}}}if(YAHOO.lang.isString(oLiveData)){lang.augmentObject(util.DataSource,util.XHRDataSource);return new util.XHRDataSource(oLiveData,oConfigs);}else{if(YAHOO.lang.isFunction(oLiveData)){lang.augmentObject(util.DataSource,util.FunctionDataSource);return new util.FunctionDataSource(oLiveData,oConfigs);}else{lang.augmentObject(util.DataSource,util.LocalDataSource);return new util.LocalDataSource(oLiveData,oConfigs);}}};lang.augmentObject(util.DataSource,DS);})();YAHOO.util.Number={format:function(B,E){if(!isFinite(+B)){return"";}B=!isFinite(+B)?0:+B;E=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,(E||{}));var C=B<0,F=Math.abs(B),A=E.decimalPlaces,I=E.thousandsSeparator,H,G,D;if(A<0){H=F-(F%1)+"";D=H.length+A;if(D>0){H=Number("."+H).toFixed(D).slice(2)+new Array(H.length-D+1).join("0");}else{H="0";}}else{H=F<1&&F>=0.5&&!A?"1":F.toFixed(A);}if(F>1000){G=H.split(/\D/);D=G[0].length%3||3;G[0]=G[0].slice(0,D)+G[0].slice(D).replace(/(\d{3})/g,I+"$1");H=G.join(E.decimalSeparator);}H=E.prefix+H+E.suffix;return C?E.negativeFormat.replace(/#/,H):H;}};YAHOO.util.Number.format.defaults={decimalSeparator:".",decimalPlaces:null,thousandsSeparator:"",prefix:"",suffix:"",negativeFormat:"-#"};(function(){var A=function(C,E,D){if(typeof D==="undefined"){D=10;}for(;parseInt(C,10)<D&&D>1;D/=10){C=E.toString()+C;}return C.toString();};var B={formats:{a:function(D,C){return C.a[D.getDay()];},A:function(D,C){return C.A[D.getDay()];},b:function(D,C){return C.b[D.getMonth()];},B:function(D,C){return C.B[D.getMonth()];},C:function(C){return A(parseInt(C.getFullYear()/100,10),0);},d:["getDate","0"],e:["getDate"," "],g:function(C){return A(parseInt(B.formats.G(C)%100,10),0);},G:function(E){var F=E.getFullYear();var D=parseInt(B.formats.V(E),10);var C=parseInt(B.formats.W(E),10);if(C>D){F++;}else{if(C===0&&D>=52){F--;}}return F;},H:["getHours","0"],I:function(D){var C=D.getHours()%12;return A(C===0?12:C,0);},j:function(G){var F=new Date(""+G.getFullYear()+"/1/1 GMT");var D=new Date(""+G.getFullYear()+"/"+(G.getMonth()+1)+"/"+G.getDate()+" GMT");var C=D-F;var E=parseInt(C/60000/60/24,10)+1;return A(E,0,100);},k:["getHours"," "],l:function(D){var C=D.getHours()%12;return A(C===0?12:C," ");},m:function(C){return A(C.getMonth()+1,0);},M:["getMinutes","0"],p:function(D,C){return C.p[D.getHours()>=12?1:0];},P:function(D,C){return C.P[D.getHours()>=12?1:0];},s:function(D,C){return parseInt(D.getTime()/1000,10);},S:["getSeconds","0"],u:function(C){var D=C.getDay();return D===0?7:D;},U:function(F){var C=parseInt(B.formats.j(F),10);var E=6-F.getDay();var D=parseInt((C+E)/7,10);return A(D,0);},V:function(F){var E=parseInt(B.formats.W(F),10);var C=(new Date(""+F.getFullYear()+"/1/1")).getDay();var D=E+(C>4||C<=1?0:1);if(D===53&&(new Date(""+F.getFullYear()+"/12/31")).getDay()<4){D=1;}else{if(D===0){D=B.formats.V(new Date(""+(F.getFullYear()-1)+"/12/31"));}}return A(D,0);},w:"getDay",W:function(F){var C=parseInt(B.formats.j(F),10);var E=7-B.formats.u(F);var D=parseInt((C+E)/7,10);return A(D,0,10);},y:function(C){return A(C.getFullYear()%100,0);},Y:"getFullYear",z:function(E){var D=E.getTimezoneOffset();var C=A(parseInt(Math.abs(D/60),10),0);var F=A(Math.abs(D%60),0);return(D>0?"-":"+")+C+F;},Z:function(C){var D=C.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(D.length>4){D=B.formats.z(C);}return D;},"%":function(C){return"%";}},aggregates:{c:"locale",D:"%m/%d/%y",F:"%Y-%m-%d",h:"%b",n:"\n",r:"locale",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"},format:function(G,F,D){F=F||{};if(!(G instanceof Date)){return YAHOO.lang.isValue(G)?G:"";}var H=F.format||"%m/%d/%Y";if(H==="YYYY/MM/DD"){H="%Y/%m/%d";}else{if(H==="DD/MM/YYYY"){H="%d/%m/%Y";}else{if(H==="MM/DD/YYYY"){H="%m/%d/%Y";}}}D=D||"en";if(!(D in YAHOO.util.DateLocale)){if(D.replace(/-[a-zA-Z]+$/,"") in YAHOO.util.DateLocale){D=D.replace(/-[a-zA-Z]+$/,"");
+}else{D="en";}}var J=YAHOO.util.DateLocale[D];var C=function(L,K){var M=B.aggregates[K];return(M==="locale"?J[K]:M);};var E=function(L,K){var M=B.formats[K];if(typeof M==="string"){return G[M]();}else{if(typeof M==="function"){return M.call(G,G,J);}else{if(typeof M==="object"&&typeof M[0]==="string"){return A(G[M[0]](),M[1]);}else{return K;}}}};while(H.match(/%[cDFhnrRtTxX]/)){H=H.replace(/%([cDFhnrRtTxX])/g,C);}var I=H.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,E);C=E=undefined;return I;}};YAHOO.namespace("YAHOO.util");YAHOO.util.Date=B;YAHOO.util.DateLocale={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],r:"%I:%M:%S %p",x:"%d/%m/%y",X:"%T"};YAHOO.util.DateLocale["en"]=YAHOO.lang.merge(YAHOO.util.DateLocale,{});YAHOO.util.DateLocale["en-US"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"],{c:"%a %d %b %Y %I:%M:%S %p %Z",x:"%m/%d/%Y",X:"%I:%M:%S %p"});YAHOO.util.DateLocale["en-GB"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"],{r:"%l:%M:%S %P %Z"});YAHOO.util.DateLocale["en-AU"]=YAHOO.lang.merge(YAHOO.util.DateLocale["en"]);})();YAHOO.register("datasource",YAHOO.util.DataSource,{version:"2.8.2r1",build:"7"});/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+*/
+YAHOO.widget.DS_JSArray=YAHOO.util.LocalDataSource;YAHOO.widget.DS_JSFunction=YAHOO.util.FunctionDataSource;YAHOO.widget.DS_XHR=function(B,A,D){var C=new YAHOO.util.XHRDataSource(B,D);C._aDeprecatedSchema=A;return C;};YAHOO.widget.DS_ScriptNode=function(B,A,D){var C=new YAHOO.util.ScriptNodeDataSource(B,D);C._aDeprecatedSchema=A;return C;};YAHOO.widget.DS_XHR.TYPE_JSON=YAHOO.util.DataSourceBase.TYPE_JSON;YAHOO.widget.DS_XHR.TYPE_XML=YAHOO.util.DataSourceBase.TYPE_XML;YAHOO.widget.DS_XHR.TYPE_FLAT=YAHOO.util.DataSourceBase.TYPE_TEXT;YAHOO.widget.AutoComplete=function(G,B,J,C){if(G&&B&&J){if(J&&YAHOO.lang.isFunction(J.sendRequest)){this.dataSource=J;}else{return;}this.key=0;var D=J.responseSchema;if(J._aDeprecatedSchema){var K=J._aDeprecatedSchema;if(YAHOO.lang.isArray(K)){if((J.responseType===YAHOO.util.DataSourceBase.TYPE_JSON)||(J.responseType===YAHOO.util.DataSourceBase.TYPE_UNKNOWN)){D.resultsList=K[0];this.key=K[1];D.fields=(K.length<3)?null:K.slice(1);}else{if(J.responseType===YAHOO.util.DataSourceBase.TYPE_XML){D.resultNode=K[0];this.key=K[1];D.fields=K.slice(1);}else{if(J.responseType===YAHOO.util.DataSourceBase.TYPE_TEXT){D.recordDelim=K[0];D.fieldDelim=K[1];}}}J.responseSchema=D;}}if(YAHOO.util.Dom.inDocument(G)){if(YAHOO.lang.isString(G)){this._sName="instance"+YAHOO.widget.AutoComplete._nIndex+" "+G;this._elTextbox=document.getElementById(G);}else{this._sName=(G.id)?"instance"+YAHOO.widget.AutoComplete._nIndex+" "+G.id:"instance"+YAHOO.widget.AutoComplete._nIndex;this._elTextbox=G;}YAHOO.util.Dom.addClass(this._elTextbox,"yui-ac-input");}else{return;}if(YAHOO.util.Dom.inDocument(B)){if(YAHOO.lang.isString(B)){this._elContainer=document.getElementById(B);}else{this._elContainer=B;}if(this._elContainer.style.display=="none"){}var E=this._elContainer.parentNode;var A=E.tagName.toLowerCase();if(A=="div"){YAHOO.util.Dom.addClass(E,"yui-ac");}else{}}else{return;}if(this.dataSource.dataType===YAHOO.util.DataSourceBase.TYPE_LOCAL){this.applyLocalFilter=true;}if(C&&(C.constructor==Object)){for(var I in C){if(I){this[I]=C[I];}}}this._initContainerEl();this._initProps();this._initListEl();this._initContainerHelperEls();var H=this;var F=this._elTextbox;YAHOO.util.Event.addListener(F,"keyup",H._onTextboxKeyUp,H);YAHOO.util.Event.addListener(F,"keydown",H._onTextboxKeyDown,H);YAHOO.util.Event.addListener(F,"focus",H._onTextboxFocus,H);YAHOO.util.Event.addListener(F,"blur",H._onTextboxBlur,H);YAHOO.util.Event.addListener(B,"mouseover",H._onContainerMouseover,H);YAHOO.util.Event.addListener(B,"mouseout",H._onContainerMouseout,H);YAHOO.util.Event.addListener(B,"click",H._onContainerClick,H);YAHOO.util.Event.addListener(B,"scroll",H._onContainerScroll,H);YAHOO.util.Event.addListener(B,"resize",H._onContainerResize,H);YAHOO.util.Event.addListener(F,"keypress",H._onTextboxKeyPress,H);YAHOO.util.Event.addListener(window,"unload",H._onWindowUnload,H);this.textboxFocusEvent=new YAHOO.util.CustomEvent("textboxFocus",this);this.textboxKeyEvent=new YAHOO.util.CustomEvent("textboxKey",this);this.dataRequestEvent=new YAHOO.util.CustomEvent("dataRequest",this);this.dataReturnEvent=new YAHOO.util.CustomEvent("dataReturn",this);this.dataErrorEvent=new YAHOO.util.CustomEvent("dataError",this);this.containerPopulateEvent=new YAHOO.util.CustomEvent("containerPopulate",this);this.containerExpandEvent=new YAHOO.util.CustomEvent("containerExpand",this);this.typeAheadEvent=new YAHOO.util.CustomEvent("typeAhead",this);this.itemMouseOverEvent=new YAHOO.util.CustomEvent("itemMouseOver",this);this.itemMouseOutEvent=new YAHOO.util.CustomEvent("itemMouseOut",this);this.itemArrowToEvent=new YAHOO.util.CustomEvent("itemArrowTo",this);this.itemArrowFromEvent=new YAHOO.util.CustomEvent("itemArrowFrom",this);this.itemSelectEvent=new YAHOO.util.CustomEvent("itemSelect",this);this.unmatchedItemSelectEvent=new YAHOO.util.CustomEvent("unmatchedItemSelect",this);this.selectionEnforceEvent=new YAHOO.util.CustomEvent("selectionEnforce",this);this.containerCollapseEvent=new YAHOO.util.CustomEvent("containerCollapse",this);this.textboxBlurEvent=new YAHOO.util.CustomEvent("textboxBlur",this);this.textboxChangeEvent=new YAHOO.util.CustomEvent("textboxChange",this);F.setAttribute("autocomplete","off");YAHOO.widget.AutoComplete._nIndex++;}else{}};YAHOO.widget.AutoComplete.prototype.dataSource=null;YAHOO.widget.AutoComplete.prototype.applyLocalFilter=null;YAHOO.widget.AutoComplete.prototype.queryMatchCase=false;YAHOO.widget.AutoComplete.prototype.queryMatchContains=false;YAHOO.widget.AutoComplete.prototype.queryMatchSubset=false;YAHOO.widget.AutoComplete.prototype.minQueryLength=1;YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed=10;YAHOO.widget.AutoComplete.prototype.queryDelay=0.2;YAHOO.widget.AutoComplete.prototype.typeAheadDelay=0.5;YAHOO.widget.AutoComplete.prototype.queryInterval=500;YAHOO.widget.AutoComplete.prototype.highlightClassName="yui-ac-highlight";YAHOO.widget.AutoComplete.prototype.prehighlightClassName=null;YAHOO.widget.AutoComplete.prototype.delimChar=null;YAHOO.widget.AutoComplete.prototype.autoHighlight=true;YAHOO.widget.AutoComplete.prototype.typeAhead=false;YAHOO.widget.AutoComplete.prototype.animHoriz=false;YAHOO.widget.AutoComplete.prototype.animVert=true;YAHOO.widget.AutoComplete.prototype.animSpeed=0.3;YAHOO.widget.AutoComplete.prototype.forceSelection=false;YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete=true;YAHOO.widget.AutoComplete.prototype.alwaysShowContainer=false;YAHOO.widget.AutoComplete.prototype.useIFrame=false;YAHOO.widget.AutoComplete.prototype.useShadow=false;YAHOO.widget.AutoComplete.prototype.suppressInputUpdate=false;YAHOO.widget.AutoComplete.prototype.resultTypeList=true;YAHOO.widget.AutoComplete.prototype.queryQuestionMark=true;YAHOO.widget.AutoComplete.prototype.autoSnapContainer=true;YAHOO.widget.AutoComplete.prototype.toString=function(){return"AutoComplete "+this._sName;};YAHOO.widget.AutoComplete.prototype.getInputEl=function(){return this._elTextbox;};YAHOO.widget.AutoComplete.prototype.getContainerEl=function(){return this._elContainer;
+};YAHOO.widget.AutoComplete.prototype.isFocused=function(){return this._bFocused;};YAHOO.widget.AutoComplete.prototype.isContainerOpen=function(){return this._bContainerOpen;};YAHOO.widget.AutoComplete.prototype.getListEl=function(){return this._elList;};YAHOO.widget.AutoComplete.prototype.getListItemMatch=function(A){if(A._sResultMatch){return A._sResultMatch;}else{return null;}};YAHOO.widget.AutoComplete.prototype.getListItemData=function(A){if(A._oResultData){return A._oResultData;}else{return null;}};YAHOO.widget.AutoComplete.prototype.getListItemIndex=function(A){if(YAHOO.lang.isNumber(A._nItemIndex)){return A._nItemIndex;}else{return null;}};YAHOO.widget.AutoComplete.prototype.setHeader=function(B){if(this._elHeader){var A=this._elHeader;if(B){A.innerHTML=B;A.style.display="";}else{A.innerHTML="";A.style.display="none";}}};YAHOO.widget.AutoComplete.prototype.setFooter=function(B){if(this._elFooter){var A=this._elFooter;if(B){A.innerHTML=B;A.style.display="";}else{A.innerHTML="";A.style.display="none";}}};YAHOO.widget.AutoComplete.prototype.setBody=function(A){if(this._elBody){var B=this._elBody;YAHOO.util.Event.purgeElement(B,true);if(A){B.innerHTML=A;B.style.display="";}else{B.innerHTML="";B.style.display="none";}this._elList=null;}};YAHOO.widget.AutoComplete.prototype.generateRequest=function(B){var A=this.dataSource.dataType;if(A===YAHOO.util.DataSourceBase.TYPE_XHR){if(!this.dataSource.connMethodPost){B=(this.queryQuestionMark?"?":"")+(this.dataSource.scriptQueryParam||"query")+"="+B+(this.dataSource.scriptQueryAppend?("&"+this.dataSource.scriptQueryAppend):"");}else{B=(this.dataSource.scriptQueryParam||"query")+"="+B+(this.dataSource.scriptQueryAppend?("&"+this.dataSource.scriptQueryAppend):"");}}else{if(A===YAHOO.util.DataSourceBase.TYPE_SCRIPTNODE){B="&"+(this.dataSource.scriptQueryParam||"query")+"="+B+(this.dataSource.scriptQueryAppend?("&"+this.dataSource.scriptQueryAppend):"");}}return B;};YAHOO.widget.AutoComplete.prototype.sendQuery=function(B){this._bFocused=true;var A=(this.delimChar)?this._elTextbox.value+B:B;this._sendQuery(A);};YAHOO.widget.AutoComplete.prototype.snapContainer=function(){var A=this._elTextbox,B=YAHOO.util.Dom.getXY(A);B[1]+=YAHOO.util.Dom.get(A).offsetHeight+2;YAHOO.util.Dom.setXY(this._elContainer,B);};YAHOO.widget.AutoComplete.prototype.expandContainer=function(){this._toggleContainer(true);};YAHOO.widget.AutoComplete.prototype.collapseContainer=function(){this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype.clearList=function(){var B=this._elList.childNodes,A=B.length-1;for(;A>-1;A--){B[A].style.display="none";}};YAHOO.widget.AutoComplete.prototype.getSubsetMatches=function(E){var D,C,A;for(var B=E.length;B>=this.minQueryLength;B--){A=this.generateRequest(E.substr(0,B));this.dataRequestEvent.fire(this,D,A);C=this.dataSource.getCachedResponse(A);if(C){return this.filterResults.apply(this.dataSource,[E,C,C,{scope:this}]);}}return null;};YAHOO.widget.AutoComplete.prototype.preparseRawResponse=function(C,B,A){var D=((this.responseStripAfter!=="")&&(B.indexOf))?B.indexOf(this.responseStripAfter):-1;if(D!=-1){B=B.substring(0,D);}return B;};YAHOO.widget.AutoComplete.prototype.filterResults=function(K,M,Q,L){if(L&&L.argument&&L.argument.query){K=L.argument.query;}if(K&&K!==""){Q=YAHOO.widget.AutoComplete._cloneObject(Q);var I=L.scope,P=this,C=Q.results,N=[],B=I.maxResultsDisplayed,J=(P.queryMatchCase||I.queryMatchCase),A=(P.queryMatchContains||I.queryMatchContains);for(var D=0,H=C.length;D<H;D++){var F=C[D];var E=null;if(YAHOO.lang.isString(F)){E=F;}else{if(YAHOO.lang.isArray(F)){E=F[0];}else{if(this.responseSchema.fields){var O=this.responseSchema.fields[0].key||this.responseSchema.fields[0];E=F[O];}else{if(this.key){E=F[this.key];}}}}if(YAHOO.lang.isString(E)){var G=(J)?E.indexOf(decodeURIComponent(K)):E.toLowerCase().indexOf(decodeURIComponent(K).toLowerCase());if((!A&&(G===0))||(A&&(G>-1))){N.push(F);}}if(H>B&&N.length===B){break;}}Q.results=N;}else{}return Q;};YAHOO.widget.AutoComplete.prototype.handleResponse=function(C,A,B){if((this instanceof YAHOO.widget.AutoComplete)&&this._sName){this._populateList(C,A,B);}};YAHOO.widget.AutoComplete.prototype.doBeforeLoadData=function(C,A,B){return true;};YAHOO.widget.AutoComplete.prototype.formatResult=function(B,D,A){var C=(A)?A:"";return C;};YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer=function(D,A,C,B){return true;};YAHOO.widget.AutoComplete.prototype.destroy=function(){var B=this.toString();var A=this._elTextbox;var D=this._elContainer;this.textboxFocusEvent.unsubscribeAll();this.textboxKeyEvent.unsubscribeAll();this.dataRequestEvent.unsubscribeAll();this.dataReturnEvent.unsubscribeAll();this.dataErrorEvent.unsubscribeAll();this.containerPopulateEvent.unsubscribeAll();this.containerExpandEvent.unsubscribeAll();this.typeAheadEvent.unsubscribeAll();this.itemMouseOverEvent.unsubscribeAll();this.itemMouseOutEvent.unsubscribeAll();this.itemArrowToEvent.unsubscribeAll();this.itemArrowFromEvent.unsubscribeAll();this.itemSelectEvent.unsubscribeAll();this.unmatchedItemSelectEvent.unsubscribeAll();this.selectionEnforceEvent.unsubscribeAll();this.containerCollapseEvent.unsubscribeAll();this.textboxBlurEvent.unsubscribeAll();this.textboxChangeEvent.unsubscribeAll();YAHOO.util.Event.purgeElement(A,true);YAHOO.util.Event.purgeElement(D,true);D.innerHTML="";for(var C in this){if(YAHOO.lang.hasOwnProperty(this,C)){this[C]=null;}}};YAHOO.widget.AutoComplete.prototype.textboxFocusEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestEvent=null;YAHOO.widget.AutoComplete.prototype.dataReturnEvent=null;YAHOO.widget.AutoComplete.prototype.dataErrorEvent=null;YAHOO.widget.AutoComplete.prototype.containerPopulateEvent=null;YAHOO.widget.AutoComplete.prototype.containerExpandEvent=null;YAHOO.widget.AutoComplete.prototype.typeAheadEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent=null;
+YAHOO.widget.AutoComplete.prototype.itemArrowToEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent=null;YAHOO.widget.AutoComplete.prototype.itemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent=null;YAHOO.widget.AutoComplete.prototype.containerCollapseEvent=null;YAHOO.widget.AutoComplete.prototype.textboxBlurEvent=null;YAHOO.widget.AutoComplete.prototype.textboxChangeEvent=null;YAHOO.widget.AutoComplete._nIndex=0;YAHOO.widget.AutoComplete.prototype._sName=null;YAHOO.widget.AutoComplete.prototype._elTextbox=null;YAHOO.widget.AutoComplete.prototype._elContainer=null;YAHOO.widget.AutoComplete.prototype._elContent=null;YAHOO.widget.AutoComplete.prototype._elHeader=null;YAHOO.widget.AutoComplete.prototype._elBody=null;YAHOO.widget.AutoComplete.prototype._elFooter=null;YAHOO.widget.AutoComplete.prototype._elShadow=null;YAHOO.widget.AutoComplete.prototype._elIFrame=null;YAHOO.widget.AutoComplete.prototype._bFocused=false;YAHOO.widget.AutoComplete.prototype._oAnim=null;YAHOO.widget.AutoComplete.prototype._bContainerOpen=false;YAHOO.widget.AutoComplete.prototype._bOverContainer=false;YAHOO.widget.AutoComplete.prototype._elList=null;YAHOO.widget.AutoComplete.prototype._nDisplayedItems=0;YAHOO.widget.AutoComplete.prototype._sCurQuery=null;YAHOO.widget.AutoComplete.prototype._sPastSelections="";YAHOO.widget.AutoComplete.prototype._sInitInputValue=null;YAHOO.widget.AutoComplete.prototype._elCurListItem=null;YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem=null;YAHOO.widget.AutoComplete.prototype._bItemSelected=false;YAHOO.widget.AutoComplete.prototype._nKeyCode=null;YAHOO.widget.AutoComplete.prototype._nDelayID=-1;YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID=-1;YAHOO.widget.AutoComplete.prototype._iFrameSrc="javascript:false;";YAHOO.widget.AutoComplete.prototype._queryInterval=null;YAHOO.widget.AutoComplete.prototype._sLastTextboxValue=null;YAHOO.widget.AutoComplete.prototype._initProps=function(){var B=this.minQueryLength;if(!YAHOO.lang.isNumber(B)){this.minQueryLength=1;}var E=this.maxResultsDisplayed;if(!YAHOO.lang.isNumber(E)||(E<1)){this.maxResultsDisplayed=10;}var F=this.queryDelay;if(!YAHOO.lang.isNumber(F)||(F<0)){this.queryDelay=0.2;}var C=this.typeAheadDelay;if(!YAHOO.lang.isNumber(C)||(C<0)){this.typeAheadDelay=0.2;}var A=this.delimChar;if(YAHOO.lang.isString(A)&&(A.length>0)){this.delimChar=[A];}else{if(!YAHOO.lang.isArray(A)){this.delimChar=null;}}var D=this.animSpeed;if((this.animHoriz||this.animVert)&&YAHOO.util.Anim){if(!YAHOO.lang.isNumber(D)||(D<0)){this.animSpeed=0.3;}if(!this._oAnim){this._oAnim=new YAHOO.util.Anim(this._elContent,{},this.animSpeed);}else{this._oAnim.duration=this.animSpeed;}}if(this.forceSelection&&A){}};YAHOO.widget.AutoComplete.prototype._initContainerHelperEls=function(){if(this.useShadow&&!this._elShadow){var A=document.createElement("div");A.className="yui-ac-shadow";A.style.width=0;A.style.height=0;this._elShadow=this._elContainer.appendChild(A);}if(this.useIFrame&&!this._elIFrame){var B=document.createElement("iframe");B.src=this._iFrameSrc;B.frameBorder=0;B.scrolling="no";B.style.position="absolute";B.style.width=0;B.style.height=0;B.style.padding=0;B.tabIndex=-1;B.role="presentation";B.title="Presentational iframe shim";this._elIFrame=this._elContainer.appendChild(B);}};YAHOO.widget.AutoComplete.prototype._initContainerEl=function(){YAHOO.util.Dom.addClass(this._elContainer,"yui-ac-container");if(!this._elContent){var C=document.createElement("div");C.className="yui-ac-content";C.style.display="none";this._elContent=this._elContainer.appendChild(C);var B=document.createElement("div");B.className="yui-ac-hd";B.style.display="none";this._elHeader=this._elContent.appendChild(B);var D=document.createElement("div");D.className="yui-ac-bd";this._elBody=this._elContent.appendChild(D);var A=document.createElement("div");A.className="yui-ac-ft";A.style.display="none";this._elFooter=this._elContent.appendChild(A);}else{}};YAHOO.widget.AutoComplete.prototype._initListEl=function(){var C=this.maxResultsDisplayed,A=this._elList||document.createElement("ul"),B;while(A.childNodes.length<C){B=document.createElement("li");B.style.display="none";B._nItemIndex=A.childNodes.length;A.appendChild(B);}if(!this._elList){var D=this._elBody;YAHOO.util.Event.purgeElement(D,true);D.innerHTML="";this._elList=D.appendChild(A);}this._elBody.style.display="";};YAHOO.widget.AutoComplete.prototype._focus=function(){var A=this;setTimeout(function(){try{A._elTextbox.focus();}catch(B){}},0);};YAHOO.widget.AutoComplete.prototype._enableIntervalDetection=function(){var A=this;if(!A._queryInterval&&A.queryInterval){A._queryInterval=setInterval(function(){A._onInterval();},A.queryInterval);}};YAHOO.widget.AutoComplete.prototype.enableIntervalDetection=YAHOO.widget.AutoComplete.prototype._enableIntervalDetection;YAHOO.widget.AutoComplete.prototype._onInterval=function(){var A=this._elTextbox.value;var B=this._sLastTextboxValue;if(A!=B){this._sLastTextboxValue=A;this._sendQuery(A);}};YAHOO.widget.AutoComplete.prototype._clearInterval=function(){if(this._queryInterval){clearInterval(this._queryInterval);this._queryInterval=null;}};YAHOO.widget.AutoComplete.prototype._isIgnoreKey=function(A){if((A==9)||(A==13)||(A==16)||(A==17)||(A>=18&&A<=20)||(A==27)||(A>=33&&A<=35)||(A>=36&&A<=40)||(A>=44&&A<=45)||(A==229)){return true;}return false;};YAHOO.widget.AutoComplete.prototype._sendQuery=function(D){if(this.minQueryLength<0){this._toggleContainer(false);return;}if(this.delimChar){var A=this._extractQuery(D);D=A.query;this._sPastSelections=A.previous;}if((D&&(D.length<this.minQueryLength))||(!D&&this.minQueryLength>0)){if(this._nDelayID!=-1){clearTimeout(this._nDelayID);}this._toggleContainer(false);return;}D=encodeURIComponent(D);this._nDelayID=-1;if(this.dataSource.queryMatchSubset||this.queryMatchSubset){var C=this.getSubsetMatches(D);if(C){this.handleResponse(D,C,{query:D});return;
+}}if(this.dataSource.responseStripAfter){this.dataSource.doBeforeParseData=this.preparseRawResponse;}if(this.applyLocalFilter){this.dataSource.doBeforeCallback=this.filterResults;}var B=this.generateRequest(D);this.dataRequestEvent.fire(this,D,B);this.dataSource.sendRequest(B,{success:this.handleResponse,failure:this.handleResponse,scope:this,argument:{query:D}});};YAHOO.widget.AutoComplete.prototype._populateListItem=function(B,A,C){B.innerHTML=this.formatResult(A,C,B._sResultMatch);};YAHOO.widget.AutoComplete.prototype._populateList=function(K,F,C){if(this._nTypeAheadDelayID!=-1){clearTimeout(this._nTypeAheadDelayID);}K=(C&&C.query)?C.query:K;var H=this.doBeforeLoadData(K,F,C);if(H&&!F.error){this.dataReturnEvent.fire(this,K,F.results);if(this._bFocused){var M=decodeURIComponent(K);this._sCurQuery=M;this._bItemSelected=false;var R=F.results,A=Math.min(R.length,this.maxResultsDisplayed),J=(this.dataSource.responseSchema.fields)?(this.dataSource.responseSchema.fields[0].key||this.dataSource.responseSchema.fields[0]):0;if(A>0){if(!this._elList||(this._elList.childNodes.length<A)){this._initListEl();}this._initContainerHelperEls();var I=this._elList.childNodes;for(var Q=A-1;Q>=0;Q--){var P=I[Q],E=R[Q];if(this.resultTypeList){var B=[];B[0]=(YAHOO.lang.isString(E))?E:E[J]||E[this.key];var L=this.dataSource.responseSchema.fields;if(YAHOO.lang.isArray(L)&&(L.length>1)){for(var N=1,S=L.length;N<S;N++){B[B.length]=E[L[N].key||L[N]];}}else{if(YAHOO.lang.isArray(E)){B=E;}else{if(YAHOO.lang.isString(E)){B=[E];}else{B[1]=E;}}}E=B;}P._sResultMatch=(YAHOO.lang.isString(E))?E:(YAHOO.lang.isArray(E))?E[0]:(E[J]||"");P._oResultData=E;this._populateListItem(P,E,M);P.style.display="";}if(A<I.length){var G;for(var O=I.length-1;O>=A;O--){G=I[O];G.style.display="none";}}this._nDisplayedItems=A;this.containerPopulateEvent.fire(this,K,R);if(this.autoHighlight){var D=this._elList.firstChild;this._toggleHighlight(D,"to");this.itemArrowToEvent.fire(this,D);this._typeAhead(D,K);}else{this._toggleHighlight(this._elCurListItem,"from");}H=this._doBeforeExpandContainer(this._elTextbox,this._elContainer,K,R);this._toggleContainer(H);}else{this._toggleContainer(false);}return;}}else{this.dataErrorEvent.fire(this,K,F);}};YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer=function(D,A,C,B){if(this.autoSnapContainer){this.snapContainer();}return this.doBeforeExpandContainer(D,A,C,B);};YAHOO.widget.AutoComplete.prototype._clearSelection=function(){var A=(this.delimChar)?this._extractQuery(this._elTextbox.value):{previous:"",query:this._elTextbox.value};this._elTextbox.value=A.previous;this.selectionEnforceEvent.fire(this,A.query);};YAHOO.widget.AutoComplete.prototype._textMatchesOption=function(){var A=null;for(var B=0;B<this._nDisplayedItems;B++){var C=this._elList.childNodes[B];var D=(""+C._sResultMatch).toLowerCase();if(D==this._sCurQuery.toLowerCase()){A=C;break;}}return(A);};YAHOO.widget.AutoComplete.prototype._typeAhead=function(B,D){if(!this.typeAhead||(this._nKeyCode==8)){return;}var A=this,C=this._elTextbox;if(C.setSelectionRange||C.createTextRange){this._nTypeAheadDelayID=setTimeout(function(){var F=C.value.length;A._updateValue(B);var G=C.value.length;A._selectText(C,F,G);var E=C.value.substr(F,G);A.typeAheadEvent.fire(A,D,E);},(this.typeAheadDelay*1000));}};YAHOO.widget.AutoComplete.prototype._selectText=function(D,A,B){if(D.setSelectionRange){D.setSelectionRange(A,B);}else{if(D.createTextRange){var C=D.createTextRange();C.moveStart("character",A);C.moveEnd("character",B-D.value.length);C.select();}else{D.select();}}};YAHOO.widget.AutoComplete.prototype._extractQuery=function(H){var C=this.delimChar,F=-1,G,E,B=C.length-1,D;for(;B>=0;B--){G=H.lastIndexOf(C[B]);if(G>F){F=G;}}if(C[B]==" "){for(var A=C.length-1;A>=0;A--){if(H[F-1]==C[A]){F--;break;}}}if(F>-1){E=F+1;while(H.charAt(E)==" "){E+=1;}D=H.substring(0,E);H=H.substr(E);}else{D="";}return{previous:D,query:H};};YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers=function(D){var E=this._elContent.offsetWidth+"px";var B=this._elContent.offsetHeight+"px";if(this.useIFrame&&this._elIFrame){var C=this._elIFrame;if(D){C.style.width=E;C.style.height=B;C.style.padding="";}else{C.style.width=0;C.style.height=0;C.style.padding=0;}}if(this.useShadow&&this._elShadow){var A=this._elShadow;if(D){A.style.width=E;A.style.height=B;}else{A.style.width=0;A.style.height=0;}}};YAHOO.widget.AutoComplete.prototype._toggleContainer=function(I){var D=this._elContainer;if(this.alwaysShowContainer&&this._bContainerOpen){return;}if(!I){this._toggleHighlight(this._elCurListItem,"from");this._nDisplayedItems=0;this._sCurQuery=null;if(this._elContent.style.display=="none"){return;}}var A=this._oAnim;if(A&&A.getEl()&&(this.animHoriz||this.animVert)){if(A.isAnimated()){A.stop(true);}var G=this._elContent.cloneNode(true);D.appendChild(G);G.style.top="-9000px";G.style.width="";G.style.height="";G.style.display="";var F=G.offsetWidth;var C=G.offsetHeight;var B=(this.animHoriz)?0:F;var E=(this.animVert)?0:C;A.attributes=(I)?{width:{to:F},height:{to:C}}:{width:{to:B},height:{to:E}};if(I&&!this._bContainerOpen){this._elContent.style.width=B+"px";this._elContent.style.height=E+"px";}else{this._elContent.style.width=F+"px";this._elContent.style.height=C+"px";}D.removeChild(G);G=null;var H=this;var J=function(){A.onComplete.unsubscribeAll();if(I){H._toggleContainerHelpers(true);H._bContainerOpen=I;H.containerExpandEvent.fire(H);}else{H._elContent.style.display="none";H._bContainerOpen=I;H.containerCollapseEvent.fire(H);}};this._toggleContainerHelpers(false);this._elContent.style.display="";A.onComplete.subscribe(J);A.animate();}else{if(I){this._elContent.style.display="";this._toggleContainerHelpers(true);this._bContainerOpen=I;this.containerExpandEvent.fire(this);}else{this._toggleContainerHelpers(false);this._elContent.style.display="none";this._bContainerOpen=I;this.containerCollapseEvent.fire(this);}}};YAHOO.widget.AutoComplete.prototype._toggleHighlight=function(A,C){if(A){var B=this.highlightClassName;
+if(this._elCurListItem){YAHOO.util.Dom.removeClass(this._elCurListItem,B);this._elCurListItem=null;}if((C=="to")&&B){YAHOO.util.Dom.addClass(A,B);this._elCurListItem=A;}}};YAHOO.widget.AutoComplete.prototype._togglePrehighlight=function(B,C){var A=this.prehighlightClassName;if(this._elCurPrehighlightItem){YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem,A);}if(B==this._elCurListItem){return;}if((C=="mouseover")&&A){YAHOO.util.Dom.addClass(B,A);this._elCurPrehighlightItem=B;}else{YAHOO.util.Dom.removeClass(B,A);}};YAHOO.widget.AutoComplete.prototype._updateValue=function(C){if(!this.suppressInputUpdate){var F=this._elTextbox;var E=(this.delimChar)?(this.delimChar[0]||this.delimChar):null;var B=C._sResultMatch;var D="";if(E){D=this._sPastSelections;D+=B+E;if(E!=" "){D+=" ";}}else{D=B;}F.value=D;if(F.type=="textarea"){F.scrollTop=F.scrollHeight;}var A=F.value.length;this._selectText(F,A,A);this._elCurListItem=C;}};YAHOO.widget.AutoComplete.prototype._selectItem=function(A){this._bItemSelected=true;this._updateValue(A);this._sPastSelections=this._elTextbox.value;this._clearInterval();this.itemSelectEvent.fire(this,A,A._oResultData);this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype._jumpSelection=function(){if(this._elCurListItem){this._selectItem(this._elCurListItem);}else{this._toggleContainer(false);}};YAHOO.widget.AutoComplete.prototype._moveSelection=function(G){if(this._bContainerOpen){var H=this._elCurListItem,D=-1;if(H){D=H._nItemIndex;}var E=(G==40)?(D+1):(D-1);if(E<-2||E>=this._nDisplayedItems){return;}if(H){this._toggleHighlight(H,"from");this.itemArrowFromEvent.fire(this,H);}if(E==-1){if(this.delimChar){this._elTextbox.value=this._sPastSelections+this._sCurQuery;}else{this._elTextbox.value=this._sCurQuery;}return;}if(E==-2){this._toggleContainer(false);return;}var F=this._elList.childNodes[E],B=this._elContent,C=YAHOO.util.Dom.getStyle(B,"overflow"),I=YAHOO.util.Dom.getStyle(B,"overflowY"),A=((C=="auto")||(C=="scroll")||(I=="auto")||(I=="scroll"));if(A&&(E>-1)&&(E<this._nDisplayedItems)){if(G==40){if((F.offsetTop+F.offsetHeight)>(B.scrollTop+B.offsetHeight)){B.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}else{if((F.offsetTop+F.offsetHeight)<B.scrollTop){B.scrollTop=F.offsetTop;}}}else{if(F.offsetTop<B.scrollTop){this._elContent.scrollTop=F.offsetTop;}else{if(F.offsetTop>(B.scrollTop+B.offsetHeight)){this._elContent.scrollTop=(F.offsetTop+F.offsetHeight)-B.offsetHeight;}}}}this._toggleHighlight(F,"to");this.itemArrowToEvent.fire(this,F);if(this.typeAhead){this._updateValue(F);}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseover=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseover");}else{C._toggleHighlight(D,"to");}C.itemMouseOverEvent.fire(C,D);break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=true;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseout=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":if(C.prehighlightClassName){C._togglePrehighlight(D,"mouseout");}else{C._toggleHighlight(D,"from");}C.itemMouseOutEvent.fire(C,D);break;case"ul":C._toggleHighlight(C._elCurListItem,"to");break;case"div":if(YAHOO.util.Dom.hasClass(D,"yui-ac-container")){C._bOverContainer=false;return;}break;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerClick=function(A,C){var D=YAHOO.util.Event.getTarget(A);var B=D.nodeName.toLowerCase();while(D&&(B!="table")){switch(B){case"body":return;case"li":C._toggleHighlight(D,"to");C._selectItem(D);return;default:break;}D=D.parentNode;if(D){B=D.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerScroll=function(A,B){B._focus();};YAHOO.widget.AutoComplete.prototype._onContainerResize=function(A,B){B._toggleContainerHelpers(B._bContainerOpen);};YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown=function(A,B){var C=A.keyCode;if(B._nTypeAheadDelayID!=-1){clearTimeout(B._nTypeAheadDelayID);}switch(C){case 9:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B.delimChar&&(B._nKeyCode!=C)){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(!YAHOO.env.ua.opera&&(navigator.userAgent.toLowerCase().indexOf("mac")==-1)||(YAHOO.env.ua.webkit>420)){if(B._elCurListItem){if(B._nKeyCode!=C){if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);}}B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 27:B._toggleContainer(false);return;case 39:B._jumpSelection();break;case 38:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;case 40:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);B._moveSelection(C);}break;default:B._bItemSelected=false;B._toggleHighlight(B._elCurListItem,"from");B.textboxKeyEvent.fire(B,C);break;}if(C===18){B._enableIntervalDetection();}B._nKeyCode=C;};YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress=function(A,B){var C=A.keyCode;if(YAHOO.env.ua.opera||(navigator.userAgent.toLowerCase().indexOf("mac")!=-1)&&(YAHOO.env.ua.webkit<420)){switch(C){case 9:if(B._bContainerOpen){if(B.delimChar){YAHOO.util.Event.stopEvent(A);}if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;case 13:if(B._bContainerOpen){YAHOO.util.Event.stopEvent(A);if(B._elCurListItem){B._selectItem(B._elCurListItem);}else{B._toggleContainer(false);}}break;default:break;}}else{if(C==229){B._enableIntervalDetection();}}};YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp=function(A,C){var B=this.value;C._initProps();var D=A.keyCode;if(C._isIgnoreKey(D)){return;
+}if(C._nDelayID!=-1){clearTimeout(C._nDelayID);}C._nDelayID=setTimeout(function(){C._sendQuery(B);},(C.queryDelay*1000));};YAHOO.widget.AutoComplete.prototype._onTextboxFocus=function(A,B){if(!B._bFocused){B._elTextbox.setAttribute("autocomplete","off");B._bFocused=true;B._sInitInputValue=B._elTextbox.value;B.textboxFocusEvent.fire(B);}};YAHOO.widget.AutoComplete.prototype._onTextboxBlur=function(A,C){if(!C._bOverContainer||(C._nKeyCode==9)){if(!C._bItemSelected){var B=C._textMatchesOption();if(!C._bContainerOpen||(C._bContainerOpen&&(B===null))){if(C.forceSelection){C._clearSelection();}else{C.unmatchedItemSelectEvent.fire(C,C._sCurQuery);}}else{if(C.forceSelection){C._selectItem(B);}}}C._clearInterval();C._bFocused=false;if(C._sInitInputValue!==C._elTextbox.value){C.textboxChangeEvent.fire(C);}C.textboxBlurEvent.fire(C);C._toggleContainer(false);}else{C._focus();}};YAHOO.widget.AutoComplete.prototype._onWindowUnload=function(A,B){if(B&&B._elTextbox&&B.allowBrowserAutocomplete){B._elTextbox.setAttribute("autocomplete","on");}};YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery=function(A){return this.generateRequest(A);};YAHOO.widget.AutoComplete.prototype.getListItems=function(){var C=[],B=this._elList.childNodes;for(var A=B.length-1;A>=0;A--){C[A]=B[A];}return C;};YAHOO.widget.AutoComplete._cloneObject=function(D){if(!YAHOO.lang.isValue(D)){return D;}var F={};if(YAHOO.lang.isFunction(D)){F=D;}else{if(YAHOO.lang.isArray(D)){var E=[];for(var C=0,B=D.length;C<B;C++){E[C]=YAHOO.widget.AutoComplete._cloneObject(D[C]);}F=E;}else{if(YAHOO.lang.isObject(D)){for(var A in D){if(YAHOO.lang.hasOwnProperty(D,A)){if(YAHOO.lang.isValue(D[A])&&YAHOO.lang.isObject(D[A])||YAHOO.lang.isArray(D[A])){F[A]=YAHOO.widget.AutoComplete._cloneObject(D[A]);}else{F[A]=D[A];}}}}else{F=D;}}}return F;};YAHOO.register("autocomplete",YAHOO.widget.AutoComplete,{version:"2.8.2r1",build:"7"});/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+*/
+(function(){YAHOO.util.Config=function(D){if(D){this.init(D);}};var B=YAHOO.lang,C=YAHOO.util.CustomEvent,A=YAHOO.util.Config;A.CONFIG_CHANGED_EVENT="configChanged";A.BOOLEAN_TYPE="boolean";A.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(D){this.owner=D;this.configChangedEvent=this.createEvent(A.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=C.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(D){return(typeof D==A.BOOLEAN_TYPE);},checkNumber:function(D){return(!isNaN(D));},fireEvent:function(D,F){var E=this.config[D];if(E&&E.event){E.event.fire(F);}},addProperty:function(E,D){E=E.toLowerCase();this.config[E]=D;D.event=this.createEvent(E,{scope:this.owner});D.event.signature=C.LIST;D.key=E;if(D.handler){D.event.subscribe(D.handler,this.owner);}this.setProperty(E,D.value,true);if(!D.suppressEvent){this.queueProperty(E,D.value);}},getConfig:function(){var D={},F=this.config,G,E;for(G in F){if(B.hasOwnProperty(F,G)){E=F[G];if(E&&E.event){D[G]=E.value;}}}return D;},getProperty:function(D){var E=this.config[D.toLowerCase()];if(E&&E.event){return E.value;}else{return undefined;}},resetProperty:function(D){D=D.toLowerCase();var E=this.config[D];if(E&&E.event){if(this.initialConfig[D]&&!B.isUndefined(this.initialConfig[D])){this.setProperty(D,this.initialConfig[D]);return true;}}else{return false;}},setProperty:function(E,G,D){var F;E=E.toLowerCase();if(this.queueInProgress&&!D){this.queueProperty(E,G);return true;}else{F=this.config[E];if(F&&F.event){if(F.validator&&!F.validator(G)){return false;}else{F.value=G;if(!D){this.fireEvent(E,G);this.configChangedEvent.fire([E,G]);}return true;}}else{return false;}}},queueProperty:function(S,P){S=S.toLowerCase();var R=this.config[S],K=false,J,G,H,I,O,Q,F,M,N,D,L,T,E;if(R&&R.event){if(!B.isUndefined(P)&&R.validator&&!R.validator(P)){return false;}else{if(!B.isUndefined(P)){R.value=P;}else{P=R.value;}K=false;J=this.eventQueue.length;for(L=0;L<J;L++){G=this.eventQueue[L];if(G){H=G[0];I=G[1];if(H==S){this.eventQueue[L]=null;this.eventQueue.push([S,(!B.isUndefined(P)?P:I)]);K=true;break;}}}if(!K&&!B.isUndefined(P)){this.eventQueue.push([S,P]);}}if(R.supercedes){O=R.supercedes.length;for(T=0;T<O;T++){Q=R.supercedes[T];F=this.eventQueue.length;for(E=0;E<F;E++){M=this.eventQueue[E];if(M){N=M[0];D=M[1];if(N==Q.toLowerCase()){this.eventQueue.push([N,D]);this.eventQueue[E]=null;break;}}}}}return true;}else{return false;}},refireEvent:function(D){D=D.toLowerCase();var E=this.config[D];if(E&&E.event&&!B.isUndefined(E.value)){if(this.queueInProgress){this.queueProperty(D);}else{this.fireEvent(D,E.value);}}},applyConfig:function(D,G){var F,E;if(G){E={};for(F in D){if(B.hasOwnProperty(D,F)){E[F.toLowerCase()]=D[F];}}this.initialConfig=E;}for(F in D){if(B.hasOwnProperty(D,F)){this.queueProperty(F,D[F]);}}},refresh:function(){var D;for(D in this.config){if(B.hasOwnProperty(this.config,D)){this.refireEvent(D);}}},fireQueue:function(){var E,H,D,G,F;this.queueInProgress=true;for(E=0;E<this.eventQueue.length;E++){H=this.eventQueue[E];if(H){D=H[0];G=H[1];F=this.config[D];F.value=G;this.eventQueue[E]=null;this.fireEvent(D,G);}}this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(D,E,G,H){var F=this.config[D.toLowerCase()];if(F&&F.event){if(!A.alreadySubscribed(F.event,E,G)){F.event.subscribe(E,G,H);}return true;}else{return false;}},unsubscribeFromConfigEvent:function(D,E,G){var F=this.config[D.toLowerCase()];if(F&&F.event){return F.event.unsubscribe(E,G);}else{return false;}},toString:function(){var D="Config";if(this.owner){D+=" ["+this.owner.toString()+"]";}return D;},outputEventQueue:function(){var D="",G,E,F=this.eventQueue.length;for(E=0;E<F;E++){G=this.eventQueue[E];if(G){D+=G[0]+"="+G[1]+", ";}}return D;},destroy:function(){var E=this.config,D,F;for(D in E){if(B.hasOwnProperty(E,D)){F=E[D];F.event.unsubscribeAll();F.event=null;}}this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};A.alreadySubscribed=function(E,H,I){var F=E.subscribers.length,D,G;if(F>0){G=F-1;do{D=E.subscribers[G];if(D&&D.obj==I&&D.fn==H){return true;}}while(G--);}return false;};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(R,Q){if(R){this.init(R,Q);}else{}};var F=YAHOO.util.Dom,D=YAHOO.util.Config,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,I=YAHOO.env.ua,H,P,O,E,A={"BEFORE_INIT":"beforeInit","INIT":"init","APPEND":"append","BEFORE_RENDER":"beforeRender","RENDER":"render","CHANGE_HEADER":"changeHeader","CHANGE_BODY":"changeBody","CHANGE_FOOTER":"changeFooter","CHANGE_CONTENT":"changeContent","DESTROY":"destroy","BEFORE_SHOW":"beforeShow","SHOW":"show","BEFORE_HIDE":"beforeHide","HIDE":"hide"},J={"VISIBLE":{key:"visible",value:true,validator:YAHOO.lang.isBoolean},"EFFECT":{key:"effect",suppressEvent:true,supercedes:["visible"]},"MONITOR_RESIZE":{key:"monitorresize",value:true},"APPEND_TO_DOCUMENT_BODY":{key:"appendtodocumentbody",value:false}};G.IMG_ROOT=null;G.IMG_ROOT_SSL=null;G.CSS_MODULE="yui-module";G.CSS_HEADER="hd";G.CSS_BODY="bd";G.CSS_FOOTER="ft";G.RESIZE_MONITOR_SECURE_URL="javascript:false;";G.RESIZE_MONITOR_BUFFER=1;G.textResizeEvent=new M("textResize");G.forceDocumentRedraw=function(){var Q=document.documentElement;if(Q){Q.className+=" ";Q.className=YAHOO.lang.trim(Q.className);}};function L(){if(!H){H=document.createElement("div");H.innerHTML=('<div class="'+G.CSS_HEADER+'"></div>'+'<div class="'+G.CSS_BODY+'"></div><div class="'+G.CSS_FOOTER+'"></div>');P=H.firstChild;O=P.nextSibling;E=O.nextSibling;}return H;}function K(){if(!P){L();}return(P.cloneNode(false));}function B(){if(!O){L();}return(O.cloneNode(false));}function C(){if(!E){L();}return(E.cloneNode(false));}G.prototype={constructor:G,element:null,header:null,body:null,footer:null,id:null,imageRoot:G.IMG_ROOT,initEvents:function(){var Q=M.LIST;
+this.beforeInitEvent=this.createEvent(A.BEFORE_INIT);this.beforeInitEvent.signature=Q;this.initEvent=this.createEvent(A.INIT);this.initEvent.signature=Q;this.appendEvent=this.createEvent(A.APPEND);this.appendEvent.signature=Q;this.beforeRenderEvent=this.createEvent(A.BEFORE_RENDER);this.beforeRenderEvent.signature=Q;this.renderEvent=this.createEvent(A.RENDER);this.renderEvent.signature=Q;this.changeHeaderEvent=this.createEvent(A.CHANGE_HEADER);this.changeHeaderEvent.signature=Q;this.changeBodyEvent=this.createEvent(A.CHANGE_BODY);this.changeBodyEvent.signature=Q;this.changeFooterEvent=this.createEvent(A.CHANGE_FOOTER);this.changeFooterEvent.signature=Q;this.changeContentEvent=this.createEvent(A.CHANGE_CONTENT);this.changeContentEvent.signature=Q;this.destroyEvent=this.createEvent(A.DESTROY);this.destroyEvent.signature=Q;this.beforeShowEvent=this.createEvent(A.BEFORE_SHOW);this.beforeShowEvent.signature=Q;this.showEvent=this.createEvent(A.SHOW);this.showEvent.signature=Q;this.beforeHideEvent=this.createEvent(A.BEFORE_HIDE);this.beforeHideEvent.signature=Q;this.hideEvent=this.createEvent(A.HIDE);this.hideEvent.signature=Q;},platform:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("windows")!=-1||Q.indexOf("win32")!=-1){return"windows";}else{if(Q.indexOf("macintosh")!=-1){return"mac";}else{return false;}}}(),browser:function(){var Q=navigator.userAgent.toLowerCase();if(Q.indexOf("opera")!=-1){return"opera";}else{if(Q.indexOf("msie 7")!=-1){return"ie7";}else{if(Q.indexOf("msie")!=-1){return"ie";}else{if(Q.indexOf("safari")!=-1){return"safari";}else{if(Q.indexOf("gecko")!=-1){return"gecko";}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf("https")===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addProperty(J.VISIBLE.key,{handler:this.configVisible,value:J.VISIBLE.value,validator:J.VISIBLE.validator});this.cfg.addProperty(J.EFFECT.key,{suppressEvent:J.EFFECT.suppressEvent,supercedes:J.EFFECT.supercedes});this.cfg.addProperty(J.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:J.MONITOR_RESIZE.value});this.cfg.addProperty(J.APPEND_TO_DOCUMENT_BODY.key,{value:J.APPEND_TO_DOCUMENT_BODY.value});},init:function(V,U){var S,W;this.initEvents();this.beforeInitEvent.fire(G);this.cfg=new D(this);if(this.isSecure){this.imageRoot=G.IMG_ROOT_SSL;}if(typeof V=="string"){S=V;V=document.getElementById(V);if(!V){V=(L()).cloneNode(false);V.id=S;}}this.id=F.generateId(V);this.element=V;W=this.element.firstChild;if(W){var R=false,Q=false,T=false;do{if(1==W.nodeType){if(!R&&F.hasClass(W,G.CSS_HEADER)){this.header=W;R=true;}else{if(!Q&&F.hasClass(W,G.CSS_BODY)){this.body=W;Q=true;}else{if(!T&&F.hasClass(W,G.CSS_FOOTER)){this.footer=W;T=true;}}}}}while((W=W.nextSibling));}this.initDefaultConfig();F.addClass(this.element,G.CSS_MODULE);if(U){this.cfg.applyConfig(U,true);}if(!D.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(G);},initResizeMonitor:function(){var R=(I.gecko&&this.platform=="windows");if(R){var Q=this;setTimeout(function(){Q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var Q,S,U;function W(){G.textResizeEvent.fire();}if(!I.opera){S=F.get("_yuiResizeMonitor");var V=this._supportsCWResize();if(!S){S=document.createElement("iframe");if(this.isSecure&&G.RESIZE_MONITOR_SECURE_URL&&I.ie){S.src=G.RESIZE_MONITOR_SECURE_URL;}if(!V){U=["<html><head><script ",'type="text/javascript">',"window.onresize=function(){window.parent.","YAHOO.widget.Module.textResizeEvent.","fire();};<","/script></head>","<body></body></html>"].join("");S.src="data:text/html;charset=utf-8,"+encodeURIComponent(U);}S.id="_yuiResizeMonitor";S.title="Text Resize Monitor";S.style.position="absolute";S.style.visibility="hidden";var R=document.body,T=R.firstChild;if(T){R.insertBefore(S,T);}else{R.appendChild(S);}S.style.backgroundColor="transparent";S.style.borderWidth="0";S.style.width="2em";S.style.height="2em";S.style.left="0";S.style.top=(-1*(S.offsetHeight+G.RESIZE_MONITOR_BUFFER))+"px";S.style.visibility="visible";if(I.webkit){Q=S.contentWindow.document;Q.open();Q.close();}}if(S&&S.contentWindow){G.textResizeEvent.subscribe(this.onDomResize,this,true);if(!G.textResizeInitialized){if(V){if(!N.on(S.contentWindow,"resize",W)){N.on(S,"resize",W);}}G.textResizeInitialized=true;}this.resizeMonitor=S;}}},_supportsCWResize:function(){var Q=true;if(I.gecko&&I.gecko<=1.8){Q=false;}return Q;},onDomResize:function(S,R){var Q=-1*(this.resizeMonitor.offsetHeight+G.RESIZE_MONITOR_BUFFER);this.resizeMonitor.style.top=Q+"px";this.resizeMonitor.style.left="0";},setHeader:function(R){var Q=this.header||(this.header=K());if(R.nodeName){Q.innerHTML="";Q.appendChild(R);}else{Q.innerHTML=R;}if(this._rendered){this._renderHeader();}this.changeHeaderEvent.fire(R);this.changeContentEvent.fire();},appendToHeader:function(R){var Q=this.header||(this.header=K());Q.appendChild(R);this.changeHeaderEvent.fire(R);this.changeContentEvent.fire();},setBody:function(R){var Q=this.body||(this.body=B());if(R.nodeName){Q.innerHTML="";Q.appendChild(R);}else{Q.innerHTML=R;}if(this._rendered){this._renderBody();}this.changeBodyEvent.fire(R);this.changeContentEvent.fire();},appendToBody:function(R){var Q=this.body||(this.body=B());Q.appendChild(R);this.changeBodyEvent.fire(R);this.changeContentEvent.fire();},setFooter:function(R){var Q=this.footer||(this.footer=C());if(R.nodeName){Q.innerHTML="";Q.appendChild(R);}else{Q.innerHTML=R;}if(this._rendered){this._renderFooter();}this.changeFooterEvent.fire(R);this.changeContentEvent.fire();},appendToFooter:function(R){var Q=this.footer||(this.footer=C());Q.appendChild(R);this.changeFooterEvent.fire(R);this.changeContentEvent.fire();},render:function(S,Q){var T=this;function R(U){if(typeof U=="string"){U=document.getElementById(U);}if(U){T._addToParent(U,T.element);T.appendEvent.fire();}}this.beforeRenderEvent.fire();
+if(!Q){Q=this.element;}if(S){R(S);}else{if(!F.inDocument(this.element)){return false;}}this._renderHeader(Q);this._renderBody(Q);this._renderFooter(Q);this._rendered=true;this.renderEvent.fire();return true;},_renderHeader:function(Q){Q=Q||this.element;if(this.header&&!F.inDocument(this.header)){var R=Q.firstChild;if(R){Q.insertBefore(this.header,R);}else{Q.appendChild(this.header);}}},_renderBody:function(Q){Q=Q||this.element;if(this.body&&!F.inDocument(this.body)){if(this.footer&&F.isAncestor(Q,this.footer)){Q.insertBefore(this.body,this.footer);}else{Q.appendChild(this.body);}}},_renderFooter:function(Q){Q=Q||this.element;if(this.footer&&!F.inDocument(this.footer)){Q.appendChild(this.footer);}},destroy:function(){var Q;if(this.element){N.purgeElement(this.element,true);Q=this.element.parentNode;}if(Q){Q.removeChild(this.element);}this.element=null;this.header=null;this.body=null;this.footer=null;G.textResizeEvent.unsubscribe(this.onDomResize,this);this.cfg.destroy();this.cfg=null;this.destroyEvent.fire();},show:function(){this.cfg.setProperty("visible",true);},hide:function(){this.cfg.setProperty("visible",false);},configVisible:function(R,Q,S){var T=Q[0];if(T){this.beforeShowEvent.fire();F.setStyle(this.element,"display","block");this.showEvent.fire();}else{this.beforeHideEvent.fire();F.setStyle(this.element,"display","none");this.hideEvent.fire();}},configMonitorResize:function(S,R,T){var Q=R[0];if(Q){this.initResizeMonitor();}else{G.textResizeEvent.unsubscribe(this.onDomResize,this,true);this.resizeMonitor=null;}},_addToParent:function(Q,R){if(!this.cfg.getProperty("appendtodocumentbody")&&Q===document.body&&Q.firstChild){Q.insertBefore(R,Q.firstChild);}else{Q.appendChild(R);}},toString:function(){return"Module "+this.id;}};YAHOO.lang.augmentProto(G,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Overlay=function(P,O){YAHOO.widget.Overlay.superclass.constructor.call(this,P,O);};var I=YAHOO.lang,M=YAHOO.util.CustomEvent,G=YAHOO.widget.Module,N=YAHOO.util.Event,F=YAHOO.util.Dom,D=YAHOO.util.Config,K=YAHOO.env.ua,B=YAHOO.widget.Overlay,H="subscribe",E="unsubscribe",C="contained",J,A={"BEFORE_MOVE":"beforeMove","MOVE":"move"},L={"X":{key:"x",validator:I.isNumber,suppressEvent:true,supercedes:["iframe"]},"Y":{key:"y",validator:I.isNumber,suppressEvent:true,supercedes:["iframe"]},"XY":{key:"xy",suppressEvent:true,supercedes:["iframe"]},"CONTEXT":{key:"context",suppressEvent:true,supercedes:["iframe"]},"FIXED_CENTER":{key:"fixedcenter",value:false,supercedes:["iframe","visible"]},"WIDTH":{key:"width",suppressEvent:true,supercedes:["context","fixedcenter","iframe"]},"HEIGHT":{key:"height",suppressEvent:true,supercedes:["context","fixedcenter","iframe"]},"AUTO_FILL_HEIGHT":{key:"autofillheight",supercedes:["height"],value:"body"},"ZINDEX":{key:"zindex",value:null},"CONSTRAIN_TO_VIEWPORT":{key:"constraintoviewport",value:false,validator:I.isBoolean,supercedes:["iframe","x","y","xy"]},"IFRAME":{key:"iframe",value:(K.ie==6?true:false),validator:I.isBoolean,supercedes:["zindex"]},"PREVENT_CONTEXT_OVERLAP":{key:"preventcontextoverlap",value:false,validator:I.isBoolean,supercedes:["constraintoviewport"]}};B.IFRAME_SRC="javascript:false;";B.IFRAME_OFFSET=3;B.VIEWPORT_OFFSET=10;B.TOP_LEFT="tl";B.TOP_RIGHT="tr";B.BOTTOM_LEFT="bl";B.BOTTOM_RIGHT="br";B.PREVENT_OVERLAP_X={"tltr":true,"blbr":true,"brbl":true,"trtl":true};B.PREVENT_OVERLAP_Y={"trbr":true,"tlbl":true,"bltl":true,"brtr":true};B.CSS_OVERLAY="yui-overlay";B.CSS_HIDDEN="yui-overlay-hidden";B.CSS_IFRAME="yui-overlay-iframe";B.STD_MOD_RE=/^\s*?(body|footer|header)\s*?$/i;B.windowScrollEvent=new M("windowScroll");B.windowResizeEvent=new M("windowResize");B.windowScrollHandler=function(P){var O=N.getTarget(P);if(!O||O===window||O===window.document){if(K.ie){if(!window.scrollEnd){window.scrollEnd=-1;}clearTimeout(window.scrollEnd);window.scrollEnd=setTimeout(function(){B.windowScrollEvent.fire();},1);}else{B.windowScrollEvent.fire();}}};B.windowResizeHandler=function(O){if(K.ie){if(!window.resizeEnd){window.resizeEnd=-1;}clearTimeout(window.resizeEnd);window.resizeEnd=setTimeout(function(){B.windowResizeEvent.fire();},100);}else{B.windowResizeEvent.fire();}};B._initialized=null;if(B._initialized===null){N.on(window,"scroll",B.windowScrollHandler);N.on(window,"resize",B.windowResizeHandler);B._initialized=true;}B._TRIGGER_MAP={"windowScroll":B.windowScrollEvent,"windowResize":B.windowResizeEvent,"textResize":G.textResizeEvent};YAHOO.extend(B,G,{CONTEXT_TRIGGERS:[],init:function(P,O){B.superclass.init.call(this,P);this.beforeInitEvent.fire(B);F.addClass(this.element,B.CSS_OVERLAY);if(O){this.cfg.applyConfig(O,true);}if(this.platform=="mac"&&K.gecko){if(!D.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)){this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);}if(!D.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)){this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true);}}this.initEvent.fire(B);},initEvents:function(){B.superclass.initEvents.call(this);var O=M.LIST;this.beforeMoveEvent=this.createEvent(A.BEFORE_MOVE);this.beforeMoveEvent.signature=O;this.moveEvent=this.createEvent(A.MOVE);this.moveEvent.signature=O;},initDefaultConfig:function(){B.superclass.initDefaultConfig.call(this);var O=this.cfg;O.addProperty(L.X.key,{handler:this.configX,validator:L.X.validator,suppressEvent:L.X.suppressEvent,supercedes:L.X.supercedes});O.addProperty(L.Y.key,{handler:this.configY,validator:L.Y.validator,suppressEvent:L.Y.suppressEvent,supercedes:L.Y.supercedes});O.addProperty(L.XY.key,{handler:this.configXY,suppressEvent:L.XY.suppressEvent,supercedes:L.XY.supercedes});O.addProperty(L.CONTEXT.key,{handler:this.configContext,suppressEvent:L.CONTEXT.suppressEvent,supercedes:L.CONTEXT.supercedes});O.addProperty(L.FIXED_CENTER.key,{handler:this.configFixedCenter,value:L.FIXED_CENTER.value,validator:L.FIXED_CENTER.validator,supercedes:L.FIXED_CENTER.supercedes});O.addProperty(L.WIDTH.key,{handler:this.configWidth,suppressEvent:L.WIDTH.suppressEvent,supercedes:L.WIDTH.supercedes});
+O.addProperty(L.HEIGHT.key,{handler:this.configHeight,suppressEvent:L.HEIGHT.suppressEvent,supercedes:L.HEIGHT.supercedes});O.addProperty(L.AUTO_FILL_HEIGHT.key,{handler:this.configAutoFillHeight,value:L.AUTO_FILL_HEIGHT.value,validator:this._validateAutoFill,supercedes:L.AUTO_FILL_HEIGHT.supercedes});O.addProperty(L.ZINDEX.key,{handler:this.configzIndex,value:L.ZINDEX.value});O.addProperty(L.CONSTRAIN_TO_VIEWPORT.key,{handler:this.configConstrainToViewport,value:L.CONSTRAIN_TO_VIEWPORT.value,validator:L.CONSTRAIN_TO_VIEWPORT.validator,supercedes:L.CONSTRAIN_TO_VIEWPORT.supercedes});O.addProperty(L.IFRAME.key,{handler:this.configIframe,value:L.IFRAME.value,validator:L.IFRAME.validator,supercedes:L.IFRAME.supercedes});O.addProperty(L.PREVENT_CONTEXT_OVERLAP.key,{value:L.PREVENT_CONTEXT_OVERLAP.value,validator:L.PREVENT_CONTEXT_OVERLAP.validator,supercedes:L.PREVENT_CONTEXT_OVERLAP.supercedes});},moveTo:function(O,P){this.cfg.setProperty("xy",[O,P]);},hideMacGeckoScrollbars:function(){F.replaceClass(this.element,"show-scrollbars","hide-scrollbars");},showMacGeckoScrollbars:function(){F.replaceClass(this.element,"hide-scrollbars","show-scrollbars");},_setDomVisibility:function(O){F.setStyle(this.element,"visibility",(O)?"visible":"hidden");var P=B.CSS_HIDDEN;if(O){F.removeClass(this.element,P);}else{F.addClass(this.element,P);}},configVisible:function(R,O,X){var Q=O[0],S=F.getStyle(this.element,"visibility"),Y=this.cfg.getProperty("effect"),V=[],U=(this.platform=="mac"&&K.gecko),g=D.alreadySubscribed,W,P,f,c,b,a,d,Z,T;if(S=="inherit"){f=this.element.parentNode;while(f.nodeType!=9&&f.nodeType!=11){S=F.getStyle(f,"visibility");if(S!="inherit"){break;}f=f.parentNode;}if(S=="inherit"){S="visible";}}if(Y){if(Y instanceof Array){Z=Y.length;for(c=0;c<Z;c++){W=Y[c];V[V.length]=W.effect(this,W.duration);}}else{V[V.length]=Y.effect(this,Y.duration);}}if(Q){if(U){this.showMacGeckoScrollbars();}if(Y){if(Q){if(S!="visible"||S===""){this.beforeShowEvent.fire();T=V.length;for(b=0;b<T;b++){P=V[b];if(b===0&&!g(P.animateInCompleteEvent,this.showEvent.fire,this.showEvent)){P.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true);}P.animateIn();}}}}else{if(S!="visible"||S===""){this.beforeShowEvent.fire();this._setDomVisibility(true);this.cfg.refireEvent("iframe");this.showEvent.fire();}else{this._setDomVisibility(true);}}}else{if(U){this.hideMacGeckoScrollbars();}if(Y){if(S=="visible"){this.beforeHideEvent.fire();T=V.length;for(a=0;a<T;a++){d=V[a];if(a===0&&!g(d.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)){d.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true);}d.animateOut();}}else{if(S===""){this._setDomVisibility(false);}}}else{if(S=="visible"||S===""){this.beforeHideEvent.fire();this._setDomVisibility(false);this.hideEvent.fire();}else{this._setDomVisibility(false);}}}},doCenterOnDOMEvent:function(){var O=this.cfg,P=O.getProperty("fixedcenter");if(O.getProperty("visible")){if(P&&(P!==C||this.fitsInViewport())){this.center();}}},fitsInViewport:function(){var S=B.VIEWPORT_OFFSET,Q=this.element,T=Q.offsetWidth,R=Q.offsetHeight,O=F.getViewportWidth(),P=F.getViewportHeight();return((T+S<O)&&(R+S<P));},configFixedCenter:function(S,Q,T){var U=Q[0],P=D.alreadySubscribed,R=B.windowResizeEvent,O=B.windowScrollEvent;if(U){this.center();if(!P(this.beforeShowEvent,this.center)){this.beforeShowEvent.subscribe(this.center);}if(!P(R,this.doCenterOnDOMEvent,this)){R.subscribe(this.doCenterOnDOMEvent,this,true);}if(!P(O,this.doCenterOnDOMEvent,this)){O.subscribe(this.doCenterOnDOMEvent,this,true);}}else{this.beforeShowEvent.unsubscribe(this.center);R.unsubscribe(this.doCenterOnDOMEvent,this);O.unsubscribe(this.doCenterOnDOMEvent,this);}},configHeight:function(R,P,S){var O=P[0],Q=this.element;F.setStyle(Q,"height",O);this.cfg.refireEvent("iframe");},configAutoFillHeight:function(T,S,P){var V=S[0],Q=this.cfg,U="autofillheight",W="height",R=Q.getProperty(U),O=this._autoFillOnHeightChange;Q.unsubscribeFromConfigEvent(W,O);G.textResizeEvent.unsubscribe(O);this.changeContentEvent.unsubscribe(O);if(R&&V!==R&&this[R]){F.setStyle(this[R],W,"");}if(V){V=I.trim(V.toLowerCase());Q.subscribeToConfigEvent(W,O,this[V],this);G.textResizeEvent.subscribe(O,this[V],this);this.changeContentEvent.subscribe(O,this[V],this);Q.setProperty(U,V,true);}},configWidth:function(R,O,S){var Q=O[0],P=this.element;F.setStyle(P,"width",Q);this.cfg.refireEvent("iframe");},configzIndex:function(Q,O,R){var S=O[0],P=this.element;if(!S){S=F.getStyle(P,"zIndex");if(!S||isNaN(S)){S=0;}}if(this.iframe||this.cfg.getProperty("iframe")===true){if(S<=0){S=1;}}F.setStyle(P,"zIndex",S);this.cfg.setProperty("zIndex",S,true);if(this.iframe){this.stackIframe();}},configXY:function(Q,P,R){var T=P[0],O=T[0],S=T[1];this.cfg.setProperty("x",O);this.cfg.setProperty("y",S);this.beforeMoveEvent.fire([O,S]);O=this.cfg.getProperty("x");S=this.cfg.getProperty("y");this.cfg.refireEvent("iframe");this.moveEvent.fire([O,S]);},configX:function(Q,P,R){var O=P[0],S=this.cfg.getProperty("y");this.cfg.setProperty("x",O,true);this.cfg.setProperty("y",S,true);this.beforeMoveEvent.fire([O,S]);O=this.cfg.getProperty("x");S=this.cfg.getProperty("y");F.setX(this.element,O,true);this.cfg.setProperty("xy",[O,S],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([O,S]);},configY:function(Q,P,R){var O=this.cfg.getProperty("x"),S=P[0];this.cfg.setProperty("x",O,true);this.cfg.setProperty("y",S,true);this.beforeMoveEvent.fire([O,S]);O=this.cfg.getProperty("x");S=this.cfg.getProperty("y");F.setY(this.element,S,true);this.cfg.setProperty("xy",[O,S],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([O,S]);},showIframe:function(){var P=this.iframe,O;if(P){O=this.element.parentNode;if(O!=P.parentNode){this._addToParent(O,P);}P.style.display="block";}},hideIframe:function(){if(this.iframe){this.iframe.style.display="none";}},syncIframe:function(){var O=this.iframe,Q=this.element,S=B.IFRAME_OFFSET,P=(S*2),R;if(O){O.style.width=(Q.offsetWidth+P+"px");
+O.style.height=(Q.offsetHeight+P+"px");R=this.cfg.getProperty("xy");if(!I.isArray(R)||(isNaN(R[0])||isNaN(R[1]))){this.syncPosition();R=this.cfg.getProperty("xy");}F.setXY(O,[(R[0]-S),(R[1]-S)]);}},stackIframe:function(){if(this.iframe){var O=F.getStyle(this.element,"zIndex");if(!YAHOO.lang.isUndefined(O)&&!isNaN(O)){F.setStyle(this.iframe,"zIndex",(O-1));}}},configIframe:function(R,Q,S){var O=Q[0];function T(){var V=this.iframe,W=this.element,X;if(!V){if(!J){J=document.createElement("iframe");if(this.isSecure){J.src=B.IFRAME_SRC;}if(K.ie){J.style.filter="alpha(opacity=0)";J.frameBorder=0;}else{J.style.opacity="0";}J.style.position="absolute";J.style.border="none";J.style.margin="0";J.style.padding="0";J.style.display="none";J.tabIndex=-1;J.className=B.CSS_IFRAME;}V=J.cloneNode(false);V.id=this.id+"_f";X=W.parentNode;var U=X||document.body;this._addToParent(U,V);this.iframe=V;}this.showIframe();this.syncIframe();this.stackIframe();if(!this._hasIframeEventListeners){this.showEvent.subscribe(this.showIframe);this.hideEvent.subscribe(this.hideIframe);this.changeContentEvent.subscribe(this.syncIframe);this._hasIframeEventListeners=true;}}function P(){T.call(this);this.beforeShowEvent.unsubscribe(P);this._iframeDeferred=false;}if(O){if(this.cfg.getProperty("visible")){T.call(this);}else{if(!this._iframeDeferred){this.beforeShowEvent.subscribe(P);this._iframeDeferred=true;}}}else{this.hideIframe();if(this._hasIframeEventListeners){this.showEvent.unsubscribe(this.showIframe);this.hideEvent.unsubscribe(this.hideIframe);this.changeContentEvent.unsubscribe(this.syncIframe);this._hasIframeEventListeners=false;}}},_primeXYFromDOM:function(){if(YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))){this.syncPosition();this.cfg.refireEvent("xy");this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);}},configConstrainToViewport:function(P,O,Q){var R=O[0];if(R){if(!D.alreadySubscribed(this.beforeMoveEvent,this.enforceConstraints,this)){this.beforeMoveEvent.subscribe(this.enforceConstraints,this,true);}if(!D.alreadySubscribed(this.beforeShowEvent,this._primeXYFromDOM)){this.beforeShowEvent.subscribe(this._primeXYFromDOM);}}else{this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);this.beforeMoveEvent.unsubscribe(this.enforceConstraints,this);}},configContext:function(U,T,Q){var X=T[0],R,O,V,S,P,W=this.CONTEXT_TRIGGERS;if(X){R=X[0];O=X[1];V=X[2];S=X[3];P=X[4];if(W&&W.length>0){S=(S||[]).concat(W);}if(R){if(typeof R=="string"){this.cfg.setProperty("context",[document.getElementById(R),O,V,S,P],true);}if(O&&V){this.align(O,V,P);}if(this._contextTriggers){this._processTriggers(this._contextTriggers,E,this._alignOnTrigger);}if(S){this._processTriggers(S,H,this._alignOnTrigger);this._contextTriggers=S;}}}},_alignOnTrigger:function(P,O){this.align();},_findTriggerCE:function(O){var P=null;if(O instanceof M){P=O;}else{if(B._TRIGGER_MAP[O]){P=B._TRIGGER_MAP[O];}}return P;},_processTriggers:function(S,U,R){var Q,T;for(var P=0,O=S.length;P<O;++P){Q=S[P];T=this._findTriggerCE(Q);if(T){T[U](R,this,true);}else{this[U](Q,R);}}},align:function(P,W,S){var V=this.cfg.getProperty("context"),T=this,O,Q,U;function R(Z,a){var Y=null,X=null;switch(P){case B.TOP_LEFT:Y=a;X=Z;break;case B.TOP_RIGHT:Y=a-Q.offsetWidth;X=Z;break;case B.BOTTOM_LEFT:Y=a;X=Z-Q.offsetHeight;break;case B.BOTTOM_RIGHT:Y=a-Q.offsetWidth;X=Z-Q.offsetHeight;break;}if(Y!==null&&X!==null){if(S){Y+=S[0];X+=S[1];}T.moveTo(Y,X);}}if(V){O=V[0];Q=this.element;T=this;if(!P){P=V[1];}if(!W){W=V[2];}if(!S&&V[4]){S=V[4];}if(Q&&O){U=F.getRegion(O);switch(W){case B.TOP_LEFT:R(U.top,U.left);break;case B.TOP_RIGHT:R(U.top,U.right);break;case B.BOTTOM_LEFT:R(U.bottom,U.left);break;case B.BOTTOM_RIGHT:R(U.bottom,U.right);break;}}}},enforceConstraints:function(P,O,Q){var S=O[0];var R=this.getConstrainedXY(S[0],S[1]);this.cfg.setProperty("x",R[0],true);this.cfg.setProperty("y",R[1],true);this.cfg.setProperty("xy",R,true);},_getConstrainedPos:function(X,P){var T=this.element,R=B.VIEWPORT_OFFSET,Z=(X=="x"),Y=(Z)?T.offsetWidth:T.offsetHeight,S=(Z)?F.getViewportWidth():F.getViewportHeight(),c=(Z)?F.getDocumentScrollLeft():F.getDocumentScrollTop(),b=(Z)?B.PREVENT_OVERLAP_X:B.PREVENT_OVERLAP_Y,O=this.cfg.getProperty("context"),U=(Y+R<S),W=this.cfg.getProperty("preventcontextoverlap")&&O&&b[(O[1]+O[2])],V=c+R,a=c+S-Y-R,Q=P;if(P<V||P>a){if(W){Q=this._preventOverlap(X,O[0],Y,S,c);}else{if(U){if(P<V){Q=V;}else{if(P>a){Q=a;}}}else{Q=V;}}}return Q;},_preventOverlap:function(X,W,Y,U,b){var Z=(X=="x"),T=B.VIEWPORT_OFFSET,S=this,Q=((Z)?F.getX(W):F.getY(W))-b,O=(Z)?W.offsetWidth:W.offsetHeight,P=Q-T,R=(U-(Q+O))-T,c=false,V=function(){var d;if((S.cfg.getProperty(X)-b)>Q){d=(Q-Y);}else{d=(Q+O);}S.cfg.setProperty(X,(d+b),true);return d;},a=function(){var e=((S.cfg.getProperty(X)-b)>Q)?R:P,d;if(Y>e){if(c){V();}else{V();c=true;d=a();}}return d;};a();return this.cfg.getProperty(X);},getConstrainedX:function(O){return this._getConstrainedPos("x",O);},getConstrainedY:function(O){return this._getConstrainedPos("y",O);},getConstrainedXY:function(O,P){return[this.getConstrainedX(O),this.getConstrainedY(P)];},center:function(){var R=B.VIEWPORT_OFFSET,S=this.element.offsetWidth,Q=this.element.offsetHeight,P=F.getViewportWidth(),T=F.getViewportHeight(),O,U;if(S<P){O=(P/2)-(S/2)+F.getDocumentScrollLeft();}else{O=R+F.getDocumentScrollLeft();}if(Q<T){U=(T/2)-(Q/2)+F.getDocumentScrollTop();}else{U=R+F.getDocumentScrollTop();}this.cfg.setProperty("xy",[parseInt(O,10),parseInt(U,10)]);this.cfg.refireEvent("iframe");if(K.webkit){this.forceContainerRedraw();}},syncPosition:function(){var O=F.getXY(this.element);this.cfg.setProperty("x",O[0],true);this.cfg.setProperty("y",O[1],true);this.cfg.setProperty("xy",O,true);},onDomResize:function(Q,P){var O=this;B.superclass.onDomResize.call(this,Q,P);setTimeout(function(){O.syncPosition();O.cfg.refireEvent("iframe");O.cfg.refireEvent("context");},0);},_getComputedHeight:(function(){if(document.defaultView&&document.defaultView.getComputedStyle){return function(P){var O=null;
+if(P.ownerDocument&&P.ownerDocument.defaultView){var Q=P.ownerDocument.defaultView.getComputedStyle(P,"");if(Q){O=parseInt(Q.height,10);}}return(I.isNumber(O))?O:null;};}else{return function(P){var O=null;if(P.style.pixelHeight){O=P.style.pixelHeight;}return(I.isNumber(O))?O:null;};}})(),_validateAutoFillHeight:function(O){return(!O)||(I.isString(O)&&B.STD_MOD_RE.test(O));},_autoFillOnHeightChange:function(R,P,Q){var O=this.cfg.getProperty("height");if((O&&O!=="auto")||(O===0)){this.fillHeight(Q);}},_getPreciseHeight:function(P){var O=P.offsetHeight;if(P.getBoundingClientRect){var Q=P.getBoundingClientRect();O=Q.bottom-Q.top;}return O;},fillHeight:function(R){if(R){var P=this.innerElement||this.element,O=[this.header,this.body,this.footer],V,W=0,X=0,T=0,Q=false;for(var U=0,S=O.length;U<S;U++){V=O[U];if(V){if(R!==V){X+=this._getPreciseHeight(V);}else{Q=true;}}}if(Q){if(K.ie||K.opera){F.setStyle(R,"height",0+"px");}W=this._getComputedHeight(P);if(W===null){F.addClass(P,"yui-override-padding");W=P.clientHeight;F.removeClass(P,"yui-override-padding");}T=Math.max(W-X,0);F.setStyle(R,"height",T+"px");if(R.offsetHeight!=T){T=Math.max(T-(R.offsetHeight-T),0);}F.setStyle(R,"height",T+"px");}}},bringToTop:function(){var S=[],R=this.element;function V(Z,Y){var b=F.getStyle(Z,"zIndex"),a=F.getStyle(Y,"zIndex"),X=(!b||isNaN(b))?0:parseInt(b,10),W=(!a||isNaN(a))?0:parseInt(a,10);if(X>W){return -1;}else{if(X<W){return 1;}else{return 0;}}}function Q(Y){var X=F.hasClass(Y,B.CSS_OVERLAY),W=YAHOO.widget.Panel;if(X&&!F.isAncestor(R,Y)){if(W&&F.hasClass(Y,W.CSS_PANEL)){S[S.length]=Y.parentNode;}else{S[S.length]=Y;}}}F.getElementsBy(Q,"DIV",document.body);S.sort(V);var O=S[0],U;if(O){U=F.getStyle(O,"zIndex");if(!isNaN(U)){var T=false;if(O!=R){T=true;}else{if(S.length>1){var P=F.getStyle(S[1],"zIndex");if(!isNaN(P)&&(U==P)){T=true;}}}if(T){this.cfg.setProperty("zindex",(parseInt(U,10)+2));}}}},destroy:function(){if(this.iframe){this.iframe.parentNode.removeChild(this.iframe);}this.iframe=null;B.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent,this);B.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent,this);G.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);if(this._contextTriggers){this._processTriggers(this._contextTriggers,E,this._alignOnTrigger);}B.superclass.destroy.call(this);},forceContainerRedraw:function(){var O=this;F.addClass(O.element,"yui-force-redraw");setTimeout(function(){F.removeClass(O.element,"yui-force-redraw");},0);},toString:function(){return"Overlay "+this.id;}});}());(function(){YAHOO.widget.OverlayManager=function(G){this.init(G);};var D=YAHOO.widget.Overlay,C=YAHOO.util.Event,E=YAHOO.util.Dom,B=YAHOO.util.Config,F=YAHOO.util.CustomEvent,A=YAHOO.widget.OverlayManager;A.CSS_FOCUSED="focused";A.prototype={constructor:A,overlays:null,initDefaultConfig:function(){this.cfg.addProperty("overlays",{suppressEvent:true});this.cfg.addProperty("focusevent",{value:"mousedown"});},init:function(I){this.cfg=new B(this);this.initDefaultConfig();if(I){this.cfg.applyConfig(I,true);}this.cfg.fireQueue();var H=null;this.getActive=function(){return H;};this.focus=function(J){var K=this.find(J);if(K){K.focus();}};this.remove=function(K){var M=this.find(K),J;if(M){if(H==M){H=null;}var L=(M.element===null&&M.cfg===null)?true:false;if(!L){J=E.getStyle(M.element,"zIndex");M.cfg.setProperty("zIndex",-1000,true);}this.overlays.sort(this.compareZIndexDesc);this.overlays=this.overlays.slice(0,(this.overlays.length-1));M.hideEvent.unsubscribe(M.blur);M.destroyEvent.unsubscribe(this._onOverlayDestroy,M);M.focusEvent.unsubscribe(this._onOverlayFocusHandler,M);M.blurEvent.unsubscribe(this._onOverlayBlurHandler,M);if(!L){C.removeListener(M.element,this.cfg.getProperty("focusevent"),this._onOverlayElementFocus);M.cfg.setProperty("zIndex",J,true);M.cfg.setProperty("manager",null);}if(M.focusEvent._managed){M.focusEvent=null;}if(M.blurEvent._managed){M.blurEvent=null;}if(M.focus._managed){M.focus=null;}if(M.blur._managed){M.blur=null;}}};this.blurAll=function(){var K=this.overlays.length,J;if(K>0){J=K-1;do{this.overlays[J].blur();}while(J--);}};this._manageBlur=function(J){var K=false;if(H==J){E.removeClass(H.element,A.CSS_FOCUSED);H=null;K=true;}return K;};this._manageFocus=function(J){var K=false;if(H!=J){if(H){H.blur();}H=J;this.bringToTop(H);E.addClass(H.element,A.CSS_FOCUSED);K=true;}return K;};var G=this.cfg.getProperty("overlays");if(!this.overlays){this.overlays=[];}if(G){this.register(G);this.overlays.sort(this.compareZIndexDesc);}},_onOverlayElementFocus:function(I){var G=C.getTarget(I),H=this.close;if(H&&(G==H||E.isAncestor(H,G))){this.blur();}else{this.focus();}},_onOverlayDestroy:function(H,G,I){this.remove(I);},_onOverlayFocusHandler:function(H,G,I){this._manageFocus(I);},_onOverlayBlurHandler:function(H,G,I){this._manageBlur(I);},_bindFocus:function(G){var H=this;if(!G.focusEvent){G.focusEvent=G.createEvent("focus");G.focusEvent.signature=F.LIST;G.focusEvent._managed=true;}else{G.focusEvent.subscribe(H._onOverlayFocusHandler,G,H);}if(!G.focus){C.on(G.element,H.cfg.getProperty("focusevent"),H._onOverlayElementFocus,null,G);G.focus=function(){if(H._manageFocus(this)){if(this.cfg.getProperty("visible")&&this.focusFirst){this.focusFirst();}this.focusEvent.fire();}};G.focus._managed=true;}},_bindBlur:function(G){var H=this;if(!G.blurEvent){G.blurEvent=G.createEvent("blur");G.blurEvent.signature=F.LIST;G.focusEvent._managed=true;}else{G.blurEvent.subscribe(H._onOverlayBlurHandler,G,H);}if(!G.blur){G.blur=function(){if(H._manageBlur(this)){this.blurEvent.fire();}};G.blur._managed=true;}G.hideEvent.subscribe(G.blur);},_bindDestroy:function(G){var H=this;G.destroyEvent.subscribe(H._onOverlayDestroy,G,H);},_syncZIndex:function(G){var H=E.getStyle(G.element,"zIndex");if(!isNaN(H)){G.cfg.setProperty("zIndex",parseInt(H,10));}else{G.cfg.setProperty("zIndex",0);}},register:function(G){var J=false,H,I;if(G instanceof D){G.cfg.addProperty("manager",{value:this});this._bindFocus(G);this._bindBlur(G);this._bindDestroy(G);
+this._syncZIndex(G);this.overlays.push(G);this.bringToTop(G);J=true;}else{if(G instanceof Array){for(H=0,I=G.length;H<I;H++){J=this.register(G[H])||J;}}}return J;},bringToTop:function(M){var I=this.find(M),L,G,J;if(I){J=this.overlays;J.sort(this.compareZIndexDesc);G=J[0];if(G){L=E.getStyle(G.element,"zIndex");if(!isNaN(L)){var K=false;if(G!==I){K=true;}else{if(J.length>1){var H=E.getStyle(J[1].element,"zIndex");if(!isNaN(H)&&(L==H)){K=true;}}}if(K){I.cfg.setProperty("zindex",(parseInt(L,10)+2));}}J.sort(this.compareZIndexDesc);}}},find:function(G){var K=G instanceof D,I=this.overlays,M=I.length,J=null,L,H;if(K||typeof G=="string"){for(H=M-1;H>=0;H--){L=I[H];if((K&&(L===G))||(L.id==G)){J=L;break;}}}return J;},compareZIndexDesc:function(J,I){var H=(J.cfg)?J.cfg.getProperty("zIndex"):null,G=(I.cfg)?I.cfg.getProperty("zIndex"):null;if(H===null&&G===null){return 0;}else{if(H===null){return 1;}else{if(G===null){return -1;}else{if(H>G){return -1;}else{if(H<G){return 1;}else{return 0;}}}}}},showAll:function(){var H=this.overlays,I=H.length,G;for(G=I-1;G>=0;G--){H[G].show();}},hideAll:function(){var H=this.overlays,I=H.length,G;for(G=I-1;G>=0;G--){H[G].hide();}},toString:function(){return"OverlayManager";}};}());(function(){YAHOO.widget.Tooltip=function(P,O){YAHOO.widget.Tooltip.superclass.constructor.call(this,P,O);};var E=YAHOO.lang,N=YAHOO.util.Event,M=YAHOO.util.CustomEvent,C=YAHOO.util.Dom,J=YAHOO.widget.Tooltip,H=YAHOO.env.ua,G=(H.ie&&(H.ie<=6||document.compatMode=="BackCompat")),F,I={"PREVENT_OVERLAP":{key:"preventoverlap",value:true,validator:E.isBoolean,supercedes:["x","y","xy"]},"SHOW_DELAY":{key:"showdelay",value:200,validator:E.isNumber},"AUTO_DISMISS_DELAY":{key:"autodismissdelay",value:5000,validator:E.isNumber},"HIDE_DELAY":{key:"hidedelay",value:250,validator:E.isNumber},"TEXT":{key:"text",suppressEvent:true},"CONTAINER":{key:"container"},"DISABLED":{key:"disabled",value:false,suppressEvent:true},"XY_OFFSET":{key:"xyoffset",value:[0,25],suppressEvent:true}},A={"CONTEXT_MOUSE_OVER":"contextMouseOver","CONTEXT_MOUSE_OUT":"contextMouseOut","CONTEXT_TRIGGER":"contextTrigger"};J.CSS_TOOLTIP="yui-tt";function K(Q,O){var P=this.cfg,R=P.getProperty("width");if(R==O){P.setProperty("width",Q);}}function D(P,O){if("_originalWidth" in this){K.call(this,this._originalWidth,this._forcedWidth);}var Q=document.body,U=this.cfg,T=U.getProperty("width"),R,S;if((!T||T=="auto")&&(U.getProperty("container")!=Q||U.getProperty("x")>=C.getViewportWidth()||U.getProperty("y")>=C.getViewportHeight())){S=this.element.cloneNode(true);S.style.visibility="hidden";S.style.top="0px";S.style.left="0px";Q.appendChild(S);R=(S.offsetWidth+"px");Q.removeChild(S);S=null;U.setProperty("width",R);U.refireEvent("xy");this._originalWidth=T||"";this._forcedWidth=R;}}function B(P,O,Q){this.render(Q);}function L(){N.onDOMReady(B,this.cfg.getProperty("container"),this);}YAHOO.extend(J,YAHOO.widget.Overlay,{init:function(P,O){J.superclass.init.call(this,P);this.beforeInitEvent.fire(J);C.addClass(this.element,J.CSS_TOOLTIP);if(O){this.cfg.applyConfig(O,true);}this.cfg.queueProperty("visible",false);this.cfg.queueProperty("constraintoviewport",true);this.setBody("");this.subscribe("changeContent",D);this.subscribe("init",L);this.subscribe("render",this.onRender);this.initEvent.fire(J);},initEvents:function(){J.superclass.initEvents.call(this);var O=M.LIST;this.contextMouseOverEvent=this.createEvent(A.CONTEXT_MOUSE_OVER);this.contextMouseOverEvent.signature=O;this.contextMouseOutEvent=this.createEvent(A.CONTEXT_MOUSE_OUT);this.contextMouseOutEvent.signature=O;this.contextTriggerEvent=this.createEvent(A.CONTEXT_TRIGGER);this.contextTriggerEvent.signature=O;},initDefaultConfig:function(){J.superclass.initDefaultConfig.call(this);this.cfg.addProperty(I.PREVENT_OVERLAP.key,{value:I.PREVENT_OVERLAP.value,validator:I.PREVENT_OVERLAP.validator,supercedes:I.PREVENT_OVERLAP.supercedes});this.cfg.addProperty(I.SHOW_DELAY.key,{handler:this.configShowDelay,value:200,validator:I.SHOW_DELAY.validator});this.cfg.addProperty(I.AUTO_DISMISS_DELAY.key,{handler:this.configAutoDismissDelay,value:I.AUTO_DISMISS_DELAY.value,validator:I.AUTO_DISMISS_DELAY.validator});this.cfg.addProperty(I.HIDE_DELAY.key,{handler:this.configHideDelay,value:I.HIDE_DELAY.value,validator:I.HIDE_DELAY.validator});this.cfg.addProperty(I.TEXT.key,{handler:this.configText,suppressEvent:I.TEXT.suppressEvent});this.cfg.addProperty(I.CONTAINER.key,{handler:this.configContainer,value:document.body});this.cfg.addProperty(I.DISABLED.key,{handler:this.configContainer,value:I.DISABLED.value,supressEvent:I.DISABLED.suppressEvent});this.cfg.addProperty(I.XY_OFFSET.key,{value:I.XY_OFFSET.value.concat(),supressEvent:I.XY_OFFSET.suppressEvent});},configText:function(P,O,Q){var R=O[0];if(R){this.setBody(R);}},configContainer:function(Q,P,R){var O=P[0];if(typeof O=="string"){this.cfg.setProperty("container",document.getElementById(O),true);}},_removeEventListeners:function(){var R=this._context,O,Q,P;if(R){O=R.length;if(O>0){P=O-1;do{Q=R[P];N.removeListener(Q,"mouseover",this.onContextMouseOver);N.removeListener(Q,"mousemove",this.onContextMouseMove);N.removeListener(Q,"mouseout",this.onContextMouseOut);}while(P--);}}},configContext:function(T,P,U){var S=P[0],V,O,R,Q;if(S){if(!(S instanceof Array)){if(typeof S=="string"){this.cfg.setProperty("context",[document.getElementById(S)],true);}else{this.cfg.setProperty("context",[S],true);}S=this.cfg.getProperty("context");}this._removeEventListeners();this._context=S;V=this._context;if(V){O=V.length;if(O>0){Q=O-1;do{R=V[Q];N.on(R,"mouseover",this.onContextMouseOver,this);N.on(R,"mousemove",this.onContextMouseMove,this);N.on(R,"mouseout",this.onContextMouseOut,this);}while(Q--);}}}},onContextMouseMove:function(P,O){O.pageX=N.getPageX(P);O.pageY=N.getPageY(P);},onContextMouseOver:function(Q,P){var O=this;if(O.title){P._tempTitle=O.title;O.title="";}if(P.fireEvent("contextMouseOver",O,Q)!==false&&!P.cfg.getProperty("disabled")){if(P.hideProcId){clearTimeout(P.hideProcId);
+P.hideProcId=null;}N.on(O,"mousemove",P.onContextMouseMove,P);P.showProcId=P.doShow(Q,O);}},onContextMouseOut:function(Q,P){var O=this;if(P._tempTitle){O.title=P._tempTitle;P._tempTitle=null;}if(P.showProcId){clearTimeout(P.showProcId);P.showProcId=null;}if(P.hideProcId){clearTimeout(P.hideProcId);P.hideProcId=null;}P.fireEvent("contextMouseOut",O,Q);P.hideProcId=setTimeout(function(){P.hide();},P.cfg.getProperty("hidedelay"));},doShow:function(R,O){var T=this.cfg.getProperty("xyoffset"),P=T[0],S=T[1],Q=this;if(H.opera&&O.tagName&&O.tagName.toUpperCase()=="A"){S+=12;}return setTimeout(function(){var U=Q.cfg.getProperty("text");if(Q._tempTitle&&(U===""||YAHOO.lang.isUndefined(U)||YAHOO.lang.isNull(U))){Q.setBody(Q._tempTitle);}else{Q.cfg.refireEvent("text");}Q.moveTo(Q.pageX+P,Q.pageY+S);if(Q.cfg.getProperty("preventoverlap")){Q.preventOverlap(Q.pageX,Q.pageY);}N.removeListener(O,"mousemove",Q.onContextMouseMove);Q.contextTriggerEvent.fire(O);Q.show();Q.hideProcId=Q.doHide();},this.cfg.getProperty("showdelay"));},doHide:function(){var O=this;return setTimeout(function(){O.hide();},this.cfg.getProperty("autodismissdelay"));},preventOverlap:function(S,R){var O=this.element.offsetHeight,Q=new YAHOO.util.Point(S,R),P=C.getRegion(this.element);P.top-=5;P.left-=5;P.right+=5;P.bottom+=5;if(P.contains(Q)){this.cfg.setProperty("y",(R-O-5));}},onRender:function(S,R){function T(){var W=this.element,V=this.underlay;if(V){V.style.width=(W.offsetWidth+6)+"px";V.style.height=(W.offsetHeight+1)+"px";}}function P(){C.addClass(this.underlay,"yui-tt-shadow-visible");if(H.ie){this.forceUnderlayRedraw();}}function O(){C.removeClass(this.underlay,"yui-tt-shadow-visible");}function U(){var X=this.underlay,W,V,Z,Y;if(!X){W=this.element;V=YAHOO.widget.Module;Z=H.ie;Y=this;if(!F){F=document.createElement("div");F.className="yui-tt-shadow";}X=F.cloneNode(false);W.appendChild(X);this.underlay=X;this._shadow=this.underlay;P.call(this);this.subscribe("beforeShow",P);this.subscribe("hide",O);if(G){window.setTimeout(function(){T.call(Y);},0);this.cfg.subscribeToConfigEvent("width",T);this.cfg.subscribeToConfigEvent("height",T);this.subscribe("changeContent",T);V.textResizeEvent.subscribe(T,this,true);this.subscribe("destroy",function(){V.textResizeEvent.unsubscribe(T,this);});}}}function Q(){U.call(this);this.unsubscribe("beforeShow",Q);}if(this.cfg.getProperty("visible")){U.call(this);}else{this.subscribe("beforeShow",Q);}},forceUnderlayRedraw:function(){var O=this;C.addClass(O.underlay,"yui-force-redraw");setTimeout(function(){C.removeClass(O.underlay,"yui-force-redraw");},0);},destroy:function(){this._removeEventListeners();J.superclass.destroy.call(this);},toString:function(){return"Tooltip "+this.id;}});}());(function(){YAHOO.widget.Panel=function(V,U){YAHOO.widget.Panel.superclass.constructor.call(this,V,U);};var S=null;var E=YAHOO.lang,F=YAHOO.util,A=F.Dom,T=F.Event,M=F.CustomEvent,K=YAHOO.util.KeyListener,I=F.Config,H=YAHOO.widget.Overlay,O=YAHOO.widget.Panel,L=YAHOO.env.ua,P=(L.ie&&(L.ie<=6||document.compatMode=="BackCompat")),G,Q,C,D={"SHOW_MASK":"showMask","HIDE_MASK":"hideMask","DRAG":"drag"},N={"CLOSE":{key:"close",value:true,validator:E.isBoolean,supercedes:["visible"]},"DRAGGABLE":{key:"draggable",value:(F.DD?true:false),validator:E.isBoolean,supercedes:["visible"]},"DRAG_ONLY":{key:"dragonly",value:false,validator:E.isBoolean,supercedes:["draggable"]},"UNDERLAY":{key:"underlay",value:"shadow",supercedes:["visible"]},"MODAL":{key:"modal",value:false,validator:E.isBoolean,supercedes:["visible","zindex"]},"KEY_LISTENERS":{key:"keylisteners",suppressEvent:true,supercedes:["visible"]},"STRINGS":{key:"strings",supercedes:["close"],validator:E.isObject,value:{close:"Close"}}};O.CSS_PANEL="yui-panel";O.CSS_PANEL_CONTAINER="yui-panel-container";O.FOCUSABLE=["a","button","select","textarea","input","iframe"];function J(V,U){if(!this.header&&this.cfg.getProperty("draggable")){this.setHeader("&#160;");}}function R(V,U,W){var Z=W[0],X=W[1],Y=this.cfg,a=Y.getProperty("width");if(a==X){Y.setProperty("width",Z);}this.unsubscribe("hide",R,W);}function B(V,U){var Y,X,W;if(P){Y=this.cfg;X=Y.getProperty("width");if(!X||X=="auto"){W=(this.element.offsetWidth+"px");Y.setProperty("width",W);this.subscribe("hide",R,[(X||""),W]);}}}YAHOO.extend(O,H,{init:function(V,U){O.superclass.init.call(this,V);this.beforeInitEvent.fire(O);A.addClass(this.element,O.CSS_PANEL);this.buildWrapper();if(U){this.cfg.applyConfig(U,true);}this.subscribe("showMask",this._addFocusHandlers);this.subscribe("hideMask",this._removeFocusHandlers);this.subscribe("beforeRender",J);this.subscribe("render",function(){this.setFirstLastFocusable();this.subscribe("changeContent",this.setFirstLastFocusable);});this.subscribe("show",this.focusFirst);this.initEvent.fire(O);},_onElementFocus:function(Z){if(S===this){var Y=T.getTarget(Z),X=document.documentElement,V=(Y!==X&&Y!==window);if(V&&Y!==this.element&&Y!==this.mask&&!A.isAncestor(this.element,Y)){try{if(this.firstElement){this.firstElement.focus();}else{if(this._modalFocus){this._modalFocus.focus();}else{this.innerElement.focus();}}}catch(W){try{if(V&&Y!==document.body){Y.blur();}}catch(U){}}}}},_addFocusHandlers:function(V,U){if(!this.firstElement){if(L.webkit||L.opera){if(!this._modalFocus){this._createHiddenFocusElement();}}else{this.innerElement.tabIndex=0;}}this.setTabLoop(this.firstElement,this.lastElement);T.onFocus(document.documentElement,this._onElementFocus,this,true);S=this;},_createHiddenFocusElement:function(){var U=document.createElement("button");U.style.height="1px";U.style.width="1px";U.style.position="absolute";U.style.left="-10000em";U.style.opacity=0;U.tabIndex=-1;this.innerElement.appendChild(U);this._modalFocus=U;},_removeFocusHandlers:function(V,U){T.removeFocusListener(document.documentElement,this._onElementFocus,this);if(S==this){S=null;}},focusFirst:function(W,U,Y){var V=this.firstElement;if(U&&U[1]){T.stopEvent(U[1]);}if(V){try{V.focus();}catch(X){}}},focusLast:function(W,U,Y){var V=this.lastElement;
+if(U&&U[1]){T.stopEvent(U[1]);}if(V){try{V.focus();}catch(X){}}},setTabLoop:function(X,Z){var V=this.preventBackTab,W=this.preventTabOut,U=this.showEvent,Y=this.hideEvent;if(V){V.disable();U.unsubscribe(V.enable,V);Y.unsubscribe(V.disable,V);V=this.preventBackTab=null;}if(W){W.disable();U.unsubscribe(W.enable,W);Y.unsubscribe(W.disable,W);W=this.preventTabOut=null;}if(X){this.preventBackTab=new K(X,{shift:true,keys:9},{fn:this.focusLast,scope:this,correctScope:true});V=this.preventBackTab;U.subscribe(V.enable,V,true);Y.subscribe(V.disable,V,true);}if(Z){this.preventTabOut=new K(Z,{shift:false,keys:9},{fn:this.focusFirst,scope:this,correctScope:true});W=this.preventTabOut;U.subscribe(W.enable,W,true);Y.subscribe(W.disable,W,true);}},getFocusableElements:function(U){U=U||this.innerElement;var X={};for(var W=0;W<O.FOCUSABLE.length;W++){X[O.FOCUSABLE[W]]=true;}function V(Y){if(Y.focus&&Y.type!=="hidden"&&!Y.disabled&&X[Y.tagName.toLowerCase()]){return true;}return false;}return A.getElementsBy(V,null,U);},setFirstLastFocusable:function(){this.firstElement=null;this.lastElement=null;var U=this.getFocusableElements();this.focusableElements=U;if(U.length>0){this.firstElement=U[0];this.lastElement=U[U.length-1];}if(this.cfg.getProperty("modal")){this.setTabLoop(this.firstElement,this.lastElement);}},initEvents:function(){O.superclass.initEvents.call(this);var U=M.LIST;this.showMaskEvent=this.createEvent(D.SHOW_MASK);this.showMaskEvent.signature=U;this.hideMaskEvent=this.createEvent(D.HIDE_MASK);this.hideMaskEvent.signature=U;this.dragEvent=this.createEvent(D.DRAG);this.dragEvent.signature=U;},initDefaultConfig:function(){O.superclass.initDefaultConfig.call(this);this.cfg.addProperty(N.CLOSE.key,{handler:this.configClose,value:N.CLOSE.value,validator:N.CLOSE.validator,supercedes:N.CLOSE.supercedes});this.cfg.addProperty(N.DRAGGABLE.key,{handler:this.configDraggable,value:(F.DD)?true:false,validator:N.DRAGGABLE.validator,supercedes:N.DRAGGABLE.supercedes});this.cfg.addProperty(N.DRAG_ONLY.key,{value:N.DRAG_ONLY.value,validator:N.DRAG_ONLY.validator,supercedes:N.DRAG_ONLY.supercedes});this.cfg.addProperty(N.UNDERLAY.key,{handler:this.configUnderlay,value:N.UNDERLAY.value,supercedes:N.UNDERLAY.supercedes});this.cfg.addProperty(N.MODAL.key,{handler:this.configModal,value:N.MODAL.value,validator:N.MODAL.validator,supercedes:N.MODAL.supercedes});this.cfg.addProperty(N.KEY_LISTENERS.key,{handler:this.configKeyListeners,suppressEvent:N.KEY_LISTENERS.suppressEvent,supercedes:N.KEY_LISTENERS.supercedes});this.cfg.addProperty(N.STRINGS.key,{value:N.STRINGS.value,handler:this.configStrings,validator:N.STRINGS.validator,supercedes:N.STRINGS.supercedes});},configClose:function(X,V,Y){var Z=V[0],W=this.close,U=this.cfg.getProperty("strings");if(Z){if(!W){if(!C){C=document.createElement("a");C.className="container-close";C.href="#";}W=C.cloneNode(true);this.innerElement.appendChild(W);W.innerHTML=(U&&U.close)?U.close:"&#160;";T.on(W,"click",this._doClose,this,true);this.close=W;}else{W.style.display="block";}}else{if(W){W.style.display="none";}}},_doClose:function(U){T.preventDefault(U);this.hide();},configDraggable:function(V,U,W){var X=U[0];if(X){if(!F.DD){this.cfg.setProperty("draggable",false);return;}if(this.header){A.setStyle(this.header,"cursor","move");this.registerDragDrop();}this.subscribe("beforeShow",B);}else{if(this.dd){this.dd.unreg();}if(this.header){A.setStyle(this.header,"cursor","auto");}this.unsubscribe("beforeShow",B);}},configUnderlay:function(d,c,Z){var b=(this.platform=="mac"&&L.gecko),e=c[0].toLowerCase(),V=this.underlay,W=this.element;function X(){var f=false;if(!V){if(!Q){Q=document.createElement("div");Q.className="underlay";}V=Q.cloneNode(false);this.element.appendChild(V);this.underlay=V;if(P){this.sizeUnderlay();this.cfg.subscribeToConfigEvent("width",this.sizeUnderlay);this.cfg.subscribeToConfigEvent("height",this.sizeUnderlay);this.changeContentEvent.subscribe(this.sizeUnderlay);YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay,this,true);}if(L.webkit&&L.webkit<420){this.changeContentEvent.subscribe(this.forceUnderlayRedraw);}f=true;}}function a(){var f=X.call(this);if(!f&&P){this.sizeUnderlay();}this._underlayDeferred=false;this.beforeShowEvent.unsubscribe(a);}function Y(){if(this._underlayDeferred){this.beforeShowEvent.unsubscribe(a);this._underlayDeferred=false;}if(V){this.cfg.unsubscribeFromConfigEvent("width",this.sizeUnderlay);this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);this.changeContentEvent.unsubscribe(this.sizeUnderlay);this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay,this,true);this.element.removeChild(V);this.underlay=null;}}switch(e){case"shadow":A.removeClass(W,"matte");A.addClass(W,"shadow");break;case"matte":if(!b){Y.call(this);}A.removeClass(W,"shadow");A.addClass(W,"matte");break;default:if(!b){Y.call(this);}A.removeClass(W,"shadow");A.removeClass(W,"matte");break;}if((e=="shadow")||(b&&!V)){if(this.cfg.getProperty("visible")){var U=X.call(this);if(!U&&P){this.sizeUnderlay();}}else{if(!this._underlayDeferred){this.beforeShowEvent.subscribe(a);this._underlayDeferred=true;}}}},configModal:function(V,U,X){var W=U[0];if(W){if(!this._hasModalityEventListeners){this.subscribe("beforeShow",this.buildMask);this.subscribe("beforeShow",this.bringToTop);this.subscribe("beforeShow",this.showMask);this.subscribe("hide",this.hideMask);H.windowResizeEvent.subscribe(this.sizeMask,this,true);this._hasModalityEventListeners=true;}}else{if(this._hasModalityEventListeners){if(this.cfg.getProperty("visible")){this.hideMask();this.removeMask();}this.unsubscribe("beforeShow",this.buildMask);this.unsubscribe("beforeShow",this.bringToTop);this.unsubscribe("beforeShow",this.showMask);this.unsubscribe("hide",this.hideMask);H.windowResizeEvent.unsubscribe(this.sizeMask,this);this._hasModalityEventListeners=false;}}},removeMask:function(){var V=this.mask,U;if(V){this.hideMask();U=V.parentNode;
+if(U){U.removeChild(V);}this.mask=null;}},configKeyListeners:function(X,U,a){var W=U[0],Z,Y,V;if(W){if(W instanceof Array){Y=W.length;for(V=0;V<Y;V++){Z=W[V];if(!I.alreadySubscribed(this.showEvent,Z.enable,Z)){this.showEvent.subscribe(Z.enable,Z,true);}if(!I.alreadySubscribed(this.hideEvent,Z.disable,Z)){this.hideEvent.subscribe(Z.disable,Z,true);this.destroyEvent.subscribe(Z.disable,Z,true);}}}else{if(!I.alreadySubscribed(this.showEvent,W.enable,W)){this.showEvent.subscribe(W.enable,W,true);}if(!I.alreadySubscribed(this.hideEvent,W.disable,W)){this.hideEvent.subscribe(W.disable,W,true);this.destroyEvent.subscribe(W.disable,W,true);}}}},configStrings:function(V,U,W){var X=E.merge(N.STRINGS.value,U[0]);this.cfg.setProperty(N.STRINGS.key,X,true);},configHeight:function(X,V,Y){var U=V[0],W=this.innerElement;A.setStyle(W,"height",U);this.cfg.refireEvent("iframe");},_autoFillOnHeightChange:function(X,V,W){O.superclass._autoFillOnHeightChange.apply(this,arguments);if(P){var U=this;setTimeout(function(){U.sizeUnderlay();},0);}},configWidth:function(X,U,Y){var W=U[0],V=this.innerElement;A.setStyle(V,"width",W);this.cfg.refireEvent("iframe");},configzIndex:function(V,U,X){O.superclass.configzIndex.call(this,V,U,X);if(this.mask||this.cfg.getProperty("modal")===true){var W=A.getStyle(this.element,"zIndex");if(!W||isNaN(W)){W=0;}if(W===0){this.cfg.setProperty("zIndex",1);}else{this.stackMask();}}},buildWrapper:function(){var W=this.element.parentNode,U=this.element,V=document.createElement("div");V.className=O.CSS_PANEL_CONTAINER;V.id=U.id+"_c";if(W){W.insertBefore(V,U);}V.appendChild(U);this.element=V;this.innerElement=U;A.setStyle(this.innerElement,"visibility","inherit");},sizeUnderlay:function(){var V=this.underlay,U;if(V){U=this.element;V.style.width=U.offsetWidth+"px";V.style.height=U.offsetHeight+"px";}},registerDragDrop:function(){var V=this;if(this.header){if(!F.DD){return;}var U=(this.cfg.getProperty("dragonly")===true);this.dd=new F.DD(this.element.id,this.id,{dragOnly:U});if(!this.header.id){this.header.id=this.id+"_h";}this.dd.startDrag=function(){var X,Z,W,c,b,a;if(YAHOO.env.ua.ie==6){A.addClass(V.element,"drag");}if(V.cfg.getProperty("constraintoviewport")){var Y=H.VIEWPORT_OFFSET;X=V.element.offsetHeight;Z=V.element.offsetWidth;W=A.getViewportWidth();c=A.getViewportHeight();b=A.getDocumentScrollLeft();a=A.getDocumentScrollTop();if(X+Y<c){this.minY=a+Y;this.maxY=a+c-X-Y;}else{this.minY=a+Y;this.maxY=a+Y;}if(Z+Y<W){this.minX=b+Y;this.maxX=b+W-Z-Y;}else{this.minX=b+Y;this.maxX=b+Y;}this.constrainX=true;this.constrainY=true;}else{this.constrainX=false;this.constrainY=false;}V.dragEvent.fire("startDrag",arguments);};this.dd.onDrag=function(){V.syncPosition();V.cfg.refireEvent("iframe");if(this.platform=="mac"&&YAHOO.env.ua.gecko){this.showMacGeckoScrollbars();}V.dragEvent.fire("onDrag",arguments);};this.dd.endDrag=function(){if(YAHOO.env.ua.ie==6){A.removeClass(V.element,"drag");}V.dragEvent.fire("endDrag",arguments);V.moveEvent.fire(V.cfg.getProperty("xy"));};this.dd.setHandleElId(this.header.id);this.dd.addInvalidHandleType("INPUT");this.dd.addInvalidHandleType("SELECT");this.dd.addInvalidHandleType("TEXTAREA");}},buildMask:function(){var U=this.mask;if(!U){if(!G){G=document.createElement("div");G.className="mask";G.innerHTML="&#160;";}U=G.cloneNode(true);U.id=this.id+"_mask";document.body.insertBefore(U,document.body.firstChild);this.mask=U;if(YAHOO.env.ua.gecko&&this.platform=="mac"){A.addClass(this.mask,"block-scrollbars");}this.stackMask();}},hideMask:function(){if(this.cfg.getProperty("modal")&&this.mask){this.mask.style.display="none";A.removeClass(document.body,"masked");this.hideMaskEvent.fire();}},showMask:function(){if(this.cfg.getProperty("modal")&&this.mask){A.addClass(document.body,"masked");this.sizeMask();this.mask.style.display="block";this.showMaskEvent.fire();}},sizeMask:function(){if(this.mask){var V=this.mask,W=A.getViewportWidth(),U=A.getViewportHeight();if(V.offsetHeight>U){V.style.height=U+"px";}if(V.offsetWidth>W){V.style.width=W+"px";}V.style.height=A.getDocumentHeight()+"px";V.style.width=A.getDocumentWidth()+"px";}},stackMask:function(){if(this.mask){var U=A.getStyle(this.element,"zIndex");if(!YAHOO.lang.isUndefined(U)&&!isNaN(U)){A.setStyle(this.mask,"zIndex",U-1);}}},render:function(U){return O.superclass.render.call(this,U,this.innerElement);},_renderHeader:function(U){U=U||this.innerElement;O.superclass._renderHeader.call(this,U);},_renderBody:function(U){U=U||this.innerElement;O.superclass._renderBody.call(this,U);},_renderFooter:function(U){U=U||this.innerElement;O.superclass._renderFooter.call(this,U);},destroy:function(){H.windowResizeEvent.unsubscribe(this.sizeMask,this);this.removeMask();if(this.close){T.purgeElement(this.close);}O.superclass.destroy.call(this);},forceUnderlayRedraw:function(){var U=this.underlay;A.addClass(U,"yui-force-redraw");setTimeout(function(){A.removeClass(U,"yui-force-redraw");},0);},toString:function(){return"Panel "+this.id;}});}());(function(){YAHOO.widget.Dialog=function(J,I){YAHOO.widget.Dialog.superclass.constructor.call(this,J,I);};var B=YAHOO.util.Event,G=YAHOO.util.CustomEvent,E=YAHOO.util.Dom,A=YAHOO.widget.Dialog,F=YAHOO.lang,H={"BEFORE_SUBMIT":"beforeSubmit","SUBMIT":"submit","MANUAL_SUBMIT":"manualSubmit","ASYNC_SUBMIT":"asyncSubmit","FORM_SUBMIT":"formSubmit","CANCEL":"cancel"},C={"POST_METHOD":{key:"postmethod",value:"async"},"POST_DATA":{key:"postdata",value:null},"BUTTONS":{key:"buttons",value:"none",supercedes:["visible"]},"HIDEAFTERSUBMIT":{key:"hideaftersubmit",value:true}};A.CSS_DIALOG="yui-dialog";function D(){var L=this._aButtons,J,K,I;if(F.isArray(L)){J=L.length;if(J>0){I=J-1;do{K=L[I];if(YAHOO.widget.Button&&K instanceof YAHOO.widget.Button){K.destroy();}else{if(K.tagName.toUpperCase()=="BUTTON"){B.purgeElement(K);B.purgeElement(K,false);}}}while(I--);}}}YAHOO.extend(A,YAHOO.widget.Panel,{form:null,initDefaultConfig:function(){A.superclass.initDefaultConfig.call(this);this.callback={success:null,failure:null,argument:null};
+this.cfg.addProperty(C.POST_METHOD.key,{handler:this.configPostMethod,value:C.POST_METHOD.value,validator:function(I){if(I!="form"&&I!="async"&&I!="none"&&I!="manual"){return false;}else{return true;}}});this.cfg.addProperty(C.POST_DATA.key,{value:C.POST_DATA.value});this.cfg.addProperty(C.HIDEAFTERSUBMIT.key,{value:C.HIDEAFTERSUBMIT.value});this.cfg.addProperty(C.BUTTONS.key,{handler:this.configButtons,value:C.BUTTONS.value,supercedes:C.BUTTONS.supercedes});},initEvents:function(){A.superclass.initEvents.call(this);var I=G.LIST;this.beforeSubmitEvent=this.createEvent(H.BEFORE_SUBMIT);this.beforeSubmitEvent.signature=I;this.submitEvent=this.createEvent(H.SUBMIT);this.submitEvent.signature=I;this.manualSubmitEvent=this.createEvent(H.MANUAL_SUBMIT);this.manualSubmitEvent.signature=I;this.asyncSubmitEvent=this.createEvent(H.ASYNC_SUBMIT);this.asyncSubmitEvent.signature=I;this.formSubmitEvent=this.createEvent(H.FORM_SUBMIT);this.formSubmitEvent.signature=I;this.cancelEvent=this.createEvent(H.CANCEL);this.cancelEvent.signature=I;},init:function(J,I){A.superclass.init.call(this,J);this.beforeInitEvent.fire(A);E.addClass(this.element,A.CSS_DIALOG);this.cfg.setProperty("visible",false);if(I){this.cfg.applyConfig(I,true);}this.showEvent.subscribe(this.focusFirst,this,true);this.beforeHideEvent.subscribe(this.blurButtons,this,true);this.subscribe("changeBody",this.registerForm);this.initEvent.fire(A);},doSubmit:function(){var P=YAHOO.util.Connect,Q=this.form,K=false,N=false,R,M,L,I;switch(this.cfg.getProperty("postmethod")){case"async":R=Q.elements;M=R.length;if(M>0){L=M-1;do{if(R[L].type=="file"){K=true;break;}}while(L--);}if(K&&YAHOO.env.ua.ie&&this.isSecure){N=true;}I=this._getFormAttributes(Q);P.setForm(Q,K,N);var J=this.cfg.getProperty("postdata");var O=P.asyncRequest(I.method,I.action,this.callback,J);this.asyncSubmitEvent.fire(O);break;case"form":Q.submit();this.formSubmitEvent.fire();break;case"none":case"manual":this.manualSubmitEvent.fire();break;}},_getFormAttributes:function(K){var I={method:null,action:null};if(K){if(K.getAttributeNode){var J=K.getAttributeNode("action");var L=K.getAttributeNode("method");if(J){I.action=J.value;}if(L){I.method=L.value;}}else{I.action=K.getAttribute("action");I.method=K.getAttribute("method");}}I.method=(F.isString(I.method)?I.method:"POST").toUpperCase();I.action=F.isString(I.action)?I.action:"";return I;},registerForm:function(){var I=this.element.getElementsByTagName("form")[0];if(this.form){if(this.form==I&&E.isAncestor(this.element,this.form)){return;}else{B.purgeElement(this.form);this.form=null;}}if(!I){I=document.createElement("form");I.name="frm_"+this.id;this.body.appendChild(I);}if(I){this.form=I;B.on(I,"submit",this._submitHandler,this,true);}},_submitHandler:function(I){B.stopEvent(I);this.submit();this.form.blur();},setTabLoop:function(I,J){I=I||this.firstButton;J=this.lastButton||J;A.superclass.setTabLoop.call(this,I,J);},setFirstLastFocusable:function(){A.superclass.setFirstLastFocusable.call(this);var J,I,K,L=this.focusableElements;this.firstFormElement=null;this.lastFormElement=null;if(this.form&&L&&L.length>0){I=L.length;for(J=0;J<I;++J){K=L[J];if(this.form===K.form){this.firstFormElement=K;break;}}for(J=I-1;J>=0;--J){K=L[J];if(this.form===K.form){this.lastFormElement=K;break;}}}},configClose:function(J,I,K){A.superclass.configClose.apply(this,arguments);},_doClose:function(I){B.preventDefault(I);this.cancel();},configButtons:function(S,R,M){var N=YAHOO.widget.Button,U=R[0],K=this.innerElement,T,P,J,Q,O,I,L;D.call(this);this._aButtons=null;if(F.isArray(U)){O=document.createElement("span");O.className="button-group";Q=U.length;this._aButtons=[];this.defaultHtmlButton=null;for(L=0;L<Q;L++){T=U[L];if(N){J=new N({label:T.text});J.appendTo(O);P=J.get("element");if(T.isDefault){J.addClass("default");this.defaultHtmlButton=P;}if(F.isFunction(T.handler)){J.set("onclick",{fn:T.handler,obj:this,scope:this});}else{if(F.isObject(T.handler)&&F.isFunction(T.handler.fn)){J.set("onclick",{fn:T.handler.fn,obj:((!F.isUndefined(T.handler.obj))?T.handler.obj:this),scope:(T.handler.scope||this)});}}this._aButtons[this._aButtons.length]=J;}else{P=document.createElement("button");P.setAttribute("type","button");if(T.isDefault){P.className="default";this.defaultHtmlButton=P;}P.innerHTML=T.text;if(F.isFunction(T.handler)){B.on(P,"click",T.handler,this,true);}else{if(F.isObject(T.handler)&&F.isFunction(T.handler.fn)){B.on(P,"click",T.handler.fn,((!F.isUndefined(T.handler.obj))?T.handler.obj:this),(T.handler.scope||this));}}O.appendChild(P);this._aButtons[this._aButtons.length]=P;}T.htmlButton=P;if(L===0){this.firstButton=P;}if(L==(Q-1)){this.lastButton=P;}}this.setFooter(O);I=this.footer;if(E.inDocument(this.element)&&!E.isAncestor(K,I)){K.appendChild(I);}this.buttonSpan=O;}else{O=this.buttonSpan;I=this.footer;if(O&&I){I.removeChild(O);this.buttonSpan=null;this.firstButton=null;this.lastButton=null;this.defaultHtmlButton=null;}}this.changeContentEvent.fire();},getButtons:function(){return this._aButtons||null;},focusFirst:function(K,I,M){var J=this.firstFormElement;if(I&&I[1]){B.stopEvent(I[1]);}if(J){try{J.focus();}catch(L){}}else{if(this.defaultHtmlButton){this.focusDefaultButton();}else{this.focusFirstButton();}}},focusLast:function(K,I,M){var N=this.cfg.getProperty("buttons"),J=this.lastFormElement;if(I&&I[1]){B.stopEvent(I[1]);}if(N&&F.isArray(N)){this.focusLastButton();}else{if(J){try{J.focus();}catch(L){}}}},_getButton:function(J){var I=YAHOO.widget.Button;if(I&&J&&J.nodeName&&J.id){J=I.getButton(J.id)||J;}return J;},focusDefaultButton:function(){var I=this._getButton(this.defaultHtmlButton);if(I){try{I.focus();}catch(J){}}},blurButtons:function(){var N=this.cfg.getProperty("buttons"),K,M,J,I;if(N&&F.isArray(N)){K=N.length;if(K>0){I=(K-1);do{M=N[I];if(M){J=this._getButton(M.htmlButton);if(J){try{J.blur();}catch(L){}}}}while(I--);}}},focusFirstButton:function(){var L=this.cfg.getProperty("buttons"),K,I;if(L&&F.isArray(L)){K=L[0];if(K){I=this._getButton(K.htmlButton);
+if(I){try{I.focus();}catch(J){}}}}},focusLastButton:function(){var M=this.cfg.getProperty("buttons"),J,L,I;if(M&&F.isArray(M)){J=M.length;if(J>0){L=M[(J-1)];if(L){I=this._getButton(L.htmlButton);if(I){try{I.focus();}catch(K){}}}}}},configPostMethod:function(J,I,K){this.registerForm();},validate:function(){return true;},submit:function(){if(this.validate()){if(this.beforeSubmitEvent.fire()){this.doSubmit();this.submitEvent.fire();if(this.cfg.getProperty("hideaftersubmit")){this.hide();}return true;}else{return false;}}else{return false;}},cancel:function(){this.cancelEvent.fire();this.hide();},getData:function(){var Y=this.form,J,R,U,L,S,P,O,I,V,K,W,Z,N,a,M,X,T;function Q(c){var b=c.tagName.toUpperCase();return((b=="INPUT"||b=="TEXTAREA"||b=="SELECT")&&c.name==L);}if(Y){J=Y.elements;R=J.length;U={};for(X=0;X<R;X++){L=J[X].name;S=E.getElementsBy(Q,"*",Y);P=S.length;if(P>0){if(P==1){S=S[0];O=S.type;I=S.tagName.toUpperCase();switch(I){case"INPUT":if(O=="checkbox"){U[L]=S.checked;}else{if(O!="radio"){U[L]=S.value;}}break;case"TEXTAREA":U[L]=S.value;break;case"SELECT":V=S.options;K=V.length;W=[];for(T=0;T<K;T++){Z=V[T];if(Z.selected){M=Z.attributes.value;W[W.length]=(M&&M.specified)?Z.value:Z.text;}}U[L]=W;break;}}else{O=S[0].type;switch(O){case"radio":for(T=0;T<P;T++){N=S[T];if(N.checked){U[L]=N.value;break;}}break;case"checkbox":W=[];for(T=0;T<P;T++){a=S[T];if(a.checked){W[W.length]=a.value;}}U[L]=W;break;}}}}}return U;},destroy:function(){D.call(this);this._aButtons=null;var I=this.element.getElementsByTagName("form"),J;if(I.length>0){J=I[0];if(J){B.purgeElement(J);if(J.parentNode){J.parentNode.removeChild(J);}this.form=null;}}A.superclass.destroy.call(this);},toString:function(){return"Dialog "+this.id;}});}());(function(){YAHOO.widget.SimpleDialog=function(E,D){YAHOO.widget.SimpleDialog.superclass.constructor.call(this,E,D);};var C=YAHOO.util.Dom,B=YAHOO.widget.SimpleDialog,A={"ICON":{key:"icon",value:"none",suppressEvent:true},"TEXT":{key:"text",value:"",suppressEvent:true,supercedes:["icon"]}};B.ICON_BLOCK="blckicon";B.ICON_ALARM="alrticon";B.ICON_HELP="hlpicon";B.ICON_INFO="infoicon";B.ICON_WARN="warnicon";B.ICON_TIP="tipicon";B.ICON_CSS_CLASSNAME="yui-icon";B.CSS_SIMPLEDIALOG="yui-simple-dialog";YAHOO.extend(B,YAHOO.widget.Dialog,{initDefaultConfig:function(){B.superclass.initDefaultConfig.call(this);this.cfg.addProperty(A.ICON.key,{handler:this.configIcon,value:A.ICON.value,suppressEvent:A.ICON.suppressEvent});this.cfg.addProperty(A.TEXT.key,{handler:this.configText,value:A.TEXT.value,suppressEvent:A.TEXT.suppressEvent,supercedes:A.TEXT.supercedes});},init:function(E,D){B.superclass.init.call(this,E);this.beforeInitEvent.fire(B);C.addClass(this.element,B.CSS_SIMPLEDIALOG);this.cfg.queueProperty("postmethod","manual");if(D){this.cfg.applyConfig(D,true);}this.beforeRenderEvent.subscribe(function(){if(!this.body){this.setBody("");}},this,true);this.initEvent.fire(B);},registerForm:function(){B.superclass.registerForm.call(this);this.form.innerHTML+='<input type="hidden" name="'+this.id+'" value=""/>';},configIcon:function(K,J,H){var D=J[0],E=this.body,F=B.ICON_CSS_CLASSNAME,L,I,G;if(D&&D!="none"){L=C.getElementsByClassName(F,"*",E);if(L.length===1){I=L[0];G=I.parentNode;if(G){G.removeChild(I);I=null;}}if(D.indexOf(".")==-1){I=document.createElement("span");I.className=(F+" "+D);I.innerHTML="&#160;";}else{I=document.createElement("img");I.src=(this.imageRoot+D);I.className=F;}if(I){E.insertBefore(I,E.firstChild);}}},configText:function(E,D,F){var G=D[0];if(G){this.setBody(G);this.cfg.refireEvent("icon");}},toString:function(){return"SimpleDialog "+this.id;}});}());(function(){YAHOO.widget.ContainerEffect=function(E,H,G,D,F){if(!F){F=YAHOO.util.Anim;}this.overlay=E;this.attrIn=H;this.attrOut=G;this.targetElement=D||E.element;this.animClass=F;};var B=YAHOO.util.Dom,C=YAHOO.util.CustomEvent,A=YAHOO.widget.ContainerEffect;A.FADE=function(D,F){var G=YAHOO.util.Easing,I={attributes:{opacity:{from:0,to:1}},duration:F,method:G.easeIn},E={attributes:{opacity:{to:0}},duration:F,method:G.easeOut},H=new A(D,I,E,D.element);H.handleUnderlayStart=function(){var K=this.overlay.underlay;if(K&&YAHOO.env.ua.ie){var J=(K.filters&&K.filters.length>0);if(J){B.addClass(D.element,"yui-effect-fade");}}};H.handleUnderlayComplete=function(){var J=this.overlay.underlay;if(J&&YAHOO.env.ua.ie){B.removeClass(D.element,"yui-effect-fade");}};H.handleStartAnimateIn=function(K,J,L){B.addClass(L.overlay.element,"hide-select");if(!L.overlay.underlay){L.overlay.cfg.refireEvent("underlay");}L.handleUnderlayStart();L.overlay._setDomVisibility(true);B.setStyle(L.overlay.element,"opacity",0);};H.handleCompleteAnimateIn=function(K,J,L){B.removeClass(L.overlay.element,"hide-select");if(L.overlay.element.style.filter){L.overlay.element.style.filter=null;}L.handleUnderlayComplete();L.overlay.cfg.refireEvent("iframe");L.animateInCompleteEvent.fire();};H.handleStartAnimateOut=function(K,J,L){B.addClass(L.overlay.element,"hide-select");L.handleUnderlayStart();};H.handleCompleteAnimateOut=function(K,J,L){B.removeClass(L.overlay.element,"hide-select");if(L.overlay.element.style.filter){L.overlay.element.style.filter=null;}L.overlay._setDomVisibility(false);B.setStyle(L.overlay.element,"opacity",1);L.handleUnderlayComplete();L.overlay.cfg.refireEvent("iframe");L.animateOutCompleteEvent.fire();};H.init();return H;};A.SLIDE=function(F,D){var I=YAHOO.util.Easing,L=F.cfg.getProperty("x")||B.getX(F.element),K=F.cfg.getProperty("y")||B.getY(F.element),M=B.getClientWidth(),H=F.element.offsetWidth,J={attributes:{points:{to:[L,K]}},duration:D,method:I.easeIn},E={attributes:{points:{to:[(M+25),K]}},duration:D,method:I.easeOut},G=new A(F,J,E,F.element,YAHOO.util.Motion);G.handleStartAnimateIn=function(O,N,P){P.overlay.element.style.left=((-25)-H)+"px";P.overlay.element.style.top=K+"px";};G.handleTweenAnimateIn=function(Q,P,R){var S=B.getXY(R.overlay.element),O=S[0],N=S[1];if(B.getStyle(R.overlay.element,"visibility")=="hidden"&&O<L){R.overlay._setDomVisibility(true);
+}R.overlay.cfg.setProperty("xy",[O,N],true);R.overlay.cfg.refireEvent("iframe");};G.handleCompleteAnimateIn=function(O,N,P){P.overlay.cfg.setProperty("xy",[L,K],true);P.startX=L;P.startY=K;P.overlay.cfg.refireEvent("iframe");P.animateInCompleteEvent.fire();};G.handleStartAnimateOut=function(O,N,R){var P=B.getViewportWidth(),S=B.getXY(R.overlay.element),Q=S[1];R.animOut.attributes.points.to=[(P+25),Q];};G.handleTweenAnimateOut=function(P,O,Q){var S=B.getXY(Q.overlay.element),N=S[0],R=S[1];Q.overlay.cfg.setProperty("xy",[N,R],true);Q.overlay.cfg.refireEvent("iframe");};G.handleCompleteAnimateOut=function(O,N,P){P.overlay._setDomVisibility(false);P.overlay.cfg.setProperty("xy",[L,K]);P.animateOutCompleteEvent.fire();};G.init();return G;};A.prototype={init:function(){this.beforeAnimateInEvent=this.createEvent("beforeAnimateIn");this.beforeAnimateInEvent.signature=C.LIST;this.beforeAnimateOutEvent=this.createEvent("beforeAnimateOut");this.beforeAnimateOutEvent.signature=C.LIST;this.animateInCompleteEvent=this.createEvent("animateInComplete");this.animateInCompleteEvent.signature=C.LIST;this.animateOutCompleteEvent=this.createEvent("animateOutComplete");this.animateOutCompleteEvent.signature=C.LIST;this.animIn=new this.animClass(this.targetElement,this.attrIn.attributes,this.attrIn.duration,this.attrIn.method);this.animIn.onStart.subscribe(this.handleStartAnimateIn,this);this.animIn.onTween.subscribe(this.handleTweenAnimateIn,this);this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);this.animOut=new this.animClass(this.targetElement,this.attrOut.attributes,this.attrOut.duration,this.attrOut.method);this.animOut.onStart.subscribe(this.handleStartAnimateOut,this);this.animOut.onTween.subscribe(this.handleTweenAnimateOut,this);this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,this);},animateIn:function(){this.beforeAnimateInEvent.fire();this.animIn.animate();},animateOut:function(){this.beforeAnimateOutEvent.fire();this.animOut.animate();},handleStartAnimateIn:function(E,D,F){},handleTweenAnimateIn:function(E,D,F){},handleCompleteAnimateIn:function(E,D,F){},handleStartAnimateOut:function(E,D,F){},handleTweenAnimateOut:function(E,D,F){},handleCompleteAnimateOut:function(E,D,F){},toString:function(){var D="ContainerEffect";if(this.overlay){D+=" ["+this.overlay.toString()+"]";}return D;}};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);})();YAHOO.register("container",YAHOO.widget.Module,{version:"2.8.2r1",build:"7"});/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+*/
+(function(){var A=YAHOO.util;A.Selector={_foundCache:[],_regexCache:{},_re:{nth:/^(?:([-]?\d*)(n){1}|(odd|even)$)*([-+]?\d*)$/,attr:/(\[.*\])/g,urls:/^(?:href|src)/},document:window.document,attrAliases:{},shorthand:{"\\#(-?[_a-z]+[-\\w]*)":"[id=$1]","\\.(-?[_a-z]+[-\\w]*)":"[class~=$1]"},operators:{"=":function(B,C){return B===C;},"!=":function(B,C){return B!==C;},"~=":function(B,D){var C=" ";return(C+B+C).indexOf((C+D+C))>-1;},"|=":function(B,C){return B===C||B.slice(0,C.length+1)===C+"-";},"^=":function(B,C){return B.indexOf(C)===0;},"$=":function(B,C){return B.slice(-C.length)===C;},"*=":function(B,C){return B.indexOf(C)>-1;},"":function(B,C){return B;}},pseudos:{"root":function(B){return B===B.ownerDocument.documentElement;},"nth-child":function(B,C){return A.Selector._getNth(B,C);},"nth-last-child":function(B,C){return A.Selector._getNth(B,C,null,true);},"nth-of-type":function(B,C){return A.Selector._getNth(B,C,B.tagName);},"nth-last-of-type":function(B,C){return A.Selector._getNth(B,C,B.tagName,true);},"first-child":function(B){return A.Selector._getChildren(B.parentNode)[0]===B;},"last-child":function(C){var B=A.Selector._getChildren(C.parentNode);return B[B.length-1]===C;},"first-of-type":function(B,C){return A.Selector._getChildren(B.parentNode,B.tagName)[0];},"last-of-type":function(C,D){var B=A.Selector._getChildren(C.parentNode,C.tagName);return B[B.length-1];},"only-child":function(C){var B=A.Selector._getChildren(C.parentNode);return B.length===1&&B[0]===C;},"only-of-type":function(B){return A.Selector._getChildren(B.parentNode,B.tagName).length===1;},"empty":function(B){return B.childNodes.length===0;},"not":function(B,C){return !A.Selector.test(B,C);},"contains":function(B,D){var C=B.innerText||B.textContent||"";return C.indexOf(D)>-1;},"checked":function(B){return B.checked===true;}},test:function(F,D){F=A.Selector.document.getElementById(F)||F;if(!F){return false;}var C=D?D.split(","):[];if(C.length){for(var E=0,B=C.length;E<B;++E){if(A.Selector._test(F,C[E])){return true;}}return false;}return A.Selector._test(F,D);},_test:function(D,G,F,E){F=F||A.Selector._tokenize(G).pop()||{};if(!D.tagName||(F.tag!=="*"&&D.tagName!==F.tag)||(E&&D._found)){return false;}if(F.attributes.length){var B,H,C=A.Selector._re.urls;if(!D.attributes||!D.attributes.length){return false;}for(var I=0,K;K=F.attributes[I++];){H=(C.test(K[0]))?2:0;B=D.getAttribute(K[0],H);if(B===null||B===undefined){return false;}if(A.Selector.operators[K[1]]&&!A.Selector.operators[K[1]](B,K[2])){return false;}}}if(F.pseudos.length){for(var I=0,J=F.pseudos.length;I<J;++I){if(A.Selector.pseudos[F.pseudos[I][0]]&&!A.Selector.pseudos[F.pseudos[I][0]](D,F.pseudos[I][1])){return false;}}}return(F.previous&&F.previous.combinator!==",")?A.Selector._combinators[F.previous.combinator](D,F):true;},filter:function(E,D){E=E||[];var G,C=[],H=A.Selector._tokenize(D);if(!E.item){for(var F=0,B=E.length;F<B;++F){if(!E[F].tagName){G=A.Selector.document.getElementById(E[F]);if(G){E[F]=G;}else{}}}}C=A.Selector._filter(E,A.Selector._tokenize(D)[0]);return C;},_filter:function(E,G,H,D){var C=H?null:[],I=A.Selector._foundCache;for(var F=0,B=E.length;F<B;F++){if(!A.Selector._test(E[F],"",G,D)){continue;}if(H){return E[F];}if(D){if(E[F]._found){continue;}E[F]._found=true;I[I.length]=E[F];}C[C.length]=E[F];}return C;},query:function(C,D,E){var B=A.Selector._query(C,D,E);return B;},_query:function(H,M,N,F){var P=(N)?null:[],E;if(!H){return P;}var D=H.split(",");if(D.length>1){var O;for(var I=0,J=D.length;I<J;++I){O=A.Selector._query(D[I],M,N,true);P=N?O:P.concat(O);}A.Selector._clearFoundCache();return P;}if(M&&!M.nodeName){M=A.Selector.document.getElementById(M);if(!M){return P;}}M=M||A.Selector.document;if(M.nodeName!=="#document"){A.Dom.generateId(M);H=M.tagName+"#"+M.id+" "+H;E=M;M=M.ownerDocument;}var L=A.Selector._tokenize(H);var K=L[A.Selector._getIdTokenIndex(L)],B=[],C,G=L.pop()||{};if(K){C=A.Selector._getId(K.attributes);}if(C){E=E||A.Selector.document.getElementById(C);if(E&&(M.nodeName==="#document"||A.Dom.isAncestor(M,E))){if(A.Selector._test(E,null,K)){if(K===G){B=[E];}else{if(K.combinator===" "||K.combinator===">"){M=E;}}}}else{return P;}}if(M&&!B.length){B=M.getElementsByTagName(G.tag);}if(B.length){P=A.Selector._filter(B,G,N,F);}return P;},_clearFoundCache:function(){var E=A.Selector._foundCache;for(var C=0,B=E.length;C<B;++C){try{delete E[C]._found;}catch(D){E[C].removeAttribute("_found");}}E=[];},_getRegExp:function(D,B){var C=A.Selector._regexCache;B=B||"";if(!C[D+B]){C[D+B]=new RegExp(D,B);}return C[D+B];},_getChildren:function(){if(document.documentElement.children&&document.documentElement.children.tags){return function(C,B){return(B)?C.children.tags(B):C.children||[];};}else{return function(F,C){var E=[],G=F.childNodes;for(var D=0,B=G.length;D<B;++D){if(G[D].tagName){if(!C||G[D].tagName===C){E.push(G[D]);}}}return E;};}}(),_combinators:{" ":function(C,B){while((C=C.parentNode)){if(A.Selector._test(C,"",B.previous)){return true;}}return false;},">":function(C,B){return A.Selector._test(C.parentNode,null,B.previous);},"+":function(D,C){var B=D.previousSibling;while(B&&B.nodeType!==1){B=B.previousSibling;}if(B&&A.Selector._test(B,null,C.previous)){return true;}return false;},"~":function(D,C){var B=D.previousSibling;while(B){if(B.nodeType===1&&A.Selector._test(B,null,C.previous)){return true;}B=B.previousSibling;}return false;}},_getNth:function(C,L,N,G){A.Selector._re.nth.test(L);var K=parseInt(RegExp.$1,10),B=RegExp.$2,H=RegExp.$3,I=parseInt(RegExp.$4,10)||0,M=[],E;var J=A.Selector._getChildren(C.parentNode,N);if(H){K=2;E="+";B="n";I=(H==="odd")?1:0;}else{if(isNaN(K)){K=(B)?1:0;}}if(K===0){if(G){I=J.length-I+1;}if(J[I-1]===C){return true;}else{return false;}}else{if(K<0){G=!!G;K=Math.abs(K);}}if(!G){for(var D=I-1,F=J.length;D<F;D+=K){if(D>=0&&J[D]===C){return true;}}}else{for(var D=J.length-I,F=J.length;D>=0;D-=K){if(D<F&&J[D]===C){return true;}}}return false;},_getId:function(C){for(var D=0,B=C.length;D<B;++D){if(C[D][0]=="id"&&C[D][1]==="="){return C[D][2];
+}}},_getIdTokenIndex:function(D){for(var C=0,B=D.length;C<B;++C){if(A.Selector._getId(D[C].attributes)){return C;}}return -1;},_patterns:{tag:/^((?:-?[_a-z]+[\w-]*)|\*)/i,attributes:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,pseudos:/^:([-\w]+)(?:\(['"]?(.+)['"]?\))*/i,combinator:/^\s*([>+~]|\s)\s*/},_tokenize:function(B){var D={},H=[],I,G=false,F=A.Selector._patterns,C;B=A.Selector._replaceShorthand(B);do{G=false;for(var E in F){if(YAHOO.lang.hasOwnProperty(F,E)){if(E!="tag"&&E!="combinator"){D[E]=D[E]||[];}if((C=F[E].exec(B))){G=true;if(E!="tag"&&E!="combinator"){if(E==="attributes"&&C[1]==="id"){D.id=C[3];}D[E].push(C.slice(1));}else{D[E]=C[1];}B=B.replace(C[0],"");if(E==="combinator"||!B.length){D.attributes=A.Selector._fixAttributes(D.attributes);D.pseudos=D.pseudos||[];D.tag=D.tag?D.tag.toUpperCase():"*";H.push(D);D={previous:D};}}}}}while(G);return H;},_fixAttributes:function(C){var D=A.Selector.attrAliases;C=C||[];for(var E=0,B=C.length;E<B;++E){if(D[C[E][0]]){C[E][0]=D[C[E][0]];}if(!C[E][1]){C[E][1]="";}}return C;},_replaceShorthand:function(C){var D=A.Selector.shorthand;var E=C.match(A.Selector._re.attr);if(E){C=C.replace(A.Selector._re.attr,"REPLACED_ATTRIBUTE");}for(var G in D){if(YAHOO.lang.hasOwnProperty(D,G)){C=C.replace(A.Selector._getRegExp(G,"gi"),D[G]);}}if(E){for(var F=0,B=E.length;F<B;++F){C=C.replace("REPLACED_ATTRIBUTE",E[F]);}}return C;}};if(YAHOO.env.ua.ie&&YAHOO.env.ua.ie<8){A.Selector.attrAliases["class"]="className";A.Selector.attrAliases["for"]="htmlFor";}})();YAHOO.register("selector",YAHOO.util.Selector,{version:"2.8.2r1",build:"7"});
\ No newline at end of file
--- a/rhodecode/templates/admin/admin_log.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/admin_log.html	Sat Dec 18 14:45:58 2010 +0100
@@ -3,8 +3,8 @@
 <table>
 	<tr>
 		<th class="left">${_('Username')}</th>
+		<th class="left">${_('Action')}</th>
 		<th class="left">${_('Repository')}</th>
-		<th class="left">${_('Action')}</th>
 		<th class="left">${_('Date')}</th>
 		<th class="left">${_('From IP')}</th>
 	</tr>
@@ -12,6 +12,7 @@
 	%for cnt,l in enumerate(c.users_log):
 	<tr class="parity${cnt%2}">
 		<td>${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}</td>
+		<td>${h.action_parser(l)}</td>
 		<td>
 		%if l.repository:
 		  ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
@@ -19,14 +20,7 @@
 		  ${l.repository_name}
 		%endif
 		</td>
-		<td>
-		% if l.action == 'push' and l.revision:
-		  ${h.link_to('%s - %s' % (l.action,l.revision),
-		  h.url('changeset_home',repo_name=l.repository.repo_name,revision=l.revision))}
-		%else:
-		  ${l.action}
-		%endif
-		</td>
+		
 		<td>${l.action_date}</td>
 		<td>${l.user_ip}</td>
 	</tr>
@@ -35,19 +29,34 @@
 
 <script type="text/javascript">
   var data_div = 'user_log';
-  YAHOO.util.Event.onDOMReady(function(){
-	YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
-			YAHOO.util.Dom.setStyle('shortlog_data','opacity','0.3');});});
+  YUE.onDOMReady(function(){
+	YUE.on(YUD.getElementsByClassName('pager_link'),"click",function(){
+			YUD.setStyle(data_div,'opacity','0.3');});
+	YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
+	      var el = e.target;
+	      YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
+	      YUD.setStyle(el.parentNode,'display','none');
+	  });
+  });
 </script>
 		
 		
 <div class="pagination-wh pagination-left">
 ${c.users_log.pager('$link_previous ~2~ $link_next',
 onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
-success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
-YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
-		YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});		
-YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
+success:function(o){
+    YUD.get(data_div).innerHTML=o.responseText;
+    YUE.on(YUD.getElementsByClassName('pager_link'),"click",function(){
+        YUD.setStyle(data_div,'opacity','0.3');
+    });		
+    YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
+      var el = e.target;
+      YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
+      YUD.setStyle(el.parentNode,'display','none');
+    });
+    YUD.setStyle(data_div,'opacity','1');}    
+
+},null); return false;""")}
 </div>
 %else: 
 	${_('No actions yet')} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/admin/ldap/ldap.html	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,73 @@
+## -*- coding: utf-8 -*-
+<%inherit file="/base/base.html"/>
+
+<%def name="title()">
+    ${_('LDAP administration')} - ${c.rhodecode_name}
+</%def>
+
+<%def name="breadcrumbs_links()">
+    ${h.link_to(_('Admin'),h.url('admin_home'))} 
+    &raquo;
+    ${_('Ldap')}    
+</%def>
+
+<%def name="page_nav()">
+    ${self.menu('admin')}
+</%def>
+
+<%def name="main()">
+<div class="box">
+    <!-- box / title -->
+    <div class="title">
+        ${self.breadcrumbs()}       
+    </div>
+    <h3>${_('LDAP administration')}</h3>
+    ${h.form(url('ldap_settings'))}
+    <div class="form">
+        <div class="fields">
+
+            <div class="field">
+                <div class="label label-checkbox"><label for="ldap_active">${_('Enable ldap')}</label></div>
+                <div class="checkboxes"><div class="checkbox">${h.checkbox('ldap_active',True,class_='small')}</div></div>
+            </div>
+            <div class="field">
+                <div class="label"><label for="ldap_host">${_('Host')}</label></div>
+                <div class="input">${h.text('ldap_host',class_='small')}</div>
+            </div>
+            <div class="field">
+                <div class="label"><label for="ldap_port">${_('Port')}</label></div>
+                <div class="input">${h.text('ldap_port',class_='small')}</div>
+            </div>
+            <div class="field">
+                <div class="label label-checkbox"><label for="ldap_ldaps">${_('Enable LDAPS')}</label></div>
+                <div class="checkboxes"><div class="checkbox">${h.checkbox('ldap_ldaps',True,class_='small')}</div></div>
+            </div>
+            <div class="field">
+                <div class="label"><label for="ldap_dn_user">${_('Account')}</label></div>
+                <div class="input">${h.text('ldap_dn_user',class_='small')}</div>
+            </div>
+            <div class="field">
+                <div class="label"><label for="ldap_dn_pass">${_('Password')}</label></div>
+                <div class="input">${h.password('ldap_dn_pass',class_='small')}</div>
+            </div>
+            <div class="field">
+                <div class="label"><label for="ldap_base_dn">${_('Base DN')}</label></div>
+                <div class="input">${h.text('ldap_base_dn',class_='small')}</div>
+            </div>
+            
+            <div class="buttons">
+            ${h.submit('save','Save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+            </div>              
+        </div>
+    </div>     
+    ${h.end_form()}    
+</div>
+</%def>    
+
+
+
+
+
+
+   
+
--- a/rhodecode/templates/admin/permissions/permissions.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/permissions/permissions.html	Sat Dec 18 14:45:58 2010 +0100
@@ -26,9 +26,18 @@
     <div class="form">
         <!-- fields -->
         <div class="fields">
-        
+            <div class="field">
+                <div class="label label-checkbox">
+                    <label for="anonymous">${_('Anonymous access')}:</label>
+                </div>
+                <div class="checkboxes">
+                    <div class="checkbox">
+                        ${h.checkbox('anonymous',True)}
+                    </div>
+                </div>
+            </div>        
 			<div class="field">
-				<div class="label">
+				<div class="label label-select">
 					<label for="default_perm">${_('Repository permission')}:</label>
 				</div>
 				<div class="select">
@@ -66,3 +75,10 @@
     ${h.end_form()}
 </div>
 </%def>    
+
+
+
+
+
+
+   
--- a/rhodecode/templates/admin/repos/repo_add.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/repos/repo_add.html	Sat Dec 18 14:45:58 2010 +0100
@@ -35,6 +35,14 @@
 	            </div>
              </div>
             <div class="field">
+                <div class="label">
+                    <label for="repo_type">${_('Type')}:</label>
+                </div>
+                <div class="input">
+                    ${h.select('repo_type','hg',c.backends,class_="small")}
+                </div>
+             </div>             
+            <div class="field">
                 <div class="label label-textarea">
                     <label for="description">${_('Description')}:</label>
                 </div>
--- a/rhodecode/templates/admin/repos/repo_add_create_repository.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/repos/repo_add_create_repository.html	Sat Dec 18 14:45:58 2010 +0100
@@ -32,6 +32,14 @@
 	            </div>
              </div>
             <div class="field">
+                <div class="label">
+                    <label for="repo_type">${_('Type')}:</label>
+                </div>
+                <div class="input">
+                    ${h.select('repo_type','hg',c.backends,class_="small")}
+                </div>
+             </div>             
+            <div class="field">
                 <div class="label label-textarea">
                     <label for="description">${_('Description')}:</label>
                 </div>
--- a/rhodecode/templates/admin/repos/repo_edit.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/repos/repo_edit.html	Sat Dec 18 14:45:58 2010 +0100
@@ -18,7 +18,7 @@
 </%def>
 
 <%def name="main()">
-<div class="box">
+<div class="box box-left">
     <!-- box / title -->
     <div class="title">
         ${self.breadcrumbs()}      
@@ -31,11 +31,18 @@
                 <div class="label">
                     <label for="repo_name">${_('Name')}:</label>
                 </div>
-                <div class="input input-medium">
-                    ${h.text('repo_name',class_="small")}
+                <div class="input">
+                    ${h.text('repo_name',class_="medium")}
                 </div>
              </div>
-             
+            <div class="field">
+                <div class="label">
+                    <label for="repo_type">${_('Type')}:</label>
+                </div>
+                <div class="input">
+                    ${h.select('repo_type','hg',c.backends,class_="medium")}
+                </div>
+             </div>             
             <div class="field">
                 <div class="label label-textarea">
                     <label for="description">${_('Description')}:</label>
@@ -53,7 +60,14 @@
                     ${h.checkbox('private',value="True")}
                 </div>
             </div>
-             
+            <div class="field">
+                <div class="label label-checkbox">
+                    <label for="enable_statistics">${_('Enable statistics')}:</label>
+                </div>
+                <div class="checkboxes">
+                    ${h.checkbox('enable_statistics',value="True")}
+                </div>
+            </div>             
             <div class="field">
                 <div class="label">
                     <label for="user">${_('Owner')}:</label>
@@ -142,7 +156,8 @@
              </div>
              
             <div class="buttons">
-              ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+              ${h.submit('save','Save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+              ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
             </div>                                                          
         </div>
     </div>
@@ -272,4 +287,50 @@
         </script>      
 
 </div>
+
+<div class="box box-right">
+    <div class="title">
+        <h5>${_('Administration')}</h5>    
+    </div>
+    
+        <h3>${_('Statistics')}</h3>
+        
+        ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
+        <div class="form">
+           <div class="fields">
+               ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="refresh_icon action_button",onclick="return confirm('Confirm to remove current statistics');")}
+               
+               <div class="field">
+               <ul>
+                    <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
+                    <li>${_('Percentage of stats gathered')}: ${c.stats_percentage} %</li>
+               </ul>
+               </div>
+               
+           </div>
+        </div>                    
+        ${h.end_form()}
+        
+        <h3>${_('Cache')}</h3>
+        ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
+        <div class="form">
+           <div class="fields">
+               ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="refresh_icon action_button",onclick="return confirm('Confirm to invalidate repository cache');")}
+           </div>
+        </div>                    
+        ${h.end_form()}
+        
+        
+        <h3>${_('Delete')}</h3>
+        ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
+        <div class="form">
+           <div class="fields">
+               ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
+           </div>
+        </div>                    
+        ${h.end_form()}
+    
+</div>
+
+
 </%def> 
\ No newline at end of file
--- a/rhodecode/templates/admin/repos/repos.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/repos/repos.html	Sat Dec 18 14:45:58 2010 +0100
@@ -37,6 +37,16 @@
             %for cnt,repo in enumerate(c.repos_list):
             <tr class="parity${cnt%2}">
                  <td>
+                 ## TYPE OF REPO
+                 %if repo['repo'].dbrepo.repo_type =='hg':
+                   <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
+                 %elif repo['repo'].dbrepo.repo_type =='git':
+                   <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
+                 %else:
+                   
+                 %endif
+                 
+                 ## PRIVATE/PUBLIC REPO                  
                  %if repo['repo'].dbrepo.private:
                     <img alt="${_('private')}" src="/images/icons/lock.png"/>
                  %else:
@@ -55,7 +65,7 @@
 	            <td>${h.age(repo['last_change'])}</td>
 	            <td>
 	            	%if repo['rev']>=0:
-	            	${h.link_to('r%s:%s' % (repo['rev'],repo['tip']),
+	            	${h.link_to('r%s:%s' % (repo['rev'],h.short_id(repo['tip'])),
 	                h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
 	                class_="tooltip",
 	                tooltip_title=h.tooltip(repo['last_msg']))}
--- a/rhodecode/templates/admin/settings/settings.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/settings/settings.html	Sat Dec 18 14:45:58 2010 +0100
@@ -42,7 +42,7 @@
 			</div>
                             
             <div class="buttons">
-            ${h.submit('rescan','rescan repositories',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+            ${h.submit('rescan','Rescan repositories',class_="ui-button ui-widget ui-state-default ui-corner-all")}
             </div>                                                          
         </div>
     </div>  
@@ -67,7 +67,7 @@
             </div>
                             
             <div class="buttons">
-            ${h.submit('reindex','reindex',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+            ${h.submit('reindex','Reindex',class_="ui-button ui-widget ui-state-default ui-corner-all")}
             </div>                                                          
         </div>
     </div>  
@@ -99,7 +99,8 @@
             </div>
                                      
             <div class="buttons">
-                ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+                ${h.submit('save','Save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+                ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
            </div>                                                          
         </div>
     </div>      
@@ -136,7 +137,15 @@
 					<div class="checkbox">
 						${h.checkbox('hooks_changegroup_repo_size','True')}
 						<label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
-					</div>					
+					</div>
+                    <div class="checkbox">
+                        ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
+                        <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
+                    </div>
+                    <div class="checkbox">
+                        ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
+                        <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
+                    </div>                    										
 				</div>
              </div>	
 							                          
@@ -153,7 +162,8 @@
             </div>
                                      
             <div class="buttons">
-                ${h.submit('save','save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+                ${h.submit('save','Save settings',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+                ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
            </div>                                                          
         </div>
     </div>      
--- a/rhodecode/templates/admin/users/user_add.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/users/user_add.html	Sat Dec 18 14:45:58 2010 +0100
@@ -47,7 +47,7 @@
             
              <div class="field">
                 <div class="label">
-                    <label for="name">${_('Name')}:</label>
+                    <label for="name">${_('First Name')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('name',class_='small')}
@@ -56,7 +56,7 @@
             
              <div class="field">
                 <div class="label">
-                    <label for="lastname">${_('Lastname')}:</label>
+                    <label for="lastname">${_('Last Name')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('lastname',class_='small')}
--- a/rhodecode/templates/admin/users/user_edit.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/users/user_edit.html	Sat Dec 18 14:45:58 2010 +0100
@@ -58,7 +58,7 @@
             
              <div class="field">
                 <div class="label">
-                    <label for="name">${_('Name')}:</label>
+                    <label for="name">${_('First Name')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('name',class_='small')}
@@ -67,7 +67,7 @@
             
              <div class="field">
                 <div class="label">
-                    <label for="lastname">${_('Lastname')}:</label>
+                    <label for="lastname">${_('Last Name')}:</label>
                 </div>
                 <div class="input">
                     ${h.text('lastname',class_='small')}
@@ -101,7 +101,8 @@
                 </div>
              </div>             
             <div class="buttons">
-              ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+              ${h.submit('save','Save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+              ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
             </div>             
     	</div>    
     </div>
--- a/rhodecode/templates/admin/users/user_edit_my_account.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/users/user_edit_my_account.html	Sat Dec 18 14:45:58 2010 +0100
@@ -24,13 +24,24 @@
     <div class="ui-tabs-panel ui-widget-content ui-corner-bottom">
     ${h.form(url('admin_settings_my_account_update'),method='put')}
 	    <div class="form">
+	    
+             <div class="field">
+                <div class="gravatar_box">
+                    <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
+                    <p>
+                    <strong>Change your avatar at <a href="http://gravatar.com">gravatar.com</a></strong><br/> 
+                    ${_('Using')} ${c.user.email}
+                    </p>
+                </div>
+             </div>   	    
+	    
 	        <div class="fields">
 	             <div class="field">
 	                <div class="label">
 	                    <label for="username">${_('Username')}:</label>
 	                </div>
 	                <div class="input">
-	                    ${h.text('username')}
+	                    ${h.text('username',class_="medium")}
 	                </div>
 	             </div>
 	            
@@ -39,25 +50,25 @@
 	                    <label for="new_password">${_('New password')}:</label>
 	                </div>
 	                <div class="input">
-	                    ${h.password('new_password')}
+	                    ${h.password('new_password',class_="medium")}
 	                </div>
 	             </div>
 	            
 	             <div class="field">
 	                <div class="label">
-	                    <label for="name">${_('Name')}:</label>
+	                    <label for="name">${_('First Name')}:</label>
 	                </div>
 	                <div class="input">
-	                    ${h.text('name')}
+	                    ${h.text('name',class_="medium")}
 	                </div>
 	             </div>
 	            
 	             <div class="field">
 	                <div class="label">
-	                    <label for="lastname">${_('Lastname')}:</label>
+	                    <label for="lastname">${_('Last Name')}:</label>
 	                </div>
 	                <div class="input">
-	                    ${h.text('lastname')}
+	                    ${h.text('lastname',class_="medium")}
 	                </div>
 	             </div>
 	            
@@ -66,12 +77,16 @@
 	                    <label for="email">${_('Email')}:</label>
 	                </div>
 	                <div class="input">
-	                    ${h.text('email')}
+	                    ${h.text('email',class_="medium")}
 	                </div>
 	             </div>
 	            
 	            <div class="buttons">
-	              ${h.submit('save','save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+	              ${h.submit('save','Save',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+	              ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+	              
+	              
+	              
 	            </div>             
 	    	</div>
 	    </div>    	
@@ -82,36 +97,57 @@
 <div class="box box-right">
     <!-- box / title -->
     <div class="title">
-        <h5>${_('My repositories')}</h5>   
+        <h5>${_('My repositories')} 
+        <input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
+        </h5>
+         %if h.HasPermissionAny('hg.admin','hg.create.repository')():
+         <ul class="links">
+           <li>
+             <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
+           </li>          
+         </ul>           
+         %endif        
     </div>
     <!-- end box / title -->
     <div class="table">
 	    <table>
+	    <thead>
+            <tr>
+            <th class="left">${_('Name')}</th>
+            <th class="left">${_('revision')}</th>
+            <th colspan="2" class="left">${_('action')}</th>            
+	    </thead>
 	     <tbody>
 	     %if c.user_repos:
 		     %for repo in c.user_repos:
 		        <tr>
 		            <td>
-		             %if repo.dbrepo.private:
+                     %if repo['repo'].dbrepo.repo_type =='hg':
+                       <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
+                     %elif repo['repo'].dbrepo.repo_type =='git':
+                       <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
+                     %else:
+                       
+                     %endif 		            
+		             %if repo['repo'].dbrepo.private:
 		                <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
 		             %else:
 		                <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
 		             %endif
 		                                             
-		            ${h.link_to(repo.name, h.url('summary_home',repo_name=repo.name))}
-		            %if repo.dbrepo.fork:
-		            	<a href="${h.url('summary_home',repo_name=repo.dbrepo.fork.repo_name)}">
+		            ${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")}
+		            %if repo['repo'].dbrepo.fork:
+		            	<a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
 		            	<img class="icon" alt="${_('public')}"
-		            	title="${_('Fork of')} ${repo.dbrepo.fork.repo_name}" 
+		            	title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}" 
 		            	src="/images/icons/arrow_divide.png"/></a>
 		            %endif		            
 		            </td> 
-		            <td>${_('revision')}: ${h.get_changeset_safe(repo,'tip').revision}</td>
-		            <td>${_('last changed')}: ${h.age(repo.last_change)}</td>
-		            <td><img class="icon" alt="${_('private')}" src="/images/icons/application_form_edit.png"/> ${h.link_to(_('edit'),h.url('repo_settings_home',repo_name=repo.name))}</td>
+		            <td><span class="tooltip" tooltip_title="${repo['repo'].last_change}">${("r%s:%s") % (h.get_changeset_safe(repo['repo'],'tip').revision,h.short_id(h.get_changeset_safe(repo['repo'],'tip').raw_id))}</span></td>
+		            <td><a href="${h.url('repo_settings_home',repo_name=repo['repo'].name)}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="/images/icons/application_form_edit.png"/></a></td>
 		            <td>
-	                  ${h.form(url('repo_settings_delete', repo_name=repo.name),method='delete')}
-	                    ${h.submit('remove_%s' % repo.name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
+	                  ${h.form(url('repo_settings_delete', repo_name=repo['repo'].name),method='delete')}
+	                    ${h.submit('remove_%s' % repo['repo'].name,'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
 	                  ${h.end_form()}	            
 		            </td>
 		        </tr>
@@ -127,4 +163,48 @@
     </div>
     
 </div>
+    <script type="text/javascript">
+     var D = YAHOO.util.Dom;
+     var E = YAHOO.util.Event;
+     var S = YAHOO.util.Selector;
+     
+     var q_filter = D.get('q_filter');
+     var F = YAHOO.namespace('q_filter'); 
+     
+     E.on(q_filter,'click',function(){
+        q_filter.value = '';
+     });
+
+     F.filterTimeout = null;
+     
+     F.updateFilter  = function() { 
+        // Reset timeout 
+        F.filterTimeout = null;
+        
+        var obsolete = [];
+        var nodes = S.query('div.table tr td a.repo_name');
+        var req = D.get('q_filter').value;
+        for (n in nodes){
+            D.setStyle(nodes[n].parentNode.parentNode,'display','')
+        }
+        if (req){
+            for (n in nodes){
+                if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
+                    obsolete.push(nodes[n]); 
+                }
+            }
+            if(obsolete){
+                for (n in obsolete){
+                    D.setStyle(obsolete[n].parentNode.parentNode,'display','none');
+                }
+            }
+        }
+     }
+     
+     E.on(q_filter,'keyup',function(e){
+         clearTimeout(F.filterTimeout); 
+         setTimeout(F.updateFilter,600); 
+     });
+     
+    </script>
 </%def>  
\ No newline at end of file
--- a/rhodecode/templates/admin/users/users.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/admin/users/users.html	Sat Dec 18 14:45:58 2010 +0100
@@ -35,20 +35,23 @@
             <th class="left">${_('lastname')}</th>
             <th class="left">${_('active')}</th>
             <th class="left">${_('admin')}</th>
+            <th class="left">${_('ldap')}</th>
             <th class="left">${_('action')}</th>
         </tr>
             %for cnt,user in enumerate(c.users_list):
              %if user.name !='default':
                 <tr class="parity${cnt%2}">
-                	<td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"> </div></td>
+                	<td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div></td>
                     <td>${h.link_to(user.username,h.url('edit_user', id=user.user_id))}</td>
                     <td>${user.name}</td>
                     <td>${user.lastname}</td>
-                    <td>${user.active}</td>
-                    <td>${user.admin}</td>
+                    <td>${h.bool2icon(user.active)}</td>
+                    <td>${h.bool2icon(user.admin)}</td>
+                    <td>${h.bool2icon(user.is_ldap)}</td>
                     <td>
                         ${h.form(url('user', id=user.user_id),method='delete')}
-                            ${h.submit('remove','delete',class_="delete_icon action_button")}
+                            ${h.submit('remove_','delete',id="remove_user_%s" % user.user_id,
+                            class_="delete_icon action_button",onclick="return confirm('Confirm to delete this user');")}
                         ${h.end_form()}
                     </td>
                 </tr>
--- a/rhodecode/templates/base/base.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/base/base.html	Sat Dec 18 14:45:58 2010 +0100
@@ -3,7 +3,7 @@
 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
 <head>
     <title>${next.title()}</title>
-    <link rel="icon" href="/images/hgicon.png" type="image/png" />
+    <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
     <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
     <meta name="robots" content="index, nofollow"/>
     <!-- stylesheets -->
@@ -16,22 +16,43 @@
     <div id="header">
         <!-- user -->
         <ul id="logged-user">
-            <li class="first">
-	            <div class="gravatar">
-	            	<img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
-	            </div>
-	            <div class="account">
-	            	${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
-	            	${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'))}
-	            </div>	
-            </li>
-            <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
+	            <li class="first">
+	                <div class="gravatar">
+	                    <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
+	                </div>
+		            <div class="account">
+		            %if c.rhodecode_user.username == 'default':
+                        %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')(): 
+                            ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
+                        %else:
+                            ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
+                        %endif		            
+                        
+                    %else:                        		            
+		            	${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
+		            %endif
+		            </div>	
+	            </li>
+	            <li>
+	               <a href="${h.url('home')}">${_('Home')}</a>
+	            </li>
+	            %if c.rhodecode_user.username != 'default':
+                <li>
+                   <a href="${h.url('journal')}">${_('Journal')}</a> 
+                   ##(${c.unread_journal})</a>
+                </li>
+                %endif
+                %if c.rhodecode_user.username == 'default':
+                    <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
+                %else:
+                    <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
+                %endif
         </ul>
         <!-- end user -->
         <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
             <!-- logo -->
             <div id="logo">
-                <h1><a href="${h.url('hg_home')}">${c.rhodecode_name}</a></h1>
+                <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
             </div>
             <!-- end logo -->
             <!-- menu -->
@@ -98,11 +119,12 @@
                     <span>&darr;</span>					
 					</a>
 					<ul class="repo_switcher">
-                        %for repo,private in c.repo_switcher_list:
-                          %if private:
-                             <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li>
+                        %for repo in c.cached_repo_list:
+                        
+                          %if repo['repo'].dbrepo.private:
+                             <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
                           %else:
-                             <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li>
+                             <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
                           %endif  
                         %endfor					
 					</ul>			
@@ -116,14 +138,14 @@
 	               <span>${_('Summary')}</span>                 
 	               </a>	            
 	            </li>
-                <li ${is_current('shortlog')}>
-                   <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
-                   <span class="icon">
-                       <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
-                   </span>
-                   <span>${_('Shortlog')}</span>                 
-                   </a>             
-                </li>	            
+                ##<li ${is_current('shortlog')}>
+                ##   <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
+                ##   <span class="icon">
+                ##       <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
+                ##   </span>
+                ##   <span>${_('Shortlog')}</span>                 
+                ##   </a>             
+                ##</li>	            
                 <li ${is_current('changelog')}>
                    <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
                    <span class="icon">
@@ -142,11 +164,11 @@
                    </a>    
                     <ul>
                         <li>
-                            ${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
+                            ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
                             <ul>
                             %if c.repository_branches.values():
 						        %for cnt,branch in enumerate(c.repository_branches.items()):
-						            <li>${h.link_to('%s - %s' % (branch[0],branch[1]),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
+						            <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
 						        %endfor
 						    %else:
 						    	<li>${h.link_to(_('There are no branches yet'),'#')}</li>
@@ -154,11 +176,11 @@
                             </ul>                        
                         </li>
                         <li>
-                            ${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
+                            ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
                             <ul>
                             %if c.repository_tags.values():
                                 %for cnt,tag in enumerate(c.repository_tags.items()):
-                                 <li>${h.link_to('%s - %s' % (tag[0],tag[1]),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
+                                 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
                                 %endfor
                             %else:
                             	<li>${h.link_to(_('There are no tags yet'),'#')}</li>
@@ -186,47 +208,72 @@
                    <ul>
                    %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
                    	<li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
-                   %endif	
                    	<li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
+                   %endif  
                    	<li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
                     
                     %if h.HasPermissionAll('hg.admin')('access admin main page'):
                     <li>
                        ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}  
+                        <%def name="admin_menu()">
                         <ul>
                             <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
                             <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
                             <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
                             <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
+                            <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
                             <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>        
                         </ul>
+                        </%def>
+                        
+                        ${admin_menu()}
                     </li>
-                    %endif                    
+                    %endif
 
-                
-##                   %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
-##                   	<li class="last">
-##                   	${h.link_to(_('delete'),'#',class_='delete')}
-##	                  ${h.form(url('repo_settings_delete', repo_name=c.repo_name),method='delete')}
-##	                    ${h.submit('remove_%s' % c.repo_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
-##	                  ${h.end_form()}
-##                   	</li>
-##                   	%endif
                    </ul>             
                 </li>
+                
+                <li>
+                    <a title="${_('Followers')}" href="#">
+                    <span class="icon_short">
+                        <img src="/images/icons/heart.png" alt="${_('Followers')}" />
+                    </span>
+                    <span class="short">${c.repository_followers}</span>
+                    </a>
+                </li>
+                <li>
+                    <a title="${_('Forks')}" href="#">
+                    <span class="icon_short">
+                        <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
+                    </span>
+                    <span class="short">${c.repository_forks}</span>
+                    </a>
+                </li>                
+                
+                
+                
 	        </ul>
 		%else:
 		    ##ROOT MENU
             <ul id="quick">
                 <li>
-                    <a title="${_('Home')}"  href="${h.url('hg_home')}">
+                    <a title="${_('Home')}"  href="${h.url('home')}">
                     <span class="icon">
                         <img src="/images/icons/home_16.png" alt="${_('Home')}" />
                     </span>
                     <span>${_('Home')}</span>                 
                     </a>        
                 </li>
-                
+                %if c.rhodecode_user.username != 'default':
+                <li>
+                    <a title="${_('Journal')}"  href="${h.url('journal')}">
+                    <span class="icon">
+                        <img src="/images/icons/book.png" alt="${_('Journal')}" />
+                    </span>
+                    <span>${_('Journal')}</span>                 
+                    </a>        
+                </li>
+                %endif          
                 <li>
                     <a title="${_('Search')}"  href="${h.url('search')}">
                     <span class="icon">
@@ -243,17 +290,10 @@
                        <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
                    </span>
                    <span>${_('Admin')}</span>                 
-                   </a>    
-				    <ul>
-				        <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
-				        <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
-				        <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
-				        <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
-				        <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>        
-				    </ul>
+                   </a>
+                    ${admin_menu()}
                 </li>
 				%endif
-				
 			</ul>
 		%endif    
 </%def>
@@ -270,10 +310,52 @@
 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
+##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
 
-<script type="text/javascript" src="/js/yui2.js"></script>
+<script type="text/javascript" src="/js/yui2a.js"></script>
 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
 <script type="text/javascript" src="/js/yui.flot.js"></script>
+
+<script type="text/javascript">
+var base_url  ='/_admin/toggle_following';
+var YUC = YAHOO.util.Connect;
+var YUD = YAHOO.util.Dom;
+var YUE = YAHOO.util.Event;
+
+function onSuccess(){
+	
+	var f = YUD.get('follow_toggle');
+    if(f.getAttribute('class')=='follow'){
+        f.setAttribute('class','following');
+        f.setAttribute('title',"${_('Stop following this repository')}");
+    }
+    else{
+        f.setAttribute('class','follow');
+        f.setAttribute('title',"${_('Start following this repository')}");
+    }
+}
+
+function toggleFollowingUser(fallows_user_id,token){
+    args = 'follows_user_id='+fallows_user_id;
+    args+= '&auth_token='+token;
+    YUC.asyncRequest('POST',base_url,{
+        success:function(o){
+        	onSuccess();
+        }
+    },args); return false;
+}
+
+function toggleFollowingRepo(fallows_repo_id,token){
+    args = 'follows_repo_id='+fallows_repo_id;
+    args+= '&auth_token='+token;
+    YUC.asyncRequest('POST',base_url,{
+        success:function(o){
+        	onSuccess();
+        }
+    },args); return false;
+}    
+</script>
+
 </%def>
 
 <%def name="breadcrumbs()">
--- a/rhodecode/templates/branches/branches_data.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/branches/branches_data.html	Sat Dec 18 14:45:58 2010 +0100
@@ -2,24 +2,28 @@
     <table class="table_disp">
         <tr>
             <th class="left">${_('date')}</th>
+            <th class="left">${_('name')}</th>
+            <th class="left">${_('author')}</th>
             <th class="left">${_('revision')}</th>
-            <th class="left">${_('name')}</th>
             <th class="left">${_('links')}</th>
         </tr>
 		%for cnt,branch in enumerate(c.repo_branches.items()):
 		<tr class="parity${cnt%2}">
-			<td>${h.age(branch[1]._ctx.date())}</td>
-			<td>r${branch[1].revision}:${branch[1].short_id}</td>
-			<td>
-				<span class="logtags">
-					<span class="branchtag">${h.link_to(branch[0],
-					h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].short_id))}</span>
-				</span>			
-			</td>
+            <td><span class="tooltip" tooltip_title="${h.age(branch[1].date)}">
+                      ${branch[1].date}</span>
+            </td>
+            <td>
+                <span class="logtags">
+                    <span class="branchtag">${h.link_to(branch[0],
+                    h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
+                </span>         
+            </td>		
+            <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
+            <td>r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</td>
 			<td class="nowrap">
-			${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].short_id))}
+			${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}
 			|
-			${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=branch[1].short_id))}
+			${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id))}
 			</td>
 		</tr>	
 		%endfor
--- a/rhodecode/templates/changelog/changelog.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/changelog/changelog.html	Sat Dec 18 14:45:58 2010 +0100
@@ -46,7 +46,7 @@
 				%for cnt,cs in enumerate(c.pagination):
 					<div id="chg_${cnt+1}" class="container">
 						<div class="left">
-							<div class="date">${_('commit')} ${cs.revision}: ${cs.short_id}@${cs.date}</div>
+							<div class="date">${_('commit')} ${cs.revision}: ${h.short_id(cs.raw_id)}@${cs.date}</div>
 							<div class="author">
 								<div class="gravatar">
 									<img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),20)}"/>
@@ -54,13 +54,26 @@
 								<span>${h.person(cs.author)}</span><br/>
 								<span><a href="mailto:${h.email_or_none(cs.author)}">${h.email_or_none(cs.author)}</a></span><br/>
 							</div>
-							<div class="message">${h.link_to(h.wrap_paragraphs(cs.message),h.url('changeset_home',repo_name=c.repo_name,revision=cs.short_id))}</div>
+							<div class="message">${h.link_to(h.wrap_paragraphs(cs.message),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
 						</div>	
 						<div class="right">
 									<div class="changes">
-										<span class="removed" title="${_('removed')}">${len(cs.removed)}</span>
-										<span class="changed" title="${_('changed')}">${len(cs.changed)}</span>
-										<span class="added" title="${_('added')}">${len(cs.added)}</span>
+									
+									   <%
+									       def changed_tooltip(cs):
+                                               if cs:
+                                                   pref = ': '
+                                                   suf = '' 
+                                                   if len(cs) > 30:
+                                                      suf='<br/>'+_(' and %s more') % (len(cs) - 30)
+                                                   return pref+'<br/> '.join([x.path for x in cs[:30]]) + suf
+                                               else:
+                                                   return ': '+_('No Files')
+                                       %>
+									
+										<span class="removed tooltip" tooltip_title="${_('removed')}${h.literal(changed_tooltip(cs.removed))}">${len(cs.removed)}</span>
+										<span class="changed tooltip" tooltip_title="${_('changed')}${h.literal(changed_tooltip(cs.changed))}">${len(cs.changed)}</span>
+										<span class="added tooltip" tooltip_title="${_('added')}${h.literal(changed_tooltip(cs.added))}">${len(cs.added)}</span>
 									</div>					
 										%if len(cs.parents)>1:
 										<div class="merge">
@@ -69,8 +82,8 @@
 										%endif
 								   %if cs.parents:							
 									%for p_cs in reversed(cs.parents):
-										<div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(p_cs.short_id,
-											h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.short_id),title=p_cs.message)}
+										<div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(h.short_id(p_cs.raw_id),
+											h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
 										</div>
 									%endfor
 								   %else:	
@@ -78,11 +91,13 @@
                                    %endif  
                     									
 								<span class="logtags">
+									%if cs.branch:
 									<span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
-									${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}</span>
+									   ${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
+									%endif
 									%for tag in cs.tags:
 										<span class="tagtag"  title="${'%s %s' % (_('tag'),tag)}">
-										${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}</span>
+										${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
 									%endfor
 								</span>																	
 						</div>				
--- a/rhodecode/templates/changeset/changeset.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/changeset/changeset.html	Sat Dec 18 14:45:58 2010 +0100
@@ -1,7 +1,7 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${c.changeset.short_id}  - ${c.rhodecode_name}
+    ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
@@ -9,7 +9,7 @@
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
-    ${_('Changeset')} - r${c.changeset.revision}:${c.changeset.short_id}
+    ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
 </%def>
 
 <%def name="page_nav()">
@@ -26,18 +26,18 @@
 		<div id="body" class="diffblock">
 			<div class="code-header">
 				<div>
-				${_('Changeset')} - r${c.changeset.revision}:${c.changeset.short_id}
+				${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
 				 &raquo; <span>${h.link_to(_('raw diff'),
-				h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.short_id,diff='show'))}</span>
+				h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span>
 				 &raquo; <span>${h.link_to(_('download diff'),
-				h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.short_id,diff='download'))}</span>
+				h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span>
 				</div>
 			</div>
 		</div>
 	    <div id="changeset_content">
 			<div class="container">
 	             <div class="left">
-	                 <div class="date">${_('commit')} ${c.changeset.revision}: ${c.changeset.short_id}@${c.changeset.date}</div>
+	                 <div class="date">${_('commit')} ${c.changeset.revision}: ${h.short_id(c.changeset.raw_id)}@${c.changeset.date}</div>
 	                 <div class="author">
 	                     <div class="gravatar">
 	                         <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
@@ -45,7 +45,7 @@
 	                     <span>${h.person(c.changeset.author)}</span><br/>
 	                     <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
 	                 </div>
-	                 <div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.short_id))}</div>
+	                 <div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</div>
 	             </div>
 	             <div class="right">
 		             <div class="changes">
@@ -61,8 +61,8 @@
 		                 
 		            %if c.changeset.parents:
 		             %for p_cs in reversed(c.changeset.parents):
-		                 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(p_cs.short_id,
-		                     h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.short_id),title=p_cs.message)}
+		                 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(h.short_id(p_cs.raw_id),
+		                     h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
 		                 </div>
 		             %endfor
                     %else: 
@@ -70,10 +70,10 @@
                     %endif		             
 		         <span class="logtags">
 		             <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
-		             ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.short_id))}</span>
+		             ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
 		             %for tag in c.changeset.tags:
 		                 <span class="tagtag"  title="${'%s %s' % (_('tag'),tag)}">
-		                 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.short_id))}</span>
+		                 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
 		             %endfor
 		         </span>                                                                 
 	                </div>              
@@ -93,10 +93,10 @@
 		<div style="clear:both;height:10px"></div>
 		<div id="body" class="diffblock">
 			<div id="${'CHANGE-%s'%filenode.path}" class="code-header">
-				<div>
-					<span>
+				<div class="changeset_header">
+					<span class="changeset_file">
 						${h.link_to_if(change!='removed',filenode.path,h.url('files_home',repo_name=c.repo_name,
-						revision=filenode.changeset.short_id,f_path=filenode.path))}
+						revision=filenode.changeset.raw_id,f_path=filenode.path))}
 					</span>
 					%if 1:
 					&raquo; <span>${h.link_to(_('diff'),
--- a/rhodecode/templates/changeset/raw_changeset.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/changeset/raw_changeset.html	Sat Dec 18 14:45:58 2010 +0100
@@ -1,6 +1,6 @@
-# HG changeset patch
+# ${c.scm_type} changeset patch
 # User ${c.changeset.author|n}
-# Date ${"%d %d" % c.changeset._ctx.date()}
+# Date ${c.changeset.date}
 # Node ID ${c.changeset.raw_id}
 # ${c.parent_tmpl}
 ${c.changeset.message}
--- a/rhodecode/templates/errors/error_404.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/errors/error_404.html	Sat Dec 18 14:45:58 2010 +0100
@@ -6,7 +6,7 @@
 </%def>
 
 <%def name="breadcrumbs()">
-	${h.link_to(u'Home',h.url('hg_home'))}
+	${h.link_to(u'Home',h.url('home'))}
 	 / 
 	${h.link_to(u'Admin',h.url('admin_home'))}
 </%def>
@@ -26,7 +26,7 @@
     ${_('Create "%s" repository as %s' % (c.repo_name,c.repo_name_cleaned))}</a>
 
     </p>
-    <p class="normal">${h.link_to(_('Go back to the main repository list page'),h.url('hg_home'))}</p>
+    <p class="normal">${h.link_to(_('Go back to the main repository list page'),h.url('home'))}</p>
     <div class="page-footer">
     </div>
 </%def>
\ No newline at end of file
--- a/rhodecode/templates/files/file_diff.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/files/file_diff.html	Sat Dec 18 14:45:58 2010 +0100
@@ -9,7 +9,7 @@
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
-    ${'%s:  %s %s %s' % (_('File diff'),c.diff2,'&rarr;',c.diff1)|n}
+    ${_('File diff')} r${c.changeset_1.revision}:${h.short_id(c.changeset_1.raw_id)} &rarr; r${c.changeset_2.revision}:${h.short_id(c.changeset_2.raw_id)}
 </%def>
 
 <%def name="page_nav()">
@@ -24,15 +24,15 @@
     <div class="table">
 		<div id="body" class="diffblock">
 			<div class="code-header">
-				<div>
-				<span>${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
-				revision=c.diff2.split(':')[1],f_path=c.f_path))}</span>
+                <div class="changeset_header">
+                <span class="changeset_file">${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
+				revision=c.changeset_2.raw_id,f_path=c.f_path))}</span>
 				 &raquo; <span>${h.link_to(_('diff'),
-				h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='diff'))}</span>
+				h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='diff'))}</span>
 				 &raquo; <span>${h.link_to(_('raw diff'),
-				h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='raw'))}</span>
+				h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))}</span>
 				 &raquo; <span>${h.link_to(_('download diff'),
-				h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='download'))}</span>
+				h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='download'))}</span>
 				</div>
 			</div>
 			<div class="code-body">
--- a/rhodecode/templates/files/files.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/files/files.html	Sat Dec 18 14:45:58 2010 +0100
@@ -11,7 +11,7 @@
     &raquo;
     ${_('files')}
     %if c.files_list:
-        @ R${c.rev_nr}:${c.cur_rev}
+        @ r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
     %endif        
 </%def>
 
@@ -23,12 +23,19 @@
 <div class="box">
     <!-- box / title -->
     <div class="title">
-        ${self.breadcrumbs()}     
+        ${self.breadcrumbs()}
+	    <ul class="links">
+		    <li>
+		      <span style="text-transform: uppercase;"><a href="#">${_('branch')}: ${c.changeset.branch}</a></span>
+	        </li>          
+	    </ul>             
     </div>
     <div class="table">
 		<div id="files_data">
 			%if c.files_list:
-				<h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cur_rev,c.files_list.path)}</h3>
+				<h3 class="files_location">
+				    ${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.files_list.path)}
+				</h3>
 					%if c.files_list.is_dir():
 						<%include file='files_browser.html'/>
 					%else:
--- a/rhodecode/templates/files/files_annotate.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/files/files_annotate.html	Sat Dec 18 14:45:58 2010 +0100
@@ -9,7 +9,7 @@
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
-    ${_('annotate')} @ R${c.rev_nr}:${c.cur_rev}
+    ${_('annotate')} @ R${c.cs.revision}:${h.short_id(c.cs.raw_id)}
 </%def>
 
 <%def name="page_nav()">
@@ -20,41 +20,67 @@
     <!-- box / title -->
     <div class="title">
         ${self.breadcrumbs()}
+        <ul class="links">
+            <li>
+              <span style="text-transform: uppercase;"><a href="#">${_('branch')}: ${c.cs.branch}</a></span>
+            </li>          
+        </ul>          
     </div>
     <div class="table">
 		<div id="files_data">
-			<h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cur_rev,c.file.path)}</h3>
+			<h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cs.revision,c.file.path)}</h3>
 			<dl class="overview">
-				<dt>${_('Last revision')}</dt>
-				<dd>${h.link_to("r%s:%s" % (c.file.last_changeset.revision,c.file.last_changeset.short_id),
-						h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.last_changeset.short_id,f_path=c.f_path))} </dd>
+				<dt>${_('Revision')}</dt>
+				<dd>${h.link_to("r%s:%s" % (c.file.last_changeset.revision,h.short_id(c.file.last_changeset.raw_id)),
+						h.url('changeset_home',repo_name=c.repo_name,revision=c.file.last_changeset.raw_id))} </dd>
 				<dt>${_('Size')}</dt>
 				<dd>${h.format_byte_size(c.file.size,binary=True)}</dd>
     			<dt>${_('Mimetype')}</dt>
 				<dd>${c.file.mimetype}</dd>				
 				<dt>${_('Options')}</dt>
 				<dd>${h.link_to(_('show source'),
-						h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}  
+						h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}  
 					/ ${h.link_to(_('show as raw'),
-						h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
+						h.url('files_raw_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
 					/ ${h.link_to(_('download as raw'),
-						h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
-				</dd>				
+						h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
+				</dd>
+			    <dt>${_('History')}</dt>
+			    <dd>
+			        <div>
+			        ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
+			        ${h.hidden('diff2',c.file.last_changeset.raw_id)}
+			        ${h.select('diff1',c.file.last_changeset.raw_id,c.file_history)}
+			        ${h.submit('diff','diff to revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+			        ${h.submit('show_rev','show at revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+			        ${h.end_form()}
+			        </div>
+			    </dd>					
 			</dl>
 			<div id="body" class="codeblock">
 				<div class="code-header">
-					<div class="revision">${c.file.name}@r${c.file.last_changeset.revision}:${c.file.last_changeset.short_id}</div>
-					<div class="commit">"${c.file_msg}"</div>
+					<div class="revision">${c.file.name}@r${c.file.last_changeset.revision}:${h.short_id(c.file.last_changeset.raw_id)}</div>
+					<div class="commit">"${c.file.message}"</div>
 				</div>
 				<div class="code-body">
-					% if c.file.size < c.file_size_limit:
+					% if c.file.size < c.cut_off_limit:
 						${h.pygmentize_annotation(c.file,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
 					%else:
 						${_('File is to big to display')} ${h.link_to(_('show as raw'),
-						h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
+						h.url('files_raw_home',repo_name=c.repo_name,revision=c.cs.revision,f_path=c.f_path))}
 					%endif				
 				</div>
 			</div>
+			<script type="text/javascript">
+			YAHOO.util.Event.onDOMReady(function(){
+			    YAHOO.util.Event.addListener('show_rev','click',function(e){
+			        YAHOO.util.Event.preventDefault(e);
+			        var cs = YAHOO.util.Dom.get('diff1').value;
+			        var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
+			        window.location = url;
+			        });
+			   });
+			</script>			
 		</div>    
     </div>
 </div>    
--- a/rhodecode/templates/files/files_browser.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/files/files_browser.html	Sat Dec 18 14:45:58 2010 +0100
@@ -10,9 +10,9 @@
 		${h.form(h.url.current())}
 		<div class="info_box">
           <span >${_('view')}@rev</span> 
-          <a href="${c.url_prev}">&laquo;</a>
-          ${h.text('at_rev',value=c.rev_nr,size=3)}
-          <a href="${c.url_next}">&raquo;</a>
+          <a href="${c.url_prev}" title="${_('previous revision')}">&laquo;</a>
+          ${h.text('at_rev',value=c.changeset.revision,size=3)}
+          <a href="${c.url_next}" title="${_('next revision')}">&raquo;</a>
           ${h.submit('view','view')}
 	    </div>           
 		${h.end_form()}
@@ -30,23 +30,23 @@
 		             </tr>
 		         </thead>
 
-          		% if c.files_list.parent:
+          		%if c.files_list.parent:
          		<tr class="parity0">
 	          		<td>		          		
-	          			${h.link_to('..',h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.files_list.parent.path),class_="browser-dir")}
+	          			${h.link_to('..',h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.files_list.parent.path),class_="browser-dir")}
 	          		</td>
 	          		<td></td>
 	          		<td></td>
 	          		<td></td>
 	          		<td></td>
 	          		<td></td>
-				</tr>	          		
+				</tr>
           		%endif
 		         	
 		    %for cnt,node in enumerate(c.files_list):
-				<tr class="parity${(cnt+1)%2}">
+				<tr class="parity${cnt+1%2}">
 		             <td>
-						${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=node.path),class_=file_class(node))}
+						${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=node.path),class_=file_class(node))}
 		             </td>
 		             <td>
 		             %if node.is_file():
@@ -59,19 +59,19 @@
 		              %endif
 		             </td>
 		             <td>
-	             	  %if node.is_file():
-	             		  ${node.last_changeset.revision}
-	             	  %endif
+		             	%if node.is_file():
+		             		<span class="tooltip" tooltip_title="${node.last_changeset.raw_id}">${node.last_changeset.revision}</span>
+		             	%endif
 		             </td>
 		             <td>
-		              %if node.is_file():
-		                  ${h.age(node.last_changeset._ctx.date())} - ${node.last_changeset.date}
-		              %endif
+		             	%if node.is_file():
+		             		${node.last_changeset.date} - ${h.age(node.last_changeset.date)}
+		             	%endif
 		             </td>
 		             <td>
-		              %if node.is_file():
-		                  ${node.last_changeset.author}
-		              %endif                    
+		             	%if node.is_file():
+		             		${node.last_changeset.author}
+		             	%endif                    
 		             </td>
 				</tr>
 			%endfor
--- a/rhodecode/templates/files/files_source.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/files/files_source.html	Sat Dec 18 14:45:58 2010 +0100
@@ -1,8 +1,8 @@
 <dl>
-	<dt>${_('Last revision')}</dt>
+	<dt>${_('Revision')}</dt>
 	<dd>
-		${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,c.files_list.last_changeset.short_id),
-						h.url('files_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.short_id,f_path=c.f_path))} 
+		${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,h.short_id(c.files_list.last_changeset.raw_id)),
+						h.url('changeset_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.raw_id))} 
 	</dd>
 	<dt>${_('Size')}</dt>
 	<dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
@@ -10,18 +10,18 @@
 	<dd>${c.files_list.mimetype}</dd>
 	<dt>${_('Options')}</dt>
 	<dd>${h.link_to(_('show annotation'),
-			h.url('files_annotate_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
+			h.url('files_annotate_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
 		 / ${h.link_to(_('show as raw'),
-			h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}			
+			h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}			
 		 / ${h.link_to(_('download as raw'),
-			h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
+			h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
 	</dd>
 	<dt>${_('History')}</dt>
 	<dd>
 		<div>
 		${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
-		${h.hidden('diff2',c.files_list.last_changeset.short_id)}
-		${h.select('diff1',c.files_list.last_changeset.short_id,c.file_history)}
+		${h.hidden('diff2',c.files_list.last_changeset.raw_id)}
+		${h.select('diff1',c.files_list.last_changeset.raw_id,c.file_history)}
 		${h.submit('diff','diff to revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
 		${h.submit('show_rev','show at revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
 		${h.end_form()}
@@ -32,15 +32,15 @@
 	
 <div id="body" class="codeblock">
 	<div class="code-header">
-		<div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${c.files_list.last_changeset.short_id}</div>
+		<div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${h.short_id(c.files_list.last_changeset.raw_id)}</div>
 		<div class="commit">"${c.files_list.last_changeset.message}"</div>
 	</div>
 	<div class="code-body">
-		% if c.files_list.size < c.file_size_limit:
+		% if c.files_list.size < c.cut_off_limit:
 			${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
 		%else:
 			${_('File is to big to display')} ${h.link_to(_('show as raw'),
-			h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
+			h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
 		%endif
 	</div>
 </div>
--- a/rhodecode/templates/index.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/index.html	Sat Dec 18 14:45:58 2010 +0100
@@ -27,72 +27,142 @@
     <div class="box">
 	    <!-- box / title -->
 	    <div class="title">
-	        <h5>${_('Dashboard')}</h5>
-	        %if h.HasPermissionAny('hg.admin','hg.create.repository')():
-	        <ul class="links">
-	          <li>
-	            <span>${h.link_to(_('ADD NEW REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
-	          </li>          
-	        </ul>  	        
-	        %endif
+	        <h5>${_('Dashboard')}
+	        <input class="top-right-rounded-corner top-left-rounded-corner bottom-left-rounded-corner bottom-right-rounded-corner" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
+	        </h5>
+	        %if c.rhodecode_user.username != 'default':
+		        %if h.HasPermissionAny('hg.admin','hg.create.repository')():
+		        <ul class="links">
+		          <li>
+		            <span>${h.link_to(_('ADD NEW REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
+		          </li>          
+		        </ul>  	        
+		        %endif
+		    %endif
 	    </div>
 	    <!-- end box / title -->
         <div class="table">
-                    <table>
+            <table>
             <thead>
 	            <tr>
 			        <th class="left">${get_sort(_('Name'))}</th>
 			        <th class="left">${get_sort(_('Description'))}</th>
 			        <th class="left">${get_sort(_('Last change'))}</th>
 			        <th class="left">${get_sort(_('Tip'))}</th>
-			        <th class="left">${get_sort(_('Contact'))}</th>
+			        <th class="left">${get_sort(_('Owner'))}</th>
 			        <th class="left">${_('RSS')}</th>
 			        <th class="left">${_('Atom')}</th>
 	            </tr>
             </thead>
-                        <tbody>
-					    %for cnt,repo in enumerate(c.repos_list):
-					        %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
-					        <tr class="parity${cnt%2}">
-					            <td>
-					             %if repo['repo'].dbrepo.private:
-					                <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
-					             %else:
-					                <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
-					             %endif  
-					            ${h.link_to(repo['name'],
-					                h.url('summary_home',repo_name=repo['name']))}
-					            %if repo['repo'].dbrepo.fork:
-					            	<a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
-					            	<img class="icon" alt="${_('public')}"
-					            	title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}" 
-					            	src="/images/icons/arrow_divide.png"/></a>
-					            %endif
-					            </td>
-					            <td title="${repo['description']}">${h.truncate(repo['description'],60)}</td>
-					            <td>${h.age(repo['last_change'])}</td>
-					            <td>
-					            	%if repo['rev']>=0:
-					            	${h.link_to('r%s:%s' % (repo['rev'],repo['tip']),
-					                h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
-					                class_="tooltip",
-					                tooltip_title=h.tooltip(repo['last_msg']))}
-					            	%else:
-					            		${_('No changesets yet')}
-					            	%endif    
-					            </td>
-					            <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
-					            <td>
-					                <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon"  href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
-					            </td>        
-					            <td>
-					                <a title="${_('Subscribe to %s atom feed')%repo['name']}"  class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
-					            </td>
-					        </tr>
-					        %endif
-					    %endfor
-                        </tbody>
-                    </table>
+            <tbody>
+		    %for cnt,repo in enumerate(c.repos_list):
+		        <tr class="parity${cnt%2}">
+		            <td>
+		            <div style="white-space: nowrap">
+		             ## TYPE OF REPO
+		             %if repo['repo'].dbrepo.repo_type =='hg':
+		               <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
+		             %elif repo['repo'].dbrepo.repo_type =='git':
+		               <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
+		             %else:
+		               
+		             %endif 
+		            
+		             ##PRIVATE/PUBLIC
+		             %if repo['repo'].dbrepo.private:
+		                <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
+		             %else:
+		                <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
+		             %endif
+		            
+		            ##NAME   
+		            ${h.link_to(repo['name'],
+		                h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
+		            %if repo['repo'].dbrepo.fork:
+		            	<a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
+		            	<img class="icon" alt="${_('fork')}"
+		            	title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}" 
+		            	src="/images/icons/arrow_divide.png"/></a>
+		            %endif
+		            </div>
+		            </td>
+		            ##DESCRIPTION
+		            <td><span class="tooltip" tooltip_title="${repo['description']}">
+		               ${h.truncate(repo['description'],60)}</span>
+		            </td>
+		            ##LAST CHANGE
+		            <td>
+		              <span class="tooltip" tooltip_title="${repo['last_change']}">
+		              ${h.age(repo['last_change'])}</span>
+		            </td>
+		            <td>
+		            	%if repo['rev']>=0:
+		            	${h.link_to('r%s:%s' % (repo['rev'],h.short_id(repo['tip'])),
+		                h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
+		                class_="tooltip",
+		                tooltip_title=h.tooltip(repo['last_msg']))}
+		            	%else:
+		            		${_('No changesets yet')}
+		            	%endif    
+		            </td>
+		            <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
+		            <td>
+		                <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon"  href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
+		            </td>        
+		            <td>
+		                <a title="${_('Subscribe to %s atom feed')%repo['name']}"  class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
+		            </td>
+		        </tr>
+		    %endfor
+            </tbody>
+            </table>
             </div>
-    </div>	
+    </div>
+    
+    
+    <script type="text/javascript">
+     var D = YAHOO.util.Dom;
+     var E = YAHOO.util.Event;
+     var S = YAHOO.util.Selector;
+     
+     var q_filter = D.get('q_filter');
+     var F = YAHOO.namespace('q_filter'); 
+     
+     E.on(q_filter,'click',function(){
+    	q_filter.value = '';
+     });
+
+     F.filterTimeout = null;
+     
+     F.updateFilter  = function() { 
+    	// Reset timeout 
+        F.filterTimeout = null;
+    	
+        var obsolete = [];
+        var nodes = S.query('div.table tr td div a.repo_name');
+        var req = D.get('q_filter').value;
+        for (n in nodes){
+            D.setStyle(nodes[n].parentNode.parentNode.parentNode,'display','')
+        }
+        if (req){
+	        for (n in nodes){
+	        	if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
+	        		obsolete.push(nodes[n]); 
+	        	}
+	    	}
+	        if(obsolete){
+		        for (n in obsolete){
+		        	D.setStyle(obsolete[n].parentNode.parentNode.parentNode,'display','none');
+		        }
+	        }
+        }
+     }
+     
+     E.on(q_filter,'keyup',function(e){
+    	 clearTimeout(F.filterTimeout); 
+    	 setTimeout(F.updateFilter,600); 
+     });
+     
+    </script>
+    	
 </%def>    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/journal.html	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,92 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base/base.html"/>
+<%def name="title()">
+    ${_('Journal')} - ${c.rhodecode_name}
+</%def>
+<%def name="breadcrumbs()">
+	${c.rhodecode_name}
+</%def>
+<%def name="page_nav()">
+	${self.menu('home')}
+</%def>
+<%def name="main()">
+	
+    <div class="box box-left">
+	    <!-- box / title -->
+	    <div class="title">
+	        <h5>${_('Journal')}</h5>
+	    </div>
+	    <div>
+	    %if c.journal:
+            %for entry in c.journal:
+            <div style="padding:10px">
+                <div class="gravatar">
+                    <img alt="gravatar" src="${h.gravatar_url(entry.user.email)}"/>
+                </div>
+                <div>${entry.user.name} ${entry.user.lastname}</div>
+                <div style="padding-left: 45px;padding-top:5px;min-height:20px">${h.action_parser(entry)}</div>
+                <div style="float: left; padding-top: 8px;padding-left:18px">
+                ${h.action_parser_icon(entry)}
+                </div>
+                <div style="margin-left: 45px;padding-top: 10px">
+                <span style="font-weight: bold;font-size: 1.1em">
+		        %if entry.repository:
+		          ${h.link_to(entry.repository.repo_name,
+		                      h.url('summary_home',repo_name=entry.repository.repo_name))}
+		        %else:
+		          ${entry.repository_name}
+		        %endif             
+                </span> - <span title="${entry.action_date}">${h.age(entry.action_date)}</span>
+                </div>
+            </div>
+            <div style="clear:both;border-bottom:1px dashed #DDD;padding:3px 3px;margin:0px 10px 0px 10px"></div>
+            %endfor
+        %else:
+            ${_('No entries yet')}
+        %endif   
+	    </div>
+    </div>
+    
+    <div class="box box-right">
+        <!-- box / title -->
+        <div class="title">
+            <h5>${_('Following')}</h5>
+        </div>
+        <div>
+        %if c.following:
+            %for entry in c.following:
+                <div class="currently_following">
+                    %if entry.follows_user_id:
+                      <img title="${_('following user')}" alt="${_('user')}" src="/images/icons/user.png"/>
+                      ${entry.follows_user.full_contact}
+                    %endif
+                    
+                    %if entry.follows_repo_id:
+                    
+                      %if entry.follows_repository.private:
+                        <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
+                      %else:
+                        <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
+                      %endif
+                      
+                      ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',
+                        repo_name=entry.follows_repository.repo_name))}
+                      
+                    %endif
+                </div>
+            %endfor
+        %else:
+            ${_('You are not following any users or repositories')}
+        %endif               
+        </div>
+    </div>
+    
+    <script type="text/javascript">
+    YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
+        var el = e.target;
+        YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
+        YUD.setStyle(el.parentNode,'display','none');
+    });    
+    </script>
+    
+</%def>    
--- a/rhodecode/templates/login.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/login.html	Sat Dec 18 14:45:58 2010 +0100
@@ -4,7 +4,7 @@
     <head>
         <title>${_('Sign In')} - ${c.rhodecode_name}</title>
         <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-        <link rel="icon" href="/images/hgicon.png" type="image/png" />
+        <link rel="icon" href="/images/icons/database_gear.png" type="image/png" />
         <meta name="robots" content="index, nofollow"/>
             
         <!-- stylesheets -->
--- a/rhodecode/templates/register.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/register.html	Sat Dec 18 14:45:58 2010 +0100
@@ -15,7 +15,7 @@
 		<div id="register">
 			
 			<div class="title top-left-rounded-corner top-right-rounded-corner">
-				<h5>${_('Sign Up to rhodecode')}</h5>
+				<h5>${_('Sign Up to RhodeCode')}</h5>
 			</div>
 			<div class="inner">
 			    ${h.form(url('register'))}
@@ -27,25 +27,34 @@
 			                    <label for="username">${_('Username')}:</label>
 			                </div>
 			                <div class="input">
-			                    ${h.text('username')}
+			                    ${h.text('username',class_="medium")}
 			                </div>
 			             </div>
 			            
 			             <div class="field">
 			                <div class="label">
-			                    <label for="password">${_('New Password')}:</label>
+			                    <label for="password">${_('Password')}:</label>
 			                </div>
 			                <div class="input">
-			                    ${h.password('password')}
+			                    ${h.password('password',class_="medium")}
 			                </div>
 			             </div>
-			            
+                         
+                         <div class="field">
+                            <div class="label">
+                                <label for="password">${_('Re-enter password')}:</label>
+                            </div>
+                            <div class="input">
+                                ${h.password('password_confirmation',class_="medium")}
+                            </div>
+                         </div>
+                         			            
 			             <div class="field">
 			                <div class="label">
 			                    <label for="name">${_('First Name')}:</label>
 			                </div>
 			                <div class="input">
-			                    ${h.text('name')}
+			                    ${h.text('name',class_="medium")}
 			                </div>
 			             </div>
 			            
@@ -54,7 +63,7 @@
 			                    <label for="lastname">${_('Last Name')}:</label>
 			                </div>
 			                <div class="input">
-			                    ${h.text('lastname')}
+			                    ${h.text('lastname',class_="medium")}
 			                </div>
 			             </div>
 			            
@@ -63,7 +72,7 @@
 			                    <label for="email">${_('Email')}:</label>
 			                </div>
 			                <div class="input">
-			                    ${h.text('email')}
+			                    ${h.text('email',class_="medium")}
 			                </div>
 			             </div>
 			                        
--- a/rhodecode/templates/settings/repo_fork.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/settings/repo_fork.html	Sat Dec 18 14:45:58 2010 +0100
@@ -30,6 +30,7 @@
 	            </div>
 	            <div class="input">
 	                ${h.text('fork_name',class_="small")}
+	                ${h.hidden('repo_type',c.repo_info.repo_type)}
 	            </div>
              </div>
             <div class="field">
--- a/rhodecode/templates/settings/repo_settings.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/settings/repo_settings.html	Sat Dec 18 14:45:58 2010 +0100
@@ -128,7 +128,8 @@
              </div>
              
             <div class="buttons">
-              ${h.submit('update','update',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+              ${h.submit('update','Update',class_="ui-button ui-widget ui-state-default ui-corner-all")}
+              ${h.reset('reset','Reset',class_="ui-button ui-widget ui-state-default ui-corner-all")}
             </div>                                                          
         </div>
     </div>    
--- a/rhodecode/templates/shortlog/shortlog_data.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/shortlog/shortlog_data.html	Sat Dec 18 14:45:58 2010 +0100
@@ -2,10 +2,10 @@
 % if c.repo_changesets:
 <table>
 	<tr>
-		<th class="left">${_('date')}</th>
+		<th class="left">${_('commit message')}</th>
+		<th class="left">${_('age')}</th>
 		<th class="left">${_('author')}</th>
 		<th class="left">${_('revision')}</th>
-		<th class="left">${_('commit message')}</th>
 		<th class="left">${_('branch')}</th>
 		<th class="left">${_('tags')}</th>
 		<th class="left">${_('links')}</th>
@@ -13,14 +13,16 @@
 	</tr>
 %for cnt,cs in enumerate(c.repo_changesets):
 	<tr class="parity${cnt%2}">
-		<td>${h.age(cs._ctx.date())} - ${h.rfc822date_notz(cs._ctx.date())} </td>
+        <td>
+            ${h.link_to(h.truncate(cs.message,50),
+            h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
+            title=cs.message)}
+        </td>
+        <td><span class="tooltip" tooltip_title="${cs.date}">
+                      ${h.age(cs.date)}</span>
+        </td>        	
 		<td title="${cs.author}">${h.person(cs.author)}</td>
-		<td>r${cs.revision}:${cs.short_id}</td>
-		<td>
-			${h.link_to(h.truncate(cs.message,60),
-			h.url('changeset_home',repo_name=c.repo_name,revision=cs.short_id),
-			title=cs.message)}
-		</td>
+		<td>r${cs.revision}:${h.short_id(cs.raw_id)}</td>
 		<td>
 			<span class="logtags">
 				<span class="branchtag">${cs.branch}</span>
@@ -34,9 +36,9 @@
 			</span>
 		</td>
 		<td class="nowrap">
-		${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=cs.short_id))}
+		${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
 		|
-		${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}
+		${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
 		</td>
 	</tr>
 %endfor
--- a/rhodecode/templates/summary/summary.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/summary/summary.html	Sat Dec 18 14:45:58 2010 +0100
@@ -17,17 +17,6 @@
 </%def>
 
 <%def name="main()">
-<script type="text/javascript">
-var E = YAHOO.util.Event;
-var D = YAHOO.util.Dom;
-
-E.onDOMReady(function(e){
-    id = 'clone_url';
-    E.addListener(id,'click',function(e){
-        D.get('clone_url').select();
-    })
-})
-</script>
 <div class="box box-left">
     <!-- box / title -->
     <div class="title">
@@ -42,12 +31,30 @@
 			      <label>${_('Name')}:</label>
 			  </div>
 			  <div class="input-short">
+		         %if c.repo_info.dbrepo.repo_type =='hg':
+		           <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
+		         %endif
+		         %if c.repo_info.dbrepo.repo_type =='git':
+		           <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
+		         %endif 
+                                 			  
 	             %if c.repo_info.dbrepo.private:
-	                <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private')}" src="/images/icons/lock.png"/>
+	                <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
 	             %else:
-	                <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public')}" src="/images/icons/lock_open.png"/>
+	                <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
 	             %endif
 			      <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo_info.name}</span>
+			      %if c.rhodecode_user.username != 'default':
+				      %if c.following:
+	                  <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
+	                        onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
+	                  </span>			      
+				      %else:
+				      <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
+				            onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
+				      </span>
+				      %endif
+				  %endif:
 			      <br/>
 		            %if c.repo_info.dbrepo.fork:
 		            	<span style="margin-top:5px">
@@ -68,7 +75,7 @@
 			      <label>${_('Description')}:</label>
 			  </div>
 			  <div class="input-short">
-			      ${c.repo_info.description}
+			      ${c.repo_info.dbrepo.description}
 			  </div>
 			 </div>
 			
@@ -92,7 +99,7 @@
 			      <label>${_('Last change')}:</label>
 			  </div>
 			  <div class="input-short">
-			      ${h.age(c.repo_info.last_change)} - ${h.rfc822date_notz(c.repo_info.last_change)} 
+			      ${h.age(c.repo_info.last_change)} - ${c.repo_info.last_change} 
 			      ${_('by')} ${h.get_changeset_safe(c.repo_info,'tip').author} 
 			      
 			  </div>
@@ -109,13 +116,19 @@
 			 
 			 <div class="field">
 			  <div class="label">
-			      <label>${_('Trending languages')}:</label>
+			      <label>${_('Trending source files')}:</label>
 			  </div>
 			  <div class="input-short">
 			    <div id="lang_stats">
 			    
 			    </div> 			  
 			  	<script type="text/javascript">
+				  	YUE.onDOMReady(function(e){
+				  	    id = 'clone_url';
+				  	    YUE.on(id,'click',function(e){
+				  	        YUD.get('clone_url').select();
+				  	    })
+				  	})
 			  		var data = ${c.trending_languages|n};
 			  		var total = 0;
 			  		var no_data = true;
@@ -125,22 +138,37 @@
 			  		} 
 					var tbl = document.createElement('table');
 					tbl.setAttribute('class','trending_language_tbl');
+					var cnt =0;
 			  		for (k in data){
+			  			cnt+=1;
+			  			var hide = cnt>2;
 				  		var tr = document.createElement('tr');
+				  		if (hide){
+				  			tr.setAttribute('style','display:none');
+				  			tr.setAttribute('class','stats_hidden');
+				  		}
 				  		var percentage = Math.round((data[k]/total*100),2);
 						var value = data[k];
 				  		var td1 = document.createElement('td');
 				  		td1.width=150;
-                        
 				  		var trending_language_label = document.createElement('div');
 				  		trending_language_label.innerHTML = k;
 				  		td1.appendChild(trending_language_label);
 
 				  		var td2 = document.createElement('td');
-				  		td2.setAttribute('style','padding-right: 12px ! important;');
+				  		td2.setAttribute('style','padding-right:14px !important');
 			  		    var trending_language = document.createElement('div');
-			  		    trending_language.title = k;
-			  		    trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>";
+			  		    var nr_files = value+" ${_('files')}";
+			  		    
+			  		    trending_language.title = k+" "+nr_files;
+			  		    
+			  		    if (percentage>20){
+			  		    	trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";	
+			  		    }
+			  		    else{
+			  		    	trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
+			  		    }
+			  		    
 			  		    trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
 			  		    trending_language.style.width=percentage+"%";
 						td2.appendChild(trending_language);
@@ -148,16 +176,37 @@
 						tr.appendChild(td1);
 						tr.appendChild(td2);
 			  		    tbl.appendChild(tr);
+			  		    if(cnt == 2){
+			  		    	var show_more = document.createElement('tr');
+			  		    	var td=document.createElement('td');
+			  		    	lnk = document.createElement('a');
+			  		    	lnk.href='#';
+			  		    	lnk.innerHTML = "${_("show more")}";
+			  		    	lnk.id='code_stats_show_more';
+			  		        td.appendChild(lnk);
+			  		    	show_more.appendChild(td);
+			  		    	show_more.appendChild(document.createElement('td'));
+			  		    	tbl.appendChild(show_more);
+			  		    }
 			  		    
 			  		}
 			  		if(no_data){
 			  			var tr = document.createElement('tr');
 			  			var td1 = document.createElement('td');
-			  			td1.innerHTML = "${_('No data loaded yet')}";
+			  			td1.innerHTML = "${c.no_data_msg}";
 			  			tr.appendChild(td1);
 			  			tbl.appendChild(tr);
 					}
-			  		YAHOO.util.Dom.get('lang_stats').appendChild(tbl);
+			  		YUD.get('lang_stats').appendChild(tbl);
+			  		YUE.on('code_stats_show_more','click',function(){
+			  			l = YUD.getElementsByClassName('stats_hidden')
+			  			for (e in l){
+			  			    YUD.setStyle(l[e],'display','');
+			  			};
+			  			YUD.setStyle(YUD.get('code_stats_show_more'),
+			  					'display','none');
+			  		})
+			  		
 			  	</script>
  
 			  </div>
@@ -199,9 +248,13 @@
     </div>
     
     <div class="table">
-        <div id="commit_history" style="width:560px;height:300px;float:left"></div>
+        
+         %if c.no_data:
+           <div style="padding:0 10px 10px 15px;font-size: 1.2em;">${c.no_data_msg}</div>
+        %endif:  
+        <div id="commit_history" style="width:460px;height:300px;float:left"></div>
         <div style="clear: both;height: 10px"></div>
-        <div id="overview" style="width:560px;height:100px;float:left"></div>
+        <div id="overview" style="width:460px;height:100px;float:left"></div>
         
     	<div id="legend_data" style="clear:both;margin-top:10px;">
 	    	<div id="legend_container"></div>
@@ -228,10 +281,10 @@
 			};
 		    var dataset = dataset;
 		    var overview_dataset = [overview_dataset];
-		    var choiceContainer = YAHOO.util.Dom.get("legend_choices");
-		    var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
-		    var plotContainer = YAHOO.util.Dom.get('commit_history');
-		    var overviewContainer = YAHOO.util.Dom.get('overview');
+		    var choiceContainer = YUD.get("legend_choices");
+		    var choiceContainerTable = YUD.get("legend_choices_tables");
+		    var plotContainer = YUD.get('commit_history');
+		    var overviewContainer = YUD.get('overview');
 		    
 		    var plot_options = {
 				bars: {show:true,align:'center',lineWidth:4},
@@ -257,7 +310,7 @@
 			    bars: {show:true,barWidth: 2,},
 			    shadowSize: 0,
 			    xaxis: {mode: "time", timeformat: "%d/%m/%y",},
-			    yaxis: {ticks: 3, min: 0,},
+			    yaxis: {ticks: 3, min: 0,tickDecimals:0,},
 			    grid: {color: "#999",},
 			    selection: {mode: "x"}
 			};
@@ -314,7 +367,7 @@
 		            div.style.backgroundColor='#fee';
 		            document.body.appendChild(div);
 		        }
-		        YAHOO.util.Dom.setStyle(div, 'opacity', 0);
+		        YUD.setStyle(div, 'opacity', 0);
 		        div.innerHTML = contents;
 		        div.style.top=(y + 5) + "px";
 		        div.style.left=(x + 5) + "px";
@@ -324,9 +377,9 @@
 		    }
 		    
 			/**
-			 * This function will detect if selected period has some changesets for this user
-			if it does this data is then pushed for displaying
-			Additionally it will only display users that are selected by the checkbox
+			 * This function will detect if selected period has some changesets 
+			   for this user if it does this data is then pushed for displaying
+			   Additionally it will only display users that are selected by the checkbox
 			*/
 		    function getDataAccordingToRanges(ranges) {
 		    	
@@ -334,31 +387,28 @@
 		        var keys = [];
 				for(var key in dataset){
 					var push = false;
+					
 					//method1 slow !!
-		            ///*
+		            //*
 		            for(var ds in dataset[key].data){
 			            commit_data = dataset[key].data[ds];
-			            //console.log(key);
-			            //console.log(new Date(commit_data.time*1000));
-			            //console.log(new Date(ranges.xaxis.from*1000));
-			            //console.log(new Date(ranges.xaxis.to*1000));
 			            if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
 			            	push = true;
 			            	break;
 					    }
 				    }
-				    //*/
+					//*/
+				    
 				    /*//method2 sorted commit data !!!
+				    
 				    var first_commit = dataset[key].data[0].time;
 				    var last_commit = dataset[key].data[dataset[key].data.length-1].time;
 				    
-				    console.log(first_commit);
-				    console.log(last_commit);
-				    
 				    if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
 						push = true;
 					}
-				    */
+				    //*/
+				    
 				    if(push){			
 				    	data.push(dataset[key]);
 				    }
@@ -399,14 +449,14 @@
 						new_data.push(getDummyData(checkbox_key));
 			        }
 		        }
-						        
+					        
 		    	var new_options = YAHOO.lang.merge(plot_options, {
 		            xaxis: { 
 		  	      		min: cur_ranges.xaxis.from, 
 		  	      		max: cur_ranges.xaxis.to,
 		  	      		mode:"time",
 		  	      		timeformat: "%d/%m",
-		        	}
+		        	},
 		    	});
 		    	if (!new_data){
 					new_data = [[0,1]];
@@ -440,7 +490,12 @@
 		  	      		max: ranges.xaxis.to,
 		  	      		mode:"time",
 		  	      		timeformat: "%d/%m",
-		        	}
+		        	},
+		        	yaxis: { 
+                        min: ranges.yaxis.from, 
+                        max: ranges.yaxis.to,
+                    },
+                    		        	
 		    	});
 		    	// do the zooming
 		        plot = YAHOO.widget.Flot(plotContainer, data, new_options);
@@ -454,7 +509,7 @@
 		        overview.setSelection(ranges, true);
 
 		        //resubscribe choiced
-		        YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
+		        YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
 		    }
 		    
 		    var previousPoint = null;
@@ -463,13 +518,13 @@
 		        var pos = o.pos;
 		        var item = o.item;
 		        
-		        //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
-		        //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
+		        //YUD.get("x").innerHTML = pos.x.toFixed(2);
+		        //YUD.get("y").innerHTML = pos.y.toFixed(2);
 		        if (item) {
 		            if (previousPoint != item.datapoint) {
 		                previousPoint = item.datapoint;
 		                
-		                var tooltip = YAHOO.util.Dom.get("tooltip");
+		                var tooltip = YUD.get("tooltip");
 		                if(tooltip) {
 		                	  tooltip.parentNode.removeChild(tooltip);
 		                }
@@ -508,7 +563,7 @@
 		            }
 		        }
 		        else {
-		        	  var tooltip = YAHOO.util.Dom.get("tooltip");
+		        	  var tooltip = YUD.get("tooltip");
 		        	  
 			          if(tooltip) {
 			                tooltip.parentNode.removeChild(tooltip);
@@ -541,7 +596,7 @@
 				
 		    plot.subscribe("plothover", plothover);
 
-		    YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
+		    YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
 		}
 			SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});		
 		</script>
@@ -551,18 +606,20 @@
 
 <div class="box">    
     <div class="title">
-        <div class="breadcrumbs">${h.link_to(_('Last ten changes'),h.url('changelog_home',repo_name=c.repo_name))}</div>
+        <div class="breadcrumbs">${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</div>
     </div>    
     <div class="table">
-        <%include file='../shortlog/shortlog_data.html'/>
-        %if c.repo_changesets:
-        	${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
-        %endif
+        <div id="shortlog_data">
+            <%include file='../shortlog/shortlog_data.html'/>
+        </div>
+        ##%if c.repo_changesets:
+        ##	${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
+        ##%endif
     </div>
 </div>
 <div class="box">    
     <div class="title">
-        <div class="breadcrumbs">${h.link_to(_('Last ten tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
+        <div class="breadcrumbs">${h.link_to(_('Tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
     </div>    
     <div class="table">
         <%include file='../tags/tags_data.html'/>
@@ -573,7 +630,7 @@
 </div>
 <div class="box">
     <div class="title">
-        <div class="breadcrumbs">${h.link_to(_('Last ten branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
+        <div class="breadcrumbs">${h.link_to(_('Branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
     </div>    
     <div class="table">
         <%include file='../branches/branches_data.html'/>
--- a/rhodecode/templates/tags/tags_data.html	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/templates/tags/tags_data.html	Sat Dec 18 14:45:58 2010 +0100
@@ -1,25 +1,29 @@
 %if c.repo_tags:    
     <table>
     	<tr>
-			<th class="left">${_('date')}</th>
-			<th class="left">${_('revision')}</th>
-			<th class="left">${_('name')}</th>
+	        <th class="left">${_('date')}</th>
+	        <th class="left">${_('name')}</th>
+	        <th class="left">${_('author')}</th>
+	        <th class="left">${_('revision')}</th>
 			<th class="left">${_('links')}</th>
     	</tr>
 		%for cnt,tag in enumerate(c.repo_tags.items()):
-		<tr class="parity${cnt%2}">
-			<td>${h.age(tag[1]._ctx.date())}</td>
-			<td>r${tag[1].revision}:${tag[1].short_id}</td>
-			<td>
-				<span class="logtags">
-					<span class="tagtag">${h.link_to(tag[0],
-					h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].short_id))}</span>
-				</span>
-			</td>
+		<tr class="parity${cnt%2}">		
+	        <td><span class="tooltip" tooltip_title="${h.age(tag[1].date)}">
+                      ${tag[1].date}</span>
+            </td>
+            <td>
+                <span class="logtags">
+                    <span class="tagtag">${h.link_to(tag[0],
+                    h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].raw_id))}</span>
+                </span>
+            </td>	        
+	        <td title="${tag[1].author}">${h.person(tag[1].author)}</td>
+	        <td>r${tag[1].revision}:${h.short_id(tag[1].raw_id)}</td>
 			<td class="nowrap">
-			${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].short_id))}
+			${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
 			|
-			${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=tag[1].short_id))}
+			${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
 			</td>
 		</tr>	
 		%endfor
--- a/rhodecode/tests/__init__.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/__init__.py	Sat Dec 18 14:45:58 2010 +0100
@@ -18,33 +18,44 @@
 from rhodecode.model import meta
 import logging
 
+
 log = logging.getLogger(__name__)
 
 import pylons.test
 
-__all__ = ['environ', 'url', 'TestController']
+__all__ = ['environ', 'url', 'TestController', 'TESTS_TMP_PATH', 'HG_REPO',
+           'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO', 'HG_FORK', 'GIT_FORK', ]
 
 # Invoke websetup with the current config file
 #SetupCommand('setup-app').run([config_file])
 
 ##RUNNING DESIRED TESTS
-#nosetests rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
+#nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
 
 environ = {}
-TEST_DIR = '/tmp'
-REPO_PATH = os.path.join(TEST_DIR, 'vcs_test')
-NEW_REPO_PATH = os.path.join(TEST_DIR, 'vcs_test_new')
-FORK_REPO_PATH = os.path.join(TEST_DIR, 'vcs_test_fork')
+
+#SOME GLOBALS FOR TESTS
+TESTS_TMP_PATH = '/tmp'
+
+HG_REPO = 'vcs_test_hg'
+GIT_REPO = 'vcs_test_git'
+
+NEW_HG_REPO = 'vcs_test_hg_new'
+NEW_GIT_REPO = 'vcs_test_git_new'
+
+HG_FORK = 'vcs_test_hg_fork'
+GIT_FORK = 'vcs_test_git_fork'
 
 class TestController(TestCase):
 
     def __init__(self, *args, **kwargs):
         wsgiapp = pylons.test.pylonsapp
         config = wsgiapp.config
+
         self.app = TestApp(wsgiapp)
         url._push_object(URLGenerator(config['routes.map'], environ))
         self.sa = meta.Session
-
+        self.index_location = config['app_conf']['index_dir']
         TestCase.__init__(self, *args, **kwargs)
 
     def log_user(self, username='test_admin', password='test12'):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_admin_ldap_settings.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,7 @@
+from rhodecode.tests import *
+
+class TestLdapSettingsController(TestController):
+
+    def test_index(self):
+        response = self.app.get(url(controller='admin/ldap_settings', action='index'))
+        # Test response...
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_admin_permissions.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,43 @@
+from rhodecode.tests import *
+
+class TestAdminPermissionsController(TestController):
+
+    def test_index(self):
+        response = self.app.get(url('permissions'))
+        # Test response...
+
+    def test_index_as_xml(self):
+        response = self.app.get(url('formatted_permissions', format='xml'))
+
+    def test_create(self):
+        response = self.app.post(url('permissions'))
+
+    def test_new(self):
+        response = self.app.get(url('new_permission'))
+
+    def test_new_as_xml(self):
+        response = self.app.get(url('formatted_new_permission', format='xml'))
+
+    def test_update(self):
+        response = self.app.put(url('permission', id=1))
+
+    def test_update_browser_fakeout(self):
+        response = self.app.post(url('permission', id=1), params=dict(_method='put'))
+
+    def test_delete(self):
+        response = self.app.delete(url('permission', id=1))
+
+    def test_delete_browser_fakeout(self):
+        response = self.app.post(url('permission', id=1), params=dict(_method='delete'))
+
+    def test_show(self):
+        response = self.app.get(url('permission', id=1))
+
+    def test_show_as_xml(self):
+        response = self.app.get(url('formatted_permission', id=1, format='xml'))
+
+    def test_edit(self):
+        response = self.app.get(url('edit_permission', id=1))
+
+    def test_edit_as_xml(self):
+        response = self.app.get(url('formatted_edit_permission', id=1, format='xml'))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_admin_repos.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,131 @@
+from rhodecode.model.db import Repository
+from rhodecode.tests import *
+
+class TestAdminReposController(TestController):
+
+    def test_index(self):
+        self.log_user()
+        response = self.app.get(url('repos'))
+        # Test response...
+
+    def test_index_as_xml(self):
+        response = self.app.get(url('formatted_repos', format='xml'))
+
+    def test_create_hg(self):
+        self.log_user()
+        repo_name = NEW_HG_REPO
+        description = 'description for newly created repo'
+        private = False
+        response = self.app.post(url('repos'), {'repo_name':repo_name,
+                                                'repo_type':'hg',
+                                                'description':description,
+                                                'private':private})
+
+
+        #test if we have a message for that repository
+        assert '''created repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about new repo'
+
+        #test if the fork was created in the database
+        new_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).one()
+
+        assert new_repo.repo_name == repo_name, 'wrong name of repo name in db'
+        assert new_repo.description == description, 'wrong description'
+
+        #test if repository is visible in the list ?
+        response = response.follow()
+
+        assert repo_name in response.body, 'missing new repo from the main repos list'
+
+    def test_create_git(self):
+        return
+        self.log_user()
+        repo_name = NEW_GIT_REPO
+        description = 'description for newly created repo'
+        private = False
+        response = self.app.post(url('repos'), {'repo_name':repo_name,
+                                                'repo_type':'git',
+                                                'description':description,
+                                                'private':private})
+
+
+        #test if we have a message for that repository
+        assert '''created repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about new repo'
+
+        #test if the fork was created in the database
+        new_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).one()
+
+        assert new_repo.repo_name == repo_name, 'wrong name of repo name in db'
+        assert new_repo.description == description, 'wrong description'
+
+        #test if repository is visible in the list ?
+        response = response.follow()
+
+        assert repo_name in response.body, 'missing new repo from the main repos list'
+
+
+    def test_new(self):
+        self.log_user()
+        response = self.app.get(url('new_repo'))
+
+    def test_new_as_xml(self):
+        response = self.app.get(url('formatted_new_repo', format='xml'))
+
+    def test_update(self):
+        response = self.app.put(url('repo', repo_name=HG_REPO))
+
+    def test_update_browser_fakeout(self):
+        response = self.app.post(url('repo', repo_name=HG_REPO), params=dict(_method='put'))
+
+    def test_delete(self):
+        self.log_user()
+        repo_name = 'vcs_test_new_to_delete'
+        description = 'description for newly created repo'
+        private = False
+        response = self.app.post(url('repos'), {'repo_name':repo_name,
+                                                'repo_type':'hg',
+                                               'description':description,
+                                               'private':private})
+
+
+        #test if we have a message for that repository
+        assert '''created repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about new repo'
+
+        #test if the repo was created in the database
+        new_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).one()
+
+        assert new_repo.repo_name == repo_name, 'wrong name of repo name in db'
+        assert new_repo.description == description, 'wrong description'
+
+        #test if repository is visible in the list ?
+        response = response.follow()
+
+        assert repo_name in response.body, 'missing new repo from the main repos list'
+
+
+        response = self.app.delete(url('repo', repo_name=repo_name))
+
+        assert '''deleted repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about delete repo'
+
+        response.follow()
+
+        #check if repo was deleted from db
+        deleted_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).scalar()
+
+        assert deleted_repo is None, 'Deleted repository was found in db'
+
+
+    def test_delete_browser_fakeout(self):
+        response = self.app.post(url('repo', repo_name=HG_REPO), params=dict(_method='delete'))
+
+    def test_show(self):
+        self.log_user()
+        response = self.app.get(url('repo', repo_name=HG_REPO))
+
+    def test_show_as_xml(self):
+        response = self.app.get(url('formatted_repo', repo_name=HG_REPO, format='xml'))
+
+    def test_edit(self):
+        response = self.app.get(url('edit_repo', repo_name=HG_REPO))
+
+    def test_edit_as_xml(self):
+        response = self.app.get(url('formatted_edit_repo', repo_name=HG_REPO, format='xml'))
--- a/rhodecode/tests/functional/test_admin_settings.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_admin_settings.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,7 +1,8 @@
-from rhodecode.tests import *
+from rhodecode.lib.auth import get_crypt_password, check_password
 from rhodecode.model.db import User
+from rhodecode.tests import *
 
-class TestSettingsController(TestController):
+class TestAdminSettingsController(TestController):
 
     def test_index(self):
         response = self.app.get(url('admin_settings'))
@@ -48,45 +49,64 @@
         response = self.app.get(url('admin_settings_my_account'))
         print response
         assert 'value="test_admin' in response.body
-        
-        
-            
+
+
+
     def test_my_account_update(self):
         self.log_user()
+
         new_email = 'new@mail.pl'
+        new_name = 'NewName'
+        new_lastname = 'NewLastname'
+        new_password = 'test123'
+
+
         response = self.app.post(url('admin_settings_my_account_update'), params=dict(
                                                             _method='put',
                                                             username='test_admin',
-                                                            new_password='test12',
+                                                            new_password=new_password,
                                                             password='',
-                                                            name='NewName',
-                                                            lastname='NewLastname',
+                                                            name=new_name,
+                                                            lastname=new_lastname,
                                                             email=new_email,))
         response.follow()
-        print response
-    
-        print 'x' * 100
-        print response.session
-        assert 'Your account was updated succesfully' in response.session['flash'][0][1], 'no flash message about success of change'
+
+        assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
         user = self.sa.query(User).filter(User.username == 'test_admin').one()
         assert user.email == new_email , 'incorrect user email after update got %s vs %s' % (user.email, new_email)
-    
-    def test_my_account_update_own_email_ok(self):
-        self.log_user()
-                
-        new_email = 'new@mail.pl'
+        assert user.name == new_name, 'updated field mismatch %s vs %s' % (user.name, new_name)
+        assert user.lastname == new_lastname, 'updated field mismatch %s vs %s' % (user.lastname, new_lastname)
+        assert check_password(new_password, user.password) is True, 'password field mismatch %s vs %s' % (user.password, new_password)
+
+        #bring back the admin settings
+        old_email = 'test_admin@mail.com'
+        old_name = 'RhodeCode'
+        old_lastname = 'Admin'
+        old_password = 'test12'
+
         response = self.app.post(url('admin_settings_my_account_update'), params=dict(
                                                             _method='put',
                                                             username='test_admin',
-                                                            new_password='test12',
-                                                            name='NewName',
-                                                            lastname='NewLastname',
-                                                            email=new_email,))
-        print response
-                
+                                                            new_password=old_password,
+                                                            password='',
+                                                            name=old_name,
+                                                            lastname=old_lastname,
+                                                            email=old_email,))
+
+        response.follow()
+        assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
+        user = self.sa.query(User).filter(User.username == 'test_admin').one()
+        assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
+
+        assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
+        assert user.name == old_name, 'updated field mismatch %s vs %s' % (user.name, old_name)
+        assert user.lastname == old_lastname, 'updated field mismatch %s vs %s' % (user.lastname, old_lastname)
+        assert check_password(old_password, user.password) is True , 'password updated field mismatch %s vs %s' % (user.password, old_password)
+
+
     def test_my_account_update_err_email_exists(self):
         self.log_user()
-                
+
         new_email = 'test_regular@mail.com'#already exisitn email
         response = self.app.post(url('admin_settings_my_account_update'), params=dict(
                                                             _method='put',
@@ -96,13 +116,13 @@
                                                             lastname='NewLastname',
                                                             email=new_email,))
         print response
-        
-        assert 'That e-mail address is already taken' in response.body, 'Missing error message about existing email'
-        
-        
+
+        assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email'
+
+
     def test_my_account_update_err(self):
         self.log_user('test_regular2', 'test12')
-                
+
         new_email = 'newmail.pl'
         response = self.app.post(url('admin_settings_my_account_update'), params=dict(
                                                             _method='put',
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_admin_users.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,119 @@
+from rhodecode.tests import *
+from rhodecode.model.db import User
+from rhodecode.lib.auth import check_password
+from sqlalchemy.orm.exc import NoResultFound
+
+class TestAdminUsersController(TestController):
+
+    def test_index(self):
+        response = self.app.get(url('users'))
+        # Test response...
+
+    def test_index_as_xml(self):
+        response = self.app.get(url('formatted_users', format='xml'))
+
+    def test_create(self):
+        self.log_user()
+        username = 'newtestuser'
+        password = 'test12'
+        name = 'name'
+        lastname = 'lastname'
+        email = 'mail@mail.com'
+
+        response = self.app.post(url('users'), {'username':username,
+                                               'password':password,
+                                               'name':name,
+                                               'active':True,
+                                               'lastname':lastname,
+                                               'email':email})
+
+
+        assert '''created user %s''' % (username) in response.session['flash'][0], 'No flash message about new user'
+
+        new_user = self.sa.query(User).filter(User.username == username).one()
+
+
+        assert new_user.username == username, 'wrong info about username'
+        assert check_password(password, new_user.password) == True , 'wrong info about password'
+        assert new_user.name == name, 'wrong info about name'
+        assert new_user.lastname == lastname, 'wrong info about lastname'
+        assert new_user.email == email, 'wrong info about email'
+
+
+        response.follow()
+        response = response.follow()
+        assert """edit">newtestuser</a>""" in response.body
+
+    def test_create_err(self):
+        self.log_user()
+        username = 'new_user'
+        password = ''
+        name = 'name'
+        lastname = 'lastname'
+        email = 'errmail.com'
+
+        response = self.app.post(url('users'), {'username':username,
+                                               'password':password,
+                                               'name':name,
+                                               'active':False,
+                                               'lastname':lastname,
+                                               'email':email})
+
+        assert """<span class="error-message">Invalid username</span>""" in response.body
+        assert """<span class="error-message">Please enter a value</span>""" in response.body
+        assert """<span class="error-message">An email address must contain a single @</span>""" in response.body
+
+        def get_user():
+            self.sa.query(User).filter(User.username == username).one()
+
+        self.assertRaises(NoResultFound, get_user), 'found user in database'
+
+    def test_new(self):
+        response = self.app.get(url('new_user'))
+
+    def test_new_as_xml(self):
+        response = self.app.get(url('formatted_new_user', format='xml'))
+
+    def test_update(self):
+        response = self.app.put(url('user', id=1))
+
+    def test_update_browser_fakeout(self):
+        response = self.app.post(url('user', id=1), params=dict(_method='put'))
+
+    def test_delete(self):
+        self.log_user()
+        username = 'newtestuserdeleteme'
+        password = 'test12'
+        name = 'name'
+        lastname = 'lastname'
+        email = 'todeletemail@mail.com'
+
+        response = self.app.post(url('users'), {'username':username,
+                                               'password':password,
+                                               'name':name,
+                                               'active':True,
+                                               'lastname':lastname,
+                                               'email':email})
+
+        response = response.follow()
+
+        new_user = self.sa.query(User).filter(User.username == username).one()
+        response = self.app.delete(url('user', id=new_user.user_id))
+
+        assert """sucessfully deleted user""" in response.session['flash'][0], 'No info about user deletion'
+
+
+    def test_delete_browser_fakeout(self):
+        response = self.app.post(url('user', id=1), params=dict(_method='delete'))
+
+    def test_show(self):
+        response = self.app.get(url('user', id=1))
+
+    def test_show_as_xml(self):
+        response = self.app.get(url('formatted_user', id=1, format='xml'))
+
+    def test_edit(self):
+        response = self.app.get(url('edit_user', id=1))
+
+    def test_edit_as_xml(self):
+        response = self.app.get(url('formatted_edit_user', id=1, format='xml'))
--- a/rhodecode/tests/functional/test_branches.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_branches.py	Sat Dec 18 14:45:58 2010 +0100
@@ -4,5 +4,15 @@
 
     def test_index(self):
         self.log_user()
-        response = self.app.get(url(controller='branches', action='index',repo_name='vcs_test'))
+        response = self.app.get(url(controller='branches', action='index', repo_name=HG_REPO))
+
+        assert """<a href="/%s/changeset/27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</a>""" % HG_REPO in response.body, 'wrong info about default branch'
+        assert """<a href="/%s/changeset/97e8b885c04894463c51898e14387d80c30ed1ee">git</a>""" % HG_REPO in response.body, 'wrong info about default git'
+        assert """<a href="/%s/changeset/2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</a>""" % HG_REPO in response.body, 'wrong info about default web'
+
+
+
+
+
+
         # Test response...
--- a/rhodecode/tests/functional/test_changelog.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_changelog.py	Sat Dec 18 14:45:58 2010 +0100
@@ -2,29 +2,37 @@
 
 class TestChangelogController(TestController):
 
-    def test_index(self):
+    def test_index_hg(self):
         self.log_user()
-        response = self.app.get(url(controller='changelog', action='index', repo_name='vcs_test'))
+        response = self.app.get(url(controller='changelog', action='index', repo_name=HG_REPO))
 
+        print response.body
         assert """<div id="chg_20" class="container">""" in response.body, 'wrong info about number of changes'
+        assert """<div class="date">commit 154: 5e204e7583b9@2010-08-10 01:18:46</div>""" in response.body , 'no info on this commit'
         assert """Small update at simplevcs app""" in response.body, 'missing info about commit message'
-        assert """<span class="removed" title="removed">0</span>""" in response.body, 'wrong info about removed nodes'
-        assert """<span class="changed" title="changed">2</span>""" in response.body, 'wrong info about changed nodes'
-        assert """<span class="added" title="added">1</span>""" in response.body, 'wrong info about added nodes'
+        assert """<span class="removed tooltip" tooltip_title="removed: No Files">0</span>""" in response.body, 'wrong info about removed nodes'
+        assert """<span class="changed tooltip" tooltip_title="changed: vcs/backends/hg.py<br/> vcs/web/simplevcs/models.py">2</span>""" in response.body, 'wrong info about changed nodes'
+        assert """<span class="added tooltip" tooltip_title="added: vcs/web/simplevcs/managers.py">1</span>""" in response.body, 'wrong info about added nodes'
 
         #pagination
 
-        response = self.app.get(url(controller='changelog', action='index', repo_name='vcs_test'), {'page':1})
-        response = self.app.get(url(controller='changelog', action='index', repo_name='vcs_test'), {'page':2})
-        response = self.app.get(url(controller='changelog', action='index', repo_name='vcs_test'), {'page':3})
-        response = self.app.get(url(controller='changelog', action='index', repo_name='vcs_test'), {'page':4})
-        response = self.app.get(url(controller='changelog', action='index', repo_name='vcs_test'), {'page':5})
-        response = self.app.get(url(controller='changelog', action='index', repo_name='vcs_test'), {'page':6})
+        response = self.app.get(url(controller='changelog', action='index', repo_name=HG_REPO), {'page':1})
+        response = self.app.get(url(controller='changelog', action='index', repo_name=HG_REPO), {'page':2})
+        response = self.app.get(url(controller='changelog', action='index', repo_name=HG_REPO), {'page':3})
+        response = self.app.get(url(controller='changelog', action='index', repo_name=HG_REPO), {'page':4})
+        response = self.app.get(url(controller='changelog', action='index', repo_name=HG_REPO), {'page':5})
+        response = self.app.get(url(controller='changelog', action='index', repo_name=HG_REPO), {'page':6})
+
         # Test response after pagination...
+        print response.body
+        assert """<div class="date">commit 64: 46ad32a4f974@2010-04-20 00:33:21</div>"""in response.body, 'wrong info about commit 64'
+        assert """<span class="removed tooltip" tooltip_title="removed: docs/api.rst">1</span>"""in response.body, 'wrong info about number of removed'
+        assert """<span class="changed tooltip" tooltip_title="changed: .hgignore<br/> README.rst<br/> docs/conf.py<br/> docs/index.rst<br/> setup.py<br/> tests/test_hg.py<br/> tests/test_nodes.py<br/> vcs/__init__.py<br/> vcs/backends/__init__.py<br/> vcs/backends/base.py<br/> vcs/backends/hg.py<br/> vcs/nodes.py<br/> vcs/utils/__init__.py">13</span>"""in response.body, 'wrong info about number of changes'
+        assert """<span class="added tooltip" tooltip_title="added: docs/api/backends/hg.rst<br/> docs/api/backends/index.rst<br/> docs/api/index.rst<br/> docs/api/nodes.rst<br/> docs/api/web/index.rst<br/> docs/api/web/simplevcs.rst<br/> docs/installation.rst<br/> docs/quickstart.rst<br/> setup.cfg<br/> vcs/utils/baseui_config.py<br/> vcs/utils/web.py<br/> vcs/web/__init__.py<br/> vcs/web/exceptions.py<br/> vcs/web/simplevcs/__init__.py<br/> vcs/web/simplevcs/exceptions.py<br/> vcs/web/simplevcs/middleware.py<br/> vcs/web/simplevcs/models.py<br/> vcs/web/simplevcs/settings.py<br/> vcs/web/simplevcs/utils.py<br/> vcs/web/simplevcs/views.py">20</span>"""in response.body, 'wrong info about number of added'
+        assert """<div class="message"><a href="/%s/changeset/46ad32a4f974e45472a898c6b0acb600320579b1">Merge with 2e6a2bf9356ca56df08807f4ad86d480da72a8f4</a></div>""" % HG_REPO in response.body, 'wrong info about commit 64 is a merge'
 
-        assert """<span class="removed" title="removed">20</span>"""in response.body, 'wrong info about number of removed'
-        assert """<span class="changed" title="changed">1</span>"""in response.body, 'wrong info about number of changes'
-        assert """<span class="added" title="added">0</span>"""in response.body, 'wrong info about number of added'
-        assert """<div class="date">commit 64: 46ad32a4f974@2010-04-20 00:33:21</div>"""in response.body, 'wrong info about commit 64'
+
 
-        assert """<div class="message"><a href="/vcs_test/changeset/46ad32a4f974">Merge with 2e6a2bf9356ca56df08807f4ad86d480da72a8f4</a></div>"""in response.body, 'wrong info about commit 64 is a merge'
+    #def test_index_git(self):
+    #    self.log_user()
+    #    response = self.app.get(url(controller='changelog', action='index', repo_name=GIT_REPO))
--- a/rhodecode/tests/functional/test_changeset.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_changeset.py	Sat Dec 18 14:45:58 2010 +0100
@@ -4,5 +4,5 @@
 
     def test_index(self):
         response = self.app.get(url(controller='changeset', action='index',
-                                    repo_name='vcs_test',revision='tip'))
+                                    repo_name=HG_REPO,revision='tip'))
         # Test response...
--- a/rhodecode/tests/functional/test_feed.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_feed.py	Sat Dec 18 14:45:58 2010 +0100
@@ -5,11 +5,11 @@
     def test_rss(self):
         self.log_user()
         response = self.app.get(url(controller='feed', action='rss',
-                                    repo_name='vcs_test'))
+                                    repo_name=HG_REPO))
         # Test response...
 
     def test_atom(self):
         self.log_user()
         response = self.app.get(url(controller='feed', action='atom',
-                                    repo_name='vcs_test'))
+                                    repo_name=HG_REPO))
         # Test response...
\ No newline at end of file
--- a/rhodecode/tests/functional/test_files.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_files.py	Sat Dec 18 14:45:58 2010 +0100
@@ -5,7 +5,186 @@
     def test_index(self):
         self.log_user()
         response = self.app.get(url(controller='files', action='index',
-                                    repo_name='vcs_test',
+                                    repo_name=HG_REPO,
                                     revision='tip',
                                     f_path='/'))
         # Test response...
+        assert '<a class="browser-dir" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/docs">docs</a>' in response.body, 'missing dir'
+        assert '<a class="browser-dir" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/tests">tests</a>' in response.body, 'missing dir'
+        assert '<a class="browser-dir" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/vcs">vcs</a>' in response.body, 'missing dir'
+        assert '<a class="browser-file" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/.hgignore">.hgignore</a>' in response.body, 'missing file'
+        assert '<a class="browser-file" href="/vcs_test_hg/files/27cd5cce30c96924232dffcd24178a07ffeb5dfc/MANIFEST.in">MANIFEST.in</a>' in response.body, 'missing file'
+
+
+    def test_index_revision(self):
+        self.log_user()
+
+        response = self.app.get(url(controller='files', action='index',
+                                    repo_name=HG_REPO,
+                                    revision='7ba66bec8d6dbba14a2155be32408c435c5f4492',
+                                    f_path='/'))
+
+
+
+        #Test response...
+
+        assert '<a class="browser-dir" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/docs">docs</a>' in response.body, 'missing dir'
+        assert '<a class="browser-dir" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/tests">tests</a>' in response.body, 'missing dir'
+        assert '<a class="browser-file" href="/vcs_test_hg/files/7ba66bec8d6dbba14a2155be32408c435c5f4492/README.rst">README.rst</a>' in response.body, 'missing file'
+        assert '1.1 KiB' in response.body, 'missing size of setup.py'
+        assert 'text/x-python' in response.body, 'missing mimetype of setup.py'
+
+
+
+    def test_index_different_branch(self):
+        self.log_user()
+
+        response = self.app.get(url(controller='files', action='index',
+                                    repo_name=HG_REPO,
+                                    revision='97e8b885c04894463c51898e14387d80c30ed1ee',
+                                    f_path='/'))
+
+
+
+        assert """<span style="text-transform: uppercase;"><a href="#">branch: git</a></span>""" in response.body, 'missing or wrong branch info'
+
+
+
+    def test_index_paging(self):
+        self.log_user()
+
+        for r in [(73, 'a066b25d5df7016b45a41b7e2a78c33b57adc235'),
+                  (92, 'cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e'),
+                  (109, '75feb4c33e81186c87eac740cee2447330288412'),
+                  (1, '3d8f361e72ab303da48d799ff1ac40d5ac37c67e'),
+                  (0, 'b986218ba1c9b0d6a259fac9b050b1724ed8e545')]:
+
+            response = self.app.get(url(controller='files', action='index',
+                                    repo_name=HG_REPO,
+                                    revision=r[1],
+                                    f_path='/'))
+
+            assert """@ r%s:%s""" % (r[0], r[1][:12]) in response.body, 'missing info about current revision'
+
+    def test_file_source(self):
+        self.log_user()
+        response = self.app.get(url(controller='files', action='index',
+                                    repo_name=HG_REPO,
+                                    revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
+                                    f_path='vcs/nodes.py'))
+
+        #test or history
+        assert """<optgroup label="Changesets">
+<option selected="selected" value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776</option>
+<option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35</option>
+<option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c</option>
+<option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329</option>
+<option value="6249fd0fb2cfb1411e764129f598e2cf0de79a6f">r113:6249fd0fb2cf</option>
+<option value="75feb4c33e81186c87eac740cee2447330288412">r109:75feb4c33e81</option>
+<option value="9a4dc232ecdc763ef2e98ae2238cfcbba4f6ad8d">r108:9a4dc232ecdc</option>
+<option value="595cce4efa21fda2f2e4eeb4fe5f2a6befe6fa2d">r107:595cce4efa21</option>
+<option value="4a8bd421fbc2dfbfb70d85a3fe064075ab2c49da">r104:4a8bd421fbc2</option>
+<option value="57be63fc8f85e65a0106a53187f7316f8c487ffa">r102:57be63fc8f85</option>
+<option value="5530bd87f7e2e124a64d07cb2654c997682128be">r101:5530bd87f7e2</option>
+<option value="e516008b1c93f142263dc4b7961787cbad654ce1">r99:e516008b1c93</option>
+<option value="41f43fc74b8b285984554532eb105ac3be5c434f">r93:41f43fc74b8b</option>
+<option value="cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e">r92:cc66b61b8455</option>
+<option value="73ab5b616b3271b0518682fb4988ce421de8099f">r91:73ab5b616b32</option>
+<option value="e0da75f308c0f18f98e9ce6257626009fdda2b39">r82:e0da75f308c0</option>
+<option value="fb2e41e0f0810be4d7103bc2a4c7be16ee3ec611">r81:fb2e41e0f081</option>
+<option value="602ae2f5e7ade70b3b66a58cdd9e3e613dc8a028">r76:602ae2f5e7ad</option>
+<option value="a066b25d5df7016b45a41b7e2a78c33b57adc235">r73:a066b25d5df7</option>
+<option value="637a933c905958ce5151f154147c25c1c7b68832">r61:637a933c9059</option>
+<option value="0c21004effeb8ce2d2d5b4a8baf6afa8394b6fbc">r60:0c21004effeb</option>
+<option value="a1f39c56d3f1d52d5fb5920370a2a2716cd9a444">r59:a1f39c56d3f1</option>
+<option value="97d32df05c715a3bbf936bf3cc4e32fb77fe1a7f">r58:97d32df05c71</option>
+<option value="08eaf14517718dccea4b67755a93368341aca919">r57:08eaf1451771</option>
+<option value="22f71ad265265a53238359c883aa976e725aa07d">r56:22f71ad26526</option>
+<option value="97501f02b7b4330924b647755663a2d90a5e638d">r49:97501f02b7b4</option>
+<option value="86ede6754f2b27309452bb11f997386ae01d0e5a">r47:86ede6754f2b</option>
+<option value="014c40c0203c423dc19ecf94644f7cac9d4cdce0">r45:014c40c0203c</option>
+<option value="ee87846a61c12153b51543bf860e1026c6d3dcba">r30:ee87846a61c1</option>
+<option value="9bb326a04ae5d98d437dece54be04f830cf1edd9">r26:9bb326a04ae5</option>
+<option value="536c1a19428381cfea92ac44985304f6a8049569">r24:536c1a194283</option>
+<option value="dc5d2c0661b61928834a785d3e64a3f80d3aad9c">r8:dc5d2c0661b6</option>
+<option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3</option>
+</optgroup>
+<optgroup label="Branches">
+<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
+<option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
+<option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
+</optgroup>
+<optgroup label="Tags">
+<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
+<option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
+<option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
+<option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
+<option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
+</optgroup>""" in response.body
+
+
+        assert """<div class="commit">"Partially implemented #16. filecontent/commit message/author/node name are safe_unicode now.
+In addition some other __str__ are unicode as well
+Added test for unicode
+Improved test to clone into uniq repository.
+removed extra unicode conversion in diff."</div>""" in response.body
+
+        assert """<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""" in response.body, 'missing or wrong branch info'
+
+    def test_file_annotation(self):
+        self.log_user()
+        response = self.app.get(url(controller='files', action='annotate',
+                                    repo_name=HG_REPO,
+                                    revision='27cd5cce30c96924232dffcd24178a07ffeb5dfc',
+                                    f_path='vcs/nodes.py'))
+
+        print response.body
+        assert """<optgroup label="Changesets">
+<option selected="selected" value="8911406ad776fdd3d0b9932a2e89677e57405a48">r167:8911406ad776</option>
+<option value="aa957ed78c35a1541f508d2ec90e501b0a9e3167">r165:aa957ed78c35</option>
+<option value="48e11b73e94c0db33e736eaeea692f990cb0b5f1">r140:48e11b73e94c</option>
+<option value="adf3cbf483298563b968a6c673cd5bde5f7d5eea">r126:adf3cbf48329</option>
+<option value="6249fd0fb2cfb1411e764129f598e2cf0de79a6f">r113:6249fd0fb2cf</option>
+<option value="75feb4c33e81186c87eac740cee2447330288412">r109:75feb4c33e81</option>
+<option value="9a4dc232ecdc763ef2e98ae2238cfcbba4f6ad8d">r108:9a4dc232ecdc</option>
+<option value="595cce4efa21fda2f2e4eeb4fe5f2a6befe6fa2d">r107:595cce4efa21</option>
+<option value="4a8bd421fbc2dfbfb70d85a3fe064075ab2c49da">r104:4a8bd421fbc2</option>
+<option value="57be63fc8f85e65a0106a53187f7316f8c487ffa">r102:57be63fc8f85</option>
+<option value="5530bd87f7e2e124a64d07cb2654c997682128be">r101:5530bd87f7e2</option>
+<option value="e516008b1c93f142263dc4b7961787cbad654ce1">r99:e516008b1c93</option>
+<option value="41f43fc74b8b285984554532eb105ac3be5c434f">r93:41f43fc74b8b</option>
+<option value="cc66b61b8455b264a7a8a2d8ddc80fcfc58c221e">r92:cc66b61b8455</option>
+<option value="73ab5b616b3271b0518682fb4988ce421de8099f">r91:73ab5b616b32</option>
+<option value="e0da75f308c0f18f98e9ce6257626009fdda2b39">r82:e0da75f308c0</option>
+<option value="fb2e41e0f0810be4d7103bc2a4c7be16ee3ec611">r81:fb2e41e0f081</option>
+<option value="602ae2f5e7ade70b3b66a58cdd9e3e613dc8a028">r76:602ae2f5e7ad</option>
+<option value="a066b25d5df7016b45a41b7e2a78c33b57adc235">r73:a066b25d5df7</option>
+<option value="637a933c905958ce5151f154147c25c1c7b68832">r61:637a933c9059</option>
+<option value="0c21004effeb8ce2d2d5b4a8baf6afa8394b6fbc">r60:0c21004effeb</option>
+<option value="a1f39c56d3f1d52d5fb5920370a2a2716cd9a444">r59:a1f39c56d3f1</option>
+<option value="97d32df05c715a3bbf936bf3cc4e32fb77fe1a7f">r58:97d32df05c71</option>
+<option value="08eaf14517718dccea4b67755a93368341aca919">r57:08eaf1451771</option>
+<option value="22f71ad265265a53238359c883aa976e725aa07d">r56:22f71ad26526</option>
+<option value="97501f02b7b4330924b647755663a2d90a5e638d">r49:97501f02b7b4</option>
+<option value="86ede6754f2b27309452bb11f997386ae01d0e5a">r47:86ede6754f2b</option>
+<option value="014c40c0203c423dc19ecf94644f7cac9d4cdce0">r45:014c40c0203c</option>
+<option value="ee87846a61c12153b51543bf860e1026c6d3dcba">r30:ee87846a61c1</option>
+<option value="9bb326a04ae5d98d437dece54be04f830cf1edd9">r26:9bb326a04ae5</option>
+<option value="536c1a19428381cfea92ac44985304f6a8049569">r24:536c1a194283</option>
+<option value="dc5d2c0661b61928834a785d3e64a3f80d3aad9c">r8:dc5d2c0661b6</option>
+<option value="3803844fdbd3b711175fc3da9bdacfcd6d29a6fb">r7:3803844fdbd3</option>
+</optgroup>
+<optgroup label="Branches">
+<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">default</option>
+<option value="97e8b885c04894463c51898e14387d80c30ed1ee">git</option>
+<option value="2e6a2bf9356ca56df08807f4ad86d480da72a8f4">web</option>
+</optgroup>
+<optgroup label="Tags">
+<option value="27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</option>
+<option value="fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</option>
+<option value="17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</option>
+<option value="a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</option>
+<option value="eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</option>
+</optgroup>""" in response.body, 'missing or wrong history in annotation'
+
+        assert """<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""" in response.body, 'missing or wrong branch info'
--- a/rhodecode/tests/functional/test_hg.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-from rhodecode.tests import *
-
-class TestAdminController(TestController):
-
-    def test_index(self):
-        self.log_user()
-        response = self.app.get(url(controller='hg', action='index'))
-        #if global permission is set
-        assert 'ADD NEW REPOSITORY' in response.body, 'Wrong main page'
-        assert 'href="/vcs_test/summary"' in response.body, ' mising repository in list'
-        # Test response...
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_home.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,11 @@
+from rhodecode.tests import *
+
+class TestHomeController(TestController):
+
+    def test_index(self):
+        self.log_user()
+        response = self.app.get(url(controller='home', action='index'))
+        #if global permission is set
+        assert 'ADD NEW REPOSITORY' in response.body, 'Wrong main page'
+        assert 'href="/%s/summary"' % HG_REPO in response.body, ' mising repository in list'
+        # Test response...
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_journal.py	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,7 @@
+from rhodecode.tests import *
+
+class TestJournalController(TestController):
+
+    def test_index(self):
+        response = self.app.get(url(controller='journal', action='index'))
+        # Test response...
--- a/rhodecode/tests/functional/test_login.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_login.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 from rhodecode.tests import *
 from rhodecode.model.db import User
 from rhodecode.lib.auth import check_password
@@ -17,8 +18,8 @@
         assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
         assert response.session['rhodecode_user'].username == 'test_admin', 'wrong logged in user'
         response = response.follow()
-        assert 'auto description for vcs_test' in response.body
-    
+        assert '%s repository' % HG_REPO in response.body
+
     def test_login_regular_ok(self):
         response = self.app.post(url(controller='login', action='index'),
                                  {'username':'test_regular',
@@ -27,9 +28,9 @@
         assert response.status == '302 Found', 'Wrong response code from login got %s' % response.status
         assert response.session['rhodecode_user'].username == 'test_regular', 'wrong logged in user'
         response = response.follow()
-        assert 'auto description for vcs_test' in response.body
+        assert '%s repository' % HG_REPO in response.body
         assert '<a title="Admin" href="/_admin">' not in response.body
-    
+
     def test_login_ok_came_from(self):
         test_came_from = '/_admin/users'
         response = self.app.post(url(controller='login', action='index', came_from=test_came_from),
@@ -37,11 +38,11 @@
                                   'password':'test12'})
         assert response.status == '302 Found', 'Wrong response code from came from redirection'
         response = response.follow()
-        
+
         assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
         assert 'Users administration' in response.body, 'No proper title in response'
-        
-                
+
+
     def test_login_short_password(self):
         response = self.app.post(url(controller='login', action='index'),
                                  {'username':'error',
@@ -55,71 +56,152 @@
                                  {'username':'error',
                                   'password':'test12'})
         assert response.status == '200 OK', 'Wrong response from login page'
-        
+
         assert 'invalid user name' in response.body, 'No error username message in response'
         assert 'invalid password' in response.body, 'No error password message in response'
-                
-        
+
+    #==========================================================================
+    # REGISTRATIONS
+    #==========================================================================
     def test_register(self):
         response = self.app.get(url(controller='login', action='register'))
-        assert 'Sign Up to rhodecode' in response.body, 'wrong page for user registration'
-        
+        assert 'Sign Up to RhodeCode' in response.body, 'wrong page for user registration'
+
     def test_register_err_same_username(self):
         response = self.app.post(url(controller='login', action='register'),
                                             {'username':'test_admin',
-                                             'password':'test',
+                                             'password':'test12',
+                                             'password_confirmation':'test12',
                                              'email':'goodmail@domain.com',
                                              'name':'test',
                                              'lastname':'test'})
-        
+
+        assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
+        assert 'This username already exists' in response.body
+
+    def test_register_err_same_email(self):
+        response = self.app.post(url(controller='login', action='register'),
+                                            {'username':'test_admin_0',
+                                             'password':'test12',
+                                             'password_confirmation':'test12',
+                                             'email':'test_admin@mail.com',
+                                             'name':'test',
+                                             'lastname':'test'})
+
         assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
-        assert 'This username already exists' in response.body 
-        
+        assert 'This e-mail address is already taken' in response.body
+
+    def test_register_err_same_email_case_sensitive(self):
+        response = self.app.post(url(controller='login', action='register'),
+                                            {'username':'test_admin_1',
+                                             'password':'test12',
+                                             'password_confirmation':'test12',
+                                             'email':'TesT_Admin@mail.COM',
+                                             'name':'test',
+                                             'lastname':'test'})
+        assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
+        assert 'This e-mail address is already taken' in response.body
+
     def test_register_err_wrong_data(self):
         response = self.app.post(url(controller='login', action='register'),
                                             {'username':'xs',
-                                             'password':'',
+                                             'password':'test',
+                                             'password_confirmation':'test',
+                                             'email':'goodmailm',
+                                             'name':'test',
+                                             'lastname':'test'})
+        assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
+        assert 'An email address must contain a single @' in response.body
+        assert 'Enter a value 6 characters long or more' in response.body
+
+
+    def test_register_err_username(self):
+        response = self.app.post(url(controller='login', action='register'),
+                                            {'username':'error user',
+                                             'password':'test12',
+                                             'password_confirmation':'test12',
+                                             'email':'goodmailm',
+                                             'name':'test',
+                                             'lastname':'test'})
+
+        print response.body
+        assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
+        assert 'An email address must contain a single @' in response.body
+        assert 'Username may only contain alphanumeric characters underscores or dashes and must begin with alphanumeric character' in response.body
+
+    def test_register_err_case_sensitive(self):
+        response = self.app.post(url(controller='login', action='register'),
+                                            {'username':'Test_Admin',
+                                             'password':'test12',
+                                             'password_confirmation':'test12',
                                              'email':'goodmailm',
                                              'name':'test',
                                              'lastname':'test'})
-        
+
         assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
         assert 'An email address must contain a single @' in response.body
-        assert 'Please enter a value' in response.body
-        
-        
-        
+        assert 'This username already exists' in response.body
+
+
+
+    def test_register_special_chars(self):
+        response = self.app.post(url(controller='login', action='register'),
+                                            {'username':'xxxaxn',
+                                             'password':'ąćźżąśśśś',
+                                             'password_confirmation':'ąćźżąśśśś',
+                                             'email':'goodmailm@test.plx',
+                                             'name':'test',
+                                             'lastname':'test'})
+
+        print response.body
+        assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
+        assert 'Invalid characters in password' in response.body
+
+
+    def test_register_password_mismatch(self):
+        response = self.app.post(url(controller='login', action='register'),
+                                            {'username':'xs',
+                                             'password':'123qwe',
+                                             'password_confirmation':'qwe123',
+                                             'email':'goodmailm@test.plxa',
+                                             'name':'test',
+                                             'lastname':'test'})
+
+        assert response.status == '200 OK', 'Wrong response from register page got %s' % response.status
+        print response.body
+        assert 'Password do not match' in response.body
+
     def test_register_ok(self):
         username = 'test_regular4'
         password = 'qweqwe'
         email = 'marcin@test.com'
         name = 'testname'
         lastname = 'testlastname'
-        
+
         response = self.app.post(url(controller='login', action='register'),
                                             {'username':username,
                                              'password':password,
+                                             'password_confirmation':password,
                                              'email':email,
                                              'name':name,
                                              'lastname':lastname})
-        print response.body
-        assert response.status == '302 Found', 'Wrong response from register page got %s' % response.status        
+        assert response.status == '302 Found', 'Wrong response from register page got %s' % response.status
         assert 'You have successfully registered into rhodecode' in response.session['flash'][0], 'No flash message about user registration'
-        
+
         ret = self.sa.query(User).filter(User.username == 'test_regular4').one()
         assert ret.username == username , 'field mismatch %s %s' % (ret.username, username)
         assert check_password(password, ret.password) == True , 'password mismatch'
         assert ret.email == email , 'field mismatch %s %s' % (ret.email, email)
         assert ret.name == name , 'field mismatch %s %s' % (ret.name, name)
         assert ret.lastname == lastname , 'field mismatch %s %s' % (ret.lastname, lastname)
-    
-        
-    def test_forgot_password_wrong_mail(self):    
+
+
+    def test_forgot_password_wrong_mail(self):
         response = self.app.post(url(controller='login', action='password_reset'),
                                             {'email':'marcin@wrongmail.org', })
-        
-        assert "That e-mail address doesn't exist" in response.body, 'Missing error message about wrong email'
-                
+
+        assert "This e-mail address doesn't exist" in response.body, 'Missing error message about wrong email'
+
     def test_forgot_password(self):
         response = self.app.get(url(controller='login', action='password_reset'))
         assert response.status == '200 OK', 'Wrong response from login page got %s' % response.status
@@ -129,19 +211,20 @@
         email = 'marcin@python-works.com'
         name = 'passwd'
         lastname = 'reset'
-                
+
         response = self.app.post(url(controller='login', action='register'),
                                             {'username':username,
                                              'password':password,
+                                             'password_confirmation':password,
                                              'email':email,
                                              'name':name,
-                                             'lastname':lastname})        
+                                             'lastname':lastname})
         #register new user for email test
         response = self.app.post(url(controller='login', action='password_reset'),
                                             {'email':email, })
         print response.session['flash']
         assert 'You have successfully registered into rhodecode' in response.session['flash'][0], 'No flash message about user registration'
         assert 'Your new password was sent' in response.session['flash'][1], 'No flash message about password reset'
-        
-        
-        
+
+
+
--- a/rhodecode/tests/functional/test_permissions.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-from rhodecode.tests import *
-
-class TestPermissionsController(TestController):
-
-    def test_index(self):
-        response = self.app.get(url('permissions'))
-        # Test response...
-
-    def test_index_as_xml(self):
-        response = self.app.get(url('formatted_permissions', format='xml'))
-
-    def test_create(self):
-        response = self.app.post(url('permissions'))
-
-    def test_new(self):
-        response = self.app.get(url('new_permission'))
-
-    def test_new_as_xml(self):
-        response = self.app.get(url('formatted_new_permission', format='xml'))
-
-    def test_update(self):
-        response = self.app.put(url('permission', id=1))
-
-    def test_update_browser_fakeout(self):
-        response = self.app.post(url('permission', id=1), params=dict(_method='put'))
-
-    def test_delete(self):
-        response = self.app.delete(url('permission', id=1))
-
-    def test_delete_browser_fakeout(self):
-        response = self.app.post(url('permission', id=1), params=dict(_method='delete'))
-
-    def test_show(self):
-        response = self.app.get(url('permission', id=1))
-
-    def test_show_as_xml(self):
-        response = self.app.get(url('formatted_permission', id=1, format='xml'))
-
-    def test_edit(self):
-        response = self.app.get(url('edit_permission', id=1))
-
-    def test_edit_as_xml(self):
-        response = self.app.get(url('formatted_edit_permission', id=1, format='xml'))
--- a/rhodecode/tests/functional/test_repos.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-from rhodecode.model.db import Repository
-from rhodecode.tests import *
-
-class TestReposController(TestController):
-
-    def test_index(self):
-        self.log_user()
-        response = self.app.get(url('repos'))
-        # Test response...
-
-    def test_index_as_xml(self):
-        response = self.app.get(url('formatted_repos', format='xml'))
-
-    def test_create(self):
-        self.log_user()
-        repo_name = 'vcs_test_new'
-        description = 'description for newly created repo'
-        private = False
-        response = self.app.post(url('repos'), {'repo_name':repo_name,
-                                               'description':description,
-                                               'private':private})
-
-        print response
-        
-        #test if we have a message for that repository
-        print '-' * 100
-        print response.session
-        assert '''created repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about new repo'
-                      
-        #test if the fork was created in the database
-        new_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).one()
-        
-        assert new_repo.repo_name == repo_name, 'wrong name of repo name in db'
-        assert new_repo.description == description, 'wrong description'
-        
-        #test if repository is visible in the list ?
-        response = response.follow()
-        
-        assert repo_name in response.body, 'missing new repo from the main repos list'
-        
-                
-
-
-    def test_new(self):
-        self.log_user()
-        response = self.app.get(url('new_repo'))
-
-    def test_new_as_xml(self):
-        response = self.app.get(url('formatted_new_repo', format='xml'))
-
-    def test_update(self):
-        response = self.app.put(url('repo', repo_name='vcs_test'))
-
-    def test_update_browser_fakeout(self):
-        response = self.app.post(url('repo', repo_name='vcs_test'), params=dict(_method='put'))
-
-    def test_delete(self):
-        self.log_user()
-        repo_name = 'vcs_test_new_to_delete'
-        description = 'description for newly created repo'
-        private = False
-        response = self.app.post(url('repos'), {'repo_name':repo_name,
-                                               'description':description,
-                                               'private':private})
-
-        print response
-        
-        #test if we have a message for that repository
-        print '-' * 100
-        print response.session
-        assert '''created repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about new repo'
-                      
-        #test if the repo was created in the database
-        new_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).one()
-        
-        assert new_repo.repo_name == repo_name, 'wrong name of repo name in db'
-        assert new_repo.description == description, 'wrong description'
-        
-        #test if repository is visible in the list ?
-        response = response.follow()
-        
-        assert repo_name in response.body, 'missing new repo from the main repos list'
-        
-                
-        response = self.app.delete(url('repo', repo_name=repo_name))
-        
-        print '-' * 100
-        print response.session
-        assert '''deleted repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about delete repo'
-                
-        response.follow()
-        
-        #check if repo was deleted from db
-        deleted_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).scalar()
-        
-        assert deleted_repo is None, 'Deleted repository was found in db'
-        
-
-    def test_delete_browser_fakeout(self):
-        response = self.app.post(url('repo', repo_name='vcs_test'), params=dict(_method='delete'))
-
-    def test_show(self):
-        self.log_user()
-        response = self.app.get(url('repo', repo_name='vcs_test'))
-
-    def test_show_as_xml(self):
-        response = self.app.get(url('formatted_repo', repo_name='vcs_test', format='xml'))
-
-    def test_edit(self):
-        response = self.app.get(url('edit_repo', repo_name='vcs_test'))
-
-    def test_edit_as_xml(self):
-        response = self.app.get(url('formatted_edit_repo', repo_name='vcs_test', format='xml'))
--- a/rhodecode/tests/functional/test_search.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_search.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,5 +1,4 @@
 from rhodecode.tests import *
-from rhodecode.lib.indexers import IDX_LOCATION
 import os
 from nose.plugins.skip import SkipTest
 
@@ -13,26 +12,25 @@
         # Test response...
 
     def test_empty_search(self):
-        
-        if os.path.isdir(IDX_LOCATION):
+        if os.path.isdir(self.index_location):
             raise SkipTest('skipped due to existing index')
         else:
             self.log_user()
-            response = self.app.get(url(controller='search', action='index'), {'q':'vcs_test'})
+            response = self.app.get(url(controller='search', action='index'), {'q':HG_REPO})
             assert 'There is no index to search in. Please run whoosh indexer' in response.body, 'No error message about empty index'
-        
+
     def test_normal_search(self):
         self.log_user()
         response = self.app.get(url(controller='search', action='index'), {'q':'def repo'})
         print response.body
         assert '10 results' in response.body, 'no message about proper search results'
         assert 'Permission denied' not in response.body, 'Wrong permissions settings for that repo and user'
-        
-    
+
+
     def test_repo_search(self):
         self.log_user()
-        response = self.app.get(url(controller='search', action='index'), {'q':'repository:vcs_test def test'})
+        response = self.app.get(url(controller='search', action='index'), {'q':'repository:%s def test' % HG_REPO})
         print response.body
         assert '4 results' in response.body, 'no message about proper search results'
         assert 'Permission denied' not in response.body, 'Wrong permissions settings for that repo and user'
-        
+
--- a/rhodecode/tests/functional/test_settings.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_settings.py	Sat Dec 18 14:45:58 2010 +0100
@@ -6,40 +6,38 @@
     def test_index(self):
         self.log_user()
         response = self.app.get(url(controller='settings', action='index',
-                                    repo_name='vcs_test'))
+                                    repo_name=HG_REPO))
         # Test response...
-    
+
     def test_fork(self):
         self.log_user()
         response = self.app.get(url(controller='settings', action='fork',
-                                    repo_name='vcs_test'))
-        
+                                    repo_name=HG_REPO))
+
 
     def test_fork_create(self):
         self.log_user()
-        fork_name = 'vcs_test_fork'
+        fork_name = HG_FORK
         description = 'fork of vcs test'
-        repo_name = 'vcs_test'
+        repo_name = HG_REPO
         response = self.app.post(url(controller='settings', action='fork_create',
                                     repo_name=repo_name),
                                     {'fork_name':fork_name,
+                                     'repo_type':'hg',
                                      'description':description,
                                      'private':'False'})
-        
-        
-        print response
-        
+
         #test if we have a message that fork is ok
-        assert 'fork %s repository as %s task added' \
+        assert 'forked %s repository as %s' \
                       % (repo_name, fork_name) in response.session['flash'][0], 'No flash message about fork'
-                      
+
         #test if the fork was created in the database
         fork_repo = self.sa.query(Repository).filter(Repository.repo_name == fork_name).one()
-        
+
         assert fork_repo.repo_name == fork_name, 'wrong name of repo name in new db fork repo'
         assert fork_repo.fork.repo_name == repo_name, 'wrong fork parrent'
-        
-        
+
+
         #test if fork is visible in the list ?
         response = response.follow()
 
@@ -47,9 +45,6 @@
         #check if fork is marked as fork
         response = self.app.get(url(controller='summary', action='index',
                                     repo_name=fork_name))
-        
-        
-        print response
-        
+
         assert 'Fork of %s' % repo_name in response.body, 'no message about that this repo is a fork'
-        
+
--- a/rhodecode/tests/functional/test_shortlog.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_shortlog.py	Sat Dec 18 14:45:58 2010 +0100
@@ -4,5 +4,5 @@
 
     def test_index(self):
         self.log_user()
-        response = self.app.get(url(controller='shortlog', action='index',repo_name='vcs_test'))
+        response = self.app.get(url(controller='shortlog', action='index',repo_name=HG_REPO))
         # Test response...
--- a/rhodecode/tests/functional/test_summary.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_summary.py	Sat Dec 18 14:45:58 2010 +0100
@@ -4,8 +4,16 @@
 
     def test_index(self):
         self.log_user()
-        response = self.app.get(url(controller='summary', action='index', repo_name='vcs_test'))
-        print response
-        assert """<img style="margin-bottom:2px" class="icon" title="public repository" alt="public" src="/images/icons/lock_open.png"/>""" in response.body
-        
-        # Test response...
+        response = self.app.get(url(controller='summary', action='index', repo_name=HG_REPO))
+
+        #repo type
+        assert """<img style="margin-bottom:2px" class="icon" title="Mercurial repository" alt="Mercurial repository" src="/images/icons/hgicon.png"/>""" in response.body
+        assert """<img style="margin-bottom:2px" class="icon" title="public repository" alt="public repository" src="/images/icons/lock_open.png"/>""" in response.body
+
+        #codes stats
+        assert """var data = {"Python": 42, "Rst": 11, "Bash": 2, "Makefile": 1, "Batch": 1, "Ini": 1, "Css": 1};""" in response.body, 'wrong info about % of codes stats'
+
+        # clone url...
+        assert """<input type="text" id="clone_url" readonly="readonly" value="hg clone http://test_admin@localhost:80/%s" size="70"/>""" % HG_REPO in response.body
+
+
--- a/rhodecode/tests/functional/test_tags.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/tests/functional/test_tags.py	Sat Dec 18 14:45:58 2010 +0100
@@ -4,5 +4,10 @@
 
     def test_index(self):
         self.log_user()
-        response = self.app.get(url(controller='tags', action='index',repo_name='vcs_test'))
+        response = self.app.get(url(controller='tags', action='index', repo_name=HG_REPO))
+        assert """<a href="/%s/changeset/27cd5cce30c96924232dffcd24178a07ffeb5dfc">tip</a>""" % HG_REPO, 'wrong info about tip tag'
+        assert """<a href="/%s/changeset/fd4bdb5e9b2a29b4393a4ac6caef48c17ee1a200">0.1.4</a>""" % HG_REPO, 'wrong info about 0.1.4 tag'
+        assert """<a href="/%s/changeset/17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">0.1.3</a>""" % HG_REPO, 'wrong info about 0.1.3 tag'
+        assert """<a href="/%s/changeset/a7e60bff65d57ac3a1a1ce3b12a70f8a9e8a7720">0.1.2</a>""" % HG_REPO, 'wrong info about 0.1.2 tag'
+        assert """<a href="/%s/changeset/eb3a60fc964309c1a318b8dfe26aa2d1586c85ae">0.1.1</a>""" % HG_REPO, 'wrong info about 0.1.1 tag'
         # Test response...
--- a/rhodecode/tests/functional/test_users.py	Thu Nov 18 21:35:52 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-from rhodecode.tests import *
-
-class TestUsersController(TestController):
-
-    def test_index(self):
-        response = self.app.get(url('users'))
-        # Test response...
-
-    def test_index_as_xml(self):
-        response = self.app.get(url('formatted_users', format='xml'))
-
-    def test_create(self):
-        response = self.app.post(url('users'))
-
-    def test_new(self):
-        response = self.app.get(url('new_user'))
-
-    def test_new_as_xml(self):
-        response = self.app.get(url('formatted_new_user', format='xml'))
-
-    def test_update(self):
-        response = self.app.put(url('user', id=1))
-
-    def test_update_browser_fakeout(self):
-        response = self.app.post(url('user', id=1), params=dict(_method='put'))
-
-    def test_delete(self):
-        response = self.app.delete(url('user', id=1))
-
-    def test_delete_browser_fakeout(self):
-        response = self.app.post(url('user', id=1), params=dict(_method='delete'))
-
-    def test_show(self):
-        response = self.app.get(url('user', id=1))
-
-    def test_show_as_xml(self):
-        response = self.app.get(url('formatted_user', id=1, format='xml'))
-
-    def test_edit(self):
-        response = self.app.get(url('edit_user', id=1))
-
-    def test_edit_as_xml(self):
-        response = self.app.get(url('formatted_edit_user', id=1, format='xml'))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/test_hg_operations.sh	Sat Dec 18 14:45:58 2010 +0100
@@ -0,0 +1,24 @@
+#!/bin/bash
+repo=/tmp/vcs_test_hg_clone
+repo_name=vcs_test_hg
+user=test_admin
+password=test12
+echo 'removing repo '$repo
+rm -rf '$repo'
+hg clone http://$user:$password@127.0.0.1:5000/$repo_name $repo
+cd $repo
+echo 'some' >> $repo/setup.py && hg ci -m 'ci1' && \
+echo 'some' >> $repo/setup.py && hg ci -m 'ci2' && \
+echo 'some' >> $repo/setup.py && hg ci -m 'ci3' && \
+echo 'some' >> $repo/setup.py && hg ci -m 'ci4' && \
+hg push
+
+echo 'new file' >> $repo/new_file.py
+hg add $repo/new_file.py
+
+for i in {1..15}
+do
+   echo "line $i" >> $repo/new_file.py && hg ci -m "autocommit $i"
+done
+
+hg push
\ No newline at end of file
Binary file rhodecode/tests/vcs_test.tar.gz has changed
Binary file rhodecode/tests/vcs_test_hg.tar.gz has changed
--- a/rhodecode/websetup.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/rhodecode/websetup.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,23 +1,51 @@
-"""Setup the rhodecode application"""
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.websetup
+    ~~~~~~~~~~~~~~~~~~
+
+    Weboperations and setup for rhodecode
+    
+    :created_on: Dec 11, 2010
+    :author: marcink
+    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+
+import os
+import logging
+
 from rhodecode.config.environment import load_environment
 from rhodecode.lib.db_manage import DbManage
-import logging
-import os
+
 
 log = logging.getLogger(__name__)
 
 def setup_app(command, conf, vars):
     """Place any commands to setup rhodecode here"""
-    dbname = os.path.split(conf['sqlalchemy.db1.url'])[-1] 
-    dbmanage = DbManage(log_sql=True, dbname=dbname, root=conf['here'],
-                         tests=False)
+    dbconf = conf['sqlalchemy.db1.url']
+    dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'], tests=False)
     dbmanage.create_tables(override=True)
+    dbmanage.set_db_version()
     dbmanage.config_prompt(None)
     dbmanage.create_default_user()
     dbmanage.admin_prompt()
     dbmanage.create_permissions()
     dbmanage.populate_default_permissions()
-           
+
     load_environment(conf.global_conf, conf.local_conf, initial=True)
 
 
--- a/setup.py	Thu Nov 18 21:35:52 2010 +0100
+++ b/setup.py	Sat Dec 18 14:45:58 2010 +0100
@@ -1,27 +1,28 @@
-from rhodecode import get_version
 import sys
 py_version = sys.version_info
 
+from rhodecode import get_version
+
 requirements = [
-        "Pylons>=1.0.0",
+        "Pylons==1.0.0",
         "SQLAlchemy==0.6.5",
-        "Mako>=0.3.2",
-        "vcs==0.1.8",
-        "pygments>=1.3.0",
-        "mercurial==1.6.4",
-        "whoosh==1.2.5",
-        "celery==2.1.3",
+        "Mako==0.3.6",
+        "vcs==0.1.10",
+        "pygments==1.3.1",
+        "mercurial==1.7.2",
+        "whoosh==1.3.4",
+        "celery==2.1.4",
         "py-bcrypt",
         "babel",
     ]
 
-classifiers = ["Development Status :: 5 - Production/Stable",
-                   'Environment :: Web Environment',
-                   'Framework :: Pylons',
-                   'Intended Audience :: Developers',
-                   'License :: OSI Approved :: BSD License',
-                   'Operating System :: OS Independent',
-                   'Programming Language :: Python', ]
+classifiers = ['Development Status :: 5 - Production/Stable',
+               'Environment :: Web Environment',
+               'Framework :: Pylons',
+               'Intended Audience :: Developers',
+               'License :: OSI Approved :: BSD License',
+               'Operating System :: OS Independent',
+               'Programming Language :: Python', ]
 
 if sys.version_info < (2, 6):
     requirements.append("simplejson")
@@ -34,14 +35,19 @@
 #additional files that goes into package itself
 package_data = {'rhodecode': ['i18n/*/LC_MESSAGES/*.mo', ], }
 
-description = 'Mercurial repository serving and browsing app'
+description = ('Mercurial repository browser/management with '
+               'build in push/pull server and full text search')
 #long description
 try:
     readme_file = 'README.rst'
-    long_description = open(readme_file).read()
+    changelog_file = 'docs/changelog.rst'
+    long_description = open(readme_file).read() + '/n/n' + \
+        open(changelog_file).read()
+
 except IOError, err:
     sys.stderr.write("[WARNING] Cannot find file specified as "
-        "long_description (%s)\n skipping that file" % readme_file)
+        "long_description (%s)\n or changelog (%s) skipping that file" \
+            % (readme_file, changelog_file))
     long_description = description
 
 
@@ -59,7 +65,7 @@
     version=get_version(),
     description=description,
     long_description=long_description,
-    keywords='rhodiumcode mercurial web hgwebdir replacement serving hgweb rhodecode',
+    keywords='rhodiumcode mercurial web hgwebdir gitweb git replacement serving hgweb rhodecode',
     license='BSD',
     author='Marcin Kuzminski',
     author_email='marcin@python-works.com',
@@ -84,5 +90,14 @@
 
     [paste.app_install]
     main = pylons.util:PylonsInstaller
+
+    [paste.global_paster_command]
+    make-index = rhodecode.lib.indexers:MakeIndex
+    upgrade-db = rhodecode.lib.dbmigrate:UpgradeDb
+    celeryd=rhodecode.lib.celerypylons.commands:CeleryDaemonCommand
+    celerybeat=rhodecode.lib.celerypylons.commands:CeleryBeatCommand
+    camqadm=rhodecode.lib.celerypylons.commands:CAMQPAdminCommand
+    celeryev=rhodecode.lib.celerypylons.commands:CeleryEventCommand
+              
     """,
 )
--- a/test.ini	Thu Nov 18 21:35:52 2010 +0100
+++ b/test.ini	Sat Dec 18 14:45:58 2010 +0100
@@ -43,6 +43,35 @@
 static_files = true
 lang=en
 cache_dir = %(here)s/data
+index_dir = /tmp/index
+cut_off_limit = 256000
+
+####################################
+###        CELERY CONFIG        ####
+####################################
+use_celery = false
+broker.host = localhost
+broker.vhost = rabbitmqhost
+broker.port = 5672
+broker.user = rabbitmq
+broker.password = qweqwe
+
+celery.imports = rhodecode.lib.celerylib.tasks
+
+celery.result.backend = amqp
+celery.result.dburi = amqp://
+celery.result.serialier = json
+
+#celery.send.task.error.emails = true
+#celery.amqp.task.result.expires = 18000
+
+celeryd.concurrency = 2
+#celeryd.log.file = celeryd.log
+celeryd.log.level = debug
+celeryd.max.tasks.per.child = 3
+
+#tasks will never be sent to the queue, but executed locally instead.
+celery.always.eager = false
 
 ####################################
 ###         BEAKER CACHE        ####