changeset 2776:63e58ef80ef1

Merge beta branch into stable
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 02 Sep 2012 21:19:54 +0200
parents 9d097c2592d3 (current diff) 5d12768a0aa1 (diff)
children 23851216ac1e
files .hgignore CONTRIBUTORS README.rst development.ini docs/api/api.rst docs/changelog.rst docs/contributing.rst docs/index.rst docs/installation.rst docs/setup.rst docs/usage/git_support.rst production.ini requires.txt rhodecode/__init__.py rhodecode/bin/rhodecode_backup.py rhodecode/config/deployment.ini_tmpl rhodecode/config/environment.py rhodecode/config/routing.py rhodecode/controllers/admin/admin.py rhodecode/controllers/admin/ldap_settings.py rhodecode/controllers/admin/permissions.py rhodecode/controllers/admin/repos.py rhodecode/controllers/admin/settings.py rhodecode/controllers/admin/users.py rhodecode/controllers/api/__init__.py rhodecode/controllers/api/api.py rhodecode/controllers/branches.py rhodecode/controllers/changelog.py rhodecode/controllers/changeset.py rhodecode/controllers/feed.py rhodecode/controllers/files.py rhodecode/controllers/home.py rhodecode/controllers/journal.py rhodecode/controllers/login.py rhodecode/controllers/search.py rhodecode/controllers/settings.py rhodecode/controllers/summary.py rhodecode/i18n/rhodecode.pot rhodecode/lib/auth.py rhodecode/lib/auth_ldap.py rhodecode/lib/backup_manager.py rhodecode/lib/base.py rhodecode/lib/celerylib/__init__.py rhodecode/lib/celerylib/tasks.py rhodecode/lib/db_manage.py rhodecode/lib/exceptions.py rhodecode/lib/helpers.py rhodecode/lib/hooks.py rhodecode/lib/indexers/__init__.py rhodecode/lib/indexers/daemon.py rhodecode/lib/middleware/https_fixup.py rhodecode/lib/middleware/simplegit.py rhodecode/lib/middleware/simplehg.py rhodecode/lib/rcmail/smtp_mailer.py rhodecode/lib/utils.py rhodecode/model/__init__.py rhodecode/model/db.py rhodecode/model/forms.py rhodecode/model/permission.py rhodecode/model/repo.py rhodecode/model/repo_permission.py rhodecode/model/scm.py rhodecode/model/user.py rhodecode/public/css/style.css rhodecode/templates/_data_table/_dt_elements.html rhodecode/templates/admin/permissions/permissions.html rhodecode/templates/admin/repos/repos.html rhodecode/templates/admin/settings/settings.html rhodecode/templates/admin/users/user_edit.html rhodecode/templates/admin/users/user_edit_my_account.html rhodecode/templates/base/base.html rhodecode/templates/changelog/changelog.html rhodecode/templates/changeset/changeset.html rhodecode/templates/errors/error_document.html rhodecode/templates/files/files_browser.html rhodecode/templates/files/files_source.html rhodecode/templates/journal/journal.html rhodecode/templates/login.html rhodecode/templates/password_reset.html rhodecode/templates/register.html rhodecode/templates/summary/summary.html rhodecode/tests/__init__.py rhodecode/tests/_test_concurency.py rhodecode/tests/functional/test_changelog.py rhodecode/tests/functional/test_summary.py rhodecode/tests/mem_watch rhodecode/tests/rhodecode_crawler.py rhodecode/tests/test_hg_operations.py rhodecode/tests/test_models.py rhodecode/websetup.py setup.cfg setup.py test.ini
diffstat 284 files changed, 47337 insertions(+), 11585 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sat May 19 14:54:50 2012 +0200
+++ b/.hgignore	Sun Sep 02 21:19:54 2012 +0200
@@ -2,6 +2,7 @@
 *.pyc
 *.swp
 *.sqlite
+*.tox
 *.egg-info
 *.egg
 
@@ -20,3 +21,4 @@
 ^RhodeCode\.egg-info$
 ^rc\.ini$
 ^fabfile.py
+^\.rhodecode$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.travis.yml	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,38 @@
+language: python
+python:
+  - "2.5"
+  - "2.6"
+  - "2.7"
+
+env:  
+  - TEST_DB=sqlite:////tmp/rhodecode_test.sqlite
+  - TEST_DB=mysql://root@127.0.0.1/rhodecode_test
+  - TEST_DB=postgresql://postgres@127.0.0.1/rhodecode_test
+
+# command to install dependencies
+before_script:
+  - mysql -e 'create database rhodecode_test;'
+  - psql -c 'create database rhodecode_test;' -U postgres
+  - git --version
+
+before_install:
+  - sudo apt-get remove git
+  - sudo add-apt-repository ppa:pdoes/ppa -y
+  - sudo apt-get update -y
+  - sudo apt-get install git -y
+
+install:
+  - pip install mysql-python psycopg2 mock unittest2
+  - pip install . --use-mirrors
+
+# command to run tests
+script: nosetests
+
+notifications:
+    email:
+        - marcinkuz@gmail.com
+    irc: "irc.freenode.org#rhodecode"
+
+branches:
+  only:
+    - dev
--- a/CONTRIBUTORS	Sat May 19 14:54:50 2012 +0200
+++ b/CONTRIBUTORS	Sun Sep 02 21:19:54 2012 +0200
@@ -18,4 +18,9 @@
     Aras Pranckevicius <aras@unity3d.com>
     Tony Bussieres <t.bussieres@gmail.com>
     Erwin Kroon <e.kroon@smartmetersolutions.nl>
-    nansenat16 <nansenat16@null.tw>
\ No newline at end of file
+    nansenat16 <nansenat16@null.tw>
+    Vincent Duvert <vincent@duvert.net>
+    Takumi IINO <trot.thunder@gmail.com>
+    Indra Talip <indra.talip@gmail.com>
+    James Rhodes <jrhodes@redpointsoftware.com.au>
+    Dominik Ruf <dominikruf@gmail.com>
\ No newline at end of file
--- a/README.rst	Sat May 19 14:54:50 2012 +0200
+++ b/README.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -72,25 +72,26 @@
   Each request can be logged and authenticated.
 - Runs on threads unlike 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.
+- Full permissions (private/read/write/admin) for each repository, additional
+  explicit forking and repository permissions.
 - Have built in users groups for easier permission management
 - Repository groups let you group repos and manage them easier.
 - Users can fork other users repo. RhodeCode have also compare view to see
   combined changeset for all changeset made within single push.
 - Build in commit-api let's you add, edit and commit files right from RhodeCode
   interface using simple editor or upload form for binaries.
+- Powerfull pull-request driven review system with inline commenting, and
+  changeset statuses, notification system.
+- Importing SVN repositories from remote locations into RhodeCode.
 - Mako templates let's you customize the look and feel of the application.
 - Beautiful diffs, annotations and source code browsing all colored by pygments. 
-  Raw diffs are made in git-diff format, including git_ binary-patches
+  Raw diffs are made in git-diff format, including GIT_ binary-patches
 - Mercurial_ branch graph and yui-flot powered graphs with zooming and statistics
 - 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 is possible to fork a project and modify it freely 
   without breaking the main repository. You can even write Your own hooks 
   and install them
-- code review with notification system, inline commenting, all parsed using
-  rst syntax
 - rst and markdown README support for repositories  
 - Full text search powered by Whoosh on the source files, and file names.
   Build in indexing daemons, with optional incremental index build
@@ -110,8 +111,9 @@
 ----------------
 
 - Finer granular permissions per branch, repo group or subrepo
-- pull requests and web based merges
-- per line file history
+- Pull requests with web based merges
+- Per line file history
+- Simple issue tracker 
 - SSH based authentication with server side key management
 - Commit based built in wiki system
 - More statistics and graph (global annotation + some more statistics)
@@ -131,7 +133,8 @@
 
 .. note::
    
-   Please try to read the documentation before posting any issues
+   Please try to read the documentation before posting any issues, especially
+   the **troubleshooting section**
  
 - Join the `Google group <http://groups.google.com/group/rhodecode>`_ and ask
   any questions.
--- a/development.ini	Sat May 19 14:54:50 2012 +0200
+++ b/development.ini	Sun Sep 02 21:19:54 2012 +0200
@@ -30,22 +30,31 @@
 
 [server:main]
 ##nr of threads to spawn
-threadpool_workers = 5
+#threadpool_workers = 5
 
 ##max request before thread respawn
-threadpool_max_requests = 10
+#threadpool_max_requests = 10
 
 ##option to use threads of process
-use_threadpool = true
+#use_threadpool = true
 
-use = egg:Paste#http
+#use = egg:Paste#http
+use = egg:waitress#main
 host = 0.0.0.0
 port = 5000
 
+[filter:proxy-prefix]
+# prefix middleware for rc
+use = egg:PasteDeploy#prefix
+prefix = /<your-prefix>
+
 [app:main]
 use = egg:rhodecode
+#filter-with = proxy-prefix
 full_stack = true
 static_files = true
+# Optional Languages
+# en, fr, ja, pt_BR, zh_CN, zh_TW
 lang = en
 cache_dir = %(here)s/data
 index_dir = %(here)s/data/index
@@ -54,6 +63,15 @@
 force_https = false
 commit_parse_limit = 25
 use_gravatar = true
+
+## alternative_gravatar_url allows you to use your own avatar server application
+## the following parts of the URL will be replaced
+## {email}        user email
+## {md5email}     md5 hash of the user email (like at gravatar.com)
+## {size}         size of the image that is expected from the server application
+#alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
+#alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
+
 container_auth_enabled = false
 proxypass_auth_enabled = false
 default_encoding = utf8
@@ -78,7 +96,8 @@
 issue_pat = (?:\s*#)(\d+)
 
 ## server url to the issue, each {id} will be replaced with match
-## fetched from the regex and {repo} is replaced with repository name
+## fetched from the regex and {repo} is replaced with full repository name
+## including groups {repo_name} is replaced with just name of repo
 
 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
@@ -165,30 +184,34 @@
 ## The storage uses the Container API 
 ## that is also used by the cache system.
 
-## db session example
-
+## db session ##
 #beaker.session.type = ext:database
 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
 #beaker.session.table_name = db_session 
 
-## encrypted cookie session, good for many instances
+## encrypted cookie client side session, good for many instances ##
 #beaker.session.type = cookie
 
-beaker.session.type = file
+## file based cookies (default) ##
+#beaker.session.type = file
+
+
 beaker.session.key = rhodecode
-# secure cookie requires AES python libraries
+## secure cookie requires AES python libraries ##
 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
 #beaker.session.validate_key = 9712sds2212c--zxc123
-beaker.session.timeout = 36000
+## sets session as invalid if it haven't been accessed for given amount of time
+beaker.session.timeout = 2592000
 beaker.session.httponly = true
+#beaker.session.cookie_path = /<your-prefix>
 
-## uncomment for https secure cookie
+## uncomment for https secure cookie ##
 beaker.session.secure = false
 
-##auto save the session to not to use .save()
+## auto save the session to not to use .save() ##
 beaker.session.auto = False
 
-##true exire at browser close
+## default cookie expiration time in seconds `true` expire at browser close ##
 #beaker.session.cookie_expires = 3600
 
 
--- a/docs/api/api.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/api/api.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -7,7 +7,7 @@
 
 Starting from RhodeCode version 1.2 a simple API was implemented.
 There's a single schema for calling all api methods. API is implemented
-with JSON protocol both ways. An url to send API request in RhodeCode is
+with JSON protocol both ways. An url to send API request to RhodeCode is
 <your_server>/_admin/api
 
 API ACCESS FOR WEB VIEWS
@@ -59,6 +59,47 @@
 calling api *error* key from response will contain failure description
 and result will be null.
 
+
+API CLIENT
+++++++++++
+
+From version 1.4 RhodeCode adds a script that allows to easily
+communicate with API. After installing RhodeCode a `rhodecode-api` script
+will be available.
+
+To get started quickly simply run::
+
+  rhodecode-api _create_config --apikey=<youapikey> --apihost=<rhodecode host>
+ 
+This will create a file named .config in the directory you executed it storing
+json config file with credentials. You can skip this step and always provide
+both of the arguments to be able to communicate with server
+
+
+after that simply run any api command for example get_repo::
+ 
+ rhodecode-api get_repo
+
+ calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
+ rhodecode said:
+ {'error': 'Missing non optional `repoid` arg in JSON DATA',
+  'id': 75,
+  'result': None}
+
+Ups looks like we forgot to add an argument
+
+Let's try again now giving the repoid as parameters::
+
+    rhodecode-api get_repo repoid:rhodecode   
+ 
+    calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "rhodecode"}, "method": "get_repo"} to http://127.0.0.1:5000
+    rhodecode said:
+    {'error': None,
+     'id': 39,
+     'result': <json data...>}
+
+
+
 API METHODS
 +++++++++++
 
@@ -76,12 +117,64 @@
     api_key : "<api_key>"
     method :  "pull"
     args :    {
-                "repo_name" : "<reponame>"
+                "repoid" : "<reponame or repo_id>"
+              }
+
+OUTPUT::
+
+    id : <id_given_in_input>
+    result : "Pulled from `<reponame>`"
+    error :  null
+
+
+rescan_repos
+------------
+
+Dispatch rescan repositories action. If remove_obsolete is set
+RhodeCode will delete repos that are in database but not in the filesystem.
+This command can be executed only using api_key belonging to user with admin 
+rights.
+
+INPUT::
+
+    id : <id_for_response>
+    api_key : "<api_key>"
+    method :  "rescan_repos"
+    args :    {
+                "remove_obsolete" : "<boolean = Optional(False)>"
               }
 
 OUTPUT::
 
-    result : "Pulled from <reponame>"
+    id : <id_given_in_input>
+    result : "{'added': [<list of names of added repos>], 
+               'removed': [<list of names of removed repos>]}"
+    error :  null
+
+
+lock
+----
+
+Set locking state on given repository by given user.
+This command can be executed only using api_key belonging to user with admin 
+rights.
+
+INPUT::
+
+    id : <id_for_response>
+    api_key : "<api_key>"
+    method :  "lock"
+    args :    {
+                "repoid" : "<reponame or repo_id>"
+                "userid" : "<user_id or username>",
+                "locked" : "<bool true|false>"
+                
+              }
+
+OUTPUT::
+
+    id : <id_given_in_input>
+    result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
     error :  null
 
 
@@ -104,13 +197,15 @@
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: None if user does not exist or 
             {
-                "id" :       "<id>",
+                "user_id" :  "<user_id>",
                 "username" : "<username>",
                 "firstname": "<firstname>",
                 "lastname" : "<lastname>",
                 "email" :    "<email>",
+                "emails":    "<list_of_all_additional_emails>",
                 "active" :   "<bool>",
                 "admin" :    "<bool>",
                 "ldap_dn" :  "<ldap_dn>",
@@ -143,13 +238,15 @@
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: [
               {
-                "id" :       "<id>",
+                "user_id" :  "<user_id>",
                 "username" : "<username>",
                 "firstname": "<firstname>",
                 "lastname" : "<lastname>",
                 "email" :    "<email>",
+                "emails":    "<list_of_all_additional_emails>",
                 "active" :   "<bool>",
                 "admin" :    "<bool>",
                 "ldap_dn" :  "<ldap_dn>",
@@ -174,20 +271,32 @@
     method :  "create_user"
     args :    {
                 "username" :  "<username>",
+                "email" :     "<useremail>",
                 "password" :  "<password>",
-                "email" :     "<useremail>",
-                "firstname" : "<firstname> = None",
-                "lastname" :  "<lastname> = None",
-                "active" :    "<bool> = True",
-                "admin" :     "<bool> = False",
-                "ldap_dn" :   "<ldap_dn> = None"
+                "firstname" : "<firstname> = Optional(None)",
+                "lastname" :  "<lastname> = Optional(None)",
+                "active" :    "<bool> = Optional(True)",
+                "admin" :     "<bool> = Optional(False)",
+                "ldap_dn" :   "<ldap_dn> = Optional(None)"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "id" : "<new_user_id>",
-              "msg" : "created new user <username>"
+              "msg" : "created new user `<username>`",
+              "user": {
+                "user_id" :  "<user_id>",
+                "username" : "<username>",
+                "firstname": "<firstname>",
+                "lastname" : "<lastname>",
+                "email" :    "<email>",
+                "emails":    "<list_of_all_additional_emails>",
+                "active" :   "<bool>",
+                "admin" :    "<bool>",
+                "ldap_dn" :  "<ldap_dn>",
+                "last_login": "<last_login>",
+              },
             }
     error:  null
 
@@ -195,7 +304,7 @@
 update_user
 -----------
 
-updates current one if such user exists. This command can 
+updates given user if such user exists. This command can 
 be executed only using api_key belonging to user with admin rights.
 
 
@@ -206,21 +315,60 @@
     method :  "update_user"
     args :    {
                 "userid" : "<user_id or username>",
-                "username" :  "<username>",
-                "password" :  "<password>",
-                "email" :     "<useremail>",
-                "firstname" : "<firstname>",
-                "lastname" :  "<lastname>",
-                "active" :    "<bool>",
-                "admin" :     "<bool>",
-                "ldap_dn" :   "<ldap_dn>"
+                "username" :  "<username> = Optional",
+                "email" :     "<useremail> = Optional",
+                "password" :  "<password> = Optional",
+                "firstname" : "<firstname> = Optional",
+                "lastname" :  "<lastname> = Optional",
+                "active" :    "<bool> = Optional",
+                "admin" :     "<bool> = Optional",
+                "ldap_dn" :   "<ldap_dn> = Optional"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "id" : "<edited_user_id>",
-              "msg" : "updated user <username>"
+              "msg" : "updated user ID:<userid> <username>",
+              "user": {
+                "user_id" :  "<user_id>",
+                "username" : "<username>",
+                "firstname": "<firstname>",
+                "lastname" : "<lastname>",
+                "email" :    "<email>",
+                "emails":    "<list_of_all_additional_emails>",
+                "active" :   "<bool>",
+                "admin" :    "<bool>",
+                "ldap_dn" :  "<ldap_dn>",
+                "last_login": "<last_login>",
+              },              
+            }
+    error:  null
+
+
+delete_user
+-----------
+
+
+deletes givenuser if such user exists. This command can 
+be executed only using api_key belonging to user with admin rights.
+
+
+INPUT::
+
+    id : <id_for_response>
+    api_key : "<api_key>"
+    method :  "delete_user"
+    args :    {
+                "userid" : "<user_id or username>",
+              }
+
+OUTPUT::
+
+    id : <id_given_in_input>
+    result: {
+              "msg" : "deleted user ID:<userid> <username>",
+              "user": null
             }
     error:  null
 
@@ -238,25 +386,29 @@
     api_key : "<api_key>"
     method :  "get_users_group"
     args :    {
-                "group_name" : "<name>"
+                "usersgroupid" : "<users group id or name>"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result : None if group not exist
              {
-               "id" :         "<id>",
-               "group_name" : "<groupname>",
-               "active":      "<bool>",
+               "users_group_id" : "<id>",
+               "group_name" :     "<groupname>",
+               "active":          "<bool>",
                "members" :  [
-                              { "id" :       "<userid>",
+                              { 
+                                "user_id" :  "<user_id>",
                                 "username" : "<username>",
                                 "firstname": "<firstname>",
                                 "lastname" : "<lastname>",
                                 "email" :    "<email>",
+                                "emails":    "<list_of_all_additional_emails>",
                                 "active" :   "<bool>",
                                 "admin" :    "<bool>",
-                                "ldap" :     "<ldap_dn>"
+                                "ldap_dn" :  "<ldap_dn>",
+                                "last_login": "<last_login>",
                               },

                             ]
@@ -280,25 +432,29 @@
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result : [
                {
-                 "id" :         "<id>",
-                 "group_name" : "<groupname>",
-                 "active":      "<bool>",
-                 "members" :  [
-	    	                    {
-	    	                      "id" :       "<userid>",
-	                              "username" : "<username>",
-	                              "firstname": "<firstname>",
-	                              "lastname" : "<lastname>",
-	                              "email" :    "<email>",
-	                              "active" :   "<bool>",
-	                              "admin" :    "<bool>",
-	                              "ldap" :     "<ldap_dn>"
-	                            },
-	    	                    …
-	                          ]
-	            }
+               "users_group_id" : "<id>",
+               "group_name" :     "<groupname>",
+               "active":          "<bool>",
+               "members" :  [
+                              { 
+                                "user_id" :  "<user_id>",
+                                "username" : "<username>",
+                                "firstname": "<firstname>",
+                                "lastname" : "<lastname>",
+                                "email" :    "<email>",
+                                "emails":    "<list_of_all_additional_emails>",
+                                "active" :   "<bool>",
+                                "admin" :    "<bool>",
+                                "ldap_dn" :  "<ldap_dn>",
+                                "last_login": "<last_login>",
+                              },
+                              …
+                            ]
+               },
+               …
               ]
     error : null
 
@@ -317,14 +473,34 @@
     method :  "create_users_group"
     args:     {
                 "group_name":  "<groupname>",
-                "active":"<bool> = True"
+                "active":"<bool> = Optional(True)"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "id":  "<newusersgroupid>",
-              "msg": "created new users group <groupname>"
+              "msg": "created new users group `<groupname>`",
+              "users_group": {
+                     "users_group_id" : "<id>",
+                     "group_name" :     "<groupname>",
+                     "active":          "<bool>",
+                     "members" :  [
+                                  { 
+                                    "user_id" :  "<user_id>",
+                                    "username" : "<username>",
+                                    "firstname": "<firstname>",
+                                    "lastname" : "<lastname>",
+                                    "email" :    "<email>",
+                                    "emails":    "<list_of_all_additional_emails>",
+                                    "active" :   "<bool>",
+                                    "admin" :    "<bool>",
+                                    "ldap_dn" :  "<ldap_dn>",
+                                    "last_login": "<last_login>",
+                                  },
+                                  …
+                     ]
+               },
             }
     error:  null
 
@@ -343,16 +519,16 @@
     api_key : "<api_key>"
     method :  "add_user_users_group"
     args:     {
-                "group_name" :  "<groupname>",
-                "username" :   "<username>"
+                "usersgroupid" : "<users group id or name>",
+                "userid" : "<user_id or username>",
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "id":  "<newusersgroupmemberid>",
               "success": True|False # depends on if member is in group
-              "msg": "added member <username> to users group <groupname> | 
+              "msg": "added member `<username>` to users group `<groupname>` | 
                       User is already in that group"
             }
     error:  null
@@ -372,12 +548,13 @@
     api_key : "<api_key>"
     method :  "remove_user_from_users_group"
     args:     {
-                "group_name" :  "<groupname>",
-                "username" :   "<username>"
+                "usersgroupid" : "<users group id or name>",
+                "userid" : "<user_id or username>",
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
               "success":  True|False,  # depends on if member is in group
               "msg": "removed member <username> from users group <groupname> | 
@@ -405,23 +582,32 @@
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: None if repository does not exist or
             {
-                "id" :          "<id>",
+                "repo_id" :     "<repo_id>",
                 "repo_name" :   "<reponame>"
-                "type" :        "<type>",
+                "repo_type" :   "<repo_type>",
+                "clone_uri" :   "<clone_uri>",
+                "private": :    "<bool>",
+                "created_on" :  "<datetimecreated>",                
                 "description" : "<description>",
+                "landing_rev":  "<landing_rev>",
+                "owner":        "<repo_owner>",
+                "fork_of":  "<name_of_fork_parent>",
                 "members" :     [
                                   { 
                                     "type": "user",
-                                    "id" :         "<userid>",
-                                    "username" :   "<username>",
-                                    "firstname":   "<firstname>",
-                                    "lastname" :   "<lastname>",
-                                    "email" :      "<email>",
-                                    "active" :     "<bool>",
-                                    "admin" :      "<bool>",
-                                    "ldap" :       "<ldap_dn>",
+                                    "user_id" :  "<user_id>",
+                                    "username" : "<username>",
+                                    "firstname": "<firstname>",
+                                    "lastname" : "<lastname>",
+                                    "email" :    "<email>",
+                                    "emails":    "<list_of_all_additional_emails>",
+                                    "active" :   "<bool>",
+                                    "admin" :    "<bool>",
+                                    "ldap_dn" :  "<ldap_dn>",
+                                    "last_login": "<last_login>",
                                     "permission" : "repository.(read|write|admin)"
                                   },

@@ -454,12 +640,19 @@
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: [
               {
-                "id" :          "<id>",
+                "repo_id" :     "<repo_id>",
                 "repo_name" :   "<reponame>"
-                "type" :        "<type>",
-                "description" : "<description>"
+                "repo_type" :   "<repo_type>",
+                "clone_uri" :   "<clone_uri>",
+                "private": :    "<bool>",
+                "created_on" :  "<datetimecreated>",                
+                "description" : "<description>",
+                "landing_rev":  "<landing_rev>",
+                "owner":        "<repo_owner>",
+                "fork_of":  "<name_of_fork_parent>",
               },

             ]
@@ -481,14 +674,15 @@
     api_key : "<api_key>"
     method :  "get_repo_nodes"
     args:     {
-                "repo_name" : "<reponame>",
+                "repoid" : "<reponame or repo_id>"
                 "revision"  : "<revision>",
                 "root_path" : "<root_path>",
-                "ret_type"  : "<ret_type>" = 'all'
+                "ret_type"  : "<ret_type> = Optional('all')"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: [
               {
                 "name" :        "<name>"
@@ -516,18 +710,31 @@
     method :  "create_repo"
     args:     {
                 "repo_name" :   "<reponame>",
-                "owner_name" :  "<ownername>",
-                "description" : "<description> = ''",
-                "repo_type" :   "<type> = 'hg'",
-                "private" :     "<bool> = False",
-                "clone_uri" :   "<clone_uri> = None",
+                "owner" :       "<onwer_name_or_id>",
+                "repo_type" :   "<repo_type>",
+                "description" : "<description> = Optional('')",
+                "private" :     "<bool> = Optional(False)",
+                "clone_uri" :   "<clone_uri> = Optional(None)",
+                "landing_rev" : "<landing_rev> = Optional('tip')",
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "id": "<newrepoid>",
-              "msg": "Created new repository <reponame>",
+              "msg": "Created new repository `<reponame>`",
+              "repo": {
+                "repo_id" :     "<repo_id>",
+                "repo_name" :   "<reponame>"
+                "repo_type" :   "<repo_type>",
+                "clone_uri" :   "<clone_uri>",
+                "private": :    "<bool>",
+                "created_on" :  "<datetimecreated>",                
+                "description" : "<description>",
+                "landing_rev":  "<landing_rev>",
+                "owner":        "<repo_owner>",
+                "fork_of":  "<name_of_fork_parent>",
+              },
             }
     error:  null
 
@@ -545,13 +752,15 @@
     api_key : "<api_key>"
     method :  "delete_repo"
     args:     {
-                "repo_name" :   "<reponame>",
+                "repoid" : "<reponame or repo_id>"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "msg": "Deleted repository <reponame>",
+              "msg": "Deleted repository `<reponame>`",
+              "success": true
             }
     error:  null
 
@@ -570,15 +779,17 @@
     api_key : "<api_key>"
     method :  "grant_user_permission"
     args:     {
-                "repo_name" :  "<reponame>",
-                "username" :   "<username>",
+                "repoid" : "<reponame or repo_id>"
+                "userid" : "<username or user_id>"
                 "perm" :       "(repository.(none|read|write|admin))",
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "msg" : "Granted perm: <perm> for user: <username> in repo: <reponame>"
+              "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
+              "success": true
             }
     error:  null
 
@@ -596,14 +807,16 @@
     api_key : "<api_key>"
     method  : "revoke_user_permission"
     args:     {
-                "repo_name" :  "<reponame>",
-                "username" :   "<username>",
+                "repoid" : "<reponame or repo_id>"
+                "userid" : "<username or user_id>"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "msg" : "Revoked perm for user: <suername> in repo: <reponame>"
+              "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
+              "success": true
             }
     error:  null
 
@@ -622,15 +835,17 @@
     api_key : "<api_key>"
     method :  "grant_users_group_permission"
     args:     {
-                "repo_name" : "<reponame>",
-                "group_name" : "<usersgroupname>",
+                "repoid" : "<reponame or repo_id>"
+                "usersgroupid" : "<users group id or name>"
                 "perm" : "(repository.(none|read|write|admin))",
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "msg" : "Granted perm: <perm> for group: <usersgroupname> in repo: <reponame>"
+              "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
+              "success": true
             }
     error:  null
     
@@ -647,13 +862,15 @@
     api_key : "<api_key>"
     method  : "revoke_users_group_permission"
     args:     {
-                "repo_name" :  "<reponame>",
-                "users_group" :   "<usersgroupname>",
+                "repoid" : "<reponame or repo_id>"
+                "usersgroupid" : "<users group id or name>"
               }
 
 OUTPUT::
 
+    id : <id_given_in_input>
     result: {
-              "msg" : "Revoked perm for group: <usersgroupname> in repo: <reponame>"
+              "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
+              "success": true
             }
     error:  null
\ No newline at end of file
--- a/docs/changelog.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/changelog.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -4,6 +4,66 @@
 Changelog
 =========
 
+1.4.0 (**2012-09-03**)
+----------------------
+
+news
+++++
+ 
+- new codereview system
+- email map, allowing users to have multiple email addresses mapped into
+  their accounts
+- improved git-hook system. Now all actions for git are logged into journal
+  including pushed revisions, user and IP address
+- changed setup-app into setup-rhodecode and added default options to it.
+- new git repos are created as bare now by default
+- #464 added links to groups in permission box
+- #465 mentions autocomplete inside comments boxes
+- #469 added --update-only option to whoosh to re-index only given list
+  of repos in index 
+- rhodecode-api CLI client
+- new git http protocol replaced buggy dulwich implementation.
+  Now based on pygrack & gitweb
+- Improved RSS/ATOM feeds. Discoverable by browsers using proper headers, and 
+  reformated based on user suggestions. Additional rss/atom feeds for user
+  journal
+- various i18n improvements
+- #478 permissions overview for admin in user edit view
+- File view now displays small gravatars off all authors of given file
+- Implemented landing revisions. Each repository will get landing_rev attribute
+  that defines 'default' revision/branch for generating readme files
+- Implemented #509, RhodeCode enforces SSL for push/pulling if requested at 
+  earliest possible call.
+- Import remote svn repositories to mercurial using hgsubversion.
+- Fixed #508 RhodeCode now has a option to explicitly set forking permissions
+- RhodeCode can use alternative server for generating avatar icons
+- implemented repositories locking. Pull locks, push unlocks. Also can be done
+  via API calls
+- #538 form for permissions can handle multiple users at once 
+
+fixes
++++++
+
+- improved translations
+- fixes issue #455 Creating an archive generates an exception on Windows
+- fixes #448 Download ZIP archive keeps file in /tmp open and results 
+  in out of disk space
+- fixes issue #454 Search results under Windows include proceeding
+  backslash
+- fixed issue #450. Rhodecode no longer will crash when bad revision is
+  present in journal data.
+- fix for issue #417, git execution was broken on windows for certain
+  commands.
+- fixed #413. Don't disable .git directory for bare repos on deleting
+- fixed issue #459. Changed the way of obtaining logger in reindex task.
+- fixed #453 added ID field in whoosh SCHEMA that solves the issue of
+  reindexing modified files
+- fixed #481 rhodecode emails are sent without Date header 
+- fixed #458 wrong count when no repos are present
+- fixed issue #492 missing `\ No newline at end of file` test at the end of 
+  new chunk in html diff
+- full text search now works also for commit messages
+
 1.3.6 (**2012-05-17**)
 ----------------------
 
--- a/docs/conf.py	Sat May 19 14:54:50 2012 +0200
+++ b/docs/conf.py	Sun Sep 02 21:19:54 2012 +0200
@@ -54,8 +54,8 @@
 # The short X.Y version.
 root = os.path.dirname(os.path.dirname(__file__))
 sys.path.append(root)
-from rhodecode import get_version, __version__
-version = get_version()
+from rhodecode import __version__
+version = __version__
 # The full version, including alpha/beta/rc tags.
 release = __version__
 
--- a/docs/contributing.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/contributing.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -27,7 +27,8 @@
 
 
 After finishing your changes make sure all tests passes ok. You can run
-the testsuite running nosetest from the project root.
+the testsuite running ``nosetest`` from the project root, or if you use tox
+run tox for python2.5-2.7 with multiple database test.
 
 | Thank you for any contributions!
 |  Marcin
--- a/docs/index.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/index.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -21,9 +21,12 @@
 
    usage/general
    usage/git_support
+   usage/performance
+   usage/locking
    usage/statistics
    usage/backup
    usage/debugging
+   usage/troubleshooting
 
 **Develop**
 
--- a/docs/installation.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/installation.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -25,13 +25,18 @@
     pip install rhodecode
 
 If you prefer to install RhodeCode manually simply grab latest release from
-http://pypi.python.org/pypi/rhodecode, decompress the archive and run::
+http://pypi.python.org/pypi/RhodeCode, decompress the archive and run::
 
     python setup.py install
 
+Step by step installation example for Windows
+---------------------------------------------
 
-Step by step installation example
----------------------------------
+:ref:`installation_win`
+
+
+Step by step installation example for Linux
+-------------------------------------------
 
 
 For installing RhodeCode i highly recommend using separate virtualenv_. This
@@ -41,7 +46,7 @@
 - Assuming you have installed virtualenv_ create a new virtual environment 
   using virtualenv command:: 
 
-    virtualenv --no-site-packages /var/www/rhodecode-venv
+    virtualenv --no-site-packages /opt/rhodecode-venv
 
 
 .. note:: Using ``--no-site-packages`` when generating your
@@ -54,10 +59,10 @@
    Python's "main" site-packages dir.
 
 
-- this will install new virtualenv_ into `/var/www/rhodecode-venv`. 
+- this will install new virtualenv_ into `/opt/rhodecode-venv`. 
 - Activate the virtualenv_ by running::
 
-    source /var/www/rhodecode-venv/bin/activate
+    source /opt/rhodecode-venv/bin/activate
 
 .. note:: If you're using UNIX, *do not* use ``sudo`` to run the
    ``virtualenv`` script.  It's perfectly acceptable (and desirable)
@@ -66,7 +71,7 @@
 - Make a folder for rhodecode data files, and configuration somewhere on the 
   filesystem. For example::
 
-    mkdir /var/www/rhodecode
+    mkdir /opt/rhodecode
   
     
 - Go into the created directory run this command to install rhodecode::
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/installation_win.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,244 @@
+.. _installation_win:
+
+
+Step by step Installation for Windows
+=====================================
+
+
+RhodeCode step-by-step install Guide for Windows  
+
+Target OS: Windows XP SP3 English (Clean installation) 
++ All Windows Updates until 24-may-2012 
+
+Step1 - Install Visual Studio 2008 Express
+------------------------------------------
+
+ 
+Optional: You can also install MingW, but VS2008 installation is easier 
+
+Download "Visual C++ 2008 Express Edition with SP1" from: 
+http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express 
+(if not found or relocated, google for "visual studio 2008 express" for 
+updated link) 
+
+You can also download full ISO file for offline installation, just 
+choose "All - Offline Install ISO image file" in the previous page and 
+choose "Visual C++ 2008 Express" when installing. 
+
+
+.. note::
+
+  Silverlight Runtime and SQL Server 2008 Express Edition are not 
+  required, you can uncheck them 
+
+
+Step2 - Install Python
+----------------------
+
+Install Python 2.x.y (x >= 5) x86 version (32bit). DO NOT USE A 3.x version.
+Download Python 2.x.y from: 
+http://www.python.org/download/ 
+
+Choose "Windows Installer" (32bit version) not "Windows X86-64 
+Installer". While writing this guide, the latest version was v2.7.3. 
+Remember the specific major and minor version installed, because it will 
+be needed in the next step. In this case, it is "2.7". 
+
+
+Step3 - Install Win32py extensions
+----------------------------------
+ 
+Download pywin32 from: 
+http://sourceforge.net/projects/pywin32/files/ 
+
+- Click on "pywin32" folder 
+- Click on the first folder (in this case, Build 217, maybe newer when you try) 
+- Choose the file ending with ".win32-py2.x.exe" -> x being the minor 
+  version of Python you installed (in this case, 7) 
+  When writing this guide, the file was: 
+  http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download 
+
+
+Step4 - Python BIN
+------------------
+
+Add Python BIN folder to the path 
+
+You have to add the Python folder to the path, you can do it manually 
+(editing "PATH" environment variable) or using Windows Support Tools 
+that came preinstalled in Vista/7 and can be installed in Windows XP. 
+
+- Using support tools on WINDOWS XP: 
+  If you use Windows XP you can install them using Windows XP CD and 
+  navigating to \SUPPORT\TOOLS. There, execute Setup.EXE (not MSI). 
+  Afterwards, open a CMD and type::
+ 
+    SETX PATH "%PATH%;[your-python-path]" -M 
+
+  Close CMD (the path variable will be updated then) 
+
+- Using support tools on WINDOWS Vista/7: 
+
+  Open a CMD and type::
+
+    SETX PATH "%PATH%;[your-python-path]" /M 
+
+  Please substitute [your-python-path] with your Python installation path. 
+  Typically: C:\\Python27 
+
+
+Step5 - RhodeCode folder structure
+----------------------------------
+
+Create a RhodeCode folder structure 
+
+This is only a example to install RhodeCode, you can of course change 
+it. However, this guide will follow the proposed structure, so please 
+later adapt the paths if you change them. My recommendation is to use 
+folders with NO SPACES. But you can try if you are brave... 
+
+Create the following folder structure::
+
+  C:\RhodeCode 
+  C:\RhodeCode\Bin 
+  C:\RhodeCode\Env 
+  C:\RhodeCode\Repos 
+
+
+Step6 - Install virtualenv
+---------------------------
+
+Install Virtual Env for Python 
+
+Navigate to: http://www.virtualenv.org/en/latest/index.html#installation 
+Right click on "virtualenv.py" file and choose "Save link as...". 
+Download to C:\\RhodeCode (or whatever you want) 
+(the file is located at 
+https://raw.github.com/pypa/virtualenv/master/virtualenv.py) 
+
+Create a virtual Python environment in C:\\RhodeCode\\Env (or similar). To 
+do so, open a CMD (Python Path should be included in Step3), navigate 
+where you downloaded "virtualenv.py", and write:: 
+
+ python virtualenv.py C:\RhodeCode\Env 
+
+(--no-site-packages is now the default behaviour of virtualenv, no need 
+to include it) 
+
+
+Step7 - Install RhodeCode
+-------------------------
+
+Finally, install RhodeCode 
+
+Close previously opened command prompt/s, and open a Visual Studio 2008 
+Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open 
+"Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" -> 
+"Visual Studio 2008 Command Prompt" 
+
+In that CMD (loaded with VS2008 PATHs) type::
+ 
+  cd C:\RhodeCode\Env\Scripts (or similar) 
+  activate 
+
+The prompt will change into "(Env) C:\\RhodeCode\\Env\\Scripts" or similar 
+(depending of your folder structure). Then type:: 
+
+ pip install rhodecode 
+
+(long step, please wait until fully complete) 
+
+Some warnings will appear, don't worry as they are normal.
+
+
+Step8 - Configuring RhodeCode
+-----------------------------
+
+
+steps taken from http://packages.python.org/RhodeCode/setup.html 
+
+You have to use the same Visual Studio 2008 command prompt as Step7, so 
+if you closed it reopen it following the same commands (including the 
+"activate" one). When ready, just type::
+ 
+  cd C:\RhodeCode\Bin 
+  paster make-config RhodeCode production.ini 
+
+Then, you must edit production.ini to fit your needs (ip address, ip 
+port, mail settings, database, whatever). I recommend using NotePad++ 
+(free) or similar text editor, as it handles well the EndOfLine 
+character differences between Unix and Windows 
+(http://notepad-plus-plus.org/) 
+
+For the sake of simplicity lets run it with the default settings. After 
+your edits (if any), in the previous Command Prompt, type:: 
+ 
+ paster setup-rhodecode production.ini 
+
+(this time a NEW database will be installed, you must follow a different 
+step to later UPGRADE to a newer RhodeCode version) 
+
+The script will ask you for confirmation about creating a NEW database, 
+answer yes (y) 
+The script will ask you for repository path, answer C:\\RhodeCode\\Repos 
+(or similar) 
+The script will ask you for admin username and password, answer "admin" 
++ "123456" (or whatever you want) 
+The script will ask you for admin mail, answer "admin@xxxx.com" (or 
+whatever you want) 
+
+If you make some mistake and the script does not end, don't worry, start 
+it again. 
+
+
+Step9 - Running RhodeCode
+-------------------------
+
+
+In the previous command prompt, being in the C:\\RhodeCode\\Bin folder, 
+just type::
+ 
+ paster serve production.ini 
+
+Open yout web server, and go to http://127.0.0.1:5000 
+
+It works!! :-) 
+
+Remark: 
+If it does not work first time, just Ctrl-C the CMD process and start it 
+again. Don't forget the "http://" in Internet Explorer 
+
+
+
+What this Guide does not cover:
+
+- Installing Celery 
+- Running RhodeCode as Windows Service. You can investigate here:
+ 
+  - http://pypi.python.org/pypi/wsgisvc 
+  - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/     
+  - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service 
+
+- Using Apache. You can investigate here:
+
+  - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4 
+
+
+Upgrading
+=========
+ 
+Stop running RhodeCode 
+Open a CommandPrompt like in Step7 (VS2008 path + activate) and type::
+ 
+ easy_install -U rhodecode 
+ cd \RhodeCode\Bin 
+
+{ backup your production.ini file now} :: 
+
+ paster make-config RhodeCode production.ini 
+
+(check changes and update your production.ini accordingly) ::
+ 
+ paster upgrade-db production.ini (update database)
+
+Full steps in http://packages.python.org/RhodeCode/upgrade.html 
\ No newline at end of file
--- a/docs/setup.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/setup.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -34,6 +34,11 @@
 and password for the initial admin account which ``setup-rhodecode`` sets 
 up for you.
 
+setup process can be fully automated, example for lazy::
+
+    paster setup-rhodecode production.ini --user=marcink --password=secret --email=marcin@rhodecode.org --repos=/home/marcink/my_repos
+    
+
 - The ``setup-rhodecode`` command will create all of the needed tables and an 
   admin account. When choosing a root path you can either use a new empty 
   location, or a location which already contains existing repositories. If you
@@ -527,6 +532,18 @@
        access_log      /var/log/nginx/rhodecode.access.log;
        error_log       /var/log/nginx/rhodecode.error.log;
 
+       # uncomment if you have nginx with chunking module compiled
+       # fixes the issues of having to put postBuffer data for large git
+       # pushes       
+       #chunkin on;
+       #error_page 411 = @my_411_error;
+       #location @my_411_error {
+       #    chunkin_resume;
+       #}
+       
+       # uncomment if you want to serve static files by nginx
+       #root /path/to/installation/rhodecode/public;
+       
        location / {
             try_files $uri @rhode;
        }
@@ -682,43 +699,9 @@
 Other configuration files
 -------------------------
 
-Some example init.d scripts can be found here, for debian and gentoo:
-
-https://rhodecode.org/rhodecode/files/tip/init.d
-
-
-Troubleshooting
----------------
-
-:Q: **Missing static files?**
-:A: 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
-   
-| 
-
-:Q: **Can't install celery/rabbitmq**
-:A: Don't worry RhodeCode works without them too. No extra setup is required.
+Some example init.d scripts can be found in init.d directory::
 
-|
- 
-:Q: **Long lasting push timeouts?**
-:A: Make sure you set a longer timeouts in your proxy/fcgi settings, timeouts
-    are caused by https server and not RhodeCode.
-    
-| 
-
-:Q: **Large pushes timeouts?**
-:A: Make sure you set a proper max_body_size for the http server.
-
-|
-
-:Q: **Apache doesn't pass basicAuth on pull/push?**
-:A: Make sure you added `WSGIPassAuthorization true`.
-
-For further questions search the `Issues tracker`_, or post a message in the 
-`google group rhodecode`_
+  https://secure.rhodecode.org/rhodecode/files/beta/init.d
 
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
 .. _python: http://www.python.org/
@@ -729,4 +712,4 @@
 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
 .. _PublishingRepositories: http://mercurial.selenic.com/wiki/PublishingRepositories
 .. _Issues tracker: https://bitbucket.org/marcinkuzminski/rhodecode/issues
-.. _google group rhodecode: http://groups.google.com/group/rhodecode
+.. _google group rhodecode: http://groups.google.com/group/rhodecode
\ No newline at end of file
--- a/docs/usage/general.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/usage/general.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -62,7 +62,6 @@
 for changelogs, files and other can be exchanged with _<ID> syntax.
 
 
-
 Mailing
 -------
 
@@ -82,4 +81,27 @@
 Trending source files are calculated based on pre defined dict of known
 types and extensions. If You miss some extension or Would like to scan some
 custom files it's possible to add new types in `LANGUAGES_EXTENSIONS_MAP` dict
-located in `/rhodecode/lib/celerylib/tasks.py`
\ No newline at end of file
+located in `/rhodecode/lib/celerylib/tasks.py`
+
+
+Cloning remote repositories
+---------------------------
+
+RhodeCode has an ability to clone remote repos from given remote locations.
+Currently it support following options:
+
+- hg  -> hg clone
+- svn -> hg clone
+- git -> git clone
+
+
+.. note::
+    
+    - *`svn -> hg` cloning requires `hgsubversion` library to be installed.*
+
+If you need to clone repositories that are protected via basic auth, you
+might pass the url with stored credentials inside eg. 
+`http://user:passw@remote.server/repo, RhodeCode will try to login and clone
+using given credentials. Please take a note that they will be stored as
+plaintext inside the database. RhodeCode will remove auth info when showing the 
+clone url in summary page.
--- a/docs/usage/git_support.rst	Sat May 19 14:54:50 2012 +0200
+++ b/docs/usage/git_support.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -5,11 +5,13 @@
 ===========
 
 
-Git support in RhodeCode 1.3 was enabled by default. 
+Git support in RhodeCode 1.3 was enabled by default. You need to have a git
+client installed on the machine to make git fully work.
+
 Although There are some limitations on git usage.
 
-- No hooks are runned for git push/pull actions.
-- logs in action journals don't have git operations
+- hooks that are executed on pull/push are not *real* hooks, they are 
+  just emulating the behavior, and are executed **BEFORE** action takes place.
 - large pushes needs http server with chunked encoding support.
  
 if you plan to use git you need to run RhodeCode with some
@@ -17,14 +19,19 @@
 i recommend using waitress_ or gunicorn_ (linux only) for `paste` wsgi app 
 replacement.
 
-To use waitress simply change change the following in the .ini file::
+To use, simply change change the following in the .ini file::
 
     use = egg:Paste#http
 
-To::
+to::
     
     use = egg:waitress#main
 
+or::
+
+    use = egg:gunicorn#main
+    
+    
 And comment out bellow options::
 
     threadpool_workers = 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/usage/locking.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,41 @@
+.. _locking:
+
+===================================
+RhodeCode repository locking system
+===================================
+
+
+| Repos with **locking function=disabled** is the default, that's how repos work 
+  today.
+| Repos with **locking function=enabled** behaves like follows:
+
+Repos have a state called `locked` that can be true or false.
+The hg/git commands `hg/git clone`, `hg/git pull`, and `hg/git push` 
+influence this state:
+
+- The command `hg/git pull <repo>` will lock that repo (locked=true) 
+  if the user has write/admin permissions on this repo
+
+- The command `hg/git clone <repo>` will lock that repo (locked=true) if the 
+  user has write/admin permissions on this repo
+
+
+RhodeCode will remember the user id who locked the repo
+only this specific user can unlock the repo (locked=false) by calling 
+
+- `hg/git push <repo>` 
+
+every other command on that repo from this user and 
+every command from any other user will result in http return code 423 (locked)
+
+
+additionally the http error includes the <user> that locked the repo 
+(e.g. “repository <repo> locked by user <user>”)
+
+
+So the scenario of use for repos with `locking function` enabled is that 
+every initial clone and every pull gives users (with write permission)
+the exclusive right to do a push.
+
+
+Each repo can be manually unlocked by admin from the repo settings menu.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/usage/performance.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,50 @@
+.. _performance:
+
+================================
+Optimizing RhodeCode Performance
+================================
+
+When serving large amount of big repositories RhodeCode can start
+performing slower than expected. Because of demanding nature of handling large
+amount of data from version control systems here are some tips how to get
+the best performance.
+
+* RhodeCode will perform better on machines with faster disks (SSD/SAN). It's
+  more important to have faster disk than faster CPU.
+
+* Slowness on initial page can be easily fixed by grouping repositories, and/or
+  increasing cache size (see below)
+
+
+Follow these few steps to improve performance of RhodeCode system.
+
+
+1. Increase cache
+
+    in the .ini file::
+       
+     beaker.cache.sql_cache_long.expire=3600 <-- set this to higher number
+
+    This option affects the cache expiration time for main page. Having
+    few hundreds of repositories on main page can sometimes make the system
+    to behave slow when cache expires for all of them. Increasing `expire`
+    option to day (86400) or a week (604800) will improve general response
+    times for the main page. RhodeCode has an intelligent cache expiration
+    system and it will expire cache for repositories that had been changed.
+
+2. Switch from sqlite to postgres or mysql
+    
+    sqlite is a good option when having small load on the system. But due to
+    locking issues with sqlite, it's not recommended to use it for larger
+    setup. Switching to mysql or postgres will result in a immediate
+    performance increase.
+    
+3. Scale RhodeCode horizontally
+
+    - running two or more instances on the same server can speed up things a lot
+    - load balance using round robin or ip hash
+    - you need to handle consistent user session storage by switching to 
+      db sessions, client side sessions or sharing session data folder across 
+      instances. See http://beaker.readthedocs.org/ docs for details.
+    - remember that each instance needs it's own .ini file and unique
+      `instance_id` set in them
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/usage/troubleshooting.rst	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,70 @@
+.. _troubleshooting:
+
+
+===============
+Troubleshooting
+===============
+
+:Q: **Missing static files?**
+:A: 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
+   
+| 
+
+:Q: **Can't install celery/rabbitmq?**
+:A: Don't worry RhodeCode works without them too. No extra setup is required.
+    Try out great celery docs for further help.
+
+|
+ 
+:Q: **Long lasting push timeouts?**
+:A: Make sure you set a longer timeouts in your proxy/fcgi settings, timeouts
+    are caused by https server and not RhodeCode.
+    
+| 
+
+:Q: **Large pushes timeouts?**
+:A: Make sure you set a proper max_body_size for the http server. Very often
+    Apache, Nginx or other http servers kill the connection due to to large
+    body.
+
+|
+
+:Q: **Apache doesn't pass basicAuth on pull/push?**
+:A: Make sure you added `WSGIPassAuthorization true`.
+
+|
+
+:Q: **Git fails on push/pull?**
+:A: Make sure you're using an wsgi http server that can handle chunked encoding
+    such as `waitress` or `gunicorn`
+
+|
+
+:Q: **How i use hooks in RhodeCode?**
+:A: It's easy if they are python hooks just use advanced link in hooks section
+    in Admin panel, that works only for Mercurial. If you want to use githooks,
+    just install proper one in repository eg. create file in 
+    `/gitrepo/hooks/pre-receive`. You can also use RhodeCode-extensions to
+    connect to callback hooks, for both Git and Mercurial.
+
+|
+
+:Q: **RhodeCode is slow for me, how can i make it faster?**
+:A: See the :ref:`performance` section
+
+For further questions search the `Issues tracker`_, or post a message in the 
+`google group rhodecode`_
+
+.. _virtualenv: http://pypi.python.org/pypi/virtualenv
+.. _python: http://www.python.org/
+.. _mercurial: http://mercurial.selenic.com/
+.. _celery: http://celeryproject.org/
+.. _rabbitmq: http://www.rabbitmq.com/
+.. _python-ldap: http://www.python-ldap.org/
+.. _mercurial-server: http://www.lshift.net/mercurial-server.html
+.. _PublishingRepositories: http://mercurial.selenic.com/wiki/PublishingRepositories
+.. _Issues tracker: https://bitbucket.org/marcinkuzminski/rhodecode/issues
+.. _google group rhodecode: http://groups.google.com/group/rhodecode
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/init.d/supervisord.conf	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,51 @@
+; RhodeCode Supervisord
+; ##########################
+; for help see http://supervisord.org/configuration.html
+; ##########################
+
+[inet_http_server]         ; inet (TCP) server disabled by default
+port=127.0.0.1:9001        ; (ip_address:port specifier, *:port for all iface)
+;username=user              ; (default is no username (open server))
+;password=123               ; (default is no password (open server))
+
+[supervisord]
+logfile=/%(here)s/supervisord_rhodecode.log ; (main log file;default $CWD/supervisord.log)
+logfile_maxbytes=50MB        ; (max main logfile bytes b4 rotation;default 50MB)
+logfile_backups=10           ; (num of main logfile rotation backups;default 10)
+loglevel=info                ; (log level;default info; others: debug,warn,trace)
+pidfile=/%(here)s/supervisord_rhodecode.pid ; (supervisord pidfile;default supervisord.pid)
+nodaemon=true               ; (start in foreground if true;default false)
+minfds=1024                  ; (min. avail startup file descriptors;default 1024)
+minprocs=200                 ; (min. avail process descriptors;default 200)
+umask=022                    ; (process file creation umask;default 022)
+user=marcink                  ; (default is current user, required if root)
+;identifier=supervisor       ; (supervisord identifier, default is 'supervisor')
+;directory=/tmp              ; (default is not to cd during start)
+;nocleanup=true              ; (don't clean up tempfiles at start;default false)
+;childlogdir=/tmp            ; ('AUTO' child log dir, default $TEMP)
+environment=HOME=/home/marcink       ; (key value pairs to add to environment)
+;strip_ansi=false            ; (strip ansi escape codes in logs; def. false)
+
+; the below section must remain in the config file for RPC
+; (supervisorctl/web interface) to work, additional interfaces may be
+; added by defining them in separate rpcinterface: sections
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
+
+[supervisorctl]
+serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
+;username=user               ; should be same as http_username if set
+;password=123                ; should be same as http_password if set
+;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
+;history_file=~/.sc_history  ; use readline history if available
+
+
+; restart with supervisorctl restart rhodecode:*
+[program:rhodecode]
+numprocs = 1
+numprocs_start = 5000 # possible should match ports
+directory=/home/marcink/rhodecode-dir
+command = /home/marcink/v-env/bin/paster serve rc.ini
+process_name = %(program_name)s_%(process_num)04d
+redirect_stderr=true 
+stdout_logfile=/%(here)s/rhodecode.log 
\ No newline at end of file
--- a/production.ini	Sat May 19 14:54:50 2012 +0200
+++ b/production.ini	Sun Sep 02 21:19:54 2012 +0200
@@ -30,22 +30,31 @@
 
 [server:main]
 ##nr of threads to spawn
-threadpool_workers = 5
+#threadpool_workers = 5
 
 ##max request before thread respawn
-threadpool_max_requests = 10
+#threadpool_max_requests = 10
 
 ##option to use threads of process
-use_threadpool = true
+#use_threadpool = true
 
-use = egg:Paste#http
+#use = egg:Paste#http
+use = egg:waitress#main
 host = 127.0.0.1
 port = 8001
 
+[filter:proxy-prefix]
+# prefix middleware for rc
+use = egg:PasteDeploy#prefix
+prefix = /<your-prefix>
+
 [app:main]
 use = egg:rhodecode
+#filter-with = proxy-prefix
 full_stack = true
 static_files = true
+# Optional Languages
+# en, fr, ja, pt_BR, zh_CN, zh_TW
 lang = en
 cache_dir = %(here)s/data
 index_dir = %(here)s/data/index
@@ -54,6 +63,15 @@
 force_https = false
 commit_parse_limit = 50
 use_gravatar = true
+
+## alternative_gravatar_url allows you to use your own avatar server application
+## the following parts of the URL will be replaced
+## {email}        user email
+## {md5email}     md5 hash of the user email (like at gravatar.com)
+## {size}         size of the image that is expected from the server application
+#alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
+#alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
+
 container_auth_enabled = false
 proxypass_auth_enabled = false
 default_encoding = utf8
@@ -78,7 +96,8 @@
 issue_pat = (?:\s*#)(\d+)
 
 ## server url to the issue, each {id} will be replaced with match
-## fetched from the regex and {repo} is replaced with repository name
+## fetched from the regex and {repo} is replaced with full repository name
+## including groups {repo_name} is replaced with just name of repo
 
 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
@@ -165,30 +184,34 @@
 ## The storage uses the Container API 
 ## that is also used by the cache system.
 
-## db session example
-
+## db session ##
 #beaker.session.type = ext:database
 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
 #beaker.session.table_name = db_session 
 
-## encrypted cookie session, good for many instances
+## encrypted cookie client side session, good for many instances ##
 #beaker.session.type = cookie
 
-beaker.session.type = file
+## file based cookies (default) ##
+#beaker.session.type = file
+
+
 beaker.session.key = rhodecode
-# secure cookie requires AES python libraries
+## secure cookie requires AES python libraries ##
 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
 #beaker.session.validate_key = 9712sds2212c--zxc123
-beaker.session.timeout = 36000
+## sets session as invalid if it haven't been accessed for given amount of time
+beaker.session.timeout = 2592000
 beaker.session.httponly = true
+#beaker.session.cookie_path = /<your-prefix>
 
-## uncomment for https secure cookie
+## uncomment for https secure cookie ##
 beaker.session.secure = false
 
-##auto save the session to not to use .save()
+## auto save the session to not to use .save() ##
 beaker.session.auto = False
 
-##true exire at browser close
+## default cookie expiration time in seconds `true` expire at browser close ##
 #beaker.session.cookie_expires = 3600
 
 
--- a/requires.txt	Sat May 19 14:54:50 2012 +0200
+++ b/requires.txt	Sun Sep 02 21:19:54 2012 +0200
@@ -1,18 +1,20 @@
+waitress==0.8.1
+webob==1.0.8
 Pylons==1.0.0
-Beaker==1.6.3
+Beaker==1.6.4
 WebHelpers==1.3
 formencode==1.2.4
-SQLAlchemy==0.7.6
-Mako==0.7.0
-pygments>=1.4
+SQLAlchemy==0.7.8
+Mako==0.7.2
+pygments>=1.5
 whoosh>=2.4.0,<2.5
 celery>=2.2.5,<2.3
 babel
 python-dateutil>=1.5.0,<2.0.0
 dulwich>=0.8.5,<0.9.0
-webob==1.0.8
 markdown==2.1.1
 docutils==0.8.1
 simplejson==2.5.2
+mock
 py-bcrypt
-mercurial>=2.2.1,<2.3
\ No newline at end of file
+mercurial>=2.3.0,<2.4
\ No newline at end of file
--- a/rhodecode/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -26,7 +26,7 @@
 import sys
 import platform
 
-VERSION = (1, 3, 6)
+VERSION = (1, 4, 0)
 
 try:
     from rhodecode.lib import get_current_revision
@@ -38,50 +38,19 @@
 
 __version__ = ('.'.join((str(each) for each in VERSION[:3])) +
                '.'.join(VERSION[3:]))
-__dbversion__ = 5  # defines current db version for migrations
+__dbversion__ = 6  # defines current db version for migrations
 __platform__ = platform.system()
 __license__ = 'GPLv3'
 __py_version__ = sys.version_info
+__author__ = 'Marcin Kuzminski'
+__url__ = 'http://rhodecode.org'
 
 PLATFORM_WIN = ('Windows')
-PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS')
+PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS') #depracated
 
 is_windows = __platform__ in PLATFORM_WIN
-is_unix = __platform__ in PLATFORM_OTHERS
+is_unix = not is_windows
 
-requirements = [
-    "Pylons==1.0.0",
-    "Beaker==1.6.3",
-    "WebHelpers==1.3",
-    "formencode==1.2.4",
-    "SQLAlchemy==0.7.6",
-    "Mako==0.7.0",
-    "pygments>=1.4",
-    "whoosh>=2.4.0,<2.5",
-    "celery>=2.2.5,<2.3",
-    "babel",
-    "python-dateutil>=1.5.0,<2.0.0",
-    "dulwich>=0.8.5,<0.9.0",
-    "webob==1.0.8",
-    "markdown==2.1.1",
-    "docutils==0.8.1",
-    "simplejson==2.5.2",
-]
-
-if __py_version__ < (2, 6):
-    requirements.append("pysqlite")
-
-if is_windows:
-    requirements.append("mercurial>=2.2.1,<2.3")
-else:
-    requirements.append("py-bcrypt")
-    requirements.append("mercurial>=2.2.1,<2.3")
-
-
-def get_version():
-    """Returns shorter version (digit parts only) as string."""
-
-    return '.'.join((str(each) for each in VERSION[:3]))
 
 BACKENDS = {
     'hg': 'Mercurial repository',
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/bin/rhodecode_api.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,249 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.bin.backup_manager
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Api CLI client for RhodeCode
+
+    :created_on: Jun 3, 2012
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+from __future__ import with_statement
+import os
+import sys
+import random
+import urllib2
+import pprint
+import argparse
+
+try:
+    from rhodecode.lib.ext_json import json
+except ImportError:
+    try:
+        import simplejson as json
+    except ImportError:
+        import json
+
+
+CONFIG_NAME = '.rhodecode'
+FORMAT_PRETTY = 'pretty'
+FORMAT_JSON = 'json'
+
+
+class RcConf(object):
+    """
+    RhodeCode config for API
+
+    conf = RcConf()
+    conf['key']
+
+    """
+
+    def __init__(self, config_location=None, autoload=True, autocreate=False,
+                 config=None):
+        self._conf_name = CONFIG_NAME if not config_location else config_location
+        self._conf = {}
+        if autocreate:
+            self.make_config(config)
+        if autoload:
+            self._conf = self.load_config()
+
+    def __getitem__(self, key):
+        return self._conf[key]
+
+    def __nonzero__(self):
+        if self._conf:
+            return True
+        return False
+
+    def __eq__(self):
+        return self._conf.__eq__()
+
+    def __repr__(self):
+        return 'RcConf<%s>' % self._conf.__repr__()
+
+    def make_config(self, config):
+        """
+        Saves given config as a JSON dump in the _conf_name location
+
+        :param config:
+        :type config:
+        """
+        update = False
+        if os.path.exists(self._conf_name):
+            update = True
+        with open(self._conf_name, 'wb') as f:
+            json.dump(config, f, indent=4)
+
+        if update:
+            sys.stdout.write('Updated config in %s\n' % self._conf_name)
+        else:
+            sys.stdout.write('Created new config in %s\n' % self._conf_name)
+
+    def update_config(self, new_config):
+        """
+        Reads the JSON config updates it's values with new_config and
+        saves it back as JSON dump
+
+        :param new_config:
+        """
+        config = {}
+        try:
+            with open(self._conf_name, 'rb') as conf:
+                config = json.load(conf)
+        except IOError, e:
+            sys.stderr.write(str(e) + '\n')
+
+        config.update(new_config)
+        self.make_config(config)
+
+    def load_config(self):
+        """
+        Loads config from file and returns loaded JSON object
+        """
+        try:
+            with open(self._conf_name, 'rb') as conf:
+                return  json.load(conf)
+        except IOError, e:
+            #sys.stderr.write(str(e) + '\n')
+            pass
+
+
+def api_call(apikey, apihost, format, method=None, **kw):
+    """
+    Api_call wrapper for RhodeCode
+
+    :param apikey:
+    :param apihost:
+    :param format: formatting, pretty means prints and pprint of json
+     json returns unparsed json
+    :param method:
+    """
+    def _build_data(random_id):
+        """
+        Builds API data with given random ID
+
+        :param random_id:
+        :type random_id:
+        """
+        return {
+            "id": random_id,
+            "api_key": apikey,
+            "method": method,
+            "args": kw
+        }
+
+    if not method:
+        raise Exception('please specify method name !')
+    id_ = random.randrange(1, 9999)
+    req = urllib2.Request('%s/_admin/api' % apihost,
+                      data=json.dumps(_build_data(id_)),
+                      headers={'content-type': 'text/plain'})
+    if format == FORMAT_PRETTY:
+        sys.stdout.write('calling %s to %s \n' % (req.get_data(), apihost))
+    ret = urllib2.urlopen(req)
+    raw_json = ret.read()
+    json_data = json.loads(raw_json)
+    id_ret = json_data['id']
+    _formatted_json = pprint.pformat(json_data)
+    if id_ret == id_:
+        if format == FORMAT_JSON:
+            sys.stdout.write(str(raw_json))
+        else:
+            sys.stdout.write('rhodecode returned:\n%s\n' % (_formatted_json))
+
+    else:
+        raise Exception('something went wrong. '
+                        'ID mismatch got %s, expected %s | %s' % (
+                                            id_ret, id_, _formatted_json))
+
+
+def argparser(argv):
+    usage = (
+      "rhodecode_api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
+      " [--config=CONFIG] "
+      "_create_config or METHOD <key:val> <key2:val> ..."
+    )
+
+    parser = argparse.ArgumentParser(description='RhodeCode API cli',
+                                     usage=usage)
+
+    ## config
+    group = parser.add_argument_group('config')
+    group.add_argument('--apikey', help='api access key')
+    group.add_argument('--apihost', help='api host')
+    group.add_argument('--config', help='config file')
+
+    group = parser.add_argument_group('API')
+    group.add_argument('method', metavar='METHOD', type=str,
+            help='API method name to call followed by key:value attributes',
+    )
+    group.add_argument('--format', dest='format', type=str,
+            help='output format default: `pretty` can '
+                 'be also `%s`' % FORMAT_JSON,
+            default=FORMAT_PRETTY
+    )
+    args, other = parser.parse_known_args()
+    return parser, args, other
+
+
+def main(argv=None):
+    """
+    Main execution function for cli
+
+    :param argv:
+    :type argv:
+    """
+    if argv is None:
+        argv = sys.argv
+
+    conf = None
+    parser, args, other = argparser(argv)
+
+    api_credentials_given = (args.apikey and args.apihost)
+    if args.method == '_create_config':
+        if not api_credentials_given:
+            raise parser.error('_create_config requires --apikey and --apihost')
+        conf = RcConf(config_location=args.config,
+                      autocreate=True, config={'apikey': args.apikey,
+                                               'apihost': args.apihost})
+
+    if not conf:
+        conf = RcConf(config_location=args.config, autoload=True)
+        if not conf:
+            if not api_credentials_given:
+                parser.error('Could not find config file and missing '
+                             '--apikey or --apihost in params')
+
+    apikey = args.apikey or conf['apikey']
+    host = args.apihost or conf['apihost']
+    method = args.method
+    if method == '_create_config':
+        sys.exit()
+
+    try:
+        margs = dict(map(lambda s: s.split(':', 1), other))
+    except:
+        sys.stderr.write('Error parsing arguments \n')
+        sys.exit()
+
+    api_call(apikey, host, args.format, method, **margs)
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/bin/rhodecode_backup.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.bin.backup_manager
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Repositories backup manager, it allows to backups all
+    repositories and send it to backup server using RSA key via ssh.
+
+    :created_on: Feb 28, 2010
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+
+import logging
+import tarfile
+import datetime
+import subprocess
+
+logging.basicConfig(level=logging.DEBUG,
+                    format="%(asctime)s %(levelname)-5.5s %(message)s")
+
+
+class BackupManager(object):
+    def __init__(self, repos_location, rsa_key, backup_server):
+        today = datetime.datetime.now().weekday() + 1
+        self.backup_file_name = "rhodecode_repos.%s.tar.gz" % today
+
+        self.id_rsa_path = self.get_id_rsa(rsa_key)
+        self.repos_path = self.get_repos_path(repos_location)
+        self.backup_server = backup_server
+
+        self.backup_file_path = '/tmp'
+
+        logging.info('starting backup for %s', self.repos_path)
+        logging.info('backup target %s', self.backup_file_path)
+
+    def get_id_rsa(self, rsa_key):
+        if not os.path.isfile(rsa_key):
+            logging.error('Could not load id_rsa key file in %s', rsa_key)
+            sys.exit()
+        return rsa_key
+
+    def get_repos_path(self, path):
+        if not os.path.isdir(path):
+            logging.error('Wrong location for repositories in %s', path)
+            sys.exit()
+        return path
+
+    def backup_repos(self):
+        bckp_file = os.path.join(self.backup_file_path, self.backup_file_name)
+        tar = tarfile.open(bckp_file, "w:gz")
+
+        for dir_name in os.listdir(self.repos_path):
+            logging.info('backing up %s', dir_name)
+            tar.add(os.path.join(self.repos_path, dir_name), dir_name)
+        tar.close()
+        logging.info('finished backup of mercurial repositories')
+
+    def transfer_files(self):
+        params = {
+                  'id_rsa_key': self.id_rsa_path,
+                  'backup_file': os.path.join(self.backup_file_path,
+                                             self.backup_file_name),
+                  'backup_server': self.backup_server
+                  }
+        cmd = ['scp', '-l', '40000', '-i', '%(id_rsa_key)s' % params,
+               '%(backup_file)s' % params,
+               '%(backup_server)s' % params]
+
+        subprocess.call(cmd)
+        logging.info('Transfered file %s to %s', self.backup_file_name, cmd[4])
+
+    def rm_file(self):
+        logging.info('Removing file %s', self.backup_file_name)
+        os.remove(os.path.join(self.backup_file_path, self.backup_file_name))
+
+if __name__ == "__main__":
+
+    repo_location = '/home/repo_path'
+    backup_server = 'root@192.168.1.100:/backups/mercurial'
+    rsa_key = '/home/id_rsa'
+
+    B_MANAGER = BackupManager(repo_location, rsa_key, backup_server)
+    B_MANAGER.backup_repos()
+    B_MANAGER.transfer_files()
+    B_MANAGER.rm_file()
--- a/rhodecode/config/deployment.ini_tmpl	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/config/deployment.ini_tmpl	Sun Sep 02 21:19:54 2012 +0200
@@ -30,22 +30,31 @@
 
 [server:main]
 ##nr of threads to spawn
-threadpool_workers = 5
+#threadpool_workers = 5
 
 ##max request before thread respawn
-threadpool_max_requests = 10
+#threadpool_max_requests = 10
 
 ##option to use threads of process
-use_threadpool = true
+#use_threadpool = true
 
-use = egg:Paste#http
+#use = egg:Paste#http
+use = egg:waitress#main
 host = 127.0.0.1
 port = 5000
 
+[filter:proxy-prefix]
+# prefix middleware for rc
+use = egg:PasteDeploy#prefix
+prefix = /<your-prefix>
+
 [app:main]
 use = egg:rhodecode
+#filter-with = proxy-prefix
 full_stack = true
 static_files = true
+# Optional Languages
+# en, fr, ja, pt_BR, zh_CN, zh_TW
 lang = en
 cache_dir = %(here)s/data
 index_dir = %(here)s/data/index
@@ -54,6 +63,15 @@
 force_https = false
 commit_parse_limit = 50
 use_gravatar = true
+
+## alternative_gravatar_url allows you to use your own avatar server application
+## the following parts of the URL will be replaced
+## {email}        user email
+## {md5email}     md5 hash of the user email (like at gravatar.com)
+## {size}         size of the image that is expected from the server application
+#alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
+#alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
+
 container_auth_enabled = false
 proxypass_auth_enabled = false
 default_encoding = utf8
@@ -78,7 +96,8 @@
 issue_pat = (?:\s*#)(\d+)
 
 ## server url to the issue, each {id} will be replaced with match
-## fetched from the regex and {repo} is replaced with repository name
+## fetched from the regex and {repo} is replaced with full repository name
+## including groups {repo_name} is replaced with just name of repo
 
 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
 
@@ -165,30 +184,34 @@
 ## The storage uses the Container API 
 ## that is also used by the cache system.
 
-## db session example
-
+## db session ##
 #beaker.session.type = ext:database
 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
 #beaker.session.table_name = db_session 
 
-## encrypted cookie session, good for many instances
+## encrypted cookie client side session, good for many instances ##
 #beaker.session.type = cookie
 
-beaker.session.type = file
+## file based cookies (default) ##
+#beaker.session.type = file
+
+
 beaker.session.key = rhodecode
-# secure cookie requires AES python libraries
-#beaker.session.encrypt_key = ${app_instance_secret}
-#beaker.session.validate_key = ${app_instance_secret}
-beaker.session.timeout = 36000
+## secure cookie requires AES python libraries ##
+#beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
+#beaker.session.validate_key = 9712sds2212c--zxc123
+## sets session as invalid if it haven't been accessed for given amount of time
+beaker.session.timeout = 2592000
 beaker.session.httponly = true
+#beaker.session.cookie_path = /<your-prefix>
 
-## uncomment for https secure cookie
+## uncomment for https secure cookie ##
 beaker.session.secure = false
 
-##auto save the session to not to use .save()
+## auto save the session to not to use .save() ##
 beaker.session.auto = False
 
-##true exire at browser close
+## default cookie expiration time in seconds `true` expire at browser close ##
 #beaker.session.cookie_expires = 3600
 
 
--- a/rhodecode/config/environment.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/config/environment.py	Sun Sep 02 21:19:54 2012 +0200
@@ -72,19 +72,28 @@
     config['pylons.strict_tmpl_context'] = True
     test = os.path.split(config['__file__'])[-1] == 'test.ini'
     if test:
+        if os.environ.get('TEST_DB'):
+            # swap config if we pass enviroment variable
+            config['sqlalchemy.db1.url'] = os.environ.get('TEST_DB')
+
         from rhodecode.lib.utils import create_test_env, create_test_index
         from rhodecode.tests import  TESTS_TMP_PATH
-        create_test_env(TESTS_TMP_PATH, config)
-        create_test_index(TESTS_TMP_PATH, config, True)
+        # set RC_NO_TMP_PATH=1 to disable re-creating the database and
+        # test repos
+        if not int(os.environ.get('RC_NO_TMP_PATH', 0)):
+            create_test_env(TESTS_TMP_PATH, config)
+        # set RC_WHOOSH_TEST_DISABLE=1 to disable whoosh index during tests
+        if not int(os.environ.get('RC_WHOOSH_TEST_DISABLE', 0)):
+            create_test_index(TESTS_TMP_PATH, config, True)
 
     # MULTIPLE DB configs
     # Setup the SQLAlchemy database engine
     sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
-
     init_model(sa_engine_db1)
 
     repos_path = make_ui('db').configitems('paths')[0][1]
-    repo2db_mapper(ScmModel().repo_scan(repos_path))
+    repo2db_mapper(ScmModel().repo_scan(repos_path),
+                   remove_obsolete=False, install_git_hook=False)
     set_available_permissions(config)
     config['base_path'] = repos_path
     set_rhodecode_config(config)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/config/post_receive_tmpl.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+import os
+import sys
+
+try:
+    import rhodecode
+    RC_HOOK_VER = '_TMPL_'
+    os.environ['RC_HOOK_VER'] = RC_HOOK_VER
+    from rhodecode.lib.hooks import handle_git_post_receive
+except ImportError:
+    rhodecode = None
+
+
+def main():
+    if rhodecode is None:
+        # exit with success if we cannot import rhodecode !!
+        # this allows simply push to this repo even without
+        # rhodecode
+        sys.exit(0)
+
+    repo_path = os.path.abspath('.')
+    push_data = sys.stdin.readlines()
+    # os.environ is modified here by a subprocess call that
+    # runs git and later git executes this hook.
+    # Environ get's some additional info from rhodecode system
+    # like IP or username from basic-auth
+    handle_git_post_receive(repo_path, push_data, os.environ)
+    sys.exit(0)
+
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/config/pre_receive_tmpl.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+import os
+import sys
+
+try:
+    import rhodecode
+    RC_HOOK_VER = '_TMPL_'
+    os.environ['RC_HOOK_VER'] = RC_HOOK_VER
+    from rhodecode.lib.hooks import handle_git_pre_receive
+except ImportError:
+    rhodecode = None
+
+
+def main():
+    if rhodecode is None:
+        # exit with success if we cannot import rhodecode !!
+        # this allows simply push to this repo even without
+        # rhodecode
+        sys.exit(0)
+
+    repo_path = os.path.abspath('.')
+    push_data = sys.stdin.readlines()
+    # os.environ is modified here by a subprocess call that
+    # runs git and later git executes this hook.
+    # Environ get's some additional info from rhodecode system
+    # like IP or username from basic-auth
+    handle_git_pre_receive(repo_path, push_data, os.environ)
+    sys.exit(0)
+
+if __name__ == '__main__':
+    main()
--- a/rhodecode/config/rcextensions/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/config/rcextensions/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,6 +1,7 @@
 # Additional mappings that are not present in the pygments lexers
 # used for building stats
-# format is {'ext':'Name'} eg. {'py':'Python'}
+# format is {'ext':['Names']} eg. {'py':['Python']} note: there can be
+# more than one name for extension
 # NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
 # build by pygments
 EXTRA_MAPPINGS = {}
@@ -39,6 +40,7 @@
      :param group_id:
      :param created_by:
     """
+
     return 0
 CREATE_REPO_HOOK = _crhook
 
--- a/rhodecode/config/rcextensions/make_rcextensions.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/config/rcextensions/make_rcextensions.py	Sun Sep 02 21:19:54 2012 +0200
@@ -54,7 +54,7 @@
         logging.config.fileConfig(self.path_to_ini_file)
         from pylons import config
 
-        def _make_file(ext_file):
+        def _make_file(ext_file, tmpl):
             bdir = os.path.split(ext_file)[0]
             if not os.path.isdir(bdir):
                 os.makedirs(bdir)
@@ -71,11 +71,11 @@
             msg = ('Extension file already exists, do you want '
                    'to overwrite it ? [y/n]')
             if ask_ok(msg):
-                _make_file(ext_file)
+                _make_file(ext_file, tmpl)
             else:
                 log.info('nothing done...')
         else:
-            _make_file(ext_file)
+            _make_file(ext_file, tmpl)
 
     def update_parser(self):
         pass
--- a/rhodecode/config/routing.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/config/routing.py	Sun Sep 02 21:19:54 2012 +0200
@@ -69,7 +69,7 @@
     rmap.connect('home', '/', controller='home', action='index')
     rmap.connect('repo_switcher', '/repos', controller='home',
                  action='repo_switcher')
-    rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*}',
+    rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
                  controller='home', action='branch_tag_switcher')
     rmap.connect('bugtracker',
                  "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
@@ -93,52 +93,54 @@
              action="new", conditions=dict(method=["GET"]))
         m.connect("formatted_new_repo", "/repos/new.{format}",
              action="new", conditions=dict(method=["GET"]))
-        m.connect("/repos/{repo_name:.*}",
+        m.connect("/repos/{repo_name:.*?}",
              action="update", conditions=dict(method=["PUT"],
                                               function=check_repo))
-        m.connect("/repos/{repo_name:.*}",
+        m.connect("/repos/{repo_name:.*?}",
              action="delete", conditions=dict(method=["DELETE"],
                                               function=check_repo))
-        m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
+        m.connect("edit_repo", "/repos/{repo_name:.*?}/edit",
              action="edit", conditions=dict(method=["GET"],
                                             function=check_repo))
-        m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
+        m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
              action="edit", conditions=dict(method=["GET"],
                                             function=check_repo))
-        m.connect("repo", "/repos/{repo_name:.*}",
+        m.connect("repo", "/repos/{repo_name:.*?}",
              action="show", conditions=dict(method=["GET"],
                                             function=check_repo))
-        m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
+        m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
              action="show", conditions=dict(method=["GET"],
                                             function=check_repo))
         #ajax delete repo perm user
-        m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
+        m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
              action="delete_perm_user",
              conditions=dict(method=["DELETE"], function=check_repo))
 
         #ajax delete repo perm users_group
         m.connect('delete_repo_users_group',
-                  "/repos_delete_users_group/{repo_name:.*}",
+                  "/repos_delete_users_group/{repo_name:.*?}",
                   action="delete_perm_users_group",
                   conditions=dict(method=["DELETE"], function=check_repo))
 
         #settings actions
-        m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
+        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:.*}",
+        m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
                   action="repo_cache", conditions=dict(method=["DELETE"],
                                                        function=check_repo))
-        m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
+        m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
                   action="repo_public_journal", conditions=dict(method=["PUT"],
                                                         function=check_repo))
-        m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
+        m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
                   action="repo_pull", conditions=dict(method=["PUT"],
                                                       function=check_repo))
-        m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*}",
+        m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
                   action="repo_as_fork", conditions=dict(method=["PUT"],
                                                       function=check_repo))
-
+        m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
+                  action="repo_locking", conditions=dict(method=["PUT"],
+                                                      function=check_repo))
     with rmap.submapper(path_prefix=ADMIN_PREFIX,
                         controller='admin/repos_groups') as m:
         m.connect("repos_groups", "/repos_groups",
@@ -157,9 +159,8 @@
         m.connect("delete_repos_group", "/repos_groups/{id}",
                   action="delete", conditions=dict(method=["DELETE"],
                                                    function=check_int))
-        m.connect("edit_repos_group", "/repos_groups/{id}/edit",
-                  action="edit", conditions=dict(method=["GET"],
-                                                 function=check_int))
+        m.connect("edit_repos_group", "/repos_groups/{id:.*?}/edit",
+                  action="edit", conditions=dict(method=["GET"],))
         m.connect("formatted_edit_repos_group",
                   "/repos_groups/{id}.{format}/edit",
                   action="edit", conditions=dict(method=["GET"],
@@ -212,8 +213,12 @@
         #EXTRAS USER ROUTES
         m.connect("user_perm", "/users_perm/{id}",
                   action="update_perm", conditions=dict(method=["PUT"]))
+        m.connect("user_emails", "/users_emails/{id}",
+                  action="add_email", conditions=dict(method=["PUT"]))
+        m.connect("user_emails_delete", "/users_emails/{id}",
+                  action="delete_email", conditions=dict(method=["DELETE"]))
 
-    #ADMIN USERS REST ROUTES
+    #ADMIN USERS GROUPS REST ROUTES
     with rmap.submapper(path_prefix=ADMIN_PREFIX,
                         controller='admin/users_groups') as m:
         m.connect("users_groups", "/users_groups",
@@ -292,6 +297,10 @@
                   action="my_account_update", conditions=dict(method=["PUT"]))
         m.connect("admin_settings_create_repository", "/create_repository",
                   action="create_repository", conditions=dict(method=["GET"]))
+        m.connect("admin_settings_my_repos", "/my_account/repos",
+                  action="my_account_my_repos", conditions=dict(method=["GET"]))
+        m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
+                  action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
 
     #NOTIFICATION REST ROUTES
     with rmap.submapper(path_prefix=ADMIN_PREFIX,
@@ -337,15 +346,27 @@
         m.connect('api', '/api')
 
     #USER JOURNAL
-    rmap.connect('journal', '%s/journal' % ADMIN_PREFIX, controller='journal')
+    rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
+                 controller='journal', action='index')
+    rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
+                 controller='journal', action='journal_rss')
+    rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
+                 controller='journal', action='journal_atom')
 
     rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
                  controller='journal', action="public_journal")
 
-    rmap.connect('public_journal_rss', '%s/public_journal_rss' % ADMIN_PREFIX,
+    rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
+                 controller='journal', action="public_journal_rss")
+
+    rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
                  controller='journal', action="public_journal_rss")
 
     rmap.connect('public_journal_atom',
+                 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
+                 action="public_journal_atom")
+
+    rmap.connect('public_journal_atom_old',
                  '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
                  action="public_journal_atom")
 
@@ -374,18 +395,18 @@
                  controller='login', action='password_reset_confirmation')
 
     #FEEDS
-    rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
+    rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
                 controller='feed', action='rss',
                 conditions=dict(function=check_repo))
 
-    rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
+    rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
                 controller='feed', action='atom',
                 conditions=dict(function=check_repo))
 
     #==========================================================================
     # REPOSITORY ROUTES
     #==========================================================================
-    rmap.connect('summary_home', '/{repo_name:.*}',
+    rmap.connect('summary_home', '/{repo_name:.*?}',
                 controller='summary',
                 conditions=dict(function=check_repo))
 
@@ -393,114 +414,166 @@
                 controller='admin/repos_groups', action="show_by_name",
                 conditions=dict(function=check_group))
 
-    rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
+    rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
                 controller='changeset', revision='tip',
                 conditions=dict(function=check_repo))
 
     rmap.connect('changeset_comment',
-                 '/{repo_name:.*}/changeset/{revision}/comment',
+                 '/{repo_name:.*?}/changeset/{revision}/comment',
                 controller='changeset', revision='tip', action='comment',
                 conditions=dict(function=check_repo))
 
     rmap.connect('changeset_comment_delete',
-                 '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
+                 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
                 controller='changeset', action='delete_comment',
                 conditions=dict(function=check_repo, method=["DELETE"]))
 
     rmap.connect('raw_changeset_home',
-                 '/{repo_name:.*}/raw-changeset/{revision}',
+                 '/{repo_name:.*?}/raw-changeset/{revision}',
                  controller='changeset', action='raw_changeset',
                  revision='tip', conditions=dict(function=check_repo))
 
-    rmap.connect('summary_home', '/{repo_name:.*}/summary',
+    rmap.connect('compare_url',
+                 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref}...{other_ref_type}@{other_ref}',
+                 controller='compare', action='index',
+                 conditions=dict(function=check_repo),
+                 requirements=dict(
+                            org_ref_type='(branch|book|tag|rev|org_ref_type)',
+                            other_ref_type='(branch|book|tag|rev|other_ref_type)')
+                 )
+
+    rmap.connect('pullrequest_home',
+                 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
+                 action='index', conditions=dict(function=check_repo,
+                                                 method=["GET"]))
+
+    rmap.connect('pullrequest',
+                 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
+                 action='create', conditions=dict(function=check_repo,
+                                                  method=["POST"]))
+
+    rmap.connect('pullrequest_show',
+                 '/{repo_name:.*?}/pull-request/{pull_request_id}',
+                 controller='pullrequests',
+                 action='show', conditions=dict(function=check_repo,
+                                                method=["GET"]))
+    rmap.connect('pullrequest_update',
+                 '/{repo_name:.*?}/pull-request/{pull_request_id}',
+                 controller='pullrequests',
+                 action='update', conditions=dict(function=check_repo,
+                                                method=["PUT"]))
+    rmap.connect('pullrequest_delete',
+                 '/{repo_name:.*?}/pull-request/{pull_request_id}',
+                 controller='pullrequests',
+                 action='delete', conditions=dict(function=check_repo,
+                                                method=["DELETE"]))
+
+    rmap.connect('pullrequest_show_all',
+                 '/{repo_name:.*?}/pull-request',
+                 controller='pullrequests',
+                 action='show_all', conditions=dict(function=check_repo,
+                                                method=["GET"]))
+
+    rmap.connect('pullrequest_comment',
+                 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
+                 controller='pullrequests',
+                 action='comment', conditions=dict(function=check_repo,
+                                                method=["POST"]))
+
+    rmap.connect('pullrequest_comment_delete',
+                 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
+                controller='pullrequests', action='delete_comment',
+                conditions=dict(function=check_repo, method=["DELETE"]))
+
+    rmap.connect('summary_home', '/{repo_name:.*?}/summary',
                 controller='summary', conditions=dict(function=check_repo))
 
-    rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
+    rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
                 controller='shortlog', conditions=dict(function=check_repo))
 
-    rmap.connect('branches_home', '/{repo_name:.*}/branches',
+    rmap.connect('branches_home', '/{repo_name:.*?}/branches',
                 controller='branches', conditions=dict(function=check_repo))
 
-    rmap.connect('tags_home', '/{repo_name:.*}/tags',
+    rmap.connect('tags_home', '/{repo_name:.*?}/tags',
                 controller='tags', conditions=dict(function=check_repo))
 
-    rmap.connect('bookmarks_home', '/{repo_name:.*}/bookmarks',
+    rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
                 controller='bookmarks', conditions=dict(function=check_repo))
 
-    rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
+    rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
                 controller='changelog', conditions=dict(function=check_repo))
 
-    rmap.connect('changelog_details', '/{repo_name:.*}/changelog_details/{cs}',
+    rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
                 controller='changelog', action='changelog_details',
                 conditions=dict(function=check_repo))
 
-    rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
+    rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
                 controller='files', revision='tip', f_path='',
                 conditions=dict(function=check_repo))
 
-    rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
+    rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
                 controller='files', action='diff', revision='tip', f_path='',
                 conditions=dict(function=check_repo))
 
     rmap.connect('files_rawfile_home',
-                 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
+                 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
                  controller='files', action='rawfile', revision='tip',
                  f_path='', conditions=dict(function=check_repo))
 
     rmap.connect('files_raw_home',
-                 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
+                 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
                  controller='files', action='raw', revision='tip', f_path='',
                  conditions=dict(function=check_repo))
 
     rmap.connect('files_annotate_home',
-                 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
+                 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
                  controller='files', action='index', revision='tip',
                  f_path='', annotate=True, conditions=dict(function=check_repo))
 
     rmap.connect('files_edit_home',
-                 '/{repo_name:.*}/edit/{revision}/{f_path:.*}',
+                 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
                  controller='files', action='edit', revision='tip',
                  f_path='', conditions=dict(function=check_repo))
 
     rmap.connect('files_add_home',
-                 '/{repo_name:.*}/add/{revision}/{f_path:.*}',
+                 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
                  controller='files', action='add', revision='tip',
                  f_path='', conditions=dict(function=check_repo))
 
-    rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
+    rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
                 controller='files', action='archivefile',
                 conditions=dict(function=check_repo))
 
     rmap.connect('files_nodelist_home',
-                 '/{repo_name:.*}/nodelist/{revision}/{f_path:.*}',
+                 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
                 controller='files', action='nodelist',
                 conditions=dict(function=check_repo))
 
-    rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
+    rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
                 controller='settings', action="delete",
                 conditions=dict(method=["DELETE"], function=check_repo))
 
-    rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
+    rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
                 controller='settings', action="update",
                 conditions=dict(method=["PUT"], function=check_repo))
 
-    rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
+    rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
                 controller='settings', action='index',
                 conditions=dict(function=check_repo))
 
-    rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
+    rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
                 controller='forks', action='fork_create',
                 conditions=dict(function=check_repo, method=["POST"]))
 
-    rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
+    rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
                 controller='forks', action='fork',
                 conditions=dict(function=check_repo))
 
-    rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
+    rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
                  controller='forks', action='forks',
                  conditions=dict(function=check_repo))
 
-    rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
+    rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
                  controller='followers', action='followers',
                  conditions=dict(function=check_repo))
 
--- a/rhodecode/controllers/admin/admin.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/admin.py	Sun Sep 02 21:19:54 2012 +0200
@@ -45,7 +45,7 @@
     @HasPermissionAllDecorator('hg.admin')
     def index(self):
 
-        users_log = self.sa.query(UserLog)\
+        users_log = UserLog.query()\
                 .options(joinedload(UserLog.user))\
                 .options(joinedload(UserLog.repository))\
                 .order_by(UserLog.action_date.desc())
--- a/rhodecode/controllers/admin/ldap_settings.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/ldap_settings.py	Sun Sep 02 21:19:54 2012 +0200
@@ -40,6 +40,7 @@
 from rhodecode.lib.exceptions import LdapImportError
 from rhodecode.model.forms import LdapSettingsForm
 from rhodecode.model.db import RhodeCodeSetting
+from rhodecode.model.meta import Session
 
 log = logging.getLogger(__name__)
 
@@ -119,9 +120,9 @@
                             v = ldap_active
                         setting = RhodeCodeSetting.get_by_name(k)
                         setting.app_settings_value = v
-                        self.sa.add(setting)
+                        Session().add(setting)
 
-                self.sa.commit()
+                Session().commit()
                 h.flash(_('Ldap settings updated successfully'),
                         category='success')
                 if not ldap_active:
--- a/rhodecode/controllers/admin/notifications.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/notifications.py	Sun Sep 02 21:19:54 2012 +0200
@@ -60,19 +60,33 @@
         """GET /_admin/notifications: All items in the collection"""
         # url('notifications')
         c.user = self.rhodecode_user
-        notif = NotificationModel().get_for_user(self.rhodecode_user.user_id)
+        notif = NotificationModel().get_for_user(self.rhodecode_user.user_id,
+                                            filter_=request.GET.getall('type'))
         p = int(request.params.get('page', 1))
         c.notifications = Page(notif, page=p, items_per_page=10)
+        c.pull_request_type = Notification.TYPE_PULL_REQUEST
+        c.comment_type = [Notification.TYPE_CHANGESET_COMMENT,
+                          Notification.TYPE_PULL_REQUEST_COMMENT]
+
+        _current_filter = request.GET.getall('type')
+        c.current_filter = 'all'
+        if _current_filter == [c.pull_request_type]:
+            c.current_filter = 'pull_request'
+        elif _current_filter == c.comment_type:
+            c.current_filter = 'comment'
+
         return render('admin/notifications/notifications.html')
 
     def mark_all_read(self):
         if request.environ.get('HTTP_X_PARTIAL_XHR'):
             nm = NotificationModel()
             # mark all read
-            nm.mark_all_read_for_user(self.rhodecode_user.user_id)
-            Session.commit()
+            nm.mark_all_read_for_user(self.rhodecode_user.user_id,
+                                      filter_=request.GET.getall('type'))
+            Session().commit()
             c.user = self.rhodecode_user
-            notif = nm.get_for_user(self.rhodecode_user.user_id)
+            notif = nm.get_for_user(self.rhodecode_user.user_id,
+                                    filter_=request.GET.getall('type'))
             c.notifications = Page(notif, page=1, items_per_page=10)
             return render('admin/notifications/notifications_data.html')
 
@@ -92,6 +106,18 @@
         #    h.form(url('notification', notification_id=ID),
         #           method='put')
         # url('notification', notification_id=ID)
+        try:
+            no = Notification.get(notification_id)
+            owner = lambda: (no.notifications_to_users.user.user_id
+                             == c.rhodecode_user.user_id)
+            if h.HasPermissionAny('hg.admin')() or owner:
+                    NotificationModel().mark_read(c.rhodecode_user.user_id, no)
+                    Session().commit()
+                    return 'ok'
+        except Exception:
+            Session.rollback()
+            log.error(traceback.format_exc())
+        return 'fail'
 
     def delete(self, notification_id):
         """DELETE /_admin/notifications/id: Delete an existing item"""
@@ -106,9 +132,9 @@
             no = Notification.get(notification_id)
             owner = lambda: (no.notifications_to_users.user.user_id
                              == c.rhodecode_user.user_id)
-            if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
+            if h.HasPermissionAny('hg.admin')() or owner:
                     NotificationModel().delete(c.rhodecode_user.user_id, no)
-                    Session.commit()
+                    Session().commit()
                     return 'ok'
         except Exception:
             Session.rollback()
@@ -132,7 +158,7 @@
             if unotification:
                 if unotification.read is False:
                     unotification.mark_as_read()
-                    Session.commit()
+                    Session().commit()
                 c.notification = no
 
                 return render('admin/notifications/show_notification.html')
--- a/rhodecode/controllers/admin/permissions.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/permissions.py	Sun Sep 02 21:19:54 2012 +0200
@@ -71,6 +71,15 @@
         self.create_choices = [('hg.create.none', _('Disabled')),
                                ('hg.create.repository', _('Enabled'))]
 
+        self.fork_choices = [('hg.fork.none', _('Disabled')),
+                             ('hg.fork.repository', _('Enabled'))]
+
+        # set the global template variables
+        c.perms_choices = self.perms_choices
+        c.register_choices = self.register_choices
+        c.create_choices = self.create_choices
+        c.fork_choices = self.fork_choices
+
     def index(self, format='html'):
         """GET /permissions: All items in the collection"""
         # url('permissions')
@@ -96,20 +105,18 @@
 
         _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])()
+                                       [x[0] for x in self.create_choices],
+                                       [x[0] for x in self.fork_choices])()
 
         try:
             form_result = _form.to_python(dict(request.POST))
             form_result.update({'perm_user_name': id})
             permission_model.update(form_result)
-            Session.commit()
+            Session().commit()
             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(
@@ -141,10 +148,8 @@
     def edit(self, id, format='html'):
         """GET /permissions/id/edit: Form to edit an existing item"""
         #url('edit_permission', id=ID)
-        c.perms_choices = self.perms_choices
-        c.register_choices = self.register_choices
-        c.create_choices = self.create_choices
 
+        #this form can only edit default user permissions
         if id == 'default':
             default_user = User.get_by_username('default')
             defaults = {'_method': 'put',
@@ -160,10 +165,14 @@
                 if p.permission.permission_name.startswith('hg.create.'):
                     defaults['default_create'] = p.permission.permission_name
 
+                if p.permission.permission_name.startswith('hg.fork.'):
+                    defaults['default_fork'] = p.permission.permission_name
+
             return htmlfill.render(
-                        render('admin/permissions/permissions.html'),
-                        defaults=defaults,
-                        encoding="UTF-8",
-                        force_defaults=True,)
+                render('admin/permissions/permissions.html'),
+                defaults=defaults,
+                encoding="UTF-8",
+                force_defaults=True,
+            )
         else:
             return redirect(url('admin_home'))
--- a/rhodecode/controllers/admin/repos.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/repos.py	Sun Sep 02 21:19:54 2012 +0200
@@ -28,12 +28,13 @@
 import formencode
 from formencode import htmlfill
 
-from paste.httpexceptions import HTTPInternalServerError
+from webob.exc import HTTPInternalServerError
 from pylons import request, session, tmpl_context as c, url
 from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
 from sqlalchemy.exc import IntegrityError
 
+import rhodecode
 from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
     HasPermissionAnyDecorator, HasRepoPermissionAllDecorator
@@ -45,6 +46,7 @@
 from rhodecode.model.forms import RepoForm
 from rhodecode.model.scm import ScmModel
 from rhodecode.model.repo import RepoModel
+from rhodecode.lib.compat import json
 
 log = logging.getLogger(__name__)
 
@@ -70,6 +72,8 @@
         repo_model = RepoModel()
         c.users_array = repo_model.get_users_js()
         c.users_groups_array = repo_model.get_users_groups_js()
+        choices, c.landing_revs = ScmModel().get_repo_landing_revs()
+        c.landing_revs_choices = choices
 
     def __load_data(self, repo_name=None):
         """
@@ -91,6 +95,9 @@
 
             return redirect(url('repos'))
 
+        choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
+        c.landing_revs_choices = choices
+
         c.default_user_id = User.get_by_username('default').user_id
         c.in_public_journal = UserFollowing.query()\
             .filter(UserFollowing.user_id == c.default_user_id)\
@@ -115,7 +122,10 @@
 
         c.repos_list = [('', _('--REMOVE FORK--'))]
         c.repos_list += [(x.repo_id, x.repo_name) for x in
-                   Repository.query().order_by(Repository.repo_name).all()]
+                    Repository.query().order_by(Repository.repo_name).all()
+                    if x.repo_id != c.repo_info.repo_id]
+
+        defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
         return defaults
 
     @HasPermissionAllDecorator('hg.admin')
@@ -123,9 +133,45 @@
         """GET /repos: All items in the collection"""
         # url('repos')
 
-        c.repos_list = ScmModel().get_repos(Repository.query()
-                                            .order_by(Repository.repo_name)
-                                            .all(), sort_key='name_sort')
+        c.repos_list = Repository.query()\
+                        .order_by(Repository.repo_name)\
+                        .all()
+
+        repos_data = []
+        total_records = len(c.repos_list)
+
+        _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
+        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
+
+        quick_menu = lambda repo_name: (template.get_def("quick_menu")
+                                        .render(repo_name, _=_, h=h, c=c))
+        repo_lnk = lambda name, rtype, private, fork_of: (
+            template.get_def("repo_name")
+            .render(name, rtype, private, fork_of, short_name=False,
+                    admin=True, _=_, h=h, c=c))
+
+        repo_actions = lambda repo_name: (template.get_def("repo_actions")
+                                       .render(repo_name, _=_, h=h, c=c))
+
+        for repo in c.repos_list:
+            repos_data.append({
+                "menu": quick_menu(repo.repo_name),
+                "raw_name": repo.repo_name,
+                "name": repo_lnk(repo.repo_name, repo.repo_type,
+                                 repo.private, repo.fork),
+                "desc": repo.description,
+                "owner": repo.user.username,
+                "action": repo_actions(repo.repo_name),
+            })
+
+        c.data = json.dumps({
+            "totalRecords": total_records,
+            "startIndex": 0,
+            "sort": "name",
+            "dir": "asc",
+            "records": repos_data
+        })
+
         return render('admin/repos/repos.html')
 
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
@@ -137,9 +183,11 @@
         self.__load_defaults()
         form_result = {}
         try:
-            form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
+            form_result = RepoForm(repo_groups=c.repo_groups_choices,
+                                   landing_revs=c.landing_revs_choices)()\
                             .to_python(dict(request.POST))
-            RepoModel().create(form_result, self.rhodecode_user)
+            new_repo = RepoModel().create(form_result,
+                                          self.rhodecode_user.user_id)
             if form_result['clone_uri']:
                 h.flash(_('created repository %s from %s') \
                     % (form_result['repo_name'], form_result['clone_uri']),
@@ -151,11 +199,13 @@
             if request.POST.get('user_created'):
                 # created by regular non admin user
                 action_logger(self.rhodecode_user, 'user_created_repo',
-                              form_result['repo_name_full'], '', self.sa)
+                              form_result['repo_name_full'], self.ip_addr,
+                              self.sa)
             else:
                 action_logger(self.rhodecode_user, 'admin_created_repo',
-                              form_result['repo_name_full'], '', self.sa)
-            Session.commit()
+                              form_result['repo_name_full'], self.ip_addr,
+                              self.sa)
+            Session().commit()
         except formencode.Invalid, errors:
 
             c.new_repo = errors.value['repo_name']
@@ -177,9 +227,9 @@
             msg = _('error occurred during creation of repository %s') \
                     % form_result.get('repo_name')
             h.flash(msg, category='error')
-        if request.POST.get('user_created'):
-            return redirect(url('home'))
-        return redirect(url('repos'))
+            return redirect(url('repos'))
+        #redirect to our new repo !
+        return redirect(url('summary_home', repo_name=new_repo.repo_name))
 
     @HasPermissionAllDecorator('hg.admin')
     def new(self, format='html'):
@@ -202,18 +252,23 @@
         self.__load_defaults()
         repo_model = RepoModel()
         changed_name = repo_name
+        #override the choices with extracted revisions !
+        choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
+        c.landing_revs_choices = choices
+
         _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
-                         repo_groups=c.repo_groups_choices)()
+                         repo_groups=c.repo_groups_choices,
+                         landing_revs=c.landing_revs_choices)()
         try:
             form_result = _form.to_python(dict(request.POST))
             repo = repo_model.update(repo_name, form_result)
             invalidate_cache('get_repo_cached_%s' % repo_name)
-            h.flash(_('Repository %s updated successfully' % repo_name),
+            h.flash(_('Repository %s updated successfully') % repo_name,
                     category='success')
             changed_name = repo.repo_name
             action_logger(self.rhodecode_user, 'admin_updated_repo',
-                              changed_name, '', self.sa)
-            Session.commit()
+                              changed_name, self.ip_addr, self.sa)
+            Session().commit()
         except formencode.Invalid, errors:
             defaults = self.__load_data(repo_name)
             defaults.update(errors.value)
@@ -253,11 +308,11 @@
             return redirect(url('repos'))
         try:
             action_logger(self.rhodecode_user, 'admin_deleted_repo',
-                              repo_name, '', self.sa)
+                              repo_name, self.ip_addr, self.sa)
             repo_model.delete(repo)
             invalidate_cache('get_repo_cached_%s' % repo_name)
             h.flash(_('deleted repository %s') % repo_name, category='success')
-            Session.commit()
+            Session().commit()
         except IntegrityError, e:
             if e.message.find('repositories_fork_id_fkey') != -1:
                 log.error(traceback.format_exc())
@@ -287,7 +342,7 @@
         try:
             RepoModel().revoke_user_permission(repo=repo_name,
                                                user=request.POST['user_id'])
-            Session.commit()
+            Session().commit()
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of repository user'),
@@ -306,7 +361,7 @@
             RepoModel().revoke_users_group_permission(
                 repo=repo_name, group_name=request.POST['users_group_id']
             )
-            Session.commit()
+            Session().commit()
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of repository'
@@ -324,8 +379,9 @@
 
         try:
             RepoModel().delete_stats(repo_name)
-            Session.commit()
+            Session().commit()
         except Exception, e:
+            log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of repository stats'),
                     category='error')
         return redirect(url('edit_repo', repo_name=repo_name))
@@ -340,13 +396,34 @@
 
         try:
             ScmModel().mark_for_invalidation(repo_name)
-            Session.commit()
+            Session().commit()
         except Exception, e:
+            log.error(traceback.format_exc())
             h.flash(_('An error occurred during cache invalidation'),
                     category='error')
         return redirect(url('edit_repo', repo_name=repo_name))
 
     @HasPermissionAllDecorator('hg.admin')
+    def repo_locking(self, repo_name):
+        """
+        Unlock repository when it is locked !
+
+        :param repo_name:
+        """
+
+        try:
+            repo = Repository.get_by_repo_name(repo_name)
+            if request.POST.get('set_lock'):
+                Repository.lock(repo, c.rhodecode_user.user_id)
+            elif request.POST.get('set_unlock'):
+                Repository.unlock(repo)
+        except Exception, e:
+            log.error(traceback.format_exc())
+            h.flash(_('An error occurred during unlocking'),
+                    category='error')
+        return redirect(url('edit_repo', repo_name=repo_name))
+
+    @HasPermissionAllDecorator('hg.admin')
     def repo_public_journal(self, repo_name):
         """
         Set's this repository to be visible in public journal,
@@ -364,7 +441,7 @@
                 self.scm_model.toggle_following_repo(repo_id, user_id)
                 h.flash(_('Updated repository visibility in public journal'),
                         category='success')
-                Session.commit()
+                Session().commit()
             except:
                 h.flash(_('An error occurred during setting this'
                           ' repository in public journal'),
@@ -403,11 +480,11 @@
             repo = ScmModel().mark_as_fork(repo_name, fork_id,
                                     self.rhodecode_user.username)
             fork = repo.fork.repo_name if repo.fork else _('Nothing')
-            Session.commit()
-            h.flash(_('Marked repo %s as fork of %s' % (repo_name,fork)),
+            Session().commit()
+            h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
                     category='success')
         except Exception, e:
-            raise
+            log.error(traceback.format_exc())
             h.flash(_('An error occurred during this operation'),
                     category='error')
 
--- a/rhodecode/controllers/admin/repos_groups.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/repos_groups.py	Sun Sep 02 21:19:54 2012 +0200
@@ -44,7 +44,7 @@
 from rhodecode.model.forms import ReposGroupForm
 from rhodecode.model.meta import Session
 from rhodecode.model.repo import RepoModel
-from webob.exc import HTTPInternalServerError
+from webob.exc import HTTPInternalServerError, HTTPNotFound
 
 log = logging.getLogger(__name__)
 
@@ -74,11 +74,8 @@
         :param group_id:
         """
         self.__load_defaults()
-
-        repo_group = RepoGroup.get(group_id)
-
+        repo_group = RepoGroup.get_or_404(group_id)
         data = repo_group.get_dict()
-
         data['group_name'] = repo_group.name
 
         # fill repository users
@@ -115,7 +112,7 @@
                     group_description=form_result['group_description'],
                     parent=form_result['group_parent_id']
             )
-            Session.commit()
+            Session().commit()
             h.flash(_('created repos group %s') \
                     % form_result['group_name'], category='success')
             #TODO: in futureaction_logger(, '', '', '', self.sa)
@@ -162,7 +159,7 @@
         try:
             form_result = repos_group_form.to_python(dict(request.POST))
             ReposGroupModel().update(id, form_result)
-            Session.commit()
+            Session().commit()
             h.flash(_('updated repos group %s') \
                     % form_result['group_name'], category='success')
             #TODO: in futureaction_logger(, '', '', '', self.sa)
@@ -179,7 +176,7 @@
             h.flash(_('error occurred during update of repos group %s') \
                     % request.POST.get('group_name'), category='error')
 
-        return redirect(url('repos_groups'))
+        return redirect(url('edit_repos_group', id=id))
 
     @HasPermissionAnyDecorator('hg.admin')
     def delete(self, id):
@@ -195,17 +192,18 @@
         repos = gr.repositories.all()
         if repos:
             h.flash(_('This group contains %s repositores and cannot be '
-                      'deleted' % len(repos)),
+                      'deleted') % len(repos),
                     category='error')
             return redirect(url('repos_groups'))
 
         try:
             ReposGroupModel().delete(id)
-            Session.commit()
-            h.flash(_('removed repos group %s' % gr.group_name), category='success')
+            Session().commit()
+            h.flash(_('removed repos group %s') % gr.group_name,
+                    category='success')
             #TODO: in future action_logger(, '', '', '', self.sa)
         except IntegrityError, e:
-            if e.message.find('groups_group_parent_id_fkey') != -1:
+            if str(e.message).find('groups_group_parent_id_fkey') != -1:
                 log.error(traceback.format_exc())
                 h.flash(_('Cannot delete this group it still contains '
                           'subgroups'),
@@ -213,12 +211,12 @@
             else:
                 log.error(traceback.format_exc())
                 h.flash(_('error occurred during deletion of repos '
-                          'group %s' % gr.group_name), category='error')
+                          'group %s') % gr.group_name, category='error')
 
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('error occurred during deletion of repos '
-                      'group %s' % gr.group_name), category='error')
+                      'group %s') % gr.group_name, category='error')
 
         return redirect(url('repos_groups'))
 
@@ -234,7 +232,7 @@
             ReposGroupModel().revoke_user_permission(
                 repos_group=group_name, user=request.POST['user_id']
             )
-            Session.commit()
+            Session().commit()
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of group user'),
@@ -254,7 +252,7 @@
                 repos_group=group_name,
                 group_name=request.POST['users_group_id']
             )
-            Session.commit()
+            Session().commit()
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of group'
@@ -268,8 +266,10 @@
         the group by id view instead
         """
         group_name = group_name.rstrip('/')
-        id_ = RepoGroup.get_by_group_name(group_name).group_id
-        return self.show(id_)
+        id_ = RepoGroup.get_by_group_name(group_name)
+        if id_:
+            return self.show(id_.group_id)
+        raise HTTPNotFound
 
     @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
                                          'group.admin')
@@ -277,12 +277,9 @@
         """GET /repos_groups/id: Show a specific item"""
         # url('repos_group', id=ID)
 
-        c.group = RepoGroup.get(id)
+        c.group = RepoGroup.get_or_404(id)
 
-        if c.group:
-            c.group_repos = c.group.repositories.all()
-        else:
-            return redirect(url('home'))
+        c.group_repos = c.group.repositories.all()
 
         #overwrite our cached list with current filter
         gr_filter = c.group_repos
@@ -292,7 +289,7 @@
 
         c.repo_cnt = 0
 
-        c.groups = self.sa.query(RepoGroup).order_by(RepoGroup.group_name)\
+        c.groups = RepoGroup.query().order_by(RepoGroup.group_name)\
             .filter(RepoGroup.group_parent_id == id).all()
 
         return render('admin/repos_groups/repos_groups.html')
@@ -302,13 +299,12 @@
         """GET /repos_groups/id/edit: Form to edit an existing item"""
         # url('edit_repos_group', id=ID)
 
-        id_ = int(id)
-
-        c.repos_group = RepoGroup.get(id_)
-        defaults = self.__load_data(id_)
+        c.repos_group = ReposGroupModel()._get_repos_group(id)
+        defaults = self.__load_data(c.repos_group.group_id)
 
         # we need to exclude this group from the group list for editing
-        c.repo_groups = filter(lambda x: x[0] != id_, c.repo_groups)
+        c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
+                               c.repo_groups)
 
         return htmlfill.render(
             render('admin/repos_groups/repos_groups_edit.html'),
--- a/rhodecode/controllers/admin/settings.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/settings.py	Sun Sep 02 21:19:54 2012 +0200
@@ -43,9 +43,9 @@
 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
     set_rhodecode_config, repo_name_slug
 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
-    RhodeCodeSetting
+    RhodeCodeSetting, PullRequest, PullRequestReviewers
 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
-    ApplicationUiSettingsForm
+    ApplicationUiSettingsForm, ApplicationVisualisationForm
 from rhodecode.model.scm import ScmModel
 from rhodecode.model.user import UserModel
 from rhodecode.model.db import User
@@ -79,7 +79,7 @@
         # url('admin_settings')
 
         defaults = RhodeCodeSetting.get_app_settings()
-        defaults.update(self.get_hg_ui_settings())
+        defaults.update(self._get_hg_ui_settings())
 
         return htmlfill.render(
             render('admin/settings/settings.html'),
@@ -107,6 +107,7 @@
         #    h.form(url('admin_setting', setting_id=ID),
         #           method='put')
         # url('admin_setting', setting_id=ID)
+
         if setting_id == 'mapping':
             rm_obsolete = request.POST.get('destroy', False)
             log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
@@ -119,122 +120,160 @@
 
             h.flash(_('Repositories successfully'
                       ' rescanned added: %s,removed: %s') % (added, removed),
-                    category='success')
+                      category='success')
 
         if setting_id == 'whoosh':
-            repo_location = self.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)
             run_task(tasks.whoosh_index, repo_location, full_index)
+            h.flash(_('Whoosh reindex task scheduled'), category='success')
 
-            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))
-
-                try:
-                    hgsettings1 = RhodeCodeSetting.get_by_name('title')
-                    hgsettings1.app_settings_value = \
-                        form_result['rhodecode_title']
+            except formencode.Invalid, errors:
+                return htmlfill.render(
+                     render('admin/settings/settings.html'),
+                     defaults=errors.value,
+                     errors=errors.error_dict or {},
+                     prefix_error=False,
+                     encoding="UTF-8"
+                )
 
-                    hgsettings2 = RhodeCodeSetting.get_by_name('realm')
-                    hgsettings2.app_settings_value = \
-                        form_result['rhodecode_realm']
+            try:
+                sett1 = RhodeCodeSetting.get_by_name_or_create('title')
+                sett1.app_settings_value = form_result['rhodecode_title']
+                Session().add(sett1)
 
-                    hgsettings3 = RhodeCodeSetting.get_by_name('ga_code')
-                    hgsettings3.app_settings_value = \
-                        form_result['rhodecode_ga_code']
+                sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
+                sett2.app_settings_value = form_result['rhodecode_realm']
+                Session().add(sett2)
 
-                    self.sa.add(hgsettings1)
-                    self.sa.add(hgsettings2)
-                    self.sa.add(hgsettings3)
-                    self.sa.commit()
-                    set_rhodecode_config(config)
-                    h.flash(_('Updated application settings'),
-                            category='success')
+                sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
+                sett3.app_settings_value = form_result['rhodecode_ga_code']
+                Session().add(sett3)
+
+                Session().commit()
+                set_rhodecode_config(config)
+                h.flash(_('Updated application settings'), category='success')
 
-                except Exception:
-                    log.error(traceback.format_exc())
-                    h.flash(_('error occurred during updating '
-                              'application settings'),
-                            category='error')
+            except Exception:
+                log.error(traceback.format_exc())
+                h.flash(_('error occurred during updating '
+                          'application settings'),
+                          category='error')
 
-                    self.sa.rollback()
+        if setting_id == 'visual':
 
+            application_form = ApplicationVisualisationForm()()
+            try:
+                form_result = application_form.to_python(dict(request.POST))
             except formencode.Invalid, errors:
                 return htmlfill.render(
                      render('admin/settings/settings.html'),
                      defaults=errors.value,
                      errors=errors.error_dict or {},
                      prefix_error=False,
-                     encoding="UTF-8")
+                     encoding="UTF-8"
+                )
+
+            try:
+                sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
+                sett1.app_settings_value = \
+                    form_result['rhodecode_show_public_icon']
+
+                sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
+                sett2.app_settings_value = \
+                    form_result['rhodecode_show_private_icon']
+
+                sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
+                sett3.app_settings_value = \
+                    form_result['rhodecode_stylify_metatags']
 
-        if setting_id == 'mercurial':
+                Session().add(sett1)
+                Session().add(sett2)
+                Session().add(sett3)
+                Session().commit()
+                set_rhodecode_config(config)
+                h.flash(_('Updated visualisation settings'),
+                        category='success')
+
+            except Exception:
+                log.error(traceback.format_exc())
+                h.flash(_('error occurred during updating '
+                          'visualisation settings'),
+                        category='error')
+
+        if setting_id == 'vcs':
             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']
-
-                    #HOOKS
-                    hgsettings3 = self.sa.query(RhodeCodeUi)\
-                    .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
-                    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'])
-
-                    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(
                      render('admin/settings/settings.html'),
                      defaults=errors.value,
                      errors=errors.error_dict or {},
                      prefix_error=False,
-                     encoding="UTF-8")
+                     encoding="UTF-8"
+                )
+
+            try:
+                # fix namespaces for hooks and extensions
+                _f = lambda s: s.replace('.', '_')
+
+                sett = RhodeCodeUi.get_by_key('push_ssl')
+                sett.ui_value = form_result['web_push_ssl']
+                Session().add(sett)
+
+                sett = RhodeCodeUi.get_by_key('/')
+                sett.ui_value = form_result['paths_root_path']
+                Session().add(sett)
+
+                #HOOKS
+                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
+                sett.ui_active = form_result[_f('hooks_%s' %
+                                                RhodeCodeUi.HOOK_UPDATE)]
+                Session().add(sett)
+
+                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
+                sett.ui_active = form_result[_f('hooks_%s' %
+                                                RhodeCodeUi.HOOK_REPO_SIZE)]
+                Session().add(sett)
+
+                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
+                sett.ui_active = form_result[_f('hooks_%s' %
+                                                RhodeCodeUi.HOOK_PUSH)]
+                Session().add(sett)
+
+                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
+                sett.ui_active = form_result[_f('hooks_%s' %
+                                                 RhodeCodeUi.HOOK_PULL)]
+
+                Session().add(sett)
+
+                ## EXTENSIONS
+                sett = RhodeCodeUi.get_by_key('largefiles')
+                sett.ui_active = form_result[_f('extensions_largefiles')]
+                Session().add(sett)
+
+                sett = RhodeCodeUi.get_by_key('hgsubversion')
+                sett.ui_active = form_result[_f('extensions_hgsubversion')]
+                Session().add(sett)
+
+#                sett = RhodeCodeUi.get_by_key('hggit')
+#                sett.ui_active = form_result[_f('extensions_hggit')]
+#                Session().add(sett)
+
+                Session().commit()
+
+                h.flash(_('Updated VCS settings'), category='success')
+
+            except Exception:
+                log.error(traceback.format_exc())
+                h.flash(_('error occurred during updating '
+                          'application settings'), category='error')
 
         if setting_id == 'hooks':
             ui_key = request.POST.get('new_hook_ui_key')
@@ -256,8 +295,8 @@
 
                 if update:
                     h.flash(_('Updated hooks'), category='success')
-                self.sa.commit()
-            except:
+                Session().commit()
+            except Exception:
                 log.error(traceback.format_exc())
                 h.flash(_('error occurred during hook creation'),
                         category='error')
@@ -293,7 +332,7 @@
         if setting_id == 'hooks':
             hook_id = request.POST.get('hook_id')
             RhodeCodeUi.delete(hook_id)
-            self.sa.commit()
+            Session().commit()
 
     @HasPermissionAllDecorator('hg.admin')
     def show(self, setting_id, format='html'):
@@ -326,7 +365,7 @@
         # url('admin_settings_my_account')
 
         c.user = User.get(self.rhodecode_user.user_id)
-        all_repos = self.sa.query(Repository)\
+        all_repos = Session().query(Repository)\
                      .filter(Repository.user_id == c.user.user_id)\
                      .order_by(func.lower(Repository.repo_name)).all()
 
@@ -338,13 +377,16 @@
             return redirect(url('users'))
 
         defaults = c.user.get_dict()
-        return htmlfill.render(
-            render('admin/users/user_edit_my_account.html'),
+
+        c.form = htmlfill.render(
+            render('admin/users/user_edit_my_account_form.html'),
             defaults=defaults,
             encoding="UTF-8",
             force_defaults=False
         )
+        return render('admin/users/user_edit_my_account.html')
 
+    @NotAnonymous()
     def my_account_update(self):
         """PUT /_admin/my_account_update: Update an existing item"""
         # Forms posted to this method should contain a hidden field:
@@ -353,32 +395,27 @@
         #    h.form(url('admin_settings_my_account_update'),
         #           method='put')
         # url('admin_settings_my_account_update', id=ID)
-        user_model = UserModel()
         uid = self.rhodecode_user.user_id
+        email = self.rhodecode_user.email
         _form = UserForm(edit=True,
-                         old_data={'user_id': uid,
-                                   'email': self.rhodecode_user.email})()
+                         old_data={'user_id': uid, 'email': email})()
         form_result = {}
         try:
             form_result = _form.to_python(dict(request.POST))
-            user_model.update_my_account(uid, form_result)
+            UserModel().update_my_account(uid, form_result)
             h.flash(_('Your account was updated successfully'),
                     category='success')
-            Session.commit()
+            Session().commit()
         except formencode.Invalid, errors:
             c.user = User.get(self.rhodecode_user.user_id)
-            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'),
+            c.form = htmlfill.render(
+                render('admin/users/user_edit_my_account_form.html'),
                 defaults=errors.value,
                 errors=errors.error_dict or {},
                 prefix_error=False,
                 encoding="UTF-8")
+            return render('admin/users/user_edit_my_account.html')
         except Exception:
             log.error(traceback.format_exc())
             h.flash(_('error occurred during update of user %s') \
@@ -387,20 +424,43 @@
         return redirect(url('my_account'))
 
     @NotAnonymous()
+    def my_account_my_repos(self):
+        all_repos = Session().query(Repository)\
+            .filter(Repository.user_id == self.rhodecode_user.user_id)\
+            .order_by(func.lower(Repository.repo_name))\
+            .all()
+        c.user_repos = ScmModel().get_repos(all_repos)
+        return render('admin/users/user_edit_my_account_repos.html')
+
+    @NotAnonymous()
+    def my_account_my_pullrequests(self):
+        c.my_pull_requests = PullRequest.query()\
+                                .filter(PullRequest.user_id==
+                                        self.rhodecode_user.user_id)\
+                                .all()
+        c.participate_in_pull_requests = \
+            [x.pull_request for x in PullRequestReviewers.query()\
+                                    .filter(PullRequestReviewers.user_id==
+                                            self.rhodecode_user.user_id)\
+                                    .all()]
+        return render('admin/users/user_edit_my_account_pullrequests.html')
+
+    @NotAnonymous()
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
     def create_repository(self):
         """GET /_admin/create_repository: Form to create a new item"""
 
         c.repo_groups = RepoGroup.groups_choices()
         c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
+        choices, c.landing_revs = ScmModel().get_repo_landing_revs()
 
         new_repo = request.GET.get('repo', '')
         c.new_repo = 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()
+    def _get_hg_ui_settings(self):
+        ret = RhodeCodeUi.query().all()
 
         if not ret:
             raise Exception('Could not get application ui settings !')
@@ -414,7 +474,7 @@
             if k.find('.') != -1:
                 k = k.replace('.', '_')
 
-            if each.ui_section == 'hooks':
+            if each.ui_section in ['hooks', 'extensions']:
                 v = each.ui_active
 
             settings[each.ui_section + '_' + k] = v
--- a/rhodecode/controllers/admin/users.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/users.py	Sun Sep 02 21:19:54 2012 +0200
@@ -26,22 +26,28 @@
 import logging
 import traceback
 import formencode
+from pylons import response
 
 from formencode import htmlfill
 from pylons import request, session, tmpl_context as c, url, config
 from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
 
+import rhodecode
 from rhodecode.lib.exceptions import DefaultUserException, \
     UserOwnsReposException
 from rhodecode.lib import helpers as h
-from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
+from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
+    AuthUser
 from rhodecode.lib.base import BaseController, render
 
-from rhodecode.model.db import User, Permission
+from rhodecode.model.db import User, UserEmailMap
 from rhodecode.model.forms import UserForm
 from rhodecode.model.user import UserModel
 from rhodecode.model.meta import Session
+from rhodecode.lib.utils import action_logger
+from rhodecode.lib.compat import json
+from rhodecode.lib.utils2 import datetime_to_time, str2bool
 
 log = logging.getLogger(__name__)
 
@@ -64,7 +70,49 @@
         """GET /users: All items in the collection"""
         # url('users')
 
-        c.users_list = self.sa.query(User).all()
+        c.users_list = User.query().order_by(User.username).all()
+
+        users_data = []
+        total_records = len(c.users_list)
+        _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
+        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
+
+        grav_tmpl = lambda user_email, size: (
+                template.get_def("user_gravatar")
+                .render(user_email, size, _=_, h=h, c=c))
+
+        user_lnk = lambda user_id, username: (
+                template.get_def("user_name")
+                .render(user_id, username, _=_, h=h, c=c))
+
+        user_actions = lambda user_id, username: (
+                template.get_def("user_actions")
+                .render(user_id, username, _=_, h=h, c=c))
+
+        for user in c.users_list:
+
+            users_data.append({
+                "gravatar": grav_tmpl(user. email, 24),
+                "raw_username": user.username,
+                "username": user_lnk(user.user_id, user.username),
+                "firstname": user.name,
+                "lastname": user.lastname,
+                "last_login": h.fmt_date(user.last_login),
+                "last_login_raw": datetime_to_time(user.last_login),
+                "active": h.bool2icon(user.active),
+                "admin": h.bool2icon(user.admin),
+                "ldap": h.bool2icon(bool(user.ldap_dn)),
+                "action": user_actions(user.user_id, user.username),
+            })
+
+        c.data = json.dumps({
+            "totalRecords": total_records,
+            "startIndex": 0,
+            "sort": None,
+            "dir": "asc",
+            "records": users_data
+        })
+
         return render('admin/users/users.html')
 
     def create(self):
@@ -76,10 +124,12 @@
         try:
             form_result = user_form.to_python(dict(request.POST))
             user_model.create(form_result)
-            h.flash(_('created user %s') % form_result['username'],
+            usr = form_result['username']
+            action_logger(self.rhodecode_user, 'admin_created_user:%s' % usr,
+                          None, self.ip_addr, self.sa)
+            h.flash(_('created user %s') % usr,
                     category='success')
-            Session.commit()
-            #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
+            Session().commit()
         except formencode.Invalid, errors:
             return htmlfill.render(
                 render('admin/users/user_add.html'),
@@ -108,22 +158,31 @@
         # url('user', id=ID)
         user_model = UserModel()
         c.user = user_model.get(id)
-
+        c.perm_user = AuthUser(user_id=id)
         _form = UserForm(edit=True, old_data={'user_id': id,
                                               'email': c.user.email})()
         form_result = {}
         try:
             form_result = _form.to_python(dict(request.POST))
             user_model.update(id, form_result)
+            usr = form_result['username']
+            action_logger(self.rhodecode_user, 'admin_updated_user:%s' % usr,
+                          None, self.ip_addr, self.sa)
             h.flash(_('User updated successfully'), category='success')
-            Session.commit()
+            Session().commit()
         except formencode.Invalid, errors:
+            c.user_email_map = UserEmailMap.query()\
+                            .filter(UserEmailMap.user == c.user).all()
+            defaults = errors.value
             e = errors.error_dict or {}
-            perm = Permission.get_by_key('hg.create.repository')
-            e.update({'create_repo_perm': user_model.has_perm(id, perm)})
+            defaults.update({
+                'create_repo_perm': user_model.has_perm(id, 'hg.create.repository'),
+                'fork_repo_perm': user_model.has_perm(id, 'hg.fork.repository'),
+                '_method': 'put'
+            })
             return htmlfill.render(
                 render('admin/users/user_edit.html'),
-                defaults=errors.value,
+                defaults=defaults,
                 errors=e,
                 prefix_error=False,
                 encoding="UTF-8")
@@ -131,8 +190,7 @@
             log.error(traceback.format_exc())
             h.flash(_('error occurred during update of user %s') \
                     % form_result.get('username'), category='error')
-
-        return redirect(url('users'))
+        return redirect(url('edit_user', id=id))
 
     def delete(self, id):
         """DELETE /users/id: Delete an existing item"""
@@ -142,10 +200,10 @@
         #    h.form(url('delete_user', id=ID),
         #           method='delete')
         # url('user', id=ID)
-        user_model = UserModel()
+        usr = User.get_or_404(id)
         try:
-            user_model.delete(id)
-            Session.commit()
+            UserModel().delete(usr)
+            Session().commit()
             h.flash(_('successfully deleted user'), category='success')
         except (UserOwnsReposException, DefaultUserException), e:
             h.flash(e, category='warning')
@@ -162,19 +220,24 @@
     def edit(self, id, format='html'):
         """GET /users/id/edit: Form to edit an existing item"""
         # url('edit_user', id=ID)
-        c.user = User.get(id)
-        if not c.user:
-            return redirect(url('users'))
+        c.user = User.get_or_404(id)
+
         if c.user.username == 'default':
             h.flash(_("You can't edit this user"), category='warning')
             return redirect(url('users'))
+
+        c.perm_user = AuthUser(user_id=id)
         c.user.permissions = {}
         c.granted_permissions = UserModel().fill_perms(c.user)\
             .permissions['global']
-
+        c.user_email_map = UserEmailMap.query()\
+                        .filter(UserEmailMap.user == c.user).all()
+        user_model = UserModel()
         defaults = c.user.get_dict()
-        perm = Permission.get_by_key('hg.create.repository')
-        defaults.update({'create_repo_perm': UserModel().has_perm(id, perm)})
+        defaults.update({
+            'create_repo_perm': user_model.has_perm(id, 'hg.create.repository'),
+            'fork_repo_perm': user_model.has_perm(id, 'hg.fork.repository'),
+        })
 
         return htmlfill.render(
             render('admin/users/user_edit.html'),
@@ -186,26 +249,72 @@
     def update_perm(self, id):
         """PUT /users_perm/id: Update an existing item"""
         # url('user_perm', id=ID, method='put')
+        usr = User.get_or_404(id)
+        grant_create_perm = str2bool(request.POST.get('create_repo_perm'))
+        grant_fork_perm = str2bool(request.POST.get('fork_repo_perm'))
+        inherit_perms = str2bool(request.POST.get('inherit_default_permissions'))
 
-        grant_perm = request.POST.get('create_repo_perm', False)
         user_model = UserModel()
 
-        if grant_perm:
-            perm = Permission.get_by_key('hg.create.none')
-            user_model.revoke_perm(id, perm)
+        try:
+            usr.inherit_default_permissions = inherit_perms
+            Session().add(usr)
+
+            if grant_create_perm:
+                user_model.revoke_perm(usr, 'hg.create.none')
+                user_model.grant_perm(usr, 'hg.create.repository')
+                h.flash(_("Granted 'repository create' permission to user"),
+                        category='success')
+            else:
+                user_model.revoke_perm(usr, 'hg.create.repository')
+                user_model.grant_perm(usr, 'hg.create.none')
+                h.flash(_("Revoked 'repository create' permission to user"),
+                        category='success')
+
+            if grant_fork_perm:
+                user_model.revoke_perm(usr, 'hg.fork.none')
+                user_model.grant_perm(usr, 'hg.fork.repository')
+                h.flash(_("Granted 'repository fork' permission to user"),
+                        category='success')
+            else:
+                user_model.revoke_perm(usr, 'hg.fork.repository')
+                user_model.grant_perm(usr, 'hg.fork.none')
+                h.flash(_("Revoked 'repository fork' permission to user"),
+                        category='success')
 
-            perm = Permission.get_by_key('hg.create.repository')
-            user_model.grant_perm(id, perm)
-            h.flash(_("Granted 'repository create' permission to user"),
-                    category='success')
-            Session.commit()
-        else:
-            perm = Permission.get_by_key('hg.create.repository')
-            user_model.revoke_perm(id, perm)
+            Session().commit()
+        except Exception:
+            log.error(traceback.format_exc())
+            h.flash(_('An error occurred during permissions saving'),
+                    category='error')
+        return redirect(url('edit_user', id=id))
+
+    def add_email(self, id):
+        """POST /user_emails:Add an existing item"""
+        # url('user_emails', id=ID, method='put')
+
+        #TODO: validation and form !!!
+        email = request.POST.get('new_email')
+        user_model = UserModel()
 
-            perm = Permission.get_by_key('hg.create.none')
-            user_model.grant_perm(id, perm)
-            h.flash(_("Revoked 'repository create' permission to user"),
-                    category='success')
-            Session.commit()
+        try:
+            user_model.add_extra_email(id, email)
+            Session().commit()
+            h.flash(_("Added email %s to user") % email, category='success')
+        except formencode.Invalid, error:
+            msg = error.error_dict['email']
+            h.flash(msg, category='error')
+        except Exception:
+            log.error(traceback.format_exc())
+            h.flash(_('An error occurred during email saving'),
+                    category='error')
         return redirect(url('edit_user', id=id))
+
+    def delete_email(self, id):
+        """DELETE /user_emails_delete/id: Delete an existing item"""
+        # url('user_emails_delete', id=ID, method='delete')
+        user_model = UserModel()
+        user_model.delete_extra_email(id, request.POST.get('del_email'))
+        Session().commit()
+        h.flash(_("Removed email from user"), category='success')
+        return redirect(url('edit_user', id=id))
--- a/rhodecode/controllers/admin/users_groups.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/admin/users_groups.py	Sun Sep 02 21:19:54 2012 +0200
@@ -34,15 +34,16 @@
 
 from rhodecode.lib import helpers as h
 from rhodecode.lib.exceptions import UsersGroupsAssignedException
-from rhodecode.lib.utils2 import safe_unicode
+from rhodecode.lib.utils2 import safe_unicode, str2bool
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 from rhodecode.lib.base import BaseController, render
 
 from rhodecode.model.users_group import UsersGroupModel
 
-from rhodecode.model.db import User, UsersGroup, Permission, UsersGroupToPerm
+from rhodecode.model.db import User, UsersGroup
 from rhodecode.model.forms import UsersGroupForm
 from rhodecode.model.meta import Session
+from rhodecode.lib.utils import action_logger
 
 log = logging.getLogger(__name__)
 
@@ -64,7 +65,7 @@
     def index(self, format='html'):
         """GET /users_groups: All items in the collection"""
         # url('users_groups')
-        c.users_groups_list = self.sa.query(UsersGroup).all()
+        c.users_groups_list = UsersGroup().query().all()
         return render('admin/users_groups/users_groups.html')
 
     def create(self):
@@ -76,10 +77,12 @@
             form_result = users_group_form.to_python(dict(request.POST))
             UsersGroupModel().create(name=form_result['users_group_name'],
                                      active=form_result['users_group_active'])
-            h.flash(_('created users group %s') \
-                    % form_result['users_group_name'], category='success')
-            #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
-            Session.commit()
+            gr = form_result['users_group_name']
+            action_logger(self.rhodecode_user,
+                          'admin_created_users_group:%s' % gr,
+                          None, self.ip_addr, self.sa)
+            h.flash(_('created users group %s') % gr, category='success')
+            Session().commit()
         except formencode.Invalid, errors:
             return htmlfill.render(
                 render('admin/users_groups/users_group_add.html'),
@@ -114,7 +117,7 @@
                            c.group_members_obj]
 
         c.available_members = [(x.user_id, x.username) for x in
-                               self.sa.query(User).all()]
+                               User.query().all()]
 
         available_members = [safe_unicode(x[0]) for x in c.available_members]
 
@@ -125,21 +128,27 @@
         try:
             form_result = users_group_form.to_python(request.POST)
             UsersGroupModel().update(c.users_group, form_result)
-            h.flash(_('updated users group %s') \
-                        % form_result['users_group_name'],
-                    category='success')
-            #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
-            Session.commit()
+            gr = form_result['users_group_name']
+            action_logger(self.rhodecode_user,
+                          'admin_updated_users_group:%s' % gr,
+                          None, self.ip_addr, self.sa)
+            h.flash(_('updated users group %s') % gr, category='success')
+            Session().commit()
         except formencode.Invalid, errors:
+            ug_model = UsersGroupModel()
+            defaults = errors.value
             e = errors.error_dict or {}
-
-            perm = Permission.get_by_key('hg.create.repository')
-            e.update({'create_repo_perm':
-                         UsersGroupModel().has_perm(id, perm)})
+            defaults.update({
+                'create_repo_perm': ug_model.has_perm(id,
+                                                      'hg.create.repository'),
+                'fork_repo_perm': ug_model.has_perm(id,
+                                                    'hg.fork.repository'),
+                '_method': 'put'
+            })
 
             return htmlfill.render(
                 render('admin/users_groups/users_group_edit.html'),
-                defaults=errors.value,
+                defaults=defaults,
                 errors=e,
                 prefix_error=False,
                 encoding="UTF-8")
@@ -148,7 +157,7 @@
             h.flash(_('error occurred during update of users group %s') \
                     % request.POST.get('users_group_name'), category='error')
 
-        return redirect(url('users_groups'))
+        return redirect(url('edit_users_group', id=id))
 
     def delete(self, id):
         """DELETE /users_groups/id: Delete an existing item"""
@@ -158,10 +167,10 @@
         #    h.form(url('users_group', id=ID),
         #           method='delete')
         # url('users_group', id=ID)
-
+        usr_gr = UsersGroup.get_or_404(id)
         try:
-            UsersGroupModel().delete(id)
-            Session.commit()
+            UsersGroupModel().delete(usr_gr)
+            Session().commit()
             h.flash(_('successfully deleted users group'), category='success')
         except UsersGroupsAssignedException, e:
             h.flash(e, category='error')
@@ -179,20 +188,23 @@
         """GET /users_groups/id/edit: Form to edit an existing item"""
         # url('edit_users_group', id=ID)
 
-        c.users_group = self.sa.query(UsersGroup).get(id)
-        if not c.users_group:
-            return redirect(url('users_groups'))
+        c.users_group = UsersGroup.get_or_404(id)
 
         c.users_group.permissions = {}
         c.group_members_obj = [x.user for x in c.users_group.members]
         c.group_members = [(x.user_id, x.username) for x in
                            c.group_members_obj]
         c.available_members = [(x.user_id, x.username) for x in
-                               self.sa.query(User).all()]
+                               User.query().all()]
+        ug_model = UsersGroupModel()
         defaults = c.users_group.get_dict()
-        perm = Permission.get_by_key('hg.create.repository')
-        defaults.update({'create_repo_perm':
-                         UsersGroupModel().has_perm(c.users_group, perm)})
+        defaults.update({
+            'create_repo_perm': ug_model.has_perm(c.users_group,
+                                                  'hg.create.repository'),
+            'fork_repo_perm': ug_model.has_perm(c.users_group,
+                                                'hg.fork.repository'),
+        })
+
         return htmlfill.render(
             render('admin/users_groups/users_group_edit.html'),
             defaults=defaults,
@@ -204,25 +216,43 @@
         """PUT /users_perm/id: Update an existing item"""
         # url('users_group_perm', id=ID, method='put')
 
-        grant_perm = request.POST.get('create_repo_perm', False)
+        users_group = UsersGroup.get_or_404(id)
+        grant_create_perm = str2bool(request.POST.get('create_repo_perm'))
+        grant_fork_perm = str2bool(request.POST.get('fork_repo_perm'))
+        inherit_perms = str2bool(request.POST.get('inherit_default_permissions'))
 
-        if grant_perm:
-            perm = Permission.get_by_key('hg.create.none')
-            UsersGroupModel().revoke_perm(id, perm)
+        usersgroup_model = UsersGroupModel()
 
-            perm = Permission.get_by_key('hg.create.repository')
-            UsersGroupModel().grant_perm(id, perm)
-            h.flash(_("Granted 'repository create' permission to user"),
-                    category='success')
+        try:
+            users_group.inherit_default_permissions = inherit_perms
+            Session().add(users_group)
 
-            Session.commit()
-        else:
-            perm = Permission.get_by_key('hg.create.repository')
-            UsersGroupModel().revoke_perm(id, perm)
+            if grant_create_perm:
+                usersgroup_model.revoke_perm(id, 'hg.create.none')
+                usersgroup_model.grant_perm(id, 'hg.create.repository')
+                h.flash(_("Granted 'repository create' permission to users group"),
+                        category='success')
+            else:
+                usersgroup_model.revoke_perm(id, 'hg.create.repository')
+                usersgroup_model.grant_perm(id, 'hg.create.none')
+                h.flash(_("Revoked 'repository create' permission to users group"),
+                        category='success')
 
-            perm = Permission.get_by_key('hg.create.none')
-            UsersGroupModel().grant_perm(id, perm)
-            h.flash(_("Revoked 'repository create' permission to user"),
-                    category='success')
-            Session.commit()
+            if grant_fork_perm:
+                usersgroup_model.revoke_perm(id, 'hg.fork.none')
+                usersgroup_model.grant_perm(id, 'hg.fork.repository')
+                h.flash(_("Granted 'repository fork' permission to users group"),
+                        category='success')
+            else:
+                usersgroup_model.revoke_perm(id, 'hg.fork.repository')
+                usersgroup_model.grant_perm(id, 'hg.fork.none')
+                h.flash(_("Revoked 'repository fork' permission to users group"),
+                        category='success')
+
+            Session().commit()
+        except Exception:
+            log.error(traceback.format_exc())
+            h.flash(_('An error occurred during permissions saving'),
+                    category='error')
+
         return redirect(url('edit_users_group', id=id))
--- a/rhodecode/controllers/api/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/api/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -30,6 +30,7 @@
 import types
 import urllib
 import traceback
+import time
 
 from rhodecode.lib.compat import izip_longest, json
 
@@ -43,6 +44,8 @@
 
 from rhodecode.model.db import User
 from rhodecode.lib.auth import AuthUser
+from rhodecode.lib.base import _get_ip_addr, _get_access_path
+from rhodecode.lib.utils2 import safe_unicode
 
 log = logging.getLogger('JSONRPC')
 
@@ -57,15 +60,16 @@
         return str(self.message)
 
 
-def jsonrpc_error(message, code=None):
+def jsonrpc_error(message, retid=None, code=None):
     """
     Generate a Response object with a JSON-RPC error body
     """
     from pylons.controllers.util import Response
-    resp = Response(body=json.dumps(dict(id=None, result=None, error=message)),
-                    status=code,
-                    content_type='application/json')
-    return resp
+    return Response(
+            body=json.dumps(dict(id=retid, result=None, error=message)),
+            status=code,
+            content_type='application/json'
+    )
 
 
 class JSONRPCController(WSGIController):
@@ -94,9 +98,12 @@
         Parse the request body as JSON, look up the method on the
         controller and if it exists, dispatch to it.
         """
+        start = time.time()
+        self._req_id = None
         if 'CONTENT_LENGTH' not in environ:
             log.debug("No Content-Length")
-            return jsonrpc_error(message="No Content-Length in request")
+            return jsonrpc_error(retid=self._req_id,
+                                 message="No Content-Length in request")
         else:
             length = environ['CONTENT_LENGTH'] or 0
             length = int(environ['CONTENT_LENGTH'])
@@ -104,7 +111,8 @@
 
         if length == 0:
             log.debug("Content-Length is 0")
-            return jsonrpc_error(message="Content-Length is 0")
+            return jsonrpc_error(retid=self._req_id,
+                                 message="Content-Length is 0")
 
         raw_body = environ['wsgi.input'].read(length)
 
@@ -112,7 +120,8 @@
             json_body = json.loads(urllib.unquote_plus(raw_body))
         except ValueError, e:
             # catch JSON errors Here
-            return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \
+            return jsonrpc_error(retid=self._req_id,
+                                 message="JSON parse error ERR:%s RAW:%r" \
                                  % (e, urllib.unquote_plus(raw_body)))
 
         # check AUTH based on API KEY
@@ -126,22 +135,26 @@
                                             self._request_params)
             )
         except KeyError, e:
-            return jsonrpc_error(message='Incorrect JSON query missing %s' % e)
+            return jsonrpc_error(retid=self._req_id,
+                                 message='Incorrect JSON query missing %s' % e)
 
         # check if we can find this session using api_key
         try:
             u = User.get_by_api_key(self._req_api_key)
             if u is None:
-                return jsonrpc_error(message='Invalid API KEY')
+                return jsonrpc_error(retid=self._req_id,
+                                     message='Invalid API KEY')
             auth_u = AuthUser(u.user_id, self._req_api_key)
         except Exception, e:
-            return jsonrpc_error(message='Invalid API KEY')
+            return jsonrpc_error(retid=self._req_id,
+                                 message='Invalid API KEY')
 
         self._error = None
         try:
             self._func = self._find_method()
         except AttributeError, e:
-            return jsonrpc_error(message=str(e))
+            return jsonrpc_error(retid=self._req_id,
+                                 message=str(e))
 
         # now that we have a method, add self._req_params to
         # self.kargs and dispatch control to WGIController
@@ -164,9 +177,12 @@
         USER_SESSION_ATTR = 'apiuser'
 
         if USER_SESSION_ATTR not in arglist:
-            return jsonrpc_error(message='This method [%s] does not support '
-                                 'authentication (missing %s param)' %
-                                 (self._func.__name__, USER_SESSION_ATTR))
+            return jsonrpc_error(
+                retid=self._req_id,
+                message='This method [%s] does not support '
+                         'authentication (missing %s param)' % (
+                                    self._func.__name__, USER_SESSION_ATTR)
+            )
 
         # get our arglist and check if we provided them as args
         for arg, default in func_kwargs.iteritems():
@@ -179,6 +195,7 @@
             # NotImplementedType (default_empty)
             if (default == default_empty and arg not in self._request_params):
                 return jsonrpc_error(
+                    retid=self._req_id,
                     message=(
                         'Missing non optional `%s` arg in JSON DATA' % arg
                     )
@@ -205,7 +222,10 @@
         headers.append(('Content-Length', str(len(output[0]))))
         replace_header(headers, 'Content-Type', 'application/json')
         start_response(status[0], headers, exc_info[0])
-
+        log.info('IP: %s Request to %s time: %.3fs' % (
+            _get_ip_addr(environ),
+            safe_unicode(_get_access_path(environ)), time.time() - start)
+        )
         return output
 
     def _dispatch_call(self):
--- a/rhodecode/controllers/api/api.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/api/api.py	Sun Sep 02 21:19:54 2012 +0200
@@ -31,18 +31,100 @@
 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
 from rhodecode.lib.auth import HasPermissionAllDecorator, \
     HasPermissionAnyDecorator, PasswordGenerator, AuthUser
-
+from rhodecode.lib.utils import map_groups, repo2db_mapper
 from rhodecode.model.meta import Session
 from rhodecode.model.scm import ScmModel
-from rhodecode.model.db import User, UsersGroup, Repository
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.user import UserModel
 from rhodecode.model.users_group import UsersGroupModel
-from rhodecode.lib.utils import map_groups
+from rhodecode.model.permission import PermissionModel
+from rhodecode.model.db import Repository
 
 log = logging.getLogger(__name__)
 
 
+class Optional(object):
+    """
+    Defines an optional parameter::
+
+        param = param.getval() if isinstance(param, Optional) else param
+        param = param() if isinstance(param, Optional) else param
+
+    is equivalent of::
+
+        param = Optional.extract(param)
+
+    """
+    def __init__(self, type_):
+        self.type_ = type_
+
+    def __repr__(self):
+        return '<Optional:%s>' % self.type_.__repr__()
+
+    def __call__(self):
+        return self.getval()
+
+    def getval(self):
+        """
+        returns value from this Optional instance
+        """
+        return self.type_
+
+    @classmethod
+    def extract(cls, val):
+        if isinstance(val, cls):
+            return val.getval()
+        return val
+
+
+def get_user_or_error(userid):
+    """
+    Get user by id or name or return JsonRPCError if not found
+
+    :param userid:
+    """
+    user = UserModel().get_user(userid)
+    if user is None:
+        raise JSONRPCError("user `%s` does not exist" % userid)
+    return user
+
+
+def get_repo_or_error(repoid):
+    """
+    Get repo by id or name or return JsonRPCError if not found
+
+    :param userid:
+    """
+    repo = RepoModel().get_repo(repoid)
+    if repo is None:
+        raise JSONRPCError('repository `%s` does not exist' % (repoid))
+    return repo
+
+
+def get_users_group_or_error(usersgroupid):
+    """
+    Get users group by id or name or return JsonRPCError if not found
+
+    :param userid:
+    """
+    users_group = UsersGroupModel().get_group(usersgroupid)
+    if users_group is None:
+        raise JSONRPCError('users group `%s` does not exist' % usersgroupid)
+    return users_group
+
+
+def get_perm_or_error(permid):
+    """
+    Get permission by id or name or return JsonRPCError if not found
+
+    :param userid:
+    """
+    perm = PermissionModel().get_permission_by_name(permid)
+    if perm is None:
+        raise JSONRPCError('permission `%s` does not exist' % (permid))
+    return perm
+
+
 class ApiController(JSONRPCController):
     """
     API Controller
@@ -60,23 +142,74 @@
     """
 
     @HasPermissionAllDecorator('hg.admin')
-    def pull(self, apiuser, repo_name):
+    def pull(self, apiuser, repoid):
         """
         Dispatch pull action on given repo
 
+        :param apiuser:
+        :param repoid:
+        """
 
-        :param user:
-        :param repo_name:
+        repo = get_repo_or_error(repoid)
+
+        try:
+            ScmModel().pull_changes(repo.repo_name,
+                                    self.rhodecode_user.username)
+            return 'Pulled from `%s`' % repo.repo_name
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError(
+                'Unable to pull changes from `%s`' % repo.repo_name
+            )
+
+    @HasPermissionAllDecorator('hg.admin')
+    def rescan_repos(self, apiuser, remove_obsolete=Optional(False)):
+        """
+        Dispatch rescan repositories action. If remove_obsolete is set
+        than also delete repos that are in database but not in the filesystem.
+        aka "clean zombies"
+
+        :param apiuser:
+        :param remove_obsolete:
         """
 
-        if Repository.is_valid(repo_name) is False:
-            raise JSONRPCError('Unknown repo "%s"' % repo_name)
-
         try:
-            ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
-            return 'Pulled from %s' % repo_name
+            rm_obsolete = Optional.extract(remove_obsolete)
+            added, removed = repo2db_mapper(ScmModel().repo_scan(),
+                                            remove_obsolete=rm_obsolete)
+            return {'added': added, 'removed': removed}
         except Exception:
-            raise JSONRPCError('Unable to pull changes from "%s"' % repo_name)
+            log.error(traceback.format_exc())
+            raise JSONRPCError(
+                'Error occurred during rescan repositories action'
+            )
+
+    @HasPermissionAllDecorator('hg.admin')
+    def lock(self, apiuser, repoid, userid, locked):
+        """
+        Set locking state on particular repository by given user
+
+        :param apiuser:
+        :param repoid:
+        :param userid:
+        :param locked:
+        """
+        repo = get_repo_or_error(repoid)
+        user = get_user_or_error(userid)
+        locked = bool(locked)
+        try:
+            if locked:
+                Repository.lock(repo, user.user_id)
+            else:
+                Repository.unlock(repo)
+
+            return ('User `%s` set lock state for repo `%s` to `%s`'
+                    % (user.username, repo.repo_name, locked))
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError(
+                'Error occurred locking repository `%s`' % repo.repo_name
+            )
 
     @HasPermissionAllDecorator('hg.admin')
     def get_user(self, apiuser, userid):
@@ -84,25 +217,13 @@
         Get a user by username
 
         :param apiuser:
-        :param username:
+        :param userid:
         """
 
-        user = UserModel().get_user(userid)
-        if user is None:
-            return user
-
-        return dict(
-            id=user.user_id,
-            username=user.username,
-            firstname=user.name,
-            lastname=user.lastname,
-            email=user.email,
-            active=user.active,
-            admin=user.admin,
-            ldap_dn=user.ldap_dn,
-            last_login=user.last_login,
-            permissions=AuthUser(user_id=user.user_id).permissions
-        )
+        user = get_user_or_error(userid)
+        data = user.get_api_data()
+        data['permissions'] = AuthUser(user_id=user.user_id).permissions
+        return data
 
     @HasPermissionAllDecorator('hg.admin')
     def get_users(self, apiuser):
@@ -113,124 +234,150 @@
         """
 
         result = []
-        for user in User.getAll():
-            result.append(
-                dict(
-                    id=user.user_id,
-                    username=user.username,
-                    firstname=user.name,
-                    lastname=user.lastname,
-                    email=user.email,
-                    active=user.active,
-                    admin=user.admin,
-                    ldap_dn=user.ldap_dn,
-                    last_login=user.last_login,
-                )
-            )
+        for user in UserModel().get_all():
+            result.append(user.get_api_data())
         return result
 
     @HasPermissionAllDecorator('hg.admin')
-    def create_user(self, apiuser, username, email, password, firstname=None,
-                    lastname=None, active=True, admin=False, ldap_dn=None):
+    def create_user(self, apiuser, username, email, password,
+                    firstname=Optional(None), lastname=Optional(None),
+                    active=Optional(True), admin=Optional(False),
+                    ldap_dn=Optional(None)):
         """
         Create new user
 
         :param apiuser:
         :param username:
+        :param email:
         :param password:
-        :param email:
-        :param name:
+        :param firstname:
         :param lastname:
         :param active:
         :param admin:
         :param ldap_dn:
         """
-        if User.get_by_username(username):
-            raise JSONRPCError("user %s already exist" % username)
+
+        if UserModel().get_by_username(username):
+            raise JSONRPCError("user `%s` already exist" % username)
 
-        if User.get_by_email(email, case_insensitive=True):
-            raise JSONRPCError("email %s already exist" % email)
+        if UserModel().get_by_email(email, case_insensitive=True):
+            raise JSONRPCError("email `%s` already exist" % email)
 
-        if ldap_dn:
+        if Optional.extract(ldap_dn):
             # generate temporary password if ldap_dn
             password = PasswordGenerator().gen_password(length=8)
 
         try:
-            usr = UserModel().create_or_update(
-                username, password, email, firstname,
-                lastname, active, admin, ldap_dn
+            user = UserModel().create_or_update(
+                username=Optional.extract(username),
+                password=Optional.extract(password),
+                email=Optional.extract(email),
+                firstname=Optional.extract(firstname),
+                lastname=Optional.extract(lastname),
+                active=Optional.extract(active),
+                admin=Optional.extract(admin),
+                ldap_dn=Optional.extract(ldap_dn)
             )
-            Session.commit()
+            Session().commit()
             return dict(
-                id=usr.user_id,
-                msg='created new user %s' % username
+                msg='created new user `%s`' % username,
+                user=user.get_api_data()
             )
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to create user %s' % username)
+            raise JSONRPCError('failed to create user `%s`' % username)
 
     @HasPermissionAllDecorator('hg.admin')
-    def update_user(self, apiuser, userid, username, password, email,
-                    firstname, lastname, active, admin, ldap_dn):
+    def update_user(self, apiuser, userid, username=Optional(None),
+                    email=Optional(None), firstname=Optional(None),
+                    lastname=Optional(None), active=Optional(None),
+                    admin=Optional(None), ldap_dn=Optional(None),
+                    password=Optional(None)):
         """
         Updates given user
 
         :param apiuser:
+        :param userid:
         :param username:
-        :param password:
         :param email:
-        :param name:
+        :param firstname:
         :param lastname:
         :param active:
         :param admin:
         :param ldap_dn:
+        :param password:
         """
-        if not UserModel().get_user(userid):
-            raise JSONRPCError("user %s does not exist" % username)
+
+        user = get_user_or_error(userid)
+
+        # call function and store only updated arguments
+        updates = {}
+
+        def store_update(attr, name):
+            if not isinstance(attr, Optional):
+                updates[name] = attr
 
         try:
-            usr = UserModel().create_or_update(
-                username, password, email, firstname,
-                lastname, active, admin, ldap_dn
-            )
-            Session.commit()
+
+            store_update(username, 'username')
+            store_update(password, 'password')
+            store_update(email, 'email')
+            store_update(firstname, 'name')
+            store_update(lastname, 'lastname')
+            store_update(active, 'active')
+            store_update(admin, 'admin')
+            store_update(ldap_dn, 'ldap_dn')
+
+            user = UserModel().update_user(user, **updates)
+            Session().commit()
             return dict(
-                id=usr.user_id,
-                msg='updated user %s' % username
+                msg='updated user ID:%s %s' % (user.user_id, user.username),
+                user=user.get_api_data()
             )
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to update user %s' % username)
+            raise JSONRPCError('failed to update user `%s`' % userid)
 
     @HasPermissionAllDecorator('hg.admin')
-    def get_users_group(self, apiuser, group_name):
+    def delete_user(self, apiuser, userid):
         """"
-        Get users group by name
+        Deletes an user
 
         :param apiuser:
-        :param group_name:
+        :param userid:
         """
+        user = get_user_or_error(userid)
 
-        users_group = UsersGroup.get_by_group_name(group_name)
-        if not users_group:
-            return None
+        try:
+            UserModel().delete(userid)
+            Session().commit()
+            return dict(
+                msg='deleted user ID:%s %s' % (user.user_id, user.username),
+                user=None
+            )
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError('failed to delete ID:%s %s' % (user.user_id,
+                                                              user.username))
+
+    @HasPermissionAllDecorator('hg.admin')
+    def get_users_group(self, apiuser, usersgroupid):
+        """"
+        Get users group by name or id
+
+        :param apiuser:
+        :param usersgroupid:
+        """
+        users_group = get_users_group_or_error(usersgroupid)
+
+        data = users_group.get_api_data()
 
         members = []
         for user in users_group.members:
             user = user.user
-            members.append(dict(id=user.user_id,
-                            username=user.username,
-                            firstname=user.name,
-                            lastname=user.lastname,
-                            email=user.email,
-                            active=user.active,
-                            admin=user.admin,
-                            ldap=user.ldap_dn))
-
-        return dict(id=users_group.users_group_id,
-                    group_name=users_group.users_group_name,
-                    active=users_group.users_group_active,
-                    members=members)
+            members.append(user.get_api_data())
+        data['members'] = members
+        return data
 
     @HasPermissionAllDecorator('hg.admin')
     def get_users_groups(self, apiuser):
@@ -241,107 +388,96 @@
         """
 
         result = []
-        for users_group in UsersGroup.getAll():
-            members = []
-            for user in users_group.members:
-                user = user.user
-                members.append(dict(id=user.user_id,
-                                username=user.username,
-                                firstname=user.name,
-                                lastname=user.lastname,
-                                email=user.email,
-                                active=user.active,
-                                admin=user.admin,
-                                ldap=user.ldap_dn))
-
-            result.append(dict(id=users_group.users_group_id,
-                                group_name=users_group.users_group_name,
-                                active=users_group.users_group_active,
-                                members=members))
+        for users_group in UsersGroupModel().get_all():
+            result.append(users_group.get_api_data())
         return result
 
     @HasPermissionAllDecorator('hg.admin')
-    def create_users_group(self, apiuser, group_name, active=True):
+    def create_users_group(self, apiuser, group_name, active=Optional(True)):
         """
         Creates an new usergroup
 
+        :param apiuser:
         :param group_name:
         :param active:
         """
 
-        if self.get_users_group(apiuser, group_name):
-            raise JSONRPCError("users group %s already exist" % group_name)
+        if UsersGroupModel().get_by_name(group_name):
+            raise JSONRPCError("users group `%s` already exist" % group_name)
 
         try:
+            active = Optional.extract(active)
             ug = UsersGroupModel().create(name=group_name, active=active)
-            Session.commit()
-            return dict(id=ug.users_group_id,
-                        msg='created new users group %s' % group_name)
+            Session().commit()
+            return dict(
+                msg='created new users group `%s`' % group_name,
+                users_group=ug.get_api_data()
+            )
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to create group %s' % group_name)
+            raise JSONRPCError('failed to create group `%s`' % group_name)
 
     @HasPermissionAllDecorator('hg.admin')
-    def add_user_to_users_group(self, apiuser, group_name, username):
+    def add_user_to_users_group(self, apiuser, usersgroupid, userid):
         """"
         Add a user to a users group
 
         :param apiuser:
-        :param group_name:
-        :param username:
+        :param usersgroupid:
+        :param userid:
         """
+        user = get_user_or_error(userid)
+        users_group = get_users_group_or_error(usersgroupid)
 
         try:
-            users_group = UsersGroup.get_by_group_name(group_name)
-            if not users_group:
-                raise JSONRPCError('unknown users group %s' % group_name)
-
-            user = User.get_by_username(username)
-            if user is None:
-                raise JSONRPCError('unknown user %s' % username)
-
             ugm = UsersGroupModel().add_user_to_group(users_group, user)
             success = True if ugm != True else False
-            msg = 'added member %s to users group %s' % (username, group_name)
+            msg = 'added member `%s` to users group `%s`' % (
+                        user.username, users_group.users_group_name
+                    )
             msg = msg if success else 'User is already in that group'
-            Session.commit()
+            Session().commit()
 
             return dict(
-                id=ugm.users_group_member_id if ugm != True else None,
                 success=success,
                 msg=msg
             )
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to add users group member')
+            raise JSONRPCError(
+                'failed to add member to users group `%s`' % (
+                    users_group.users_group_name
+                )
+            )
 
     @HasPermissionAllDecorator('hg.admin')
-    def remove_user_from_users_group(self, apiuser, group_name, username):
+    def remove_user_from_users_group(self, apiuser, usersgroupid, userid):
         """
         Remove user from a group
 
-        :param apiuser
-        :param group_name
-        :param username
+        :param apiuser:
+        :param usersgroupid:
+        :param userid:
         """
+        user = get_user_or_error(userid)
+        users_group = get_users_group_or_error(usersgroupid)
 
         try:
-            users_group = UsersGroup.get_by_group_name(group_name)
-            if not users_group:
-                raise JSONRPCError('unknown users group %s' % group_name)
-
-            user = User.get_by_username(username)
-            if user is None:
-                raise JSONRPCError('unknown user %s' % username)
-
-            success = UsersGroupModel().remove_user_from_group(users_group, user)
-            msg = 'removed member %s from users group %s' % (username, group_name)
+            success = UsersGroupModel().remove_user_from_group(users_group,
+                                                               user)
+            msg = 'removed member `%s` from users group `%s`' % (
+                        user.username, users_group.users_group_name
+                    )
             msg = msg if success else "User wasn't in group"
-            Session.commit()
+            Session().commit()
             return dict(success=success, msg=msg)
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to remove user from group')
+            raise JSONRPCError(
+                'failed to remove member from users group `%s`' % (
+                        users_group.users_group_name
+                    )
+            )
 
     @HasPermissionAnyDecorator('hg.admin')
     def get_repo(self, apiuser, repoid):
@@ -349,51 +485,30 @@
         Get repository by name
 
         :param apiuser:
-        :param repo_name:
+        :param repoid:
         """
-
-        repo = RepoModel().get_repo(repoid)
-        if repo is None:
-            raise JSONRPCError('unknown repository %s' % repo)
+        repo = get_repo_or_error(repoid)
 
         members = []
         for user in repo.repo_to_perm:
             perm = user.permission.permission_name
             user = user.user
-            members.append(
-                dict(
-                    type="user",
-                    id=user.user_id,
-                    username=user.username,
-                    firstname=user.name,
-                    lastname=user.lastname,
-                    email=user.email,
-                    active=user.active,
-                    admin=user.admin,
-                    ldap=user.ldap_dn,
-                    permission=perm
-                )
-            )
+            user_data = user.get_api_data()
+            user_data['type'] = "user"
+            user_data['permission'] = perm
+            members.append(user_data)
+
         for users_group in repo.users_group_to_perm:
             perm = users_group.permission.permission_name
             users_group = users_group.users_group
-            members.append(
-                dict(
-                    type="users_group",
-                    id=users_group.users_group_id,
-                    name=users_group.users_group_name,
-                    active=users_group.users_group_active,
-                    permission=perm
-                )
-            )
+            users_group_data = users_group.get_api_data()
+            users_group_data['type'] = "users_group"
+            users_group_data['permission'] = perm
+            members.append(users_group_data)
 
-        return dict(
-            id=repo.repo_id,
-            repo_name=repo.repo_name,
-            type=repo.repo_type,
-            description=repo.description,
-            members=members
-        )
+        data = repo.get_api_data()
+        data['members'] = members
+        return data
 
     @HasPermissionAnyDecorator('hg.admin')
     def get_repos(self, apiuser):
@@ -404,19 +519,12 @@
         """
 
         result = []
-        for repository in Repository.getAll():
-            result.append(
-                dict(
-                    id=repository.repo_id,
-                    repo_name=repository.repo_name,
-                    type=repository.repo_type,
-                    description=repository.description
-                )
-            )
+        for repo in RepoModel().get_all():
+            result.append(repo.get_api_data())
         return result
 
     @HasPermissionAnyDecorator('hg.admin')
-    def get_repo_nodes(self, apiuser, repo_name, revision, root_path,
+    def get_repo_nodes(self, apiuser, repoid, revision, root_path,
                        ret_type='all'):
         """
         returns a list of nodes and it's children
@@ -424,13 +532,14 @@
         to show only files or dirs
 
         :param apiuser:
-        :param repo_name: name of repository
+        :param repoid: name or id of repository
         :param revision: revision for which listing should be done
         :param root_path: path from which start displaying
         :param ret_type: return type 'all|files|dirs' nodes
         """
+        repo = get_repo_or_error(repoid)
         try:
-            _d, _f = ScmModel().get_nodes(repo_name, revision, root_path,
+            _d, _f = ScmModel().get_nodes(repo, revision, root_path,
                                           flat=False)
             _map = {
                 'all': _d + _f,
@@ -440,218 +549,264 @@
             return _map[ret_type]
         except KeyError:
             raise JSONRPCError('ret_type must be one of %s' % _map.keys())
-        except Exception, e:
-            raise JSONRPCError(e)
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError(
+                'failed to get repo: `%s` nodes' % repo.repo_name
+            )
 
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
-    def create_repo(self, apiuser, repo_name, owner_name, description='',
-                    repo_type='hg', private=False, clone_uri=None):
+    def create_repo(self, apiuser, repo_name, owner, repo_type,
+                    description=Optional(''), private=Optional(False),
+                    clone_uri=Optional(None), landing_rev=Optional('tip')):
         """
         Create repository, if clone_url is given it makes a remote clone
+        if repo_name is withina  group name the groups will be created
+        automatically if they aren't present
 
         :param apiuser:
         :param repo_name:
-        :param owner_name:
+        :param onwer:
+        :param repo_type:
         :param description:
-        :param repo_type:
         :param private:
         :param clone_uri:
+        :param landing_rev:
         """
+        owner = get_user_or_error(owner)
+
+        if RepoModel().get_by_repo_name(repo_name):
+            raise JSONRPCError("repo `%s` already exist" % repo_name)
+
+        private = Optional.extract(private)
+        clone_uri = Optional.extract(clone_uri)
+        description = Optional.extract(description)
+        landing_rev = Optional.extract(landing_rev)
 
         try:
-            owner = User.get_by_username(owner_name)
-            if owner is None:
-                raise JSONRPCError('unknown user %s' % owner_name)
-
-            if Repository.get_by_repo_name(repo_name):
-                raise JSONRPCError("repo %s already exist" % repo_name)
-
-            groups = repo_name.split(Repository.url_sep())
-            real_name = groups[-1]
-            # create structure of groups
+            # create structure of groups and return the last group
             group = map_groups(repo_name)
 
-            repo = RepoModel().create(
-                dict(
-                    repo_name=real_name,
-                    repo_name_full=repo_name,
-                    description=description,
-                    private=private,
-                    repo_type=repo_type,
-                    repo_group=group.group_id if group else None,
-                    clone_uri=clone_uri
-                ),
-                owner
+            repo = RepoModel().create_repo(
+                repo_name=repo_name,
+                repo_type=repo_type,
+                description=description,
+                owner=owner,
+                private=private,
+                clone_uri=clone_uri,
+                repos_group=group,
+                landing_rev=landing_rev,
             )
-            Session.commit()
+
+            Session().commit()
 
             return dict(
-                id=repo.repo_id,
-                msg="Created new repository %s" % repo.repo_name
+                msg="Created new repository `%s`" % (repo.repo_name),
+                repo=repo.get_api_data()
             )
 
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to create repository %s' % repo_name)
+            raise JSONRPCError('failed to create repository `%s`' % repo_name)
 
     @HasPermissionAnyDecorator('hg.admin')
-    def delete_repo(self, apiuser, repo_name):
-        """
-        Deletes a given repository
+    def fork_repo(self, apiuser, repoid, fork_name, owner,
+                  description=Optional(''), copy_permissions=Optional(False),
+                  private=Optional(False), landing_rev=Optional('tip')):
+        repo = get_repo_or_error(repoid)
+        repo_name = repo.repo_name
+        owner = get_user_or_error(owner)
+
+        _repo = RepoModel().get_by_repo_name(fork_name)
+        if _repo:
+            type_ = 'fork' if _repo.fork else 'repo'
+            raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
+
+        try:
+            # create structure of groups and return the last group
+            group = map_groups(fork_name)
 
-        :param repo_name:
-        """
-        if not Repository.get_by_repo_name(repo_name):
-            raise JSONRPCError("repo %s does not exist" % repo_name)
-        try:
-            RepoModel().delete(repo_name)
-            Session.commit()
+            form_data = dict(
+                repo_name=fork_name,
+                repo_name_full=fork_name,
+                repo_group=group,
+                repo_type=repo.repo_type,
+                description=Optional.extract(description),
+                private=Optional.extract(private),
+                copy_permissions=Optional.extract(copy_permissions),
+                landing_rev=Optional.extract(landing_rev),
+                update_after_clone=False,
+                fork_parent_id=repo.repo_id,
+            )
+            RepoModel().create_fork(form_data, cur_user=owner)
             return dict(
-                msg='Deleted repository %s' % repo_name
+                msg='Created fork of `%s` as `%s`' % (repo.repo_name,
+                                                      fork_name),
+                success=True  # cannot return the repo data here since fork
+                              # cann be done async
             )
         except Exception:
             log.error(traceback.format_exc())
-            raise JSONRPCError('failed to delete repository %s' % repo_name)
+            raise JSONRPCError(
+                'failed to fork repository `%s` as `%s`' % (repo_name,
+                                                            fork_name)
+            )
 
     @HasPermissionAnyDecorator('hg.admin')
-    def grant_user_permission(self, apiuser, repo_name, username, perm):
+    def delete_repo(self, apiuser, repoid):
         """
-        Grant permission for user on given repository, or update existing one
-        if found
+        Deletes a given repository
 
-        :param repo_name:
-        :param username:
-        :param perm:
+        :param apiuser:
+        :param repoid:
         """
+        repo = get_repo_or_error(repoid)
 
         try:
-            repo = Repository.get_by_repo_name(repo_name)
-            if repo is None:
-                raise JSONRPCError('unknown repository %s' % repo)
-
-            user = User.get_by_username(username)
-            if user is None:
-                raise JSONRPCError('unknown user %s' % username)
-
-            RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
-
-            Session.commit()
+            RepoModel().delete(repo)
+            Session().commit()
             return dict(
-                msg='Granted perm: %s for user: %s in repo: %s' % (
-                    perm, username, repo_name
-                )
+                msg='Deleted repository `%s`' % repo.repo_name,
+                success=True
             )
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to edit permission %(repo)s for %(user)s' % dict(
-                    user=username, repo=repo_name
+                'failed to delete repository `%s`' % repo.repo_name
+            )
+
+    @HasPermissionAnyDecorator('hg.admin')
+    def grant_user_permission(self, apiuser, repoid, userid, perm):
+        """
+        Grant permission for user on given repository, or update existing one
+        if found
+
+        :param repoid:
+        :param userid:
+        :param perm:
+        """
+        repo = get_repo_or_error(repoid)
+        user = get_user_or_error(userid)
+        perm = get_perm_or_error(perm)
+
+        try:
+
+            RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
+
+            Session().commit()
+            return dict(
+                msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
+                    perm.permission_name, user.username, repo.repo_name
+                ),
+                success=True
+            )
+        except Exception:
+            log.error(traceback.format_exc())
+            raise JSONRPCError(
+                'failed to edit permission for user: `%s` in repo: `%s`' % (
+                    userid, repoid
                 )
             )
 
     @HasPermissionAnyDecorator('hg.admin')
-    def revoke_user_permission(self, apiuser, repo_name, username):
+    def revoke_user_permission(self, apiuser, repoid, userid):
         """
         Revoke permission for user on given repository
 
-        :param repo_name:
-        :param username:
+        :param apiuser:
+        :param repoid:
+        :param userid:
         """
 
+        repo = get_repo_or_error(repoid)
+        user = get_user_or_error(userid)
         try:
-            repo = Repository.get_by_repo_name(repo_name)
-            if repo is None:
-                raise JSONRPCError('unknown repository %s' % repo)
+
+            RepoModel().revoke_user_permission(repo=repo, user=user)
 
-            user = User.get_by_username(username)
-            if user is None:
-                raise JSONRPCError('unknown user %s' % username)
-
-            RepoModel().revoke_user_permission(repo=repo_name, user=username)
-
-            Session.commit()
+            Session().commit()
             return dict(
-                msg='Revoked perm for user: %s in repo: %s' % (
-                    username, repo_name
-                )
+                msg='Revoked perm for user: `%s` in repo: `%s`' % (
+                    user.username, repo.repo_name
+                ),
+                success=True
             )
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to edit permission %(repo)s for %(user)s' % dict(
-                    user=username, repo=repo_name
+                'failed to edit permission for user: `%s` in repo: `%s`' % (
+                    userid, repoid
                 )
             )
 
     @HasPermissionAnyDecorator('hg.admin')
-    def grant_users_group_permission(self, apiuser, repo_name, group_name, perm):
+    def grant_users_group_permission(self, apiuser, repoid, usersgroupid,
+                                     perm):
         """
         Grant permission for users group on given repository, or update
         existing one if found
 
-        :param repo_name:
-        :param group_name:
+        :param apiuser:
+        :param repoid:
+        :param usersgroupid:
         :param perm:
         """
+        repo = get_repo_or_error(repoid)
+        perm = get_perm_or_error(perm)
+        users_group = get_users_group_or_error(usersgroupid)
 
         try:
-            repo = Repository.get_by_repo_name(repo_name)
-            if repo is None:
-                raise JSONRPCError('unknown repository %s' % repo)
-
-            user_group = UsersGroup.get_by_group_name(group_name)
-            if user_group is None:
-                raise JSONRPCError('unknown users group %s' % user_group)
-
-            RepoModel().grant_users_group_permission(repo=repo_name,
-                                                     group_name=group_name,
+            RepoModel().grant_users_group_permission(repo=repo,
+                                                     group_name=users_group,
                                                      perm=perm)
 
-            Session.commit()
+            Session().commit()
             return dict(
-                msg='Granted perm: %s for group: %s in repo: %s' % (
-                    perm, group_name, repo_name
-                )
+                msg='Granted perm: `%s` for users group: `%s` in '
+                    'repo: `%s`' % (
+                    perm.permission_name, users_group.users_group_name,
+                    repo.repo_name
+                ),
+                success=True
             )
         except Exception:
+            print traceback.format_exc()
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to edit permission %(repo)s for %(usersgr)s' % dict(
-                    usersgr=group_name, repo=repo_name
+                'failed to edit permission for users group: `%s` in '
+                'repo: `%s`' % (
+                    usersgroupid, repo.repo_name
                 )
             )
 
     @HasPermissionAnyDecorator('hg.admin')
-    def revoke_users_group_permission(self, apiuser, repo_name, group_name):
+    def revoke_users_group_permission(self, apiuser, repoid, usersgroupid):
         """
         Revoke permission for users group on given repository
 
-        :param repo_name:
-        :param group_name:
+        :param apiuser:
+        :param repoid:
+        :param usersgroupid:
         """
+        repo = get_repo_or_error(repoid)
+        users_group = get_users_group_or_error(usersgroupid)
 
         try:
-            repo = Repository.get_by_repo_name(repo_name)
-            if repo is None:
-                raise JSONRPCError('unknown repository %s' % repo)
-
-            user_group = UsersGroup.get_by_group_name(group_name)
-            if user_group is None:
-                raise JSONRPCError('unknown users group %s' % user_group)
+            RepoModel().revoke_users_group_permission(repo=repo,
+                                                      group_name=users_group)
 
-            RepoModel().revoke_users_group_permission(repo=repo_name,
-                                                      group_name=group_name)
-
-            Session.commit()
+            Session().commit()
             return dict(
-                msg='Revoked perm for group: %s in repo: %s' % (
-                    group_name, repo_name
-                )
+                msg='Revoked perm for users group: `%s` in repo: `%s`' % (
+                    users_group.users_group_name, repo.repo_name
+                ),
+                success=True
             )
         except Exception:
             log.error(traceback.format_exc())
             raise JSONRPCError(
-                'failed to edit permission %(repo)s for %(usersgr)s' % dict(
-                    usersgr=group_name, repo=repo_name
+                'failed to edit permission for users group: `%s` in '
+                'repo: `%s`' % (
+                    users_group.users_group_name, repo.repo_name
                 )
             )
--- a/rhodecode/controllers/branches.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/branches.py	Sun Sep 02 21:19:54 2012 +0200
@@ -24,14 +24,15 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import logging
+import binascii
 
 from pylons import tmpl_context as c
-import binascii
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.compat import OrderedDict
 from rhodecode.lib.utils2 import safe_unicode
+
 log = logging.getLogger(__name__)
 
 
--- a/rhodecode/controllers/changelog.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/changelog.py	Sun Sep 02 21:19:54 2012 +0200
@@ -26,7 +26,6 @@
 import logging
 import traceback
 
-from mercurial import graphmod
 from pylons import request, url, session, tmpl_context as c
 from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
@@ -36,9 +35,8 @@
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.helpers import RepoPage
 from rhodecode.lib.compat import json
-
+from rhodecode.lib.graphmod import _colored, _dagwalker
 from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError
-from rhodecode.model.db import Repository
 
 log = logging.getLogger(__name__)
 
@@ -60,13 +58,13 @@
                 int_size = int(request.params.get('size'))
             except ValueError:
                 int_size = default
-            int_size = int_size if int_size <= limit else limit
-            c.size = int_size
+            c.size = max(min(int_size, limit), 1)
             session['changelog_size'] = c.size
             session.save()
         else:
             c.size = int(session.get('changelog_size', default))
-
+        # min size must be 1
+        c.size = max(c.size, 1)
         p = int(request.params.get('page', 1))
         branch_name = request.params.get('branch', None)
         try:
@@ -83,8 +81,8 @@
                                     items_per_page=c.size, branch=branch_name)
             collection = list(c.pagination)
             page_revisions = [x.raw_id for x in collection]
-            c.comments = c.rhodecode_db_repo.comments(page_revisions)
-
+            c.comments = c.rhodecode_db_repo.get_comments(page_revisions)
+            c.statuses = c.rhodecode_db_repo.statuses(page_revisions)
         except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
             log.error(traceback.format_exc())
             h.flash(str(e), category='warning')
@@ -118,18 +116,9 @@
         data = []
         revs = [x.revision for x in collection]
 
-        if repo.alias == 'git':
-            for _ in revs:
-                vtx = [0, 1]
-                edges = [[0, 0, 1]]
-                data.append(['', vtx, edges])
-
-        elif repo.alias == 'hg':
-            dag = graphmod.dagwalker(repo._repo, revs)
-            c.dag = graphmod.colored(dag, repo._repo)
-            for (id, type, ctx, vtx, edges) in c.dag:
-                if type != graphmod.CHANGESET:
-                    continue
-                data.append(['', vtx, edges])
+        dag = _dagwalker(repo, revs, repo.alias)
+        dag = _colored(dag)
+        for (id, type, ctx, vtx, edges) in dag:
+            data.append(['', vtx, edges])
 
         c.jsdata = json.dumps(data)
--- a/rhodecode/controllers/changeset.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/changeset.py	Sun Sep 02 21:19:54 2012 +0200
@@ -40,13 +40,17 @@
 import rhodecode.lib.helpers as h
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
-from rhodecode.lib.utils import EmptyChangeset
+from rhodecode.lib.utils import action_logger
 from rhodecode.lib.compat import OrderedDict
 from rhodecode.lib import diffs
-from rhodecode.model.db import ChangesetComment
+from rhodecode.model.db import ChangesetComment, ChangesetStatus
 from rhodecode.model.comment import ChangesetCommentsModel
+from rhodecode.model.changeset_status import ChangesetStatusModel
 from rhodecode.model.meta import Session
 from rhodecode.lib.diffs import wrapped_diff
+from rhodecode.model.repo import RepoModel
+from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
 log = logging.getLogger(__name__)
 
@@ -165,6 +169,9 @@
     def __before__(self):
         super(ChangesetController, self).__before__()
         c.affected_files_cut_off = 60
+        repo_model = RepoModel()
+        c.users_array = repo_model.get_users_js()
+        c.users_groups_array = repo_model.get_users_groups_js()
 
     def index(self, revision):
 
@@ -201,18 +208,24 @@
 
         cumulative_diff = 0
         c.cut_off = False  # defines if cut off limit is reached
-
+        c.changeset_statuses = ChangesetStatus.STATUSES
         c.comments = []
+        c.statuses = []
         c.inline_comments = []
         c.inline_cnt = 0
         # Iterate over ranges (default changeset view is always one changeset)
         for changeset in c.cs_ranges:
+
+            c.statuses.extend([ChangesetStatusModel()\
+                              .get_status(c.rhodecode_db_repo.repo_id,
+                                          changeset.raw_id)])
+
             c.comments.extend(ChangesetCommentsModel()\
                               .get_comments(c.rhodecode_db_repo.repo_id,
-                                            changeset.raw_id))
+                                            revision=changeset.raw_id))
             inlines = ChangesetCommentsModel()\
                         .get_inline_comments(c.rhodecode_db_repo.repo_id,
-                                             changeset.raw_id)
+                                             revision=changeset.raw_id)
             c.inline_comments.extend(inlines)
             c.changes[changeset.raw_id] = []
             try:
@@ -284,7 +297,7 @@
                 )
 
         # count inline comments
-        for path, lines in c.inline_comments:
+        for __, lines in c.inline_comments:
             for comments in lines.values():
                 c.inline_cnt += len(comments)
 
@@ -361,15 +374,48 @@
 
     @jsonify
     def comment(self, repo_name, revision):
+        status = request.POST.get('changeset_status')
+        change_status = request.POST.get('change_changeset_status')
+
         comm = ChangesetCommentsModel().create(
             text=request.POST.get('text'),
-            repo_id=c.rhodecode_db_repo.repo_id,
-            user_id=c.rhodecode_user.user_id,
+            repo=c.rhodecode_db_repo.repo_id,
+            user=c.rhodecode_user.user_id,
             revision=revision,
             f_path=request.POST.get('f_path'),
-            line_no=request.POST.get('line')
+            line_no=request.POST.get('line'),
+            status_change=(ChangesetStatus.get_status_lbl(status)
+                           if status and change_status else None)
         )
-        Session.commit()
+
+        # get status if set !
+        if status and change_status:
+            # if latest status was from pull request and it's closed
+            # disallow changing status ! 
+            # dont_allow_on_closed_pull_request = True !
+
+            try:
+                ChangesetStatusModel().set_status(
+                    c.rhodecode_db_repo.repo_id,
+                    status,
+                    c.rhodecode_user.user_id,
+                    comm,
+                    revision=revision,
+                    dont_allow_on_closed_pull_request=True
+                )
+            except StatusChangeOnClosedPullRequestError:
+                log.error(traceback.format_exc())
+                msg = _('Changing status on a changeset associated with'
+                        'a closed pull request is not allowed')
+                h.flash(msg, category='warning')
+                return redirect(h.url('changeset_home', repo_name=repo_name,
+                                      revision=revision))
+        action_logger(self.rhodecode_user,
+                      'user_commented_revision:%s' % revision,
+                      c.rhodecode_db_repo, self.ip_addr, self.sa)
+
+        Session().commit()
+
         if not request.environ.get('HTTP_X_PARTIAL_XHR'):
             return redirect(h.url('changeset_home', repo_name=repo_name,
                                   revision=revision))
@@ -391,7 +437,7 @@
         owner = lambda: co.author.user_id == c.rhodecode_user.user_id
         if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
             ChangesetCommentsModel().delete(comment=co)
-            Session.commit()
+            Session().commit()
             return True
         else:
             raise HTTPForbidden()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/controllers/compare.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.compare
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    compare controller for pylons showoing differences between two
+    repos, branches, bookmarks or tips
+
+    :created_on: May 6, 2012
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+import logging
+import traceback
+
+from webob.exc import HTTPNotFound
+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.vcs.exceptions import EmptyRepositoryError, RepositoryError
+from rhodecode.lib import helpers as h
+from rhodecode.lib.base import BaseRepoController, render
+from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
+from rhodecode.lib import diffs
+
+from rhodecode.model.db import Repository
+from rhodecode.model.pull_request import PullRequestModel
+
+log = logging.getLogger(__name__)
+
+
+class CompareController(BaseRepoController):
+
+    @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')
+    def __before__(self):
+        super(CompareController, self).__before__()
+
+    def __get_cs_or_redirect(self, rev, repo, redirect_after=True):
+        """
+        Safe way to get changeset if error occur it redirects to changeset with
+        proper message
+
+        :param rev: revision to fetch
+        :param repo: repo instance
+        """
+
+        try:
+            type_, rev = rev
+            return repo.scm_instance.get_changeset(rev)
+        except EmptyRepositoryError, e:
+            if not redirect_after:
+                return None
+            h.flash(h.literal(_('There are no changesets yet')),
+                    category='warning')
+            redirect(url('summary_home', repo_name=repo.repo_name))
+
+        except RepositoryError, e:
+            log.error(traceback.format_exc())
+            h.flash(str(e), category='warning')
+            redirect(h.url('summary_home', repo_name=repo.repo_name))
+
+    def index(self, org_ref_type, org_ref, other_ref_type, other_ref):
+
+        org_repo = c.rhodecode_db_repo.repo_name
+        org_ref = (org_ref_type, org_ref)
+        other_ref = (other_ref_type, other_ref)
+        other_repo = request.GET.get('repo', org_repo)
+
+        c.swap_url = h.url('compare_url', repo_name=other_repo,
+              org_ref_type=other_ref[0], org_ref=other_ref[1],
+              other_ref_type=org_ref[0], other_ref=org_ref[1],
+              repo=org_repo)
+
+        c.org_repo = org_repo = Repository.get_by_repo_name(org_repo)
+        c.other_repo = other_repo = Repository.get_by_repo_name(other_repo)
+
+        if c.org_repo is None or c.other_repo is None:
+            log.error('Could not found repo %s or %s' % (org_repo, other_repo))
+            raise HTTPNotFound
+
+        if c.org_repo.scm_instance.alias != 'hg':
+            log.error('Review not available for GIT REPOS')
+            raise HTTPNotFound
+
+        self.__get_cs_or_redirect(rev=org_ref, repo=org_repo)
+        self.__get_cs_or_redirect(rev=other_ref, repo=other_repo)
+
+        c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
+                                       org_repo, org_ref, other_repo, other_ref
+                                      )
+
+        c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
+                                                   c.cs_ranges])
+        c.target_repo = c.repo_name
+        # defines that we need hidden inputs with changesets
+        c.as_form = request.GET.get('as_form', False)
+        if request.environ.get('HTTP_X_PARTIAL_XHR'):
+            return render('compare/compare_cs.html')
+
+        c.org_ref = org_ref[1]
+        c.other_ref = other_ref[1]
+        # diff needs to have swapped org with other to generate proper diff
+        _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
+                             discovery_data)
+        diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
+        _parsed = diff_processor.prepare()
+
+        c.files = []
+        c.changes = {}
+
+        for f in _parsed:
+            fid = h.FID('', f['filename'])
+            c.files.append([fid, f['operation'], f['filename'], f['stats']])
+            diff = diff_processor.as_html(enable_comments=False, diff_lines=[f])
+            c.changes[fid] = [f['operation'], f['filename'], diff]
+
+        return render('compare/compare_diff.html')
--- a/rhodecode/controllers/feed.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/feed.py	Sun Sep 02 21:19:54 2012 +0200
@@ -28,11 +28,12 @@
 from pylons import url, response, tmpl_context as c
 from pylons.i18n.translation import _
 
-from rhodecode.lib.utils2 import safe_unicode
+from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
+
+from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController
-
-from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
+from rhodecode.lib.diffs import DiffProcessor
 
 log = logging.getLogger(__name__)
 
@@ -49,31 +50,36 @@
         self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s')
         self.language = 'en-us'
         self.ttl = "5"
-        self.feed_nr = 10
+        self.feed_nr = 20
 
     def _get_title(self, cs):
-        return "R%s:%s - %s" % (
-            cs.revision, cs.short_id, cs.message
+        return "%s" % (
+            h.shorter(cs.message, 160)
         )
 
     def __changes(self, cs):
         changes = []
 
-        a = [safe_unicode(n.path) for n in cs.added]
-        if a:
-            changes.append('\nA ' + '\nA '.join(a))
-
-        m = [safe_unicode(n.path) for n in cs.changed]
-        if m:
-            changes.append('\nM ' + '\nM '.join(m))
+        diffprocessor = DiffProcessor(cs.diff())
+        stats = diffprocessor.prepare(inline_diff=False)
+        for st in stats:
+            st.update({'added': st['stats'][0],
+                       'removed': st['stats'][1]})
+            changes.append('\n %(operation)s %(filename)s '
+                           '(%(added)s lines added, %(removed)s lines removed)'
+                            % st)
+        return changes
 
-        d = [safe_unicode(n.path) for n in cs.removed]
-        if d:
-            changes.append('\nD ' + '\nD '.join(d))
-
-        changes.append('</pre>')
-
-        return ''.join(changes)
+    def __get_desc(self, cs):
+        desc_msg = []
+        desc_msg.append('%s %s %s:<br/>' % (cs.author, _('commited on'),
+                                           h.fmt_date(cs.date)))
+        desc_msg.append('<pre>')
+        desc_msg.append(cs.message)
+        desc_msg.append('\n')
+        desc_msg.extend(self.__changes(cs))
+        desc_msg.append('</pre>')
+        return desc_msg
 
     def atom(self, repo_name):
         """Produce an atom-1.0 feed via feedgenerator module"""
@@ -87,15 +93,13 @@
         )
 
         for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
-            desc_msg = []
-            desc_msg.append('%s - %s<br/><pre>' % (cs.author, cs.date))
-            desc_msg.append(self.__changes(cs))
-
             feed.add_item(title=self._get_title(cs),
                           link=url('changeset_home', repo_name=repo_name,
                                    revision=cs.raw_id, qualified=True),
                           author_name=cs.author,
-                          description=''.join(desc_msg))
+                          description=''.join(self.__get_desc(cs)),
+                          pubdate=cs.date,
+                          )
 
         response.content_type = feed.mime_type
         return feed.writeString('utf-8')
@@ -112,15 +116,12 @@
         )
 
         for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
-            desc_msg = []
-            desc_msg.append('%s - %s<br/><pre>' % (cs.author, cs.date))
-            desc_msg.append(self.__changes(cs))
-
             feed.add_item(title=self._get_title(cs),
                           link=url('changeset_home', repo_name=repo_name,
                                    revision=cs.raw_id, qualified=True),
                           author_name=cs.author,
-                          description=''.join(desc_msg),
+                          description=''.join(self.__get_desc(cs)),
+                          pubdate=cs.date,
                          )
 
         response.content_type = feed.mime_type
--- a/rhodecode/controllers/files.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/files.py	Sun Sep 02 21:19:54 2012 +0200
@@ -32,7 +32,6 @@
 from pylons.i18n.translation import _
 from pylons.controllers.util import redirect
 from pylons.decorators import jsonify
-from paste.fileapp import FileApp, _FileIter
 
 from rhodecode.lib import diffs
 from rhodecode.lib import helpers as h
@@ -41,7 +40,7 @@
 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
-from rhodecode.lib.utils import EmptyChangeset
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
 from rhodecode.lib.vcs.conf import settings
 from rhodecode.lib.vcs.exceptions import RepositoryError, \
     ChangesetDoesNotExistError, EmptyRepositoryError, \
@@ -61,7 +60,6 @@
 
 class FilesController(BaseRepoController):
 
-    @LoginRequired()
     def __before__(self):
         super(FilesController, self).__before__()
         c.cut_off_limit = self.cut_off_limit
@@ -83,8 +81,8 @@
             url_ = url('files_add_home',
                        repo_name=c.repo_name,
                        revision=0, f_path='')
-            add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
-            h.flash(h.literal(_('There are no files yet %s' % add_new)),
+            add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file'))
+            h.flash(h.literal(_('There are no files yet %s') % add_new),
                     category='warning')
             redirect(h.url('summary_home', repo_name=repo_name))
 
@@ -113,6 +111,7 @@
 
         return file_node
 
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
     def index(self, repo_name, revision, f_path, annotate=False):
@@ -154,16 +153,25 @@
             c.file = c.changeset.get_node(f_path)
 
             if c.file.is_file():
-                c.file_history = self._get_node_history(c.changeset, f_path)
+                _hist = c.changeset.get_file_history(f_path)
+                c.file_history = self._get_node_history(c.changeset, f_path,
+                                                        _hist)
+                c.authors = []
+                for a in set([x.author for x in _hist]):
+                    c.authors.append((h.email(a), h.person(a)))
             else:
-                c.file_history = []
+                c.authors = c.file_history = []
         except RepositoryError, e:
             h.flash(str(e), category='warning')
             redirect(h.url('files_home', repo_name=repo_name,
-                           revision=revision))
+                           revision='tip'))
+
+        if request.environ.get('HTTP_X_PARTIAL_XHR'):
+            return render('files/files_ypjax.html')
 
         return render('files/files.html')
 
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
     def rawfile(self, repo_name, revision, f_path):
@@ -176,6 +184,7 @@
         response.content_type = file_node.mimetype
         return file_node.content
 
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
     def raw(self, repo_name, revision, f_path):
@@ -222,8 +231,18 @@
         response.content_type = mimetype
         return file_node.content
 
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
     def edit(self, repo_name, revision, f_path):
+        repo = Repository.get_by_repo_name(repo_name)
+        if repo.enable_locking and repo.locked[0]:
+            h.flash(_('This repository is has been locked by %s on %s')
+                % (h.person_by_id(repo.locked[0]),
+                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
+                  'warning')
+            return redirect(h.url('files_home',
+                                  repo_name=repo_name, revision='tip'))
+
         r_post = request.POST
 
         c.cs = self.__get_cs_or_redirect(revision, repo_name)
@@ -260,7 +279,7 @@
                                              user=self.rhodecode_user,
                                              author=author, message=message,
                                              content=content, f_path=f_path)
-                h.flash(_('Successfully committed to %s' % f_path),
+                h.flash(_('Successfully committed to %s') % f_path,
                         category='success')
 
             except Exception:
@@ -271,8 +290,19 @@
 
         return render('files/files_edit.html')
 
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
     def add(self, repo_name, revision, f_path):
+
+        repo = Repository.get_by_repo_name(repo_name)
+        if repo.enable_locking and repo.locked[0]:
+            h.flash(_('This repository is has been locked by %s on %s')
+                % (h.person_by_id(repo.locked[0]),
+                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
+                  'warning')
+            return redirect(h.url('files_home',
+                                  repo_name=repo_name, revision='tip'))
+
         r_post = request.POST
         c.cs = self.__get_cs_or_redirect(revision, repo_name,
                                          redirect_after=False)
@@ -313,7 +343,7 @@
                                            user=self.rhodecode_user,
                                            author=author, message=message,
                                            content=content, f_path=node_path)
-                h.flash(_('Successfully committed to %s' % node_path),
+                h.flash(_('Successfully committed to %s') % node_path,
                         category='success')
             except NodeAlreadyExistsError, e:
                 h.flash(_(e), category='error')
@@ -325,6 +355,7 @@
 
         return render('files/files_add.html')
 
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
     def archivefile(self, repo_name, fname):
@@ -361,27 +392,28 @@
         except (ImproperArchiveTypeError, KeyError):
             return _('Unknown archive type')
 
-        fd, _archive_name = tempfile.mkstemp(suffix='rcarchive')
-        with open(_archive_name, 'wb') as f:
-            cs.fill_archive(stream=f, kind=fileformat, subrepos=subrepos)
-
-        content_disposition = 'attachment; filename=%s-%s%s' \
-            % (repo_name, revision[:12], ext)
-        content_length = os.path.getsize(_archive_name)
+        fd, archive = tempfile.mkstemp()
+        t = open(archive, 'wb')
+        cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
+        t.close()
 
-        headers = [('Content-Disposition', str(content_disposition)),
-                   ('Content-Type', str(content_type)),
-                   ('Content-Length', str(content_length))]
+        def get_chunked_archive(archive):
+            stream = open(archive, 'rb')
+            while True:
+                data = stream.read(16 * 1024)
+                if not data:
+                    stream.close()
+                    os.close(fd)
+                    os.remove(archive)
+                    break
+                yield data
 
-        class _DestroyingFileWrapper(_FileIter):
-            def close(self):
-                self.file.close
-                os.remove(self.file.name)
+        response.content_disposition = str('attachment; filename=%s-%s%s' \
+                                           % (repo_name, revision[:12], ext))
+        response.content_type = str(content_type)
+        return get_chunked_archive(archive)
 
-        request.environ['wsgi.file_wrapper'] = _DestroyingFileWrapper
-        fapp = FileApp(_archive_name, headers=headers)
-        return fapp(request.environ, self.start_response)
-
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
     def diff(self, repo_name, f_path):
@@ -454,8 +486,9 @@
 
         return render('files/file_diff.html')
 
-    def _get_node_history(self, cs, f_path):
-        changesets = cs.get_file_history(f_path)
+    def _get_node_history(self, cs, f_path, changesets=None):
+        if changesets is None:
+            changesets = cs.get_file_history(f_path)
         hist_l = []
 
         changesets_group = ([], _("Changesets"))
@@ -479,12 +512,13 @@
 
         return hist_l
 
-    @jsonify
+    @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
+    @jsonify
     def nodelist(self, repo_name, revision, f_path):
         if request.environ.get('HTTP_X_PARTIAL_XHR'):
             cs = self.__get_cs_or_redirect(revision, repo_name)
             _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
                                           flat=False)
-            return _d + _f
+            return {'nodes': _d + _f}
--- a/rhodecode/controllers/forks.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/forks.py	Sun Sep 02 21:19:54 2012 +0200
@@ -35,11 +35,13 @@
 
 from rhodecode.lib.helpers import Page
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
-    NotAnonymous, HasRepoPermissionAny
+    NotAnonymous, HasRepoPermissionAny, HasPermissionAllDecorator,\
+    HasPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.model.db import Repository, RepoGroup, UserFollowing, User
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.forms import RepoForkForm
+from rhodecode.model.scm import ScmModel
 
 log = logging.getLogger(__name__)
 
@@ -53,6 +55,8 @@
     def __load_defaults(self):
         c.repo_groups = RepoGroup.groups_choices()
         c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
+        choices, c.landing_revs = ScmModel().get_repo_landing_revs()
+        c.landing_revs_choices = choices
 
     def __load_data(self, repo_name=None):
         """
@@ -120,6 +124,7 @@
         return render('/forks/forks.html')
 
     @NotAnonymous()
+    @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
     def fork(self, repo_name):
@@ -142,24 +147,23 @@
             force_defaults=False
         )
 
-
     @NotAnonymous()
+    @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
     def fork_create(self, repo_name):
         self.__load_defaults()
         c.repo_info = Repository.get_by_repo_name(repo_name)
         _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
-                             repo_groups=c.repo_groups_choices,)()
+                             repo_groups=c.repo_groups_choices,
+                             landing_revs=c.landing_revs_choices)()
         form_result = {}
         try:
             form_result = _form.to_python(dict(request.POST))
-            # add org_path of repo so we can do a clone from it later
-            form_result['org_path'] = c.repo_info.repo_name
 
             # create fork is done sometimes async on celery, db transaction
             # management is handled there.
-            RepoModel().create_fork(form_result, self.rhodecode_user)
+            RepoModel().create_fork(form_result, self.rhodecode_user.user_id)
             h.flash(_('forked %s repository as %s') \
                       % (repo_name, form_result['repo_name']),
                     category='success')
--- a/rhodecode/controllers/home.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/home.py	Sun Sep 02 21:19:54 2012 +0200
@@ -26,7 +26,7 @@
 import logging
 
 from pylons import tmpl_context as c, request
-from paste.httpexceptions import HTTPBadRequest
+from webob.exc import HTTPBadRequest
 
 from rhodecode.lib.auth import LoginRequired
 from rhodecode.lib.base import BaseController, render
@@ -51,7 +51,8 @@
         if request.is_xhr:
             all_repos = Repository.query().order_by(Repository.repo_name).all()
             c.repos_list = self.scm_model.get_repos(all_repos,
-                                                    sort_key='name_sort')
+                                                    sort_key='name_sort',
+                                                    simple=True)
             return render('/repo_switcher_list.html')
         else:
             return HTTPBadRequest()
--- a/rhodecode/controllers/journal.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/journal.py	Sun Sep 02 21:19:54 2012 +0200
@@ -30,7 +30,7 @@
 from webhelpers.paginate import Page
 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
 
-from paste.httpexceptions import HTTPBadRequest
+from webob.exc import HTTPBadRequest
 from pylons import request, tmpl_context as c, response, url
 from pylons.i18n.translation import _
 
@@ -49,8 +49,6 @@
 
     def __before__(self):
         super(JournalController, self).__before__()
-        self.rhodecode_user = self.rhodecode_user
-        self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s')
         self.language = 'en-us'
         self.ttl = "5"
         self.feed_nr = 20
@@ -84,6 +82,30 @@
             return c.journal_data
         return render('journal/journal.html')
 
+    @LoginRequired(api_access=True)
+    @NotAnonymous()
+    def journal_atom(self):
+        """
+        Produce an atom-1.0 feed via feedgenerator module
+        """
+        following = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
+            .options(joinedload(UserFollowing.follows_repository))\
+            .all()
+        return self._atom_feed(following, public=False)
+
+    @LoginRequired(api_access=True)
+    @NotAnonymous()
+    def journal_rss(self):
+        """
+        Produce an rss feed via feedgenerator module
+        """
+        following = self.sa.query(UserFollowing)\
+            .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
+            .options(joinedload(UserFollowing.follows_repository))\
+            .all()
+        return self._rss_feed(following, public=False)
+
     def _get_daily_aggregate(self, journal):
         groups = []
         for k, g in groupby(journal, lambda x: x.action_as_day):
@@ -173,6 +195,80 @@
             return c.journal_data
         return render('journal/public_journal.html')
 
+    def _atom_feed(self, repos, public=True):
+        journal = self._get_journal_data(repos)
+        if public:
+            _link = url('public_journal_atom', qualified=True)
+            _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'),
+                                  'atom feed')
+        else:
+            _link = url('journal_atom', qualified=True)
+            _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'atom feed')
+
+        feed = Atom1Feed(title=_desc,
+                         link=_link,
+                         description=_desc,
+                         language=self.language,
+                         ttl=self.ttl)
+
+        for entry in journal[:self.feed_nr]:
+            action, action_extra, ico = h.action_parser(entry, feed=True)
+            title = "%s - %s %s" % (entry.user.short_contact, action(),
+                                 entry.repository.repo_name)
+            desc = action_extra()
+            _url = None
+            if entry.repository is not None:
+                _url = url('changelog_home',
+                           repo_name=entry.repository.repo_name,
+                           qualified=True)
+
+            feed.add_item(title=title,
+                          pubdate=entry.action_date,
+                          link=_url or url('', qualified=True),
+                          author_email=entry.user.email,
+                          author_name=entry.user.full_contact,
+                          description=desc)
+
+        response.content_type = feed.mime_type
+        return feed.writeString('utf-8')
+
+    def _rss_feed(self, repos, public=True):
+        journal = self._get_journal_data(repos)
+        if public:
+            _link = url('public_journal_atom', qualified=True)
+            _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'),
+                                  'rss feed')
+        else:
+            _link = url('journal_atom', qualified=True)
+            _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'rss feed')
+
+        feed = Rss201rev2Feed(title=_desc,
+                         link=_link,
+                         description=_desc,
+                         language=self.language,
+                         ttl=self.ttl)
+
+        for entry in journal[:self.feed_nr]:
+            action, action_extra, ico = h.action_parser(entry, feed=True)
+            title = "%s - %s %s" % (entry.user.short_contact, action(),
+                                 entry.repository.repo_name)
+            desc = action_extra()
+            _url = None
+            if entry.repository is not None:
+                _url = url('changelog_home',
+                           repo_name=entry.repository.repo_name,
+                           qualified=True)
+
+            feed.add_item(title=title,
+                          pubdate=entry.action_date,
+                          link=_url or url('', qualified=True),
+                          author_email=entry.user.email,
+                          author_name=entry.user.full_contact,
+                          description=desc)
+
+        response.content_type = feed.mime_type
+        return feed.writeString('utf-8')
+
     @LoginRequired(api_access=True)
     def public_journal_atom(self):
         """
@@ -183,29 +279,7 @@
             .options(joinedload(UserFollowing.follows_repository))\
             .all()
 
-        journal = self._get_journal_data(c.following)
-
-        feed = Atom1Feed(title=self.title % 'atom',
-                         link=url('public_journal_atom', qualified=True),
-                         description=_('Public journal'),
-                         language=self.language,
-                         ttl=self.ttl)
-
-        for entry in journal[:self.feed_nr]:
-            #tmpl = h.action_parser(entry)[0]
-            action, action_extra = h.action_parser(entry, feed=True)
-            title = "%s - %s %s" % (entry.user.short_contact, action,
-                                 entry.repository.repo_name)
-            desc = action_extra()
-            feed.add_item(title=title,
-                          pubdate=entry.action_date,
-                          link=url('', qualified=True),
-                          author_email=entry.user.email,
-                          author_name=entry.user.full_contact,
-                          description=desc)
-
-        response.content_type = feed.mime_type
-        return feed.writeString('utf-8')
+        return self._atom_feed(c.following)
 
     @LoginRequired(api_access=True)
     def public_journal_rss(self):
@@ -217,26 +291,4 @@
             .options(joinedload(UserFollowing.follows_repository))\
             .all()
 
-        journal = self._get_journal_data(c.following)
-
-        feed = Rss201rev2Feed(title=self.title % 'rss',
-                         link=url('public_journal_rss', qualified=True),
-                         description=_('Public journal'),
-                         language=self.language,
-                         ttl=self.ttl)
-
-        for entry in journal[:self.feed_nr]:
-            #tmpl = h.action_parser(entry)[0]
-            action, action_extra = h.action_parser(entry, feed=True)
-            title = "%s - %s %s" % (entry.user.short_contact, action,
-                                 entry.repository.repo_name)
-            desc = action_extra()
-            feed.add_item(title=title,
-                          pubdate=entry.action_date,
-                          link=url('', qualified=True),
-                          author_email=entry.user.email,
-                          author_name=entry.user.full_contact,
-                          description=desc)
-
-        response.content_type = feed.mime_type
-        return feed.writeString('utf-8')
+        return self._rss_feed(c.following)
--- a/rhodecode/controllers/login.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/login.py	Sun Sep 02 21:19:54 2012 +0200
@@ -25,9 +25,11 @@
 
 import logging
 import formencode
+import datetime
+import urlparse
 
 from formencode import htmlfill
-
+from webob.exc import HTTPFound
 from pylons.i18n.translation import _
 from pylons.controllers.util import abort, redirect
 from pylons import request, response, session, tmpl_context as c, url
@@ -51,7 +53,7 @@
 
     def index(self):
         # redirect if already logged in
-        c.came_from = request.GET.get('came_from', None)
+        c.came_from = request.GET.get('came_from')
 
         if self.rhodecode_user.is_authenticated \
                             and self.rhodecode_user.username != 'default':
@@ -62,6 +64,7 @@
             # import Login Form validator class
             login_form = LoginForm()
             try:
+                session.invalidate()
                 c.form_result = login_form.to_python(dict(request.POST))
                 # form checks for username/password, now we're authenticated
                 username = c.form_result['username']
@@ -70,22 +73,46 @@
                 auth_user.set_authenticated()
                 cs = auth_user.get_cookie_store()
                 session['rhodecode_user'] = cs
+                user.update_lastlogin()
+                Session().commit()
+
                 # If they want to be remembered, update the cookie
                 if c.form_result['remember'] is not False:
-                    session.cookie_expires = False
-                session._set_cookie_values()
-                session._update_cookie_out()
+                    _year = (datetime.datetime.now() +
+                             datetime.timedelta(seconds=60 * 60 * 24 * 365))
+                    session._set_cookie_expires(_year)
+
                 session.save()
 
                 log.info('user %s is now authenticated and stored in '
                          'session, session attrs %s' % (username, cs))
-                user.update_lastlogin()
-                Session.commit()
+
+                # dumps session attrs back to cookie
+                session._update_cookie_out()
 
+                # we set new cookie
+                headers = None
+                if session.request['set_cookie']:
+                    # send set-cookie headers back to response to update cookie
+                    headers = [('Set-Cookie', session.request['cookie_out'])]
+
+                allowed_schemes = ['http', 'https']
                 if c.came_from:
-                    return redirect(c.came_from)
+                    parsed = urlparse.urlparse(c.came_from)
+                    server_parsed = urlparse.urlparse(url.current())
+                    if parsed.scheme and parsed.scheme not in allowed_schemes:
+                        log.error(
+                            'Suspicious URL scheme detected %s for url %s' %
+                            (parsed.scheme, parsed))
+                        c.came_from = url('home')
+                    elif server_parsed.netloc != parsed.netloc:
+                        log.error('Suspicious NETLOC detected %s for url %s'
+                                  'server url is: %s' %
+                                  (parsed.netloc, parsed, server_parsed))
+                        c.came_from = url('home')
+                    raise HTTPFound(location=c.came_from, headers=headers)
                 else:
-                    return redirect(url('home'))
+                    raise HTTPFound(location=url('home'), headers=headers)
 
             except formencode.Invalid, errors:
                 return htmlfill.render(
@@ -115,7 +142,7 @@
                 UserModel().create_registration(form_result)
                 h.flash(_('You have successfully registered into rhodecode'),
                             category='success')
-                Session.commit()
+                Session().commit()
                 return redirect(url('login_home'))
 
             except formencode.Invalid, errors:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/controllers/pullrequests.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,404 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.controllers.pullrequests
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    pull requests controller for rhodecode for initializing pull requests
+
+    :created_on: May 7, 2012
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+import logging
+import traceback
+import formencode
+
+from webob.exc import HTTPNotFound, HTTPForbidden
+from collections import defaultdict
+from itertools import groupby
+
+from pylons import request, response, session, tmpl_context as c, url
+from pylons.controllers.util import abort, redirect
+from pylons.i18n.translation import _
+from pylons.decorators import jsonify
+
+from rhodecode.lib.compat import json
+from rhodecode.lib.base import BaseRepoController, render
+from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
+    NotAnonymous
+from rhodecode.lib import helpers as h
+from rhodecode.lib import diffs
+from rhodecode.lib.utils import action_logger
+from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
+    ChangesetComment
+from rhodecode.model.pull_request import PullRequestModel
+from rhodecode.model.meta import Session
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.comment import ChangesetCommentsModel
+from rhodecode.model.changeset_status import ChangesetStatusModel
+from rhodecode.model.forms import PullRequestForm
+
+log = logging.getLogger(__name__)
+
+
+class PullrequestsController(BaseRepoController):
+
+    @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')
+    def __before__(self):
+        super(PullrequestsController, self).__before__()
+        repo_model = RepoModel()
+        c.users_array = repo_model.get_users_js()
+        c.users_groups_array = repo_model.get_users_groups_js()
+
+    def _get_repo_refs(self, repo):
+        hist_l = []
+
+        branches_group = ([('branch:%s:%s' % (k, v), k) for
+                         k, v in repo.branches.iteritems()], _("Branches"))
+        bookmarks_group = ([('book:%s:%s' % (k, v), k) for
+                         k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
+        tags_group = ([('tag:%s:%s' % (k, v), k) for
+                         k, v in repo.tags.iteritems()], _("Tags"))
+
+        hist_l.append(bookmarks_group)
+        hist_l.append(branches_group)
+        hist_l.append(tags_group)
+
+        return hist_l
+
+    def show_all(self, repo_name):
+        c.pull_requests = PullRequestModel().get_all(repo_name)
+        c.repo_name = repo_name
+        return render('/pullrequests/pullrequest_show_all.html')
+
+    @NotAnonymous()
+    def index(self):
+        org_repo = c.rhodecode_db_repo
+
+        if org_repo.scm_instance.alias != 'hg':
+            log.error('Review not available for GIT REPOS')
+            raise HTTPNotFound
+
+        other_repos_info = {}
+
+        c.org_refs = self._get_repo_refs(c.rhodecode_repo)
+        c.org_repos = []
+        c.other_repos = []
+        c.org_repos.append((org_repo.repo_name, '%s/%s' % (
+                                org_repo.user.username, c.repo_name))
+                           )
+
+        # add org repo to other so we can open pull request agains itself
+        c.other_repos.extend(c.org_repos)
+
+        c.default_pull_request = org_repo.repo_name
+        c.default_revs = self._get_repo_refs(org_repo.scm_instance)
+        #add orginal repo
+        other_repos_info[org_repo.repo_name] = {
+            'gravatar': h.gravatar_url(org_repo.user.email, 24),
+            'description': org_repo.description,
+            'revs': h.select('other_ref', '', c.default_revs, class_='refs')
+        }
+
+        #gather forks and add to this list
+        for fork in org_repo.forks:
+            c.other_repos.append((fork.repo_name, '%s/%s' % (
+                                    fork.user.username, fork.repo_name))
+                                 )
+            other_repos_info[fork.repo_name] = {
+                'gravatar': h.gravatar_url(fork.user.email, 24),
+                'description': fork.description,
+                'revs': h.select('other_ref', '',
+                                 self._get_repo_refs(fork.scm_instance),
+                                 class_='refs')
+            }
+        #add parents of this fork also
+        if org_repo.parent:
+            c.default_pull_request = org_repo.parent.repo_name
+            c.other_repos.append((org_repo.parent.repo_name, '%s/%s' % (
+                                        org_repo.parent.user.username,
+                                        org_repo.parent.repo_name))
+                                     )
+            other_repos_info[org_repo.parent.repo_name] = {
+                'gravatar': h.gravatar_url(org_repo.parent.user.email, 24),
+                'description': org_repo.parent.description,
+                'revs': h.select('other_ref', '',
+                                 self._get_repo_refs(org_repo.parent.scm_instance),
+                                 class_='refs')
+            }
+
+        c.other_repos_info = json.dumps(other_repos_info)
+        c.review_members = [org_repo.user]
+        return render('/pullrequests/pullrequest.html')
+
+    @NotAnonymous()
+    def create(self, repo_name):
+        try:
+            _form = PullRequestForm()().to_python(request.POST)
+        except formencode.Invalid, errors:
+            log.error(traceback.format_exc())
+            if errors.error_dict.get('revisions'):
+                msg = 'Revisions: %s' % errors.error_dict['revisions']
+            elif errors.error_dict.get('pullrequest_title'):
+                msg = _('Pull request requires a title with min. 3 chars')
+            else:
+                msg = _('error during creation of pull request')
+
+            h.flash(msg, 'error')
+            return redirect(url('pullrequest_home', repo_name=repo_name))
+
+        org_repo = _form['org_repo']
+        org_ref = _form['org_ref']
+        other_repo = _form['other_repo']
+        other_ref = _form['other_ref']
+        revisions = _form['revisions']
+        reviewers = _form['review_members']
+
+        title = _form['pullrequest_title']
+        description = _form['pullrequest_desc']
+
+        try:
+            pull_request = PullRequestModel().create(
+                self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
+                other_ref, revisions, reviewers, title, description
+            )
+            Session().commit()
+            h.flash(_('Successfully opened new pull request'),
+                    category='success')
+        except Exception:
+            h.flash(_('Error occurred during sending pull request'),
+                    category='error')
+            log.error(traceback.format_exc())
+            return redirect(url('pullrequest_home', repo_name=repo_name))
+
+        return redirect(url('pullrequest_show', repo_name=other_repo,
+                            pull_request_id=pull_request.pull_request_id))
+
+    @NotAnonymous()
+    @jsonify
+    def update(self, repo_name, pull_request_id):
+        pull_request = PullRequest.get_or_404(pull_request_id)
+        if pull_request.is_closed():
+            raise HTTPForbidden()
+        #only owner or admin can update it
+        owner = pull_request.author.user_id == c.rhodecode_user.user_id
+        if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
+            reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
+                       request.POST.get('reviewers_ids', '').split(',')))
+
+            PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
+            Session.commit()
+            return True
+        raise HTTPForbidden()
+
+    @NotAnonymous()
+    @jsonify
+    def delete(self, repo_name, pull_request_id):
+        pull_request = PullRequest.get_or_404(pull_request_id)
+        #only owner can delete it !
+        if pull_request.author.user_id == c.rhodecode_user.user_id:
+            PullRequestModel().delete(pull_request)
+            Session().commit()
+            h.flash(_('Successfully deleted pull request'),
+                    category='success')
+            return redirect(url('admin_settings_my_account'))
+        raise HTTPForbidden()
+
+    def _load_compare_data(self, pull_request, enable_comments=True):
+        """
+        Load context data needed for generating compare diff
+
+        :param pull_request:
+        :type pull_request:
+        """
+
+        org_repo = pull_request.org_repo
+        (org_ref_type,
+         org_ref_name,
+         org_ref_rev) = pull_request.org_ref.split(':')
+
+        other_repo = pull_request.other_repo
+        (other_ref_type,
+         other_ref_name,
+         other_ref_rev) = pull_request.other_ref.split(':')
+
+        # despite opening revisions for bookmarks/branches/tags, we always
+        # convert this to rev to prevent changes after book or branch change
+        org_ref = ('rev', org_ref_rev)
+        other_ref = ('rev', other_ref_rev)
+
+        c.org_repo = org_repo
+        c.other_repo = other_repo
+
+        c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
+                                       org_repo, org_ref, other_repo, other_ref
+                                      )
+
+        c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
+                                                   c.cs_ranges])
+        # defines that we need hidden inputs with changesets
+        c.as_form = request.GET.get('as_form', False)
+
+        c.org_ref = org_ref[1]
+        c.other_ref = other_ref[1]
+        # diff needs to have swapped org with other to generate proper diff
+        _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
+                             discovery_data)
+        diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
+        _parsed = diff_processor.prepare()
+
+        c.files = []
+        c.changes = {}
+
+        for f in _parsed:
+            fid = h.FID('', f['filename'])
+            c.files.append([fid, f['operation'], f['filename'], f['stats']])
+            diff = diff_processor.as_html(enable_comments=enable_comments,
+                                          diff_lines=[f])
+            c.changes[fid] = [f['operation'], f['filename'], diff]
+
+    def show(self, repo_name, pull_request_id):
+        repo_model = RepoModel()
+        c.users_array = repo_model.get_users_js()
+        c.users_groups_array = repo_model.get_users_groups_js()
+        c.pull_request = PullRequest.get_or_404(pull_request_id)
+
+        cc_model = ChangesetCommentsModel()
+        cs_model = ChangesetStatusModel()
+        _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
+                                            pull_request=c.pull_request,
+                                            with_revisions=True)
+
+        cs_statuses = defaultdict(list)
+        for st in _cs_statuses:
+            cs_statuses[st.author.username] += [st]
+
+        c.pull_request_reviewers = []
+        c.pull_request_pending_reviewers = []
+        for o in c.pull_request.reviewers:
+            st = cs_statuses.get(o.user.username, None)
+            if st:
+                sorter = lambda k: k.version
+                st = [(x, list(y)[0])
+                      for x, y in (groupby(sorted(st, key=sorter), sorter))]
+            else:
+                c.pull_request_pending_reviewers.append(o.user)
+            c.pull_request_reviewers.append([o.user, st])
+
+        # pull_requests repo_name we opened it against
+        # ie. other_repo must match
+        if repo_name != c.pull_request.other_repo.repo_name:
+            raise HTTPNotFound
+
+        # load compare data into template context
+        enable_comments = not c.pull_request.is_closed()
+        self._load_compare_data(c.pull_request, enable_comments=enable_comments)
+
+        # inline comments
+        c.inline_cnt = 0
+        c.inline_comments = cc_model.get_inline_comments(
+                                c.rhodecode_db_repo.repo_id,
+                                pull_request=pull_request_id)
+        # count inline comments
+        for __, lines in c.inline_comments:
+            for comments in lines.values():
+                c.inline_cnt += len(comments)
+        # comments
+        c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
+                                           pull_request=pull_request_id)
+
+        # changeset(pull-request) status
+        c.current_changeset_status = cs_model.calculate_status(
+                                        c.pull_request_reviewers
+                                     )
+        c.changeset_statuses = ChangesetStatus.STATUSES
+        c.target_repo = c.pull_request.org_repo.repo_name
+        return render('/pullrequests/pullrequest_show.html')
+
+    @NotAnonymous()
+    @jsonify
+    def comment(self, repo_name, pull_request_id):
+        pull_request = PullRequest.get_or_404(pull_request_id)
+        if pull_request.is_closed():
+            raise HTTPForbidden()
+
+        status = request.POST.get('changeset_status')
+        change_status = request.POST.get('change_changeset_status')
+
+        comm = ChangesetCommentsModel().create(
+            text=request.POST.get('text'),
+            repo=c.rhodecode_db_repo.repo_id,
+            user=c.rhodecode_user.user_id,
+            pull_request=pull_request_id,
+            f_path=request.POST.get('f_path'),
+            line_no=request.POST.get('line'),
+            status_change=(ChangesetStatus.get_status_lbl(status)
+                           if status and change_status else None)
+        )
+
+        # get status if set !
+        if status and change_status:
+            ChangesetStatusModel().set_status(
+                c.rhodecode_db_repo.repo_id,
+                status,
+                c.rhodecode_user.user_id,
+                comm,
+                pull_request=pull_request_id
+            )
+        action_logger(self.rhodecode_user,
+                      'user_commented_pull_request:%s' % pull_request_id,
+                      c.rhodecode_db_repo, self.ip_addr, self.sa)
+
+        if request.POST.get('save_close'):
+            PullRequestModel().close_pull_request(pull_request_id)
+            action_logger(self.rhodecode_user,
+                      'user_closed_pull_request:%s' % pull_request_id,
+                      c.rhodecode_db_repo, self.ip_addr, self.sa)
+
+        Session().commit()
+
+        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
+            return redirect(h.url('pullrequest_show', repo_name=repo_name,
+                                  pull_request_id=pull_request_id))
+
+        data = {
+           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
+        }
+        if comm:
+            c.co = comm
+            data.update(comm.get_dict())
+            data.update({'rendered_text':
+                         render('changeset/changeset_comment_block.html')})
+
+        return data
+
+    @NotAnonymous()
+    @jsonify
+    def delete_comment(self, repo_name, comment_id):
+        co = ChangesetComment.get(comment_id)
+        if co.pull_request.is_closed():
+            #don't allow deleting comments on closed pull request
+            raise HTTPForbidden()
+
+        owner = lambda: co.author.user_id == c.rhodecode_user.user_id
+        if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
+            ChangesetCommentsModel().delete(comment=co)
+            Session().commit()
+            return True
+        else:
+            raise HTTPForbidden()
--- a/rhodecode/controllers/search.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/search.py	Sun Sep 02 21:19:54 2012 +0200
@@ -3,7 +3,7 @@
     rhodecode.controllers.search
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    Search controller for rhodecode
+    Search controller for RhodeCode
 
     :created_on: Aug 7, 2010
     :author: marcink
@@ -30,7 +30,8 @@
 
 from rhodecode.lib.auth import LoginRequired
 from rhodecode.lib.base import BaseController, render
-from rhodecode.lib.indexers import SCHEMA, IDX_NAME, ResultWrapper
+from rhodecode.lib.indexers import CHGSETS_SCHEMA, SCHEMA, CHGSET_IDX_NAME, \
+    IDX_NAME, WhooshResultWrapper
 
 from webhelpers.paginate import Page
 from webhelpers.util import update_params
@@ -38,6 +39,7 @@
 from whoosh.index import open_dir, EmptyIndexError
 from whoosh.qparser import QueryParser, QueryParserError
 from whoosh.query import Phrase, Wildcard, Term, Prefix
+from rhodecode.model.repo import RepoModel
 
 log = logging.getLogger(__name__)
 
@@ -53,25 +55,41 @@
         c.formated_results = []
         c.runtime = ''
         c.cur_query = request.GET.get('q', None)
-        c.cur_type = request.GET.get('type', 'source')
+        c.cur_type = request.GET.get('type', 'content')
         c.cur_search = search_type = {'content': 'content',
-                                      'commit': 'content',
+                                      'commit': 'message',
                                       'path': 'path',
-                                      'repository': 'repository'}\
-                                      .get(c.cur_type, 'content')
+                                      'repository': 'repository'
+                                      }.get(c.cur_type, 'content')
+
+        index_name = {
+            'content': IDX_NAME,
+            'commit': CHGSET_IDX_NAME,
+            'path': IDX_NAME
+        }.get(c.cur_type, IDX_NAME)
+
+        schema_defn = {
+            'content': SCHEMA,
+            'commit': CHGSETS_SCHEMA,
+            'path': SCHEMA
+        }.get(c.cur_type, SCHEMA)
+
+        log.debug('IDX: %s' % index_name)
+        log.debug('SCHEMA: %s' % schema_defn)
 
         if c.cur_query:
             cur_query = c.cur_query.lower()
+            log.debug(cur_query)
 
         if c.cur_query:
             p = int(request.params.get('page', 1))
             highlight_items = set()
             try:
                 idx = open_dir(config['app_conf']['index_dir'],
-                               indexname=IDX_NAME)
+                               indexname=index_name)
                 searcher = idx.searcher()
 
-                qp = QueryParser(search_type, schema=SCHEMA)
+                qp = QueryParser(search_type, schema=schema_defn)
                 if c.repo_name:
                     cur_query = u'repository:%s %s' % (c.repo_name, cur_query)
                 try:
@@ -83,13 +101,13 @@
                         highlight_items.add(query.text)
                     else:
                         for i in query.all_terms():
-                            if i[0] == 'content':
+                            if i[0] in ['content', 'message']:
                                 highlight_items.add(i[1])
 
                     matcher = query.matcher(searcher)
 
-                    log.debug(query)
-                    log.debug(highlight_items)
+                    log.debug('query: %s' % query)
+                    log.debug('hl terms: %s' % highlight_items)
                     results = searcher.search(query)
                     res_ln = len(results)
                     c.runtime = '%s results (%.3f seconds)' % (
@@ -98,11 +116,11 @@
 
                     def url_generator(**kw):
                         return update_params("?q=%s&type=%s" \
-                                           % (c.cur_query, c.cur_search), **kw)
-
+                                           % (c.cur_query, c.cur_type), **kw)
+                    repo_location = RepoModel().repos_path
                     c.formated_results = Page(
-                        ResultWrapper(search_type, searcher, matcher,
-                                      highlight_items),
+                        WhooshResultWrapper(search_type, searcher, matcher,
+                                            highlight_items, repo_location),
                         page=p,
                         item_count=res_ln,
                         items_per_page=10,
@@ -121,6 +139,5 @@
                 log.error(traceback.format_exc())
                 c.runtime = _('An error occurred during this search operation')
 
-
         # Return a rendered template
         return render('/search/search.html')
--- a/rhodecode/controllers/settings.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/settings.py	Sun Sep 02 21:19:54 2012 +0200
@@ -43,6 +43,7 @@
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.db import RepoGroup
 from rhodecode.model.meta import Session
+from rhodecode.model.scm import ScmModel
 
 log = logging.getLogger(__name__)
 
@@ -60,6 +61,8 @@
         repo_model = RepoModel()
         c.users_array = repo_model.get_users_js()
         c.users_groups_array = repo_model.get_users_groups_js()
+        choices, c.landing_revs = ScmModel().get_repo_landing_revs()
+        c.landing_revs_choices = choices
 
     @HasRepoPermissionAllDecorator('repository.admin')
     def index(self, repo_name):
@@ -94,17 +97,18 @@
 
         _form = RepoSettingsForm(edit=True,
                                  old_data={'repo_name': repo_name},
-                                 repo_groups=c.repo_groups_choices)()
+                                 repo_groups=c.repo_groups_choices,
+                                 landing_revs=c.landing_revs_choices)()
         try:
             form_result = _form.to_python(dict(request.POST))
 
             repo_model.update(repo_name, form_result)
             invalidate_cache('get_repo_cached_%s' % repo_name)
-            h.flash(_('Repository %s updated successfully' % repo_name),
+            h.flash(_('Repository %s updated successfully') % repo_name,
                     category='success')
             changed_name = form_result['repo_name_full']
             action_logger(self.rhodecode_user, 'user_updated_repo',
-                          changed_name, '', self.sa)
+                          changed_name, self.ip_addr, self.sa)
             Session.commit()
         except formencode.Invalid, errors:
             c.repo_info = repo_model.get_by_repo_name(repo_name)
@@ -145,7 +149,7 @@
             return redirect(url('home'))
         try:
             action_logger(self.rhodecode_user, 'user_deleted_repo',
-                              repo_name, '', self.sa)
+                              repo_name, self.ip_addr, self.sa)
             repo_model.delete(repo)
             invalidate_cache('get_repo_cached_%s' % repo_name)
             h.flash(_('deleted repository %s') % repo_name, category='success')
--- a/rhodecode/controllers/summary.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/controllers/summary.py	Sun Sep 02 21:19:54 2012 +0200
@@ -45,12 +45,13 @@
 from rhodecode.lib.utils2 import safe_unicode
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from rhodecode.lib.base import BaseRepoController, render
-from rhodecode.lib.utils import EmptyChangeset
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
 from rhodecode.lib.markup_renderer import MarkupRenderer
 from rhodecode.lib.celerylib import run_task
 from rhodecode.lib.celerylib.tasks import get_commits_stats
 from rhodecode.lib.helpers import RepoPage
 from rhodecode.lib.compat import json, OrderedDict
+from rhodecode.lib.vcs.nodes import FileNode
 
 log = logging.getLogger(__name__)
 
@@ -179,27 +180,31 @@
         if c.enable_downloads:
             c.download_options = self._get_download_links(c.rhodecode_repo)
 
-        c.readme_data, c.readme_file = self.__get_readme_data(
-            c.rhodecode_db_repo.repo_name, c.rhodecode_repo
-        )
+        c.readme_data, c.readme_file = \
+            self.__get_readme_data(c.rhodecode_db_repo)
         return render('summary/summary.html')
 
-    def __get_readme_data(self, repo_name, repo):
+    def __get_readme_data(self, db_repo):
+        repo_name = db_repo.repo_name
 
         @cache_region('long_term')
         def _get_readme_from_cache(key):
             readme_data = None
             readme_file = None
-            log.debug('Fetching readme file')
+            log.debug('Looking for README file')
             try:
-                cs = repo.get_changeset()  # fetches TIP
+                # get's the landing revision! or tip if fails
+                cs = db_repo.get_landing_changeset()
                 renderer = MarkupRenderer()
                 for f in README_FILES:
                     try:
                         readme = cs.get_node(f)
+                        if not isinstance(readme, FileNode):
+                            continue
                         readme_file = f
+                        log.debug('Found README file `%s` rendering...' %
+                                  readme_file)
                         readme_data = renderer.render(readme.content, f)
-                        log.debug('Found readme %s' % readme_file)
                         break
                     except NodeDoesNotExistError:
                         continue
--- a/rhodecode/i18n/en/LC_MESSAGES/rhodecode.po	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/i18n/en/LC_MESSAGES/rhodecode.po	Sun Sep 02 21:19:54 2012 +0200
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: rhodecode 0.1\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2011-09-14 15:50-0300\n"
+"POT-Creation-Date: 2012-09-02 20:30+0200\n"
 "PO-Revision-Date: 2011-02-25 19:13+0100\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: en <LL@li.org>\n"
@@ -17,20 +17,36 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: Babel 0.9.6\n"
 
-#: rhodecode/controllers/changeset.py:108
-#: rhodecode/controllers/changeset.py:149
-#: rhodecode/controllers/changeset.py:216
-#: rhodecode/controllers/changeset.py:229
+#: rhodecode/controllers/changelog.py:94
+msgid "All Branches"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:83
+msgid "show white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:90 rhodecode/controllers/changeset.py:97
+msgid "ignore white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:157
+#, python-format
+msgid "%s line context"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:333
+#: rhodecode/controllers/changeset.py:348 rhodecode/lib/diffs.py:70
 msgid "binary file"
 msgstr ""
 
-#: rhodecode/controllers/changeset.py:123
-#: rhodecode/controllers/changeset.py:168
-msgid "Changeset is to big and was cut off, see raw changeset instead"
-msgstr ""
-
-#: rhodecode/controllers/changeset.py:159
-msgid "Diff is to big and was cut off, see raw diff instead"
+#: rhodecode/controllers/changeset.py:408
+msgid ""
+"Changing status on a changeset associated witha closed pull request is "
+"not allowed"
+msgstr ""
+
+#: rhodecode/controllers/compare.py:69
+msgid "There are no changesets yet"
 msgstr ""
 
 #: rhodecode/controllers/error.py:69
@@ -59,117 +75,107 @@
 "fulfilling the request."
 msgstr ""
 
-#: rhodecode/controllers/feed.py:48
+#: rhodecode/controllers/feed.py:49
 #, python-format
 msgid "Changes on %s repository"
 msgstr ""
 
-#: rhodecode/controllers/feed.py:49
+#: rhodecode/controllers/feed.py:50
 #, python-format
 msgid "%s %s feed"
 msgstr ""
 
-#: rhodecode/controllers/files.py:72
-msgid "There are no files yet"
-msgstr ""
-
-#: rhodecode/controllers/files.py:262
+#: rhodecode/controllers/feed.py:75
+msgid "commited on"
+msgstr ""
+
+#: rhodecode/controllers/files.py:84
+msgid "click here to add new file"
+msgstr ""
+
+#: rhodecode/controllers/files.py:85
+#, python-format
+msgid "There are no files yet %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:239 rhodecode/controllers/files.py:299
+#, python-format
+msgid "This repository is has been locked by %s on %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:266
 #, python-format
 msgid "Edited %s via RhodeCode"
 msgstr ""
 
-#: rhodecode/controllers/files.py:267
-#: rhodecode/templates/files/file_diff.html:40
+#: rhodecode/controllers/files.py:271
 msgid "No changes"
 msgstr ""
 
-#: rhodecode/controllers/files.py:278
+#: rhodecode/controllers/files.py:282 rhodecode/controllers/files.py:346
 #, python-format
 msgid "Successfully committed to %s"
 msgstr ""
 
-#: rhodecode/controllers/files.py:283
+#: rhodecode/controllers/files.py:287 rhodecode/controllers/files.py:352
 msgid "Error occurred during commit"
 msgstr ""
 
-#: rhodecode/controllers/files.py:308
+#: rhodecode/controllers/files.py:318
+#, python-format
+msgid "Added %s via RhodeCode"
+msgstr ""
+
+#: rhodecode/controllers/files.py:332
+msgid "No content"
+msgstr ""
+
+#: rhodecode/controllers/files.py:336
+msgid "No filename"
+msgstr ""
+
+#: rhodecode/controllers/files.py:378
 msgid "downloads disabled"
 msgstr ""
 
-#: rhodecode/controllers/files.py:313
+#: rhodecode/controllers/files.py:389
 #, python-format
 msgid "Unknown revision %s"
 msgstr ""
 
-#: rhodecode/controllers/files.py:315
+#: rhodecode/controllers/files.py:391
 msgid "Empty repository"
 msgstr ""
 
-#: rhodecode/controllers/files.py:317
+#: rhodecode/controllers/files.py:393
 msgid "Unknown archive type"
 msgstr ""
 
-#: rhodecode/controllers/files.py:385 rhodecode/controllers/files.py:398
-msgid "Binary file"
-msgstr ""
-
-#: rhodecode/controllers/files.py:417
-#: rhodecode/templates/changeset/changeset_range.html:4
-#: rhodecode/templates/changeset/changeset_range.html:12
-#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/controllers/files.py:494
+#: rhodecode/templates/changeset/changeset_range.html:13
+#: rhodecode/templates/changeset/changeset_range.html:31
 msgid "Changesets"
 msgstr ""
 
-#: rhodecode/controllers/files.py:418 rhodecode/controllers/summary.py:175
-#: rhodecode/templates/branches/branches.html:5
-#: rhodecode/templates/summary/summary.html:690
+#: rhodecode/controllers/files.py:495 rhodecode/controllers/pullrequests.py:72
+#: rhodecode/controllers/summary.py:232 rhodecode/model/scm.py:543
 msgid "Branches"
 msgstr ""
 
-#: rhodecode/controllers/files.py:419 rhodecode/controllers/summary.py:176
-#: rhodecode/templates/summary/summary.html:679
-#: rhodecode/templates/tags/tags.html:5
+#: rhodecode/controllers/files.py:496 rhodecode/controllers/pullrequests.py:76
+#: rhodecode/controllers/summary.py:233 rhodecode/model/scm.py:554
 msgid "Tags"
 msgstr ""
 
-#: rhodecode/controllers/journal.py:50
+#: rhodecode/controllers/forks.py:73 rhodecode/controllers/admin/repos.py:90
 #, python-format
-msgid "%s public journal %s feed"
-msgstr ""
-
-#: rhodecode/controllers/journal.py:178 rhodecode/controllers/journal.py:212
-#: rhodecode/templates/admin/repos/repo_edit.html:171
-#: rhodecode/templates/base/base.html:50
-msgid "Public journal"
-msgstr ""
-
-#: rhodecode/controllers/login.py:111
-msgid "You have successfully registered into rhodecode"
-msgstr ""
-
-#: rhodecode/controllers/login.py:133
-msgid "Your password reset link was sent"
-msgstr ""
-
-#: rhodecode/controllers/login.py:155
 msgid ""
-"Your password reset was successful, new password has been sent to your "
-"email"
-msgstr ""
-
-#: rhodecode/controllers/search.py:109
-msgid "Invalid search query. Try quoting it."
-msgstr ""
-
-#: rhodecode/controllers/search.py:114
-msgid "There is no index to search in. Please run whoosh indexer"
-msgstr ""
-
-#: rhodecode/controllers/search.py:118
-msgid "An error occurred during this search operation"
-msgstr ""
-
-#: rhodecode/controllers/settings.py:61 rhodecode/controllers/settings.py:171
+"%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"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:133 rhodecode/controllers/settings.py:72
 #, python-format
 msgid ""
 "%s repository is not mapped to db perhaps it was created or renamed from "
@@ -177,20 +183,89 @@
 "repositories"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:109
-#: rhodecode/controllers/admin/repos.py:239
+#: rhodecode/controllers/forks.py:167
+#, python-format
+msgid "forked %s repository as %s"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:181
+#, python-format
+msgid "An error occurred during repository forking %s"
+msgstr ""
+
+#: rhodecode/controllers/journal.py:202 rhodecode/controllers/journal.py:239
+msgid "public journal"
+msgstr ""
+
+#: rhodecode/controllers/journal.py:206 rhodecode/controllers/journal.py:243
+#: rhodecode/templates/base/base.html:220
+msgid "journal"
+msgstr ""
+
+#: rhodecode/controllers/login.py:143
+msgid "You have successfully registered into rhodecode"
+msgstr ""
+
+#: rhodecode/controllers/login.py:164
+msgid "Your password reset link was sent"
+msgstr ""
+
+#: rhodecode/controllers/login.py:184
+msgid ""
+"Your password reset was successful, new password has been sent to your "
+"email"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:74 rhodecode/model/scm.py:549
+msgid "Bookmarks"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:158
+msgid "Pull request requires a title with min. 3 chars"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:160
+msgid "error during creation of pull request"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:181
+msgid "Successfully opened new pull request"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:184
+msgid "Error occurred during sending pull request"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:217
+msgid "Successfully deleted pull request"
+msgstr ""
+
+#: rhodecode/controllers/search.py:131
+msgid "Invalid search query. Try quoting it."
+msgstr ""
+
+#: rhodecode/controllers/search.py:136
+msgid "There is no index to search in. Please run whoosh indexer"
+msgstr ""
+
+#: rhodecode/controllers/search.py:140
+msgid "An error occurred during this search operation"
+msgstr ""
+
+#: rhodecode/controllers/settings.py:107
+#: rhodecode/controllers/admin/repos.py:266
 #, python-format
 msgid "Repository %s updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:126
-#: rhodecode/controllers/admin/repos.py:257
+#: rhodecode/controllers/settings.py:125
+#: rhodecode/controllers/admin/repos.py:284
 #, python-format
 msgid "error occurred during update of repository %s"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:144
-#: rhodecode/controllers/admin/repos.py:275
+#: rhodecode/controllers/settings.py:143
+#: rhodecode/controllers/admin/repos.py:302
 #, python-format
 msgid ""
 "%s repository is not mapped to db perhaps it was moved or renamed  from "
@@ -198,111 +273,102 @@
 "repositories"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:156
-#: rhodecode/controllers/admin/repos.py:287
+#: rhodecode/controllers/settings.py:155
+#: rhodecode/controllers/admin/repos.py:314
 #, python-format
 msgid "deleted repository %s"
 msgstr ""
 
 #: rhodecode/controllers/settings.py:159
-#: rhodecode/controllers/admin/repos.py:297
-#: rhodecode/controllers/admin/repos.py:303
+#: rhodecode/controllers/admin/repos.py:324
+#: rhodecode/controllers/admin/repos.py:330
 #, python-format
 msgid "An error occurred during deletion of %s"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:193
-#, python-format
-msgid "forked %s repository as %s"
-msgstr ""
-
-#: rhodecode/controllers/settings.py:211
-#, python-format
-msgid "An error occurred during repository forking %s"
-msgstr ""
-
-#: rhodecode/controllers/summary.py:123
+#: rhodecode/controllers/summary.py:138
 msgid "No data loaded yet"
 msgstr ""
 
-#: rhodecode/controllers/summary.py:126
+#: rhodecode/controllers/summary.py:142
+#: rhodecode/templates/summary/summary.html:148
 msgid "Statistics are disabled for this repository"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:49
-msgid "BASE"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:50
-msgid "ONELEVEL"
+msgid "BASE"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:51
+msgid "ONELEVEL"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:52
 msgid "SUBTREE"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:55
-msgid "NEVER"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:56
-msgid "ALLOW"
+msgid "NEVER"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:57
-msgid "TRY"
+msgid "ALLOW"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:58
-msgid "DEMAND"
+msgid "TRY"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:59
+msgid "DEMAND"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:60
 msgid "HARD"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:63
-msgid "No encryption"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:64
-msgid "LDAPS connection"
+msgid "No encryption"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:65
+msgid "LDAPS connection"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:66
 msgid "START_TLS on LDAP connection"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:115
+#: rhodecode/controllers/admin/ldap_settings.py:126
 msgid "Ldap settings updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:120
+#: rhodecode/controllers/admin/ldap_settings.py:130
 msgid "Unable to activate ldap. The \"python-ldap\" library is missing."
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:134
+#: rhodecode/controllers/admin/ldap_settings.py:147
 msgid "error occurred during update of ldap settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:56
-msgid "None"
-msgstr ""
-
-#: rhodecode/controllers/admin/permissions.py:57
-msgid "Read"
-msgstr ""
-
-#: rhodecode/controllers/admin/permissions.py:58
-msgid "Write"
-msgstr ""
-
 #: rhodecode/controllers/admin/permissions.py:59
+msgid "None"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:60
+msgid "Read"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:61
+msgid "Write"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:62
 #: rhodecode/templates/admin/ldap/ldap.html:9
 #: rhodecode/templates/admin/permissions/permissions.html:9
 #: rhodecode/templates/admin/repos/repo_add.html:9
 #: rhodecode/templates/admin/repos/repo_edit.html:9
-#: rhodecode/templates/admin/repos/repos.html:10
+#: rhodecode/templates/admin/repos/repos.html:9
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
@@ -310,550 +376,871 @@
 #: rhodecode/templates/admin/settings/settings.html:9
 #: rhodecode/templates/admin/users/user_add.html:8
 #: rhodecode/templates/admin/users/user_edit.html:9
-#: rhodecode/templates/admin/users/user_edit.html:110
+#: rhodecode/templates/admin/users/user_edit.html:122
 #: rhodecode/templates/admin/users/users.html:9
 #: rhodecode/templates/admin/users_groups/users_group_add.html:8
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:9
 #: rhodecode/templates/admin/users_groups/users_groups.html:9
-#: rhodecode/templates/base/base.html:279
-#: rhodecode/templates/base/base.html:366
-#: rhodecode/templates/base/base.html:368
-#: rhodecode/templates/base/base.html:370
+#: rhodecode/templates/base/base.html:197
+#: rhodecode/templates/base/base.html:337
+#: rhodecode/templates/base/base.html:339
+#: rhodecode/templates/base/base.html:341
 msgid "Admin"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:62
+#: rhodecode/controllers/admin/permissions.py:65
 msgid "disabled"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:64
+#: rhodecode/controllers/admin/permissions.py:67
 msgid "allowed with manual account activation"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:66
-msgid "allowed with automatic account activation"
-msgstr ""
-
-#: rhodecode/controllers/admin/permissions.py:68
-msgid "Disabled"
-msgstr ""
-
 #: rhodecode/controllers/admin/permissions.py:69
+msgid "allowed with automatic account activation"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:71
+#: rhodecode/controllers/admin/permissions.py:74
+msgid "Disabled"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:72
+#: rhodecode/controllers/admin/permissions.py:75
 msgid "Enabled"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:102
+#: rhodecode/controllers/admin/permissions.py:116
 msgid "Default permissions updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:119
+#: rhodecode/controllers/admin/permissions.py:130
 msgid "error occurred during update of permissions"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:96
-#, python-format
-msgid ""
-"%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"
-msgstr ""
-
-#: rhodecode/controllers/admin/repos.py:172
+#: rhodecode/controllers/admin/repos.py:123
+msgid "--REMOVE FORK--"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:192
 #, python-format
 msgid "created repository %s from %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:176
+#: rhodecode/controllers/admin/repos.py:196
 #, python-format
 msgid "created repository %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:205
+#: rhodecode/controllers/admin/repos.py:227
 #, python-format
 msgid "error occurred during creation of repository %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:292
+#: rhodecode/controllers/admin/repos.py:319
 #, python-format
 msgid "Cannot delete %s it still contains attached forks"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:320
+#: rhodecode/controllers/admin/repos.py:348
 msgid "An error occurred during deletion of repository user"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:335
-msgid "An error occurred during deletion of repository users groups"
-msgstr ""
-
-#: rhodecode/controllers/admin/repos.py:352
-msgid "An error occurred during deletion of repository stats"
-msgstr ""
-
 #: rhodecode/controllers/admin/repos.py:367
+msgid "An error occurred during deletion of repository users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:385
+msgid "An error occurred during deletion of repository stats"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:402
 msgid "An error occurred during cache invalidation"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:387
+#: rhodecode/controllers/admin/repos.py:422
+msgid "An error occurred during unlocking"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:442
 msgid "Updated repository visibility in public journal"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:390
+#: rhodecode/controllers/admin/repos.py:446
 msgid "An error occurred during setting this repository in public journal"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:395 rhodecode/model/forms.py:53
+#: rhodecode/controllers/admin/repos.py:451 rhodecode/model/validators.py:299
 msgid "Token mismatch"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:408
+#: rhodecode/controllers/admin/repos.py:464
 msgid "Pulled from remote location"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:410
+#: rhodecode/controllers/admin/repos.py:466
 msgid "An error occurred during pull from remote location"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:83
+#: rhodecode/controllers/admin/repos.py:482
+msgid "Nothing"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:484
+#, python-format
+msgid "Marked repo %s as fork of %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:488
+msgid "An error occurred during this operation"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:116
 #, python-format
 msgid "created repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:96
+#: rhodecode/controllers/admin/repos_groups.py:129
 #, python-format
 msgid "error occurred during creation of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:130
+#: rhodecode/controllers/admin/repos_groups.py:163
 #, python-format
 msgid "updated repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:143
+#: rhodecode/controllers/admin/repos_groups.py:176
 #, python-format
 msgid "error occurred during update of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:164
+#: rhodecode/controllers/admin/repos_groups.py:194
 #, python-format
 msgid "This group contains %s repositores and cannot be deleted"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:171
+#: rhodecode/controllers/admin/repos_groups.py:202
 #, python-format
 msgid "removed repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:175
+#: rhodecode/controllers/admin/repos_groups.py:208
+msgid "Cannot delete this group it still contains subgroups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:213
+#: rhodecode/controllers/admin/repos_groups.py:218
 #, python-format
 msgid "error occurred during deletion of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:109
+#: rhodecode/controllers/admin/repos_groups.py:238
+msgid "An error occurred during deletion of group user"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:258
+msgid "An error occurred during deletion of group users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:121
 #, python-format
 msgid "Repositories successfully rescanned added: %s,removed: %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:118
+#: rhodecode/controllers/admin/settings.py:129
 msgid "Whoosh reindex task scheduled"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:143
+#: rhodecode/controllers/admin/settings.py:160
 msgid "Updated application settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:148
-#: rhodecode/controllers/admin/settings.py:215
+#: rhodecode/controllers/admin/settings.py:164
+#: rhodecode/controllers/admin/settings.py:275
 msgid "error occurred during updating application settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:210
-msgid "Updated mercurial settings"
-msgstr ""
-
-#: rhodecode/controllers/admin/settings.py:236
+#: rhodecode/controllers/admin/settings.py:200
+msgid "Updated visualisation settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:205
+msgid "error occurred during updating visualisation settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:271
+msgid "Updated VCS settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:285
 msgid "Added new hook"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:247
+#: rhodecode/controllers/admin/settings.py:297
 msgid "Updated hooks"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:251
+#: rhodecode/controllers/admin/settings.py:301
 msgid "error occurred during hook creation"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:310
+#: rhodecode/controllers/admin/settings.py:320
+msgid "Email task created"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:375
 msgid "You can't edit this user since it's crucial for entire application"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:339
+#: rhodecode/controllers/admin/settings.py:406
 msgid "Your account was updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:359
+#: rhodecode/controllers/admin/settings.py:421
+#: rhodecode/controllers/admin/users.py:191
+#, python-format
+msgid "error occurred during update of user %s"
+msgstr ""
+
 #: rhodecode/controllers/admin/users.py:130
 #, python-format
-msgid "error occurred during update of user %s"
-msgstr ""
-
-#: rhodecode/controllers/admin/users.py:78
-#, python-format
 msgid "created user %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:90
+#: rhodecode/controllers/admin/users.py:142
 #, python-format
 msgid "error occurred during creation of user %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:116
+#: rhodecode/controllers/admin/users.py:171
 msgid "User updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:146
+#: rhodecode/controllers/admin/users.py:207
 msgid "successfully deleted user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:150
+#: rhodecode/controllers/admin/users.py:212
 msgid "An error occurred during deletion of user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:166
+#: rhodecode/controllers/admin/users.py:226
 msgid "You can't edit this user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:195
-#: rhodecode/controllers/admin/users_groups.py:202
+#: rhodecode/controllers/admin/users.py:266
 msgid "Granted 'repository create' permission to user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:204
-#: rhodecode/controllers/admin/users_groups.py:211
+#: rhodecode/controllers/admin/users.py:271
 msgid "Revoked 'repository create' permission to user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:74
+#: rhodecode/controllers/admin/users.py:277
+msgid "Granted 'repository fork' permission to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:282
+msgid "Revoked 'repository fork' permission to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:288
+#: rhodecode/controllers/admin/users_groups.py:255
+msgid "An error occurred during permissions saving"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:303
+#, python-format
+msgid "Added email %s to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:309
+msgid "An error occurred during email saving"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:319
+msgid "Removed email from user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:84
 #, python-format
 msgid "created users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:86
+#: rhodecode/controllers/admin/users_groups.py:95
 #, python-format
 msgid "error occurred during creation of users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:119
+#: rhodecode/controllers/admin/users_groups.py:135
 #, python-format
 msgid "updated users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:138
+#: rhodecode/controllers/admin/users_groups.py:157
 #, python-format
 msgid "error occurred during update of users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:154
+#: rhodecode/controllers/admin/users_groups.py:174
 msgid "successfully deleted users group"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:158
+#: rhodecode/controllers/admin/users_groups.py:179
 msgid "An error occurred during deletion of users group"
 msgstr ""
 
-#: rhodecode/lib/__init__.py:279
-msgid "year"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:280
-msgid "month"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:281
-msgid "day"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:282
-msgid "hour"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:283
-msgid "minute"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:284
-msgid "second"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:293
-msgid "ago"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:296
-msgid "just now"
-msgstr ""
-
-#: rhodecode/lib/auth.py:377
+#: rhodecode/controllers/admin/users_groups.py:233
+msgid "Granted 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:238
+msgid "Revoked 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:244
+msgid "Granted 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:249
+msgid "Revoked 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/lib/auth.py:499
 msgid "You need to be a registered user to perform this action"
 msgstr ""
 
-#: rhodecode/lib/auth.py:421
+#: rhodecode/lib/auth.py:540
 msgid "You need to be a signed in to view this page"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:307
+#: rhodecode/lib/diffs.py:86
+msgid "Changeset was too big and was cut off, use diff menu to display this diff"
+msgstr ""
+
+#: rhodecode/lib/diffs.py:96
+msgid "No changes detected"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:372
+#, python-format
+msgid "%a, %d %b %Y %H:%M:%S"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:484
 msgid "True"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:311
+#: rhodecode/lib/helpers.py:488
 msgid "False"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:352
+#: rhodecode/lib/helpers.py:532
+msgid "Changeset not found"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:555
 #, python-format
 msgid "Show all combined changesets %s->%s"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:356
+#: rhodecode/lib/helpers.py:561
 msgid "compare view"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:365
-msgid "and"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:365
-#, python-format
-msgid "%s more"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:367 rhodecode/templates/changelog/changelog.html:14
-#: rhodecode/templates/changelog/changelog.html:39
-msgid "revisions"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:385
-msgid "fork name "
-msgstr ""
-
-#: rhodecode/lib/helpers.py:388
-msgid "[deleted] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:389 rhodecode/lib/helpers.py:393
-msgid "[created] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:390 rhodecode/lib/helpers.py:394
-msgid "[forked] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:391 rhodecode/lib/helpers.py:395
-msgid "[updated] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:392
-msgid "[delete] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:396
-msgid "[pushed] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:397
-msgid "[committed via RhodeCode] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:398
-msgid "[pulled from remote] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:399
-msgid "[pulled] from"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:400
-msgid "[started following] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:401
-msgid "[stopped following] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:577
-#, python-format
-msgid " and %s more"
-msgstr ""
-
 #: rhodecode/lib/helpers.py:581
+msgid "and"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:582
+#, python-format
+msgid "%s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:583 rhodecode/templates/changelog/changelog.html:48
+msgid "revisions"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:606
+msgid "fork name "
+msgstr ""
+
+#: rhodecode/lib/helpers.py:620
+#: rhodecode/templates/pullrequests/pullrequest_show.html:4
+#: rhodecode/templates/pullrequests/pullrequest_show.html:12
+#, python-format
+msgid "Pull request #%s"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:626
+msgid "[deleted] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:628 rhodecode/lib/helpers.py:638
+msgid "[created] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:630
+msgid "[created] repository as fork"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:632 rhodecode/lib/helpers.py:640
+msgid "[forked] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:634 rhodecode/lib/helpers.py:642
+msgid "[updated] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:636
+msgid "[delete] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:644
+msgid "[created] user"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:646
+msgid "[updated] user"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:648
+msgid "[created] users group"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:650
+msgid "[updated] users group"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:652
+msgid "[commented] on revision in repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:654
+msgid "[commented] on pull request for"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:656
+msgid "[closed] pull request for"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:658
+msgid "[pushed] into"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:660
+msgid "[committed via RhodeCode] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:662
+msgid "[pulled from remote] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:664
+msgid "[pulled] from"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:666
+msgid "[started following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:668
+msgid "[stopped following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:840
+#, python-format
+msgid " and %s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:844
 msgid "No Files"
 msgstr ""
 
-#: rhodecode/model/forms.py:66
-msgid "Invalid username"
-msgstr ""
-
-#: rhodecode/model/forms.py:75
-msgid "This username already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:79
+#: rhodecode/lib/utils2.py:335
+#, python-format
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:336
+#, python-format
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:337
+#, python-format
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:338
+#, python-format
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:339
+#, python-format
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:340
+#, python-format
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:355
+#, python-format
+msgid "%s ago"
+msgstr ""
+
+#: rhodecode/lib/utils2.py:357
+#, python-format
+msgid "%s and %s ago"
+msgstr ""
+
+#: rhodecode/lib/utils2.py:360
+msgid "just now"
+msgstr ""
+
+#: rhodecode/lib/celerylib/tasks.py:269
+msgid "password reset link"
+msgstr ""
+
+#: rhodecode/model/comment.py:110
+#, python-format
+msgid "on line %s"
+msgstr ""
+
+#: rhodecode/model/comment.py:157
+msgid "[Mention]"
+msgstr ""
+
+#: rhodecode/model/db.py:1140
+msgid "Repository no access"
+msgstr ""
+
+#: rhodecode/model/db.py:1141
+msgid "Repository read access"
+msgstr ""
+
+#: rhodecode/model/db.py:1142
+msgid "Repository write access"
+msgstr ""
+
+#: rhodecode/model/db.py:1143
+msgid "Repository admin access"
+msgstr ""
+
+#: rhodecode/model/db.py:1145
+msgid "Repositories Group no access"
+msgstr ""
+
+#: rhodecode/model/db.py:1146
+msgid "Repositories Group read access"
+msgstr ""
+
+#: rhodecode/model/db.py:1147
+msgid "Repositories Group write access"
+msgstr ""
+
+#: rhodecode/model/db.py:1148
+msgid "Repositories Group admin access"
+msgstr ""
+
+#: rhodecode/model/db.py:1150
+msgid "RhodeCode Administrator"
+msgstr ""
+
+#: rhodecode/model/db.py:1151
+msgid "Repository creation disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1152
+msgid "Repository creation enabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1153
+msgid "Repository forking disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1154
+msgid "Repository forking enabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1155
+msgid "Register disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1156
+msgid "Register new user with RhodeCode with manual activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1159
+msgid "Register new user with RhodeCode with auto activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1579
+msgid "Not Reviewed"
+msgstr ""
+
+#: rhodecode/model/db.py:1580
+msgid "Approved"
+msgstr ""
+
+#: rhodecode/model/db.py:1581
+msgid "Rejected"
+msgstr ""
+
+#: rhodecode/model/db.py:1582
+msgid "Under Review"
+msgstr ""
+
+#: rhodecode/model/forms.py:43
+msgid "Please enter a login"
+msgstr ""
+
+#: rhodecode/model/forms.py:44
+#, python-format
+msgid "Enter a value %(min)i characters long or more"
+msgstr ""
+
+#: rhodecode/model/forms.py:52
+msgid "Please enter a password"
+msgstr ""
+
+#: rhodecode/model/forms.py:53
+#, python-format
+msgid "Enter %(min)i characters or more"
+msgstr ""
+
+#: rhodecode/model/notification.py:220
+msgid "commented on commit"
+msgstr ""
+
+#: rhodecode/model/notification.py:221
+msgid "sent message"
+msgstr ""
+
+#: rhodecode/model/notification.py:222
+msgid "mentioned you"
+msgstr ""
+
+#: rhodecode/model/notification.py:223
+msgid "registered in RhodeCode"
+msgstr ""
+
+#: rhodecode/model/notification.py:224
+msgid "opened new pull request"
+msgstr ""
+
+#: rhodecode/model/notification.py:225
+msgid "commented on pull request"
+msgstr ""
+
+#: rhodecode/model/pull_request.py:84
+#, python-format
+msgid "%(user)s wants you to review pull request #%(pr_id)s"
+msgstr ""
+
+#: rhodecode/model/scm.py:535
+msgid "latest tip"
+msgstr ""
+
+#: rhodecode/model/user.py:230
+msgid "new user registration"
+msgstr ""
+
+#: rhodecode/model/user.py:255 rhodecode/model/user.py:277
+#: rhodecode/model/user.py:299
+msgid "You can't Edit this user since it's crucial for entire application"
+msgstr ""
+
+#: rhodecode/model/user.py:323
+msgid "You can't remove this user since it's crucial for entire application"
+msgstr ""
+
+#: rhodecode/model/user.py:329
+#, python-format
+msgid ""
+"user \"%s\" still owns %s repositories and cannot be removed. Switch "
+"owners or remove those repositories. %s"
+msgstr ""
+
+#: rhodecode/model/validators.py:35 rhodecode/model/validators.py:36
+msgid "Value cannot be an empty list"
+msgstr ""
+
+#: rhodecode/model/validators.py:82
+#, python-format
+msgid "Username \"%(username)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:84
+#, python-format
+msgid "Username \"%(username)s\" is forbidden"
+msgstr ""
+
+#: rhodecode/model/validators.py:86
 msgid ""
 "Username may only contain alphanumeric characters underscores, periods or"
 " dashes and must begin with alphanumeric character"
 msgstr ""
 
-#: rhodecode/model/forms.py:94
-msgid "Invalid group name"
-msgstr ""
-
-#: rhodecode/model/forms.py:104
-msgid "This users group already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:110
+#: rhodecode/model/validators.py:114
+#, python-format
+msgid "Username %(username)s is not valid"
+msgstr ""
+
+#: rhodecode/model/validators.py:133
+msgid "Invalid users group name"
+msgstr ""
+
+#: rhodecode/model/validators.py:134
+#, python-format
+msgid "Users group \"%(usersgroup)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:136
 msgid ""
-"Group name may only contain alphanumeric characters underscores, periods "
-"or dashes and must begin with alphanumeric character"
-msgstr ""
-
-#: rhodecode/model/forms.py:132
+"users group name may only contain  alphanumeric characters underscores, "
+"periods or dashes and must begin with alphanumeric character"
+msgstr ""
+
+#: rhodecode/model/validators.py:174
 msgid "Cannot assign this group as parent"
 msgstr ""
 
-#: rhodecode/model/forms.py:148
-msgid "This group already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:164 rhodecode/model/forms.py:172
-#: rhodecode/model/forms.py:180
-msgid "Invalid characters in password"
-msgstr ""
-
-#: rhodecode/model/forms.py:191
+#: rhodecode/model/validators.py:175
+#, python-format
+msgid "Group \"%(group_name)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:177
+#, python-format
+msgid "Repository with name \"%(group_name)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:235
+msgid "Invalid characters (non-ascii) in password"
+msgstr ""
+
+#: rhodecode/model/validators.py:250
 msgid "Passwords do not match"
 msgstr ""
 
-#: rhodecode/model/forms.py:196
+#: rhodecode/model/validators.py:267
 msgid "invalid password"
 msgstr ""
 
-#: rhodecode/model/forms.py:197
+#: rhodecode/model/validators.py:268
 msgid "invalid user name"
 msgstr ""
 
-#: rhodecode/model/forms.py:198
+#: rhodecode/model/validators.py:269
 msgid "Your account is disabled"
 msgstr ""
 
-#: rhodecode/model/forms.py:233
-msgid "This username is not valid"
-msgstr ""
-
-#: rhodecode/model/forms.py:245
-msgid "This repository name is disallowed"
-msgstr ""
-
-#: rhodecode/model/forms.py:266
+#: rhodecode/model/validators.py:313
+#, python-format
+msgid "Repository name %(repo)s is disallowed"
+msgstr ""
+
+#: rhodecode/model/validators.py:315
 #, python-format
-msgid "This repository already exists in group \"%s\""
-msgstr ""
-
-#: rhodecode/model/forms.py:274
-msgid "This repository already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:312 rhodecode/model/forms.py:319
+msgid "Repository named %(repo)s already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:316
+#, python-format
+msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
+msgstr ""
+
+#: rhodecode/model/validators.py:318
+#, python-format
+msgid "Repositories group with name \"%(repo)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:431
 msgid "invalid clone url"
 msgstr ""
 
-#: rhodecode/model/forms.py:322
-msgid "Invalid clone url, provide a valid clone http\\s url"
-msgstr ""
-
-#: rhodecode/model/forms.py:334
-msgid "Fork have to be the same type as original"
-msgstr ""
-
-#: rhodecode/model/forms.py:341
+#: rhodecode/model/validators.py:432
+msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url"
+msgstr ""
+
+#: rhodecode/model/validators.py:457
+msgid "Fork have to be the same type as parent"
+msgstr ""
+
+#: rhodecode/model/validators.py:478
 msgid "This username or users group name is not valid"
 msgstr ""
 
-#: rhodecode/model/forms.py:403
+#: rhodecode/model/validators.py:562
 msgid "This is not a valid path"
 msgstr ""
 
-#: rhodecode/model/forms.py:416
+#: rhodecode/model/validators.py:577
 msgid "This e-mail address is already taken"
 msgstr ""
 
-#: rhodecode/model/forms.py:427
-msgid "This e-mail address doesn't exist."
-msgstr ""
-
-#: rhodecode/model/forms.py:447
+#: rhodecode/model/validators.py:597
+#, python-format
+msgid "e-mail \"%(email)s\" does not exist."
+msgstr ""
+
+#: rhodecode/model/validators.py:634
 msgid ""
 "The LDAP Login attribute of the CN must be specified - this is the name "
-"of the attribute that is equivalent to 'username'"
-msgstr ""
-
-#: rhodecode/model/forms.py:466
-msgid "Please enter a login"
-msgstr ""
-
-#: rhodecode/model/forms.py:467
-#, python-format
-msgid "Enter a value %(min)i characters long or more"
-msgstr ""
-
-#: rhodecode/model/forms.py:475
-msgid "Please enter a password"
-msgstr ""
-
-#: rhodecode/model/forms.py:476
+"of the attribute that is equivalent to \"username\""
+msgstr ""
+
+#: rhodecode/model/validators.py:653
 #, python-format
-msgid "Enter %(min)i characters or more"
-msgstr ""
-
-#: rhodecode/model/user.py:145
-msgid "[RhodeCode] New User registration"
-msgstr ""
-
-#: rhodecode/model/user.py:157 rhodecode/model/user.py:179
-msgid "You can't Edit this user since it's crucial for entire application"
-msgstr ""
-
-#: rhodecode/model/user.py:201
-msgid "You can't remove this user since it's crucial for entire application"
-msgstr ""
-
-#: rhodecode/model/user.py:204
-#, python-format
-msgid ""
-"This user still owns %s repositories and cannot be removed. Switch owners"
-" or remove those repositories"
-msgstr ""
-
-#: rhodecode/templates/index.html:4
+msgid "Revisions %(revs)s are already part of pull request or have set status"
+msgstr ""
+
+#: rhodecode/templates/index.html:3
 msgid "Dashboard"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:22
-#: rhodecode/templates/admin/users/user_edit_my_account.html:102
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/repo_switcher_list.html:4
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/users/user_edit_my_account.html:31
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/bookmarks/bookmarks.html:10
+#: rhodecode/templates/branches/branches.html:9
+#: rhodecode/templates/journal/journal.html:40
+#: rhodecode/templates/tags/tags.html:10
 msgid "quick filter..."
 msgstr ""
 
-#: rhodecode/templates/index_base.html:23
-#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/base/base.html:221
 msgid "repositories"
 msgstr ""
 
+#: rhodecode/templates/index_base.html:13
+#: rhodecode/templates/index_base.html:15
+#: rhodecode/templates/admin/repos/repos.html:21
+msgid "ADD REPOSITORY"
+msgstr ""
+
 #: rhodecode/templates/index_base.html:29
-#: rhodecode/templates/admin/repos/repos.html:22
-msgid "ADD NEW REPOSITORY"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:33
@@ -862,158 +1249,158 @@
 msgid "Group name"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:42
-#: rhodecode/templates/index_base.html:73
-#: rhodecode/templates/admin/repos/repo_add_base.html:44
-#: rhodecode/templates/admin/repos/repo_edit.html:64
-#: rhodecode/templates/admin/repos/repos.html:31
+#: rhodecode/templates/index_base.html:30
+#: rhodecode/templates/index_base.html:71
+#: rhodecode/templates/index_base.html:142
+#: rhodecode/templates/index_base.html:168
+#: rhodecode/templates/admin/repos/repo_add_base.html:56
+#: rhodecode/templates/admin/repos/repo_edit.html:75
+#: rhodecode/templates/admin/repos/repos.html:72
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:34
-#: rhodecode/templates/settings/repo_fork.html:40
-#: rhodecode/templates/settings/repo_settings.html:40
-#: rhodecode/templates/summary/summary.html:92
+#: rhodecode/templates/forks/fork.html:59
+#: rhodecode/templates/settings/repo_settings.html:66
+#: rhodecode/templates/summary/summary.html:105
 msgid "Description"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:53
+#: rhodecode/templates/index_base.html:40
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46
 msgid "Repositories group"
 msgstr ""
 
+#: rhodecode/templates/index_base.html:70
+#: rhodecode/templates/index_base.html:166
+#: rhodecode/templates/admin/repos/repo_add_base.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:32
+#: rhodecode/templates/admin/repos/repos.html:70
+#: rhodecode/templates/admin/users/user_edit.html:192
+#: rhodecode/templates/admin/users/user_edit_my_account.html:59
+#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:6
+#: rhodecode/templates/bookmarks/bookmarks.html:36
+#: rhodecode/templates/bookmarks/bookmarks_data.html:6
+#: rhodecode/templates/branches/branches.html:51
+#: rhodecode/templates/files/files_browser.html:47
+#: rhodecode/templates/journal/journal.html:59
+#: rhodecode/templates/journal/journal.html:107
+#: rhodecode/templates/journal/journal.html:186
+#: rhodecode/templates/settings/repo_settings.html:31
+#: rhodecode/templates/summary/summary.html:43
+#: rhodecode/templates/summary/summary.html:123
+#: rhodecode/templates/tags/tags.html:36
+#: rhodecode/templates/tags/tags_data.html:6
+msgid "Name"
+msgstr ""
+
 #: rhodecode/templates/index_base.html:72
-#: rhodecode/templates/admin/repos/repo_add_base.html:9
-#: rhodecode/templates/admin/repos/repo_edit.html:32
-#: rhodecode/templates/admin/repos/repos.html:30
-#: rhodecode/templates/admin/users/user_edit_my_account.html:117
-#: rhodecode/templates/files/files_browser.html:157
-#: rhodecode/templates/settings/repo_settings.html:31
-#: rhodecode/templates/summary/summary.html:31
-#: rhodecode/templates/summary/summary.html:107
-msgid "Name"
+msgid "Last change"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:73
+#: rhodecode/templates/index_base.html:171
+#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/journal/journal.html:188
+msgid "Tip"
 msgstr ""
 
 #: rhodecode/templates/index_base.html:74
-#: rhodecode/templates/admin/repos/repos.html:32
-#: rhodecode/templates/summary/summary.html:114
-msgid "Last change"
+#: rhodecode/templates/index_base.html:173
+#: rhodecode/templates/admin/repos/repo_edit.html:121
+#: rhodecode/templates/admin/repos/repos.html:73
+msgid "Owner"
 msgstr ""
 
 #: rhodecode/templates/index_base.html:75
-#: rhodecode/templates/admin/repos/repos.html:33
-msgid "Tip"
+#: rhodecode/templates/summary/summary.html:48
+#: rhodecode/templates/summary/summary.html:51
+msgid "RSS"
 msgstr ""
 
 #: rhodecode/templates/index_base.html:76
-#: rhodecode/templates/admin/repos/repo_edit.html:97
-msgid "Owner"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:77
-#: rhodecode/templates/journal/public_journal.html:20
-#: rhodecode/templates/summary/summary.html:180
-#: rhodecode/templates/summary/summary.html:183
-msgid "RSS"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:78
-#: rhodecode/templates/journal/public_journal.html:23
-#: rhodecode/templates/summary/summary.html:181
-#: rhodecode/templates/summary/summary.html:184
 msgid "Atom"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:87
-#: rhodecode/templates/index_base.html:89
-#: rhodecode/templates/index_base.html:91
-#: rhodecode/templates/base/base.html:209
-#: rhodecode/templates/base/base.html:211
-#: rhodecode/templates/base/base.html:213
-#: rhodecode/templates/summary/summary.html:4
-msgid "Summary"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:95
-#: rhodecode/templates/index_base.html:97
-#: rhodecode/templates/index_base.html:99
-#: rhodecode/templates/base/base.html:225
-#: rhodecode/templates/base/base.html:227
-#: rhodecode/templates/base/base.html:229
-#: rhodecode/templates/changelog/changelog.html:6
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "Changelog"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:103
-#: rhodecode/templates/index_base.html:105
-#: rhodecode/templates/index_base.html:107
-#: rhodecode/templates/base/base.html:268
-#: rhodecode/templates/base/base.html:270
-#: rhodecode/templates/base/base.html:272
-#: rhodecode/templates/files/files.html:4
-msgid "Files"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:116
-#: rhodecode/templates/admin/repos/repos.html:42
-#: rhodecode/templates/admin/users/user_edit_my_account.html:127
-#: rhodecode/templates/summary/summary.html:48
-msgid "Mercurial repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:118
-#: rhodecode/templates/admin/repos/repos.html:44
-#: rhodecode/templates/admin/users/user_edit_my_account.html:129
-#: rhodecode/templates/summary/summary.html:51
-msgid "Git repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:123
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
-#: rhodecode/templates/journal/journal.html:53
-#: rhodecode/templates/summary/summary.html:56
-msgid "private repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:125
-#: rhodecode/templates/journal/journal.html:55
-#: rhodecode/templates/summary/summary.html:58
-msgid "public repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:133
-#: rhodecode/templates/base/base.html:291
-#: rhodecode/templates/settings/repo_fork.html:13
-msgid "fork"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:134
-#: rhodecode/templates/admin/repos/repos.html:60
-#: rhodecode/templates/admin/users/user_edit_my_account.html:143
-#: rhodecode/templates/summary/summary.html:69
-#: rhodecode/templates/summary/summary.html:71
-msgid "Fork of"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:155
-#: rhodecode/templates/admin/repos/repos.html:73
-msgid "No changesets yet"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:161
-#: rhodecode/templates/index_base.html:163
+#: rhodecode/templates/index_base.html:110
+#: rhodecode/templates/index_base.html:112
 #, python-format
 msgid "Subscribe to %s rss feed"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:168
-#: rhodecode/templates/index_base.html:170
+#: rhodecode/templates/index_base.html:117
+#: rhodecode/templates/index_base.html:119
 #, python-format
 msgid "Subscribe to %s atom feed"
 msgstr ""
 
+#: rhodecode/templates/index_base.html:140
+msgid "Group Name"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:158
+#: rhodecode/templates/index_base.html:198
+#: rhodecode/templates/admin/repos/repos.html:94
+#: rhodecode/templates/admin/users/user_edit_my_account.html:179
+#: rhodecode/templates/admin/users/users.html:107
+#: rhodecode/templates/bookmarks/bookmarks.html:60
+#: rhodecode/templates/branches/branches.html:77
+#: rhodecode/templates/journal/journal.html:211
+#: rhodecode/templates/tags/tags.html:60
+msgid "Click to sort ascending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:159
+#: rhodecode/templates/index_base.html:199
+#: rhodecode/templates/admin/repos/repos.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account.html:180
+#: rhodecode/templates/admin/users/users.html:108
+#: rhodecode/templates/bookmarks/bookmarks.html:61
+#: rhodecode/templates/branches/branches.html:78
+#: rhodecode/templates/journal/journal.html:212
+#: rhodecode/templates/tags/tags.html:61
+msgid "Click to sort descending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:169
+msgid "Last Change"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:200
+#: rhodecode/templates/admin/repos/repos.html:96
+#: rhodecode/templates/admin/users/user_edit_my_account.html:181
+#: rhodecode/templates/admin/users/users.html:109
+#: rhodecode/templates/bookmarks/bookmarks.html:62
+#: rhodecode/templates/branches/branches.html:79
+#: rhodecode/templates/journal/journal.html:213
+#: rhodecode/templates/tags/tags.html:62
+msgid "No records found."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:201
+#: rhodecode/templates/admin/repos/repos.html:97
+#: rhodecode/templates/admin/users/user_edit_my_account.html:182
+#: rhodecode/templates/admin/users/users.html:110
+#: rhodecode/templates/bookmarks/bookmarks.html:63
+#: rhodecode/templates/branches/branches.html:80
+#: rhodecode/templates/journal/journal.html:214
+#: rhodecode/templates/tags/tags.html:63
+msgid "Data error."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:202
+#: rhodecode/templates/admin/repos/repos.html:98
+#: rhodecode/templates/admin/users/user_edit_my_account.html:183
+#: rhodecode/templates/admin/users/users.html:111
+#: rhodecode/templates/bookmarks/bookmarks.html:64
+#: rhodecode/templates/branches/branches.html:81
+#: rhodecode/templates/journal/journal.html:215
+#: rhodecode/templates/tags/tags.html:64
+msgid "Loading..."
+msgstr ""
+
 #: rhodecode/templates/login.html:5 rhodecode/templates/login.html:54
-#: rhodecode/templates/base/base.html:38
 msgid "Sign In"
 msgstr ""
 
@@ -1024,25 +1411,29 @@
 #: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20
 #: rhodecode/templates/admin/admin_log.html:5
 #: rhodecode/templates/admin/users/user_add.html:32
-#: rhodecode/templates/admin/users/user_edit.html:47
-#: rhodecode/templates/admin/users/user_edit_my_account.html:45
-#: rhodecode/templates/base/base.html:15
-#: rhodecode/templates/summary/summary.html:106
+#: rhodecode/templates/admin/users/user_edit.html:50
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:26
+#: rhodecode/templates/base/base.html:83
+#: rhodecode/templates/summary/summary.html:122
 msgid "Username"
 msgstr ""
 
 #: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29
 #: rhodecode/templates/admin/ldap/ldap.html:46
 #: rhodecode/templates/admin/users/user_add.html:41
-#: rhodecode/templates/base/base.html:24
+#: rhodecode/templates/base/base.html:92
 msgid "Password"
 msgstr ""
 
+#: rhodecode/templates/login.html:50
+msgid "Remember me"
+msgstr ""
+
 #: rhodecode/templates/login.html:60
 msgid "Forgot your password ?"
 msgstr ""
 
-#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:35
+#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:103
 msgid "Don't have an account ?"
 msgstr ""
 
@@ -1079,24 +1470,24 @@
 msgstr ""
 
 #: rhodecode/templates/register.html:47
-#: rhodecode/templates/admin/users/user_add.html:50
-#: rhodecode/templates/admin/users/user_edit.html:74
-#: rhodecode/templates/admin/users/user_edit_my_account.html:63
+#: rhodecode/templates/admin/users/user_add.html:59
+#: rhodecode/templates/admin/users/user_edit.html:86
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53
 msgid "First Name"
 msgstr ""
 
 #: rhodecode/templates/register.html:56
-#: rhodecode/templates/admin/users/user_add.html:59
-#: rhodecode/templates/admin/users/user_edit.html:83
-#: rhodecode/templates/admin/users/user_edit_my_account.html:72
+#: rhodecode/templates/admin/users/user_add.html:68
+#: rhodecode/templates/admin/users/user_edit.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62
 msgid "Last Name"
 msgstr ""
 
 #: rhodecode/templates/register.html:65
-#: rhodecode/templates/admin/users/user_add.html:68
-#: rhodecode/templates/admin/users/user_edit.html:92
-#: rhodecode/templates/admin/users/user_edit_my_account.html:81
-#: rhodecode/templates/summary/summary.html:108
+#: rhodecode/templates/admin/users/user_add.html:77
+#: rhodecode/templates/admin/users/user_edit.html:104
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71
+#: rhodecode/templates/summary/summary.html:124
 msgid "Email"
 msgstr ""
 
@@ -1108,20 +1499,59 @@
 msgid "Your account must wait for activation by administrator"
 msgstr ""
 
-#: rhodecode/templates/repo_switcher_list.html:14
+#: rhodecode/templates/repo_switcher_list.html:11
+#: rhodecode/templates/admin/repos/repo_add_base.html:65
+#: rhodecode/templates/admin/repos/repo_edit.html:85
+#: rhodecode/templates/settings/repo_settings.html:76
 msgid "Private repository"
 msgstr ""
 
-#: rhodecode/templates/repo_switcher_list.html:19
+#: rhodecode/templates/repo_switcher_list.html:16
 msgid "Public repository"
 msgstr ""
 
+#: rhodecode/templates/switch_to_list.html:3
+#: rhodecode/templates/branches/branches.html:14
+msgid "branches"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:10
+#: rhodecode/templates/branches/branches_data.html:57
+msgid "There are no branches yet"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:15
+#: rhodecode/templates/shortlog/shortlog_data.html:10
+#: rhodecode/templates/tags/tags.html:15
+msgid "tags"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:22
+#: rhodecode/templates/tags/tags_data.html:33
+msgid "There are no tags yet"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:28
+#: rhodecode/templates/bookmarks/bookmarks.html:15
+msgid "bookmarks"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:35
+#: rhodecode/templates/bookmarks/bookmarks_data.html:32
+msgid "There are no bookmarks yet"
+msgstr ""
+
 #: rhodecode/templates/admin/admin.html:5
 #: rhodecode/templates/admin/admin.html:9
 msgid "Admin journal"
 msgstr ""
 
 #: rhodecode/templates/admin/admin_log.html:6
+#: rhodecode/templates/admin/repos/repos.html:74
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:8
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:9
+#: rhodecode/templates/journal/journal.html:61
+#: rhodecode/templates/journal/journal.html:62
 msgid "Action"
 msgstr ""
 
@@ -1130,6 +1560,11 @@
 msgstr ""
 
 #: rhodecode/templates/admin/admin_log.html:8
+#: rhodecode/templates/bookmarks/bookmarks.html:37
+#: rhodecode/templates/bookmarks/bookmarks_data.html:7
+#: rhodecode/templates/branches/branches.html:52
+#: rhodecode/templates/tags/tags.html:37
+#: rhodecode/templates/tags/tags_data.html:7
 msgid "Date"
 msgstr ""
 
@@ -1137,7 +1572,7 @@
 msgid "From IP"
 msgstr ""
 
-#: rhodecode/templates/admin/admin_log.html:52
+#: rhodecode/templates/admin/admin_log.html:53
 msgid "No actions yet"
 msgstr ""
 
@@ -1214,23 +1649,64 @@
 msgstr ""
 
 #: rhodecode/templates/admin/ldap/ldap.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:141
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:74
 #: rhodecode/templates/admin/settings/hooks.html:73
-#: rhodecode/templates/admin/users/user_edit.html:117
-#: rhodecode/templates/admin/users/user_edit.html:142
-#: rhodecode/templates/admin/users/user_edit_my_account.html:89
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:263
+#: rhodecode/templates/admin/users/user_edit.html:129
+#: rhodecode/templates/admin/users/user_edit.html:174
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:79
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:135
+#: rhodecode/templates/settings/repo_settings.html:93
 msgid "Save"
 msgstr ""
 
+#: rhodecode/templates/admin/notifications/notifications.html:5
+#: rhodecode/templates/admin/notifications/notifications.html:9
+msgid "My Notifications"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:29
+msgid "All"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:30
+#, fuzzy
+msgid "Comments"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:31
+#: rhodecode/templates/base/base.html:254
+#: rhodecode/templates/base/base.html:256
+msgid "Pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:35
+msgid "Mark all read"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications_data.html:39
+msgid "No notifications here yet"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/show_notification.html:5
+#: rhodecode/templates/admin/notifications/show_notification.html:11
+msgid "Show notification"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/show_notification.html:9
+msgid "Notifications"
+msgstr ""
+
 #: rhodecode/templates/admin/permissions/permissions.html:5
 msgid "Permissions administration"
 msgstr ""
 
 #: rhodecode/templates/admin/permissions/permissions.html:11
-#: rhodecode/templates/admin/repos/repo_edit.html:109
-#: rhodecode/templates/admin/users/user_edit.html:127
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:248
-#: rhodecode/templates/settings/repo_settings.html:58
+#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
+#: rhodecode/templates/admin/users/user_edit.html:139
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:100
+#: rhodecode/templates/settings/repo_settings.html:86
 msgid "Permissions"
 msgstr ""
 
@@ -1266,6 +1742,11 @@
 msgstr ""
 
 #: rhodecode/templates/admin/permissions/permissions.html:71
+msgid "Repository forking"
+msgstr ""
+
+#: rhodecode/templates/admin/permissions/permissions.html:78
+#: rhodecode/templates/admin/repos/repo_edit.html:241
 msgid "set"
 msgstr ""
 
@@ -1276,7 +1757,6 @@
 
 #: rhodecode/templates/admin/repos/repo_add.html:11
 #: rhodecode/templates/admin/repos/repo_edit.html:11
-#: rhodecode/templates/admin/repos/repos.html:10
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
 msgid "Repositories"
 msgstr ""
@@ -1286,30 +1766,70 @@
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_add_base.html:20
-#: rhodecode/templates/summary/summary.html:80
-#: rhodecode/templates/summary/summary.html:82
+#: rhodecode/templates/summary/summary.html:95
+#: rhodecode/templates/summary/summary.html:96
 msgid "Clone from"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:28
-#: rhodecode/templates/admin/repos/repo_edit.html:48
+#: rhodecode/templates/admin/repos/repo_add_base.html:24
+#: rhodecode/templates/admin/repos/repo_edit.html:44
+#: rhodecode/templates/settings/repo_settings.html:43
+msgid "Optional http[s] url from which repository should be cloned."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:29
+#: rhodecode/templates/admin/repos/repo_edit.html:49
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:4
+#: rhodecode/templates/forks/fork.html:50
+#: rhodecode/templates/settings/repo_settings.html:48
 msgid "Repository group"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:36
-#: rhodecode/templates/admin/repos/repo_edit.html:56
+#: rhodecode/templates/admin/repos/repo_add_base.html:33
+#: rhodecode/templates/forks/fork.html:54
+msgid "Optionaly select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:38
+#: rhodecode/templates/admin/repos/repo_edit.html:58
 msgid "Type"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:52
-#: rhodecode/templates/admin/repos/repo_edit.html:73
-#: rhodecode/templates/settings/repo_fork.html:48
-#: rhodecode/templates/settings/repo_settings.html:49
-msgid "Private"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_add_base.html:59
+#: rhodecode/templates/admin/repos/repo_add_base.html:42
+msgid "Type of repository to create."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:47
+#: rhodecode/templates/admin/repos/repo_edit.html:66
+#: rhodecode/templates/forks/fork.html:41
+#: rhodecode/templates/settings/repo_settings.html:57
+msgid "Landing revision"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:51
+#: rhodecode/templates/admin/repos/repo_edit.html:70
+#: rhodecode/templates/forks/fork.html:45
+#: rhodecode/templates/settings/repo_settings.html:61
+msgid "Default revision for files page, downloads, whoosh and readme"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:60
+#: rhodecode/templates/admin/repos/repo_edit.html:79
+#: rhodecode/templates/forks/fork.html:63
+#: rhodecode/templates/settings/repo_settings.html:70
+msgid "Keep it short and to the point. Use a README file for longer descriptions."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:69
+#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/forks/fork.html:72
+#: rhodecode/templates/settings/repo_settings.html:80
+msgid ""
+"Private repositories are only visible to people explicitly added as "
+"collaborators."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:73
 msgid "add"
 msgstr ""
 
@@ -1323,183 +1843,269 @@
 
 #: rhodecode/templates/admin/repos/repo_edit.html:13
 #: rhodecode/templates/admin/users/user_edit.html:13
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
+#: rhodecode/templates/admin/users/user_edit.html:224
+#: rhodecode/templates/admin/users/user_edit.html:226
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:13
-#: rhodecode/templates/files/files_annotate.html:49
-#: rhodecode/templates/files/files_source.html:20
+#: rhodecode/templates/files/files_source.html:44
+#: rhodecode/templates/journal/journal.html:81
 msgid "edit"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit.html:40
+#: rhodecode/templates/settings/repo_settings.html:39
 msgid "Clone uri"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:81
+#: rhodecode/templates/admin/repos/repo_edit.html:53
+#: rhodecode/templates/settings/repo_settings.html:52
+msgid "Optional select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:94
 msgid "Enable statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:98
+msgid "Enable statistics window on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:103
 msgid "Enable downloads"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:127
+#: rhodecode/templates/admin/repos/repo_edit.html:107
+msgid "Enable download menu on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:112
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:66
+msgid "Enable locking"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:116
+msgid "Enable lock-by-pulling on repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:126
+msgid "Change owner of this repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:142
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:75
+#: rhodecode/templates/admin/settings/settings.html:113
+#: rhodecode/templates/admin/settings/settings.html:168
+#: rhodecode/templates/admin/settings/settings.html:258
+#: rhodecode/templates/admin/users/user_edit.html:130
+#: rhodecode/templates/admin/users/user_edit.html:175
+#: rhodecode/templates/admin/users/user_edit.html:278
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:136
+#: rhodecode/templates/files/files_add.html:82
+#: rhodecode/templates/files/files_edit.html:68
+#: rhodecode/templates/pullrequests/pullrequest.html:124
+#: rhodecode/templates/settings/repo_settings.html:94
+msgid "Reset"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:152
 msgid "Administration"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:130
+#: rhodecode/templates/admin/repos/repo_edit.html:155
 msgid "Statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Reset current statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Confirm to remove current statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:137
-msgid "Fetched to rev"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:138
-msgid "Percentage of stats gathered"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:147
-msgid "Remote"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:151
-msgid "Pull changes from remote location"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:151
-msgid "Confirm to pull changes from remote side"
-msgstr ""
-
 #: rhodecode/templates/admin/repos/repo_edit.html:162
+msgid "Fetched to rev"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:163
+msgid "Stats gathered"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:171
+msgid "Remote"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Pull changes from remote location"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Confirm to pull changes from remote side"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:186
 msgid "Cache"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Invalidate repository cache"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Confirm to invalidate repository cache"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:177
+#: rhodecode/templates/admin/repos/repo_edit.html:195
+#: rhodecode/templates/base/base.html:318
+#: rhodecode/templates/base/base.html:320
+#: rhodecode/templates/base/base.html:322
+msgid "Public journal"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:201
 msgid "Remove from public journal"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:179
+#: rhodecode/templates/admin/repos/repo_edit.html:203
 msgid "Add to public journal"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:185
+#: rhodecode/templates/admin/repos/repo_edit.html:208
+msgid ""
+"All actions made on this repository will be accessible to everyone in "
+"public journal"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:215
+msgid "Locking"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Unlock locked repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Confirm to unlock repository"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "lock repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "Confirm to lock repository"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:224
+msgid "Repository is not locked"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:229
+msgid "Force locking on repository. Works only when anonymous access is disabled"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:236
+msgid "Set as fork of"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:245
+msgid "Manually set this repository as a fork of another from the list"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:251
+#: rhodecode/templates/changeset/changeset_file_comment.html:26
 msgid "Delete"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
+#: rhodecode/templates/admin/repos/repo_edit.html:255
 msgid "Remove this repository"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
-#: rhodecode/templates/admin/repos/repos.html:79
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+#: rhodecode/templates/journal/journal.html:84
 msgid "Confirm to delete this repository"
 msgstr ""
 
+#: rhodecode/templates/admin/repos/repo_edit.html:259
+msgid ""
+"This repository will be renamed in a special way in order to be "
+"unaccesible for RhodeCode and VCS systems.\n"
+"                         If you need fully delete it from filesystem "
+"please do it manually"
+msgstr ""
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:3
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3
 msgid "none"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:4
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4
 msgid "read"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:5
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5
 msgid "write"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:6
-#: rhodecode/templates/admin/users/users.html:38
-#: rhodecode/templates/base/base.html:296
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6
+#: rhodecode/templates/admin/users/users.html:85
+#: rhodecode/templates/base/base.html:217
 msgid "admin"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:7
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7
 msgid "member"
 msgstr ""
 
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
+#: rhodecode/templates/data_table/_dt_elements.html:67
+#: rhodecode/templates/journal/journal.html:132
+#: rhodecode/templates/summary/summary.html:76
+msgid "private repository"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:19
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:28
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:18
+msgid "default"
+msgstr ""
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:33
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:53
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:58
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:23
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:42
 msgid "revoke"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:75
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:83
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:67
 msgid "Add another member"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:89
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:97
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81
 msgid "Failed to remove user"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:104
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:112
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:96
 msgid "Failed to remove users group"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:205
-msgid "Group"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:206
-#: rhodecode/templates/admin/users_groups/users_groups.html:33
-msgid "members"
-msgstr ""
-
 #: rhodecode/templates/admin/repos/repos.html:5
 msgid "Repositories administration"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repos.html:34
-#: rhodecode/templates/summary/summary.html:100
-msgid "Contact"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:35
-#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
-#: rhodecode/templates/admin/users/user_edit_my_account.html:119
-#: rhodecode/templates/admin/users/users.html:40
-#: rhodecode/templates/admin/users_groups/users_groups.html:35
-msgid "action"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:51
-#: rhodecode/templates/admin/users/user_edit_my_account.html:134
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
-msgid "private"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:53
-#: rhodecode/templates/admin/repos/repos.html:59
-#: rhodecode/templates/admin/users/user_edit_my_account.html:136
-#: rhodecode/templates/admin/users/user_edit_my_account.html:142
-#: rhodecode/templates/summary/summary.html:68
-msgid "public"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:79
-#: rhodecode/templates/admin/users/users.html:55
-msgid "delete"
-msgstr ""
-
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:8
 msgid "Groups"
 msgstr ""
 
-#: rhodecode/templates/admin/repos_groups/repos_groups.html:13
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:12
 msgid "with"
 msgstr ""
 
@@ -1522,10 +2128,10 @@
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:58
-#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
-#: rhodecode/templates/admin/users/user_add.html:85
+#: rhodecode/templates/admin/users/user_add.html:94
 #: rhodecode/templates/admin/users_groups/users_group_add.html:49
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:90
+#: rhodecode/templates/pullrequests/pullrequest_show.html:113
 msgid "save"
 msgstr ""
 
@@ -1537,6 +2143,12 @@
 msgid "edit repos group"
 msgstr ""
 
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:70
+msgid ""
+"Enable lock-by-pulling on group. This option will be applied to all other"
+" groups and repositories inside"
+msgstr ""
+
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5
 msgid "Repositories groups administration"
 msgstr ""
@@ -1546,11 +2158,26 @@
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:35
-msgid "Number of repositories"
+msgid "Number of toplevel repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
+#: rhodecode/templates/admin/users/users.html:87
+#: rhodecode/templates/admin/users_groups/users_groups.html:35
+msgid "action"
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
-msgid "Confirm to delete this group"
+#: rhodecode/templates/admin/users/user_edit.html:255
+#: rhodecode/templates/admin/users_groups/users_groups.html:44
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#: rhodecode/templates/data_table/_dt_elements.html:103
+msgid "delete"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#, python-format
+msgid "Confirm to delete this group: %s"
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:62
@@ -1564,7 +2191,6 @@
 
 #: rhodecode/templates/admin/settings/hooks.html:9
 #: rhodecode/templates/admin/settings/settings.html:9
-#: rhodecode/templates/settings/repo_settings.html:5
 #: rhodecode/templates/settings/repo_settings.html:13
 msgid "Settings"
 msgstr ""
@@ -1604,115 +2230,185 @@
 msgid "destroy old data"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:45
+#: rhodecode/templates/admin/settings/settings.html:41
+msgid ""
+"Rescan repositories location for new repositories. Also deletes obsolete "
+"if `destroy` flag is checked "
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:46
 msgid "Rescan repositories"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:51
+#: rhodecode/templates/admin/settings/settings.html:52
 msgid "Whoosh indexing"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:59
+#: rhodecode/templates/admin/settings/settings.html:60
 msgid "index build option"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:64
+#: rhodecode/templates/admin/settings/settings.html:65
 msgid "build from scratch"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:70
+#: rhodecode/templates/admin/settings/settings.html:71
 msgid "Reindex"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:76
+#: rhodecode/templates/admin/settings/settings.html:77
 msgid "Global application settings"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:85
+#: rhodecode/templates/admin/settings/settings.html:86
 msgid "Application name"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:94
+#: rhodecode/templates/admin/settings/settings.html:95
 msgid "Realm text"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:103
+#: rhodecode/templates/admin/settings/settings.html:104
 msgid "GA code"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:111
-#: rhodecode/templates/admin/settings/settings.html:177
-msgid "Save settings"
-msgstr ""
-
 #: rhodecode/templates/admin/settings/settings.html:112
-#: rhodecode/templates/admin/settings/settings.html:178
-#: rhodecode/templates/admin/users/user_edit.html:118
-#: rhodecode/templates/admin/users/user_edit.html:143
-#: rhodecode/templates/admin/users/user_edit_my_account.html:90
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:264
-#: rhodecode/templates/files/files_edit.html:50
-msgid "Reset"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:118
-msgid "Mercurial settings"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:127
+#: rhodecode/templates/admin/settings/settings.html:167
+#: rhodecode/templates/admin/settings/settings.html:257
+msgid "Save settings"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:119
+msgid "Visualisation settings"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:128
+msgid "Icons"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:133
+msgid "Show public repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:137
+msgid "Show private repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:144
+msgid "Meta-Tagging"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:149
+msgid "Stylify recognised metatags:"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:176
+msgid "VCS settings"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:185
 msgid "Web"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:132
-msgid "require ssl for pushing"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:139
+#: rhodecode/templates/admin/settings/settings.html:190
+msgid "require ssl for vcs operations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:192
+msgid ""
+"RhodeCode will require SSL for pushing or pulling. If SSL is missing it "
+"will return HTTP Error 406: Not Acceptable"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:198
 msgid "Hooks"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:142
-msgid "advanced setup"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:147
+#: rhodecode/templates/admin/settings/settings.html:203
 msgid "Update repository after push (hg update)"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:151
+#: rhodecode/templates/admin/settings/settings.html:207
 msgid "Show repository size after push"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:155
+#: rhodecode/templates/admin/settings/settings.html:211
 msgid "Log user push commands"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:159
+#: rhodecode/templates/admin/settings/settings.html:215
 msgid "Log user pull commands"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:166
+#: rhodecode/templates/admin/settings/settings.html:219
+msgid "advanced setup"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:224
+msgid "Mercurial Extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:229
+msgid "largefiles extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:233
+msgid "hgsubversion extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:235
+msgid ""
+"Requires hgsubversion library installed. Allows clonning from svn remote "
+"locations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:245
 msgid "Repositories location"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:171
+#: rhodecode/templates/admin/settings/settings.html:250
 msgid ""
 "This a crucial application setting. If you are really sure you need to "
 "change this, you must restart application in order to make this setting "
 "take effect. Click this label to unlock."
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:172
+#: rhodecode/templates/admin/settings/settings.html:251
 msgid "unlock"
 msgstr ""
 
+#: rhodecode/templates/admin/settings/settings.html:252
+msgid ""
+"Location where repositories are stored. After changing this value a "
+"restart, and rescan is required"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:272
+msgid "Test Email"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:280
+msgid "Email to"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:288
+msgid "Send"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:294
+msgid "System Info and Packages"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:297
+msgid "show"
+msgstr ""
+
 #: rhodecode/templates/admin/users/user_add.html:5
 msgid "Add user"
 msgstr ""
 
 #: rhodecode/templates/admin/users/user_add.html:10
 #: rhodecode/templates/admin/users/user_edit.html:11
-#: rhodecode/templates/admin/users/users.html:9
 msgid "Users"
 msgstr ""
 
@@ -1720,8 +2416,12 @@
 msgid "add new user"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_add.html:77
-#: rhodecode/templates/admin/users/user_edit.html:101
+#: rhodecode/templates/admin/users/user_add.html:50
+msgid "Password confirmation"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_add.html:86
+#: rhodecode/templates/admin/users/user_edit.html:113
 #: rhodecode/templates/admin/users_groups/users_group_add.html:41
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:42
 msgid "Active"
@@ -1731,36 +2431,93 @@
 msgid "Edit user"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:33
-#: rhodecode/templates/admin/users/user_edit_my_account.html:32
+#: rhodecode/templates/admin/users/user_edit.html:34
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10
 msgid "Change your avatar at"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:34
-#: rhodecode/templates/admin/users/user_edit_my_account.html:33
+#: rhodecode/templates/admin/users/user_edit.html:35
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11
 msgid "Using"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:40
-#: rhodecode/templates/admin/users/user_edit_my_account.html:39
+#: rhodecode/templates/admin/users/user_edit.html:43
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20
 msgid "API key"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:56
+#: rhodecode/templates/admin/users/user_edit.html:59
 msgid "LDAP DN"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:65
-#: rhodecode/templates/admin/users/user_edit_my_account.html:54
+#: rhodecode/templates/admin/users/user_edit.html:68
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:35
 msgid "New password"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:135
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:256
+#: rhodecode/templates/admin/users/user_edit.html:77
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44
+msgid "New password confirmation"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:147
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:108
+msgid "Inherit default permissions"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:152
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:113
+#, python-format
+msgid ""
+"Select to inherit permissions from %s settings. With this selected below "
+"options does not have any action"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:158
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:119
 msgid "Create repositories"
 msgstr ""
 
+#: rhodecode/templates/admin/users/user_edit.html:166
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:127
+msgid "Fork repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:186
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:22
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:39
+msgid "Nothing here yet"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account.html:60
+#: rhodecode/templates/admin/users/user_edit_my_account.html:194
+msgid "Permission"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:194
+msgid "Edit Permission"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:243
+msgid "Email addresses"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:256
+#, python-format
+msgid "Confirm to delete this email: %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:270
+msgid "New email address"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:277
+msgid "Add"
+msgstr ""
+
 #: rhodecode/templates/admin/users/user_edit_my_account.html:5
+#: rhodecode/templates/base/base.html:124
 msgid "My account"
 msgstr ""
 
@@ -1768,26 +2525,74 @@
 msgid "My Account"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:101
-msgid "My repositories"
-msgstr ""
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:107
-msgid "ADD REPOSITORY"
-msgstr ""
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:118
-#: rhodecode/templates/branches/branches_data.html:7
-#: rhodecode/templates/shortlog/shortlog_data.html:8
-#: rhodecode/templates/tags/tags_data.html:7
-msgid "revision"
-msgstr ""
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:35
+msgid "My permissions"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:38
+#: rhodecode/templates/journal/journal.html:41
+msgid "My repos"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:41
+msgid "My pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:45
+msgid "Add repo"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2
+msgid "Opened by me"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:10
+#, python-format
+msgid "Pull request #%s opened on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15
+msgid "Confirm to delete this pull request"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:26
+msgid "I participate in"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:33
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:30
+#, python-format
+msgid "Pull request #%s opened by %s on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:7
+#: rhodecode/templates/bookmarks/bookmarks.html:40
+#: rhodecode/templates/bookmarks/bookmarks_data.html:9
+#: rhodecode/templates/branches/branches.html:55
+#: rhodecode/templates/journal/journal.html:60
+#: rhodecode/templates/tags/tags.html:40
+#: rhodecode/templates/tags/tags_data.html:9
+msgid "Revision"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/journal/journal.html:81
+msgid "private"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#, python-format
+msgid "Confirm to delete this repository: %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:38
+#: rhodecode/templates/journal/journal.html:94
 msgid "No repositories yet"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:40
+#: rhodecode/templates/journal/journal.html:96
 msgid "create one now"
 msgstr ""
 
@@ -1795,42 +2600,41 @@
 msgid "Users administration"
 msgstr ""
 
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/base/base.html:223
+msgid "users"
+msgstr ""
+
 #: rhodecode/templates/admin/users/users.html:23
 msgid "ADD NEW USER"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:33
+#: rhodecode/templates/admin/users/users.html:77
 msgid "username"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:34
-#: rhodecode/templates/branches/branches_data.html:5
-#: rhodecode/templates/tags/tags_data.html:5
-msgid "name"
-msgstr ""
-
-#: rhodecode/templates/admin/users/users.html:35
+#: rhodecode/templates/admin/users/users.html:80
+msgid "firstname"
+msgstr ""
+
+#: rhodecode/templates/admin/users/users.html:81
 msgid "lastname"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:36
+#: rhodecode/templates/admin/users/users.html:82
 msgid "last login"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:37
+#: rhodecode/templates/admin/users/users.html:84
 #: rhodecode/templates/admin/users_groups/users_groups.html:34
 msgid "active"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:39
-#: rhodecode/templates/base/base.html:305
+#: rhodecode/templates/admin/users/users.html:86
+#: rhodecode/templates/base/base.html:226
 msgid "ldap"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:56
-msgid "Confirm to delete this user"
-msgstr ""
-
 #: rhodecode/templates/admin/users_groups/users_group_add.html:5
 msgid "Add users group"
 msgstr ""
@@ -1872,6 +2676,10 @@
 msgid "Add all elements"
 msgstr ""
 
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:146
+msgid "Group members"
+msgstr ""
+
 #: rhodecode/templates/admin/users_groups/users_groups.html:5
 msgid "Users groups administration"
 msgstr ""
@@ -1884,396 +2692,616 @@
 msgid "group name"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:32
+#: rhodecode/templates/admin/users_groups/users_groups.html:33
+#: rhodecode/templates/base/root.html:46
+msgid "members"
+msgstr ""
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:45
+#, python-format
+msgid "Confirm to delete this users group: %s"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:41
+msgid "Submit a bug"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:77
+msgid "Login to your account"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:100
 msgid "Forgot password ?"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:57 rhodecode/templates/base/base.html:338
-#: rhodecode/templates/base/base.html:340
-#: rhodecode/templates/base/base.html:342
-msgid "Home"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:61 rhodecode/templates/base/base.html:347
-#: rhodecode/templates/base/base.html:349
-#: rhodecode/templates/base/base.html:351
-#: rhodecode/templates/journal/journal.html:4
-#: rhodecode/templates/journal/journal.html:17
-#: rhodecode/templates/journal/public_journal.html:4
-msgid "Journal"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:66
-msgid "Login"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:68
-msgid "Log Out"
-msgstr ""
-
 #: rhodecode/templates/base/base.html:107
-msgid "Submit a bug"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:141
+msgid "Log In"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:118
+msgid "Inbox"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:122
+#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/base/base.html:302
+#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/bookmarks/bookmarks.html:11
+#: rhodecode/templates/branches/branches.html:10
+#: rhodecode/templates/changelog/changelog.html:10
+#: rhodecode/templates/changeset/changeset.html:10
+#: rhodecode/templates/changeset/changeset_range.html:9
+#: rhodecode/templates/compare/compare_diff.html:9
+#: rhodecode/templates/files/file_diff.html:8
+#: rhodecode/templates/files/files.html:8
+#: rhodecode/templates/files/files_add.html:15
+#: rhodecode/templates/files/files_edit.html:15
+#: rhodecode/templates/followers/followers.html:9
+#: rhodecode/templates/forks/fork.html:9 rhodecode/templates/forks/forks.html:9
+#: rhodecode/templates/pullrequests/pullrequest.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8
+#: rhodecode/templates/settings/repo_settings.html:9
+#: rhodecode/templates/shortlog/shortlog.html:10
+#: rhodecode/templates/summary/summary.html:8
+#: rhodecode/templates/tags/tags.html:11
+msgid "Home"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:123
+#: rhodecode/templates/base/base.html:309
+#: rhodecode/templates/base/base.html:311
+#: rhodecode/templates/base/base.html:313
+#: rhodecode/templates/journal/journal.html:4
+#: rhodecode/templates/journal/journal.html:21
+#: rhodecode/templates/journal/public_journal.html:4
+msgid "Journal"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:125
+msgid "Log Out"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:144
 msgid "Switch repository"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:143
+#: rhodecode/templates/base/base.html:146
 msgid "Products"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:149
+#: rhodecode/templates/base/base.html:152
+#: rhodecode/templates/base/base.html:182
 msgid "loading..."
 msgstr ""
 
-#: rhodecode/templates/base/base.html:234
-#: rhodecode/templates/base/base.html:236
-#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:158
+#: rhodecode/templates/base/base.html:160
+#: rhodecode/templates/base/base.html:162
+#: rhodecode/templates/data_table/_dt_elements.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:17
+#: rhodecode/templates/data_table/_dt_elements.html:19
+msgid "Summary"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:166
+#: rhodecode/templates/base/base.html:168
+#: rhodecode/templates/base/base.html:170
+#: rhodecode/templates/changelog/changelog.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:23
+#: rhodecode/templates/data_table/_dt_elements.html:25
+#: rhodecode/templates/data_table/_dt_elements.html:27
+msgid "Changelog"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:175
+#: rhodecode/templates/base/base.html:177
+#: rhodecode/templates/base/base.html:179
 msgid "Switch to"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:242
-#: rhodecode/templates/branches/branches.html:13
-msgid "branches"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:249
-#: rhodecode/templates/branches/branches_data.html:52
-msgid "There are no branches yet"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:254
-#: rhodecode/templates/shortlog/shortlog_data.html:10
-#: rhodecode/templates/tags/tags.html:14
-msgid "tags"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:261
-#: rhodecode/templates/tags/tags_data.html:32
-msgid "There are no tags yet"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:277
-#: rhodecode/templates/base/base.html:281
-#: rhodecode/templates/files/files_annotate.html:40
-#: rhodecode/templates/files/files_source.html:11
+#: rhodecode/templates/base/base.html:186
+#: rhodecode/templates/base/base.html:188
+#: rhodecode/templates/base/base.html:190
+#: rhodecode/templates/data_table/_dt_elements.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:33
+#: rhodecode/templates/data_table/_dt_elements.html:35
+msgid "Files"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:195
+#: rhodecode/templates/base/base.html:199
 msgid "Options"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:286
-#: rhodecode/templates/base/base.html:288
-#: rhodecode/templates/base/base.html:306
+#: rhodecode/templates/base/base.html:204
+#: rhodecode/templates/base/base.html:206
+#: rhodecode/templates/base/base.html:227
 msgid "settings"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:292
+#: rhodecode/templates/base/base.html:209
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/forks/fork.html:13
+msgid "fork"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:211
+#: rhodecode/templates/changelog/changelog.html:40
+msgid "Open new pull request"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:213
 msgid "search"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:299
-msgid "journal"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:301
+#: rhodecode/templates/base/base.html:222
 msgid "repositories groups"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:302
-msgid "users"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:303
+#: rhodecode/templates/base/base.html:224
 msgid "users groups"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/base/base.html:225
 msgid "permissions"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:317
-#: rhodecode/templates/base/base.html:319
-#: rhodecode/templates/followers/followers.html:5
+#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:240
 msgid "Followers"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:325
+#: rhodecode/templates/base/base.html:246
+#: rhodecode/templates/base/base.html:248
+msgid "Forks"
+msgstr ""
+
 #: rhodecode/templates/base/base.html:327
-#: rhodecode/templates/forks/forks.html:5
-msgid "Forks"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:356
-#: rhodecode/templates/base/base.html:358
-#: rhodecode/templates/base/base.html:360
-#: rhodecode/templates/search/search.html:4
-#: rhodecode/templates/search/search.html:24
-#: rhodecode/templates/search/search.html:46
+#: rhodecode/templates/base/base.html:329
+#: rhodecode/templates/base/base.html:331
+#: rhodecode/templates/search/search.html:52
 msgid "Search"
 msgstr ""
 
-#: rhodecode/templates/base/root.html:57
-#: rhodecode/templates/journal/journal.html:48
-#: rhodecode/templates/summary/summary.html:36
+#: rhodecode/templates/base/root.html:42
+msgid "add another comment"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:43
+#: rhodecode/templates/journal/journal.html:120
+#: rhodecode/templates/summary/summary.html:57
 msgid "Stop following this repository"
 msgstr ""
 
-#: rhodecode/templates/base/root.html:66
-#: rhodecode/templates/summary/summary.html:40
+#: rhodecode/templates/base/root.html:44
+#: rhodecode/templates/summary/summary.html:61
 msgid "Start following this repository"
 msgstr ""
 
-#: rhodecode/templates/branches/branches_data.html:4
-#: rhodecode/templates/tags/tags_data.html:4
-msgid "date"
+#: rhodecode/templates/base/root.html:45
+msgid "Group"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:47
+msgid "search truncated"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:48
+msgid "no matching files"
+msgstr ""
+
+#: rhodecode/templates/bookmarks/bookmarks.html:5
+#, python-format
+msgid "%s Bookmarks"
+msgstr ""
+
+#: rhodecode/templates/bookmarks/bookmarks.html:39
+#: rhodecode/templates/bookmarks/bookmarks_data.html:8
+#: rhodecode/templates/branches/branches.html:54
+#: rhodecode/templates/tags/tags.html:39
+#: rhodecode/templates/tags/tags_data.html:8
+msgid "Author"
+msgstr ""
+
+#: rhodecode/templates/branches/branches.html:5
+#, python-format
+msgid "%s Branches"
+msgstr ""
+
+#: rhodecode/templates/branches/branches.html:29
+msgid "Compare branches"
+msgstr ""
+
+#: rhodecode/templates/branches/branches.html:57
+#: rhodecode/templates/compare/compare_diff.html:5
+#: rhodecode/templates/compare/compare_diff.html:13
+msgid "Compare"
 msgstr ""
 
 #: rhodecode/templates/branches/branches_data.html:6
-#: rhodecode/templates/shortlog/shortlog_data.html:7
-#: rhodecode/templates/tags/tags_data.html:6
-msgid "author"
+msgid "name"
+msgstr ""
+
+#: rhodecode/templates/branches/branches_data.html:7
+msgid "date"
 msgstr ""
 
 #: rhodecode/templates/branches/branches_data.html:8
-#: rhodecode/templates/shortlog/shortlog_data.html:11
-#: rhodecode/templates/tags/tags_data.html:8
-msgid "links"
-msgstr ""
-
-#: rhodecode/templates/branches/branches_data.html:23
-#: rhodecode/templates/branches/branches_data.html:43
-#: rhodecode/templates/shortlog/shortlog_data.html:39
-#: rhodecode/templates/tags/tags_data.html:24
-msgid "changeset"
-msgstr ""
-
-#: rhodecode/templates/branches/branches_data.html:25
-#: rhodecode/templates/branches/branches_data.html:45
-#: rhodecode/templates/files/files.html:12
-#: rhodecode/templates/shortlog/shortlog_data.html:41
-#: rhodecode/templates/summary/summary.html:233
-#: rhodecode/templates/tags/tags_data.html:26
-msgid "files"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "showing "
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "out of"
+#: rhodecode/templates/shortlog/shortlog_data.html:8
+msgid "author"
+msgstr ""
+
+#: rhodecode/templates/branches/branches_data.html:9
+#: rhodecode/templates/shortlog/shortlog_data.html:5
+msgid "revision"
+msgstr ""
+
+#: rhodecode/templates/branches/branches_data.html:10
+msgid "compare"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:6
+#, python-format
+msgid "%s Changelog"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:15
+#, python-format
+msgid "showing %d out of %d revision"
+msgid_plural "showing %d out of %d revisions"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:19
+#, python-format
+msgid "compare fork with %s"
 msgstr ""
 
 #: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:21
+msgid "Compare fork"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:46
 msgid "Show"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:50
-#: rhodecode/templates/changeset/changeset.html:42
-#: rhodecode/templates/summary/summary.html:609
-msgid "commit"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:63
-msgid "Affected number of files, click to show more details"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:67
-#: rhodecode/templates/changeset/changeset.html:66
-msgid "merge"
-msgstr ""
-
 #: rhodecode/templates/changelog/changelog.html:72
-#: rhodecode/templates/changeset/changeset.html:72
+#: rhodecode/templates/summary/summary.html:364
+msgid "show more"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:76
+msgid "Affected number of files, click to show more details"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:89
+#: rhodecode/templates/changeset/changeset.html:38
+#: rhodecode/templates/changeset/changeset_file_comment.html:20
+#: rhodecode/templates/changeset/changeset_range.html:46
+msgid "Changeset status"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:92
+msgid "Click to open associated pull request"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:102
+#: rhodecode/templates/changeset/changeset.html:78
 msgid "Parent"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:77
-#: rhodecode/templates/changeset/changeset.html:77
+#: rhodecode/templates/changelog/changelog.html:108
+#: rhodecode/templates/changeset/changeset.html:84
 msgid "No parents"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:82
-#: rhodecode/templates/changeset/changeset.html:80
+#: rhodecode/templates/changelog/changelog.html:113
+#: rhodecode/templates/changeset/changeset.html:88
+msgid "merge"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:116
+#: rhodecode/templates/changeset/changeset.html:91
 #: rhodecode/templates/files/files.html:29
-#: rhodecode/templates/files/files_annotate.html:25
+#: rhodecode/templates/files/files_add.html:33
 #: rhodecode/templates/files/files_edit.html:33
 #: rhodecode/templates/shortlog/shortlog_data.html:9
 msgid "branch"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:86
-#: rhodecode/templates/changeset/changeset.html:83
+#: rhodecode/templates/changelog/changelog.html:122
+msgid "bookmark"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:128
+#: rhodecode/templates/changeset/changeset.html:96
 msgid "tag"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:122
+#: rhodecode/templates/changelog/changelog.html:164
 msgid "Show selected changes __S -> __E"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:172
-#: rhodecode/templates/shortlog/shortlog_data.html:61
+#: rhodecode/templates/changelog/changelog.html:255
 msgid "There are no changes yet"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog_details.html:2
-#: rhodecode/templates/changeset/changeset.html:55
-msgid "removed"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog_details.html:3
-#: rhodecode/templates/changeset/changeset.html:56
-msgid "changed"
-msgstr ""
-
 #: rhodecode/templates/changelog/changelog_details.html:4
-#: rhodecode/templates/changeset/changeset.html:57
-msgid "added"
+#: rhodecode/templates/changeset/changeset.html:66
+msgid "removed"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog_details.html:5
+#: rhodecode/templates/changeset/changeset.html:67
+msgid "changed"
 msgstr ""
 
 #: rhodecode/templates/changelog/changelog_details.html:6
-#: rhodecode/templates/changelog/changelog_details.html:7
+#: rhodecode/templates/changeset/changeset.html:68
+msgid "added"
+msgstr ""
+
 #: rhodecode/templates/changelog/changelog_details.html:8
-#: rhodecode/templates/changeset/changeset.html:59
-#: rhodecode/templates/changeset/changeset.html:60
-#: rhodecode/templates/changeset/changeset.html:61
+#: rhodecode/templates/changelog/changelog_details.html:9
+#: rhodecode/templates/changelog/changelog_details.html:10
+#: rhodecode/templates/changeset/changeset.html:70
+#: rhodecode/templates/changeset/changeset.html:71
+#: rhodecode/templates/changeset/changeset.html:72
 #, python-format
 msgid "affected %s files"
 msgstr ""
 
 #: rhodecode/templates/changeset/changeset.html:6
+#, python-format
+msgid "%s Changeset"
+msgstr ""
+
 #: rhodecode/templates/changeset/changeset.html:14
-#: rhodecode/templates/changeset/changeset.html:31
 msgid "Changeset"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:32
-#: rhodecode/templates/changeset/changeset.html:121
-#: rhodecode/templates/changeset/changeset_range.html:78
-#: rhodecode/templates/files/file_diff.html:32
-#: rhodecode/templates/files/file_diff.html:42
+#: rhodecode/templates/changeset/changeset.html:43
+#: rhodecode/templates/changeset/diff_block.html:20
 msgid "raw diff"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:34
-#: rhodecode/templates/changeset/changeset.html:123
-#: rhodecode/templates/changeset/changeset_range.html:80
-#: rhodecode/templates/files/file_diff.html:34
+#: rhodecode/templates/changeset/changeset.html:44
+#: rhodecode/templates/changeset/diff_block.html:21
 msgid "download diff"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:90
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
 #, python-format
-msgid "%s files affected with %s additions and %s deletions."
-msgstr ""
-
-#: rhodecode/templates/changeset/changeset.html:101
-msgid "Changeset was too big and was cut off..."
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "(%d inline)"
+msgid_plural "(%d inline)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/changeset/changeset.html:103
+#, python-format
+msgid "%s files affected with %s insertions and %s deletions:"
 msgstr ""
 
 #: rhodecode/templates/changeset/changeset.html:119
-#: rhodecode/templates/changeset/changeset_range.html:76
-#: rhodecode/templates/files/file_diff.html:30
+msgid "Changeset was too big and was cut off..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:42
+msgid "Submitting..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:45
+msgid "Commenting on line {1}."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:46
+#: rhodecode/templates/changeset/changeset_file_comment.html:121
+#, python-format
+msgid "Comments parsed using %s syntax with %s support."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:123
+msgid "Use @username inside this text to send notification to this RhodeCode user"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:59
+#: rhodecode/templates/changeset/changeset_file_comment.html:138
+msgid "Comment"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:60
+#: rhodecode/templates/changeset/changeset_file_comment.html:71
+msgid "Hide"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "You need to be logged in to comment."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "Login now"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:118
+msgid "Leave a comment"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "Check this to change current status of code-review for this changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "change status"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:140
+msgid "Comment and close"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:5
+#, python-format
+msgid "%s Changesets"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/templates/compare/compare_diff.html:29
+msgid "Compare View"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:54
+#: rhodecode/templates/compare/compare_diff.html:41
+#: rhodecode/templates/pullrequests/pullrequest_show.html:69
+msgid "Files affected"
+msgstr ""
+
+#: rhodecode/templates/changeset/diff_block.html:19
 msgid "diff"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:132
-#: rhodecode/templates/changeset/changeset_range.html:89
-msgid "No changes in this file"
-msgstr ""
-
-#: rhodecode/templates/changeset/changeset_range.html:30
-msgid "Compare View"
-msgstr ""
-
-#: rhodecode/templates/changeset/changeset_range.html:52
-msgid "Files affected"
-msgstr ""
-
-#: rhodecode/templates/errors/error_document.html:44
+#: rhodecode/templates/changeset/diff_block.html:27
+msgid "show inline comments"
+msgstr ""
+
+#: rhodecode/templates/compare/compare_cs.html:5
+msgid "No changesets"
+msgstr ""
+
+#: rhodecode/templates/compare/compare_diff.html:37
+msgid "Outgoing changesets"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:39
+#: rhodecode/templates/data_table/_dt_elements.html:41
+#: rhodecode/templates/data_table/_dt_elements.html:43
+msgid "Fork"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:60
+#: rhodecode/templates/journal/journal.html:126
+#: rhodecode/templates/summary/summary.html:68
+msgid "Mercurial repository"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:62
+#: rhodecode/templates/journal/journal.html:128
+#: rhodecode/templates/summary/summary.html:71
+msgid "Git repository"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:69
+#: rhodecode/templates/journal/journal.html:134
+#: rhodecode/templates/summary/summary.html:78
+msgid "public repository"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/summary/summary.html:87
+#: rhodecode/templates/summary/summary.html:88
+msgid "Fork of"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:92
+msgid "No changesets yet"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:104
+#, python-format
+msgid "Confirm to delete this user: %s"
+msgstr ""
+
+#: rhodecode/templates/email_templates/main.html:8
+msgid "This is an notification from RhodeCode."
+msgstr ""
+
+#: rhodecode/templates/errors/error_document.html:46
 #, python-format
 msgid "You will be redirected to %s in %s seconds"
 msgstr ""
 
 #: rhodecode/templates/files/file_diff.html:4
+#, python-format
+msgid "%s File diff"
+msgstr ""
+
 #: rhodecode/templates/files/file_diff.html:12
 msgid "File diff"
 msgstr ""
 
-#: rhodecode/templates/files/file_diff.html:42
-msgid "Diff is to big to display"
-msgstr ""
-
-#: rhodecode/templates/files/files.html:37
-#: rhodecode/templates/files/files_annotate.html:31
+#: rhodecode/templates/files/files.html:4
+#: rhodecode/templates/files/files.html:72
+#, python-format
+msgid "%s files"
+msgstr ""
+
+#: rhodecode/templates/files/files.html:12
+#: rhodecode/templates/summary/summary.html:340
+msgid "files"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:4
+#: rhodecode/templates/files/files_edit.html:4
+#, python-format
+msgid "%s Edit file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:19
+msgid "add file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:40
+msgid "Add new file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:45
+msgid "File Name"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:58
+msgid "or"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:54
+msgid "Upload file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:58
+msgid "Create new file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:63
 #: rhodecode/templates/files/files_edit.html:39
+#: rhodecode/templates/files/files_ypjax.html:3
 msgid "Location"
 msgstr ""
 
-#: rhodecode/templates/files/files.html:46
-msgid "Go back"
-msgstr ""
-
-#: rhodecode/templates/files/files.html:47
-msgid "No files at given path"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:4
-msgid "File annotate"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:12
-msgid "annotate"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:33
-#: rhodecode/templates/files/files_browser.html:160
-#: rhodecode/templates/files/files_source.html:2
-msgid "Revision"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:36
-#: rhodecode/templates/files/files_browser.html:158
-#: rhodecode/templates/files/files_source.html:7
-msgid "Size"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:38
-#: rhodecode/templates/files/files_browser.html:159
-#: rhodecode/templates/files/files_source.html:9
-msgid "Mimetype"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:41
-msgid "show source"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:43
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:14
-#: rhodecode/templates/files/files_source.html:51
-msgid "show as raw"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:45
-#: rhodecode/templates/files/files_source.html:16
-msgid "download as raw"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:54
-#: rhodecode/templates/files/files_source.html:25
-msgid "History"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:73
-#: rhodecode/templates/files/files_source.html:46
-#, python-format
-msgid "Binary file (%s)"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:51
-msgid "File is too big to display"
+#: rhodecode/templates/files/files_add.html:67
+msgid "use / to separate directories"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:77
+#: rhodecode/templates/files/files_edit.html:63
+#: rhodecode/templates/shortlog/shortlog_data.html:6
+msgid "commit message"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:81
+#: rhodecode/templates/files/files_edit.html:67
+msgid "Commit changes"
 msgstr ""
 
 #: rhodecode/templates/files/files_browser.html:13
@@ -2296,57 +3324,161 @@
 msgid "search file list"
 msgstr ""
 
-#: rhodecode/templates/files/files_browser.html:32
+#: rhodecode/templates/files/files_browser.html:31
+#: rhodecode/templates/shortlog/shortlog_data.html:65
+msgid "add new file"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:35
 msgid "Loading file list..."
 msgstr ""
 
-#: rhodecode/templates/files/files_browser.html:111
-msgid "search truncated"
-msgstr ""
-
-#: rhodecode/templates/files/files_browser.html:122
-msgid "no matching files"
-msgstr ""
-
-#: rhodecode/templates/files/files_browser.html:161
+#: rhodecode/templates/files/files_browser.html:48
+msgid "Size"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:49
+msgid "Mimetype"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:50
+msgid "Last Revision"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:51
 msgid "Last modified"
 msgstr ""
 
-#: rhodecode/templates/files/files_browser.html:162
+#: rhodecode/templates/files/files_browser.html:52
 msgid "Last commiter"
 msgstr ""
 
-#: rhodecode/templates/files/files_edit.html:4
-msgid "Edit file"
-msgstr ""
-
 #: rhodecode/templates/files/files_edit.html:19
 msgid "edit file"
 msgstr ""
 
-#: rhodecode/templates/files/files_edit.html:45
-#: rhodecode/templates/shortlog/shortlog_data.html:5
-msgid "commit message"
+#: rhodecode/templates/files/files_edit.html:49
+#: rhodecode/templates/files/files_source.html:38
+msgid "show annotation"
+msgstr ""
+
+#: rhodecode/templates/files/files_edit.html:50
+#: rhodecode/templates/files/files_source.html:40
+#: rhodecode/templates/files/files_source.html:68
+msgid "show as raw"
 msgstr ""
 
 #: rhodecode/templates/files/files_edit.html:51
-msgid "Commit changes"
-msgstr ""
-
-#: rhodecode/templates/files/files_source.html:12
-msgid "show annotation"
-msgstr ""
-
-#: rhodecode/templates/files/files_source.html:153
+#: rhodecode/templates/files/files_source.html:41
+msgid "download as raw"
+msgstr ""
+
+#: rhodecode/templates/files/files_edit.html:54
+msgid "source"
+msgstr ""
+
+#: rhodecode/templates/files/files_edit.html:59
+msgid "Editing file"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:2
+msgid "History"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:9
+msgid "diff to revision"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:10
+#, fuzzy
+msgid "show at revision"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:14
+#, fuzzy, python-format
+msgid "%s author"
+msgid_plural "%s authors"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/files/files_source.html:36
+msgid "show source"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:59
+#, python-format
+msgid "Binary file (%s)"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:68
+msgid "File is too big to display"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:124
 msgid "Selection link"
 msgstr ""
 
+#: rhodecode/templates/files/files_ypjax.html:5
+msgid "annotation"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:15
+msgid "Go back"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:16
+msgid "No files at given path"
+msgstr ""
+
+#: rhodecode/templates/followers/followers.html:5
+#, python-format
+msgid "%s Followers"
+msgstr ""
+
 #: rhodecode/templates/followers/followers.html:13
 msgid "followers"
 msgstr ""
 
 #: rhodecode/templates/followers/followers_data.html:12
-msgid "Started following"
+msgid "Started following -"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:5
+#, python-format
+msgid "%s Fork"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:31
+msgid "Fork name"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:68
+msgid "Private"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:77
+msgid "Copy permissions"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:81
+msgid "Copy permissions from forked repository"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:86
+msgid "Update after clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:90
+msgid "Checkout source after making a clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:94
+msgid "fork this repository"
+msgstr ""
+
+#: rhodecode/templates/forks/forks.html:5
+#, python-format
+msgid "%s Forks"
 msgstr ""
 
 #: rhodecode/templates/forks/forks.html:13
@@ -2357,184 +3489,395 @@
 msgid "forked"
 msgstr ""
 
-#: rhodecode/templates/forks/forks_data.html:34
+#: rhodecode/templates/forks/forks_data.html:38
 msgid "There are no forks yet"
 msgstr ""
 
-#: rhodecode/templates/journal/journal.html:34
-msgid "Following"
-msgstr ""
-
-#: rhodecode/templates/journal/journal.html:41
-msgid "following user"
+#: rhodecode/templates/journal/journal.html:13
+msgid "ATOM journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:14
+msgid "RSS journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:24
+#: rhodecode/templates/pullrequests/pullrequest.html:27
+msgid "Refresh"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:27
+#: rhodecode/templates/journal/public_journal.html:24
+msgid "RSS feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:30
+#: rhodecode/templates/journal/public_journal.html:27
+msgid "ATOM feed"
 msgstr ""
 
 #: rhodecode/templates/journal/journal.html:41
+msgid "Watched"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:46
+msgid "ADD"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "following user"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:114
 msgid "user"
 msgstr ""
 
-#: rhodecode/templates/journal/journal.html:65
+#: rhodecode/templates/journal/journal.html:147
 msgid "You are not following any users or repositories"
 msgstr ""
 
-#: rhodecode/templates/journal/journal_data.html:46
+#: rhodecode/templates/journal/journal_data.html:47
 msgid "No entries yet"
 msgstr ""
 
-#: rhodecode/templates/journal/public_journal.html:17
+#: rhodecode/templates/journal/public_journal.html:13
+msgid "ATOM public journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/public_journal.html:14
+msgid "RSS public journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/public_journal.html:21
 msgid "Public Journal"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:7
-#: rhodecode/templates/search/search.html:26
-msgid "in repository: "
-msgstr ""
-
-#: rhodecode/templates/search/search.html:9
-#: rhodecode/templates/search/search.html:28
-msgid "in all repositories"
-msgstr ""
-
-#: rhodecode/templates/search/search.html:42
+#: rhodecode/templates/pullrequests/pullrequest.html:4
+#: rhodecode/templates/pullrequests/pullrequest.html:12
+msgid "New pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:28
+msgid "refresh overview"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:66
+msgid "Detailed compare view"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:70
+#: rhodecode/templates/pullrequests/pullrequest_show.html:82
+msgid "Pull request reviewers"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:79
+#: rhodecode/templates/pullrequests/pullrequest_show.html:94
+msgid "owner"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:91
+#: rhodecode/templates/pullrequests/pullrequest_show.html:109
+msgid "Add reviewer to this pull request."
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:97
+msgid "Create new pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:106
+#: rhodecode/templates/pullrequests/pullrequest_show.html:25
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:33
+msgid "Title"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:115
+msgid "description"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:123
+msgid "Send pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:23
+#, python-format
+msgid "Closed %s"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:31
+msgid "Status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:36
+msgid "Pull request status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:44
+msgid "Still not reviewed by"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:47
+#, python-format
+msgid "%d reviewer"
+msgid_plural "%d reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:54
+msgid "Created on"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:61
+msgid "Compare view"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:65
+msgid "Incoming changesets"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4
+msgid "all pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:12
+msgid "All pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:27
+msgid "Closed"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:6
+#, python-format
+msgid "Search \"%s\" in repository: %s"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:8
+#, python-format
+msgid "Search \"%s\" in all repositories"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:12
+#: rhodecode/templates/search/search.html:32
+#, python-format
+msgid "Search in repository: %s"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:14
+#: rhodecode/templates/search/search.html:34
+msgid "Search in all repositories"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:48
 msgid "Search term"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:54
+#: rhodecode/templates/search/search.html:60
 msgid "Search in"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:57
+#: rhodecode/templates/search/search.html:63
 msgid "File contents"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:59
+#: rhodecode/templates/search/search.html:64
+msgid "Commit messages"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:65
 msgid "File names"
 msgstr ""
 
-#: rhodecode/templates/search/search_content.html:20
+#: rhodecode/templates/search/search_commit.html:35
+#: rhodecode/templates/search/search_content.html:21
 #: rhodecode/templates/search/search_path.html:15
 msgid "Permission denied"
 msgstr ""
 
-#: rhodecode/templates/settings/repo_fork.html:5
-msgid "Fork"
-msgstr ""
-
-#: rhodecode/templates/settings/repo_fork.html:31
-msgid "Fork name"
-msgstr ""
-
-#: rhodecode/templates/settings/repo_fork.html:55
-msgid "fork this repository"
+#: rhodecode/templates/settings/repo_settings.html:5
+#, python-format
+msgid "%s Settings"
 msgstr ""
 
 #: rhodecode/templates/shortlog/shortlog.html:5
-#: rhodecode/templates/summary/summary.html:666
-msgid "Shortlog"
+#, python-format
+msgid "%s Shortlog"
 msgstr ""
 
 #: rhodecode/templates/shortlog/shortlog.html:14
 msgid "shortlog"
 msgstr ""
 
-#: rhodecode/templates/shortlog/shortlog_data.html:6
+#: rhodecode/templates/shortlog/shortlog_data.html:7
 msgid "age"
 msgstr ""
 
+#: rhodecode/templates/shortlog/shortlog_data.html:18
+msgid "No commit message"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:62
+msgid "Add or upload files directly via RhodeCode"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:71
+msgid "Push new repo"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:79
+msgid "Existing repository?"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:4
+#, python-format
+msgid "%s Summary"
+msgstr ""
+
 #: rhodecode/templates/summary/summary.html:12
 msgid "summary"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:79
+#: rhodecode/templates/summary/summary.html:20
+#, python-format
+msgid "repo %s ATOM feed"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:21
+#, python-format
+msgid "repo %s RSS feed"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:49
+#: rhodecode/templates/summary/summary.html:52
+msgid "ATOM"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:82
+#, python-format
+msgid "Non changable ID %s"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:87
+msgid "public"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:95
 msgid "remote clone"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:121
-msgid "by"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:128
+#: rhodecode/templates/summary/summary.html:116
+msgid "Contact"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:130
 msgid "Clone url"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:137
-msgid "Trending source files"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:146
-msgid "Download"
+#: rhodecode/templates/summary/summary.html:133
+msgid "Show by Name"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:134
+msgid "Show by ID"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:142
+msgid "Trending files"
 msgstr ""
 
 #: rhodecode/templates/summary/summary.html:150
-msgid "There are no downloads yet"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:152
-msgid "Downloads are disabled for this repository"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:154
-#: rhodecode/templates/summary/summary.html:320
+#: rhodecode/templates/summary/summary.html:166
+#: rhodecode/templates/summary/summary.html:194
 msgid "enable"
 msgstr ""
 
+#: rhodecode/templates/summary/summary.html:158
+msgid "Download"
+msgstr ""
+
 #: rhodecode/templates/summary/summary.html:162
-#: rhodecode/templates/summary/summary.html:297
+msgid "There are no downloads yet"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:164
+msgid "Downloads are disabled for this repository"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:170
+msgid "Download as zip"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "Check this to download archive with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:186
+msgid "Commit activity by day / author"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:197
+msgid "Stats gathered: "
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:218
+msgid "Shortlog"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:220
+msgid "Quick start"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:233
+#, python-format
+msgid "Readme file at revision '%s'"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:236
+msgid "Permalink to this readme"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:293
 #, python-format
 msgid "Download %s as %s"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:168
-msgid "Check this to download archive with subrepos"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:168
-msgid "with subrepos"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:176
-msgid "Feeds"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:257
-#: rhodecode/templates/summary/summary.html:684
-#: rhodecode/templates/summary/summary.html:695
-msgid "show more"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:312
-msgid "Commit activity by day / author"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:324
-msgid "Loaded in"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:603
+#: rhodecode/templates/summary/summary.html:650
 msgid "commits"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:604
+#: rhodecode/templates/summary/summary.html:651
 msgid "files added"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:605
+#: rhodecode/templates/summary/summary.html:652
 msgid "files changed"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:606
+#: rhodecode/templates/summary/summary.html:653
 msgid "files removed"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:610
+#: rhodecode/templates/summary/summary.html:656
+msgid "commit"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:657
 msgid "file added"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:611
+#: rhodecode/templates/summary/summary.html:658
 msgid "file changed"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:612
+#: rhodecode/templates/summary/summary.html:659
 msgid "file removed"
 msgstr ""
 
+#: rhodecode/templates/tags/tags.html:5
+#, python-format
+msgid "%s Tags"
+msgstr ""
+
Binary file rhodecode/i18n/fr/LC_MESSAGES/rhodecode.mo has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/i18n/fr/LC_MESSAGES/rhodecode.po	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,4047 @@
+# French translations for RhodeCode.
+# Copyright (C) 2011 ORGANIZATION
+# This file is distributed under the same license as the RhodeCode project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: RhodeCode 1.1.5\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-02 20:30+0200\n"
+"PO-Revision-Date: 2012-06-05 20:07+0100\n"
+"Last-Translator: Vincent Duvert <vincent@duvert.net>\n"
+"Language-Team: fr <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: rhodecode/controllers/changelog.py:94
+msgid "All Branches"
+msgstr "Toutes les branches"
+
+#: rhodecode/controllers/changeset.py:83
+msgid "show white space"
+msgstr "afficher les espaces et tabulations"
+
+#: rhodecode/controllers/changeset.py:90 rhodecode/controllers/changeset.py:97
+msgid "ignore white space"
+msgstr "ignorer les espaces et tabulations"
+
+#: rhodecode/controllers/changeset.py:157
+#, python-format
+msgid "%s line context"
+msgstr "afficher %s lignes de contexte"
+
+#: rhodecode/controllers/changeset.py:333
+#: rhodecode/controllers/changeset.py:348 rhodecode/lib/diffs.py:70
+msgid "binary file"
+msgstr "fichier binaire"
+
+#: rhodecode/controllers/changeset.py:408
+msgid ""
+"Changing status on a changeset associated witha closed pull request is "
+"not allowed"
+msgstr ""
+
+#: rhodecode/controllers/compare.py:69
+#, fuzzy
+msgid "There are no changesets yet"
+msgstr "Il n’y a aucun changement pour le moment"
+
+#: rhodecode/controllers/error.py:69
+msgid "Home page"
+msgstr "Accueil"
+
+#: rhodecode/controllers/error.py:98
+msgid "The request could not be understood by the server due to malformed syntax."
+msgstr ""
+"Le serveur n’a pas pu interpréter la requête à cause d’une erreur de "
+"syntaxe"
+
+#: rhodecode/controllers/error.py:101
+msgid "Unauthorized access to resource"
+msgstr "Accès interdit à cet ressource"
+
+#: rhodecode/controllers/error.py:103
+msgid "You don't have permission to view this page"
+msgstr "Vous n’avez pas la permission de voir cette page"
+
+#: rhodecode/controllers/error.py:105
+msgid "The resource could not be found"
+msgstr "Ressource introuvable"
+
+#: rhodecode/controllers/error.py:107
+msgid ""
+"The server encountered an unexpected condition which prevented it from "
+"fulfilling the request."
+msgstr ""
+"La requête n’a pu être traitée en raison d’une erreur survenue sur le "
+"serveur."
+
+#: rhodecode/controllers/feed.py:49
+#, python-format
+msgid "Changes on %s repository"
+msgstr "Changements sur le dépôt %s"
+
+#: rhodecode/controllers/feed.py:50
+#, python-format
+msgid "%s %s feed"
+msgstr "Flux %s de %s"
+
+#: rhodecode/controllers/feed.py:75
+msgid "commited on"
+msgstr "a commité, le"
+
+#: rhodecode/controllers/files.py:84
+#, fuzzy
+msgid "click here to add new file"
+msgstr "Ajouter un fichier"
+
+#: rhodecode/controllers/files.py:85
+#, python-format
+msgid "There are no files yet %s"
+msgstr "Il n’y a pas encore de fichiers %s"
+
+#: rhodecode/controllers/files.py:239 rhodecode/controllers/files.py:299
+#, python-format
+msgid "This repository is has been locked by %s on %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:266
+#, python-format
+msgid "Edited %s via RhodeCode"
+msgstr "%s édité via RhodeCode"
+
+#: rhodecode/controllers/files.py:271
+msgid "No changes"
+msgstr "Aucun changement"
+
+#: rhodecode/controllers/files.py:282 rhodecode/controllers/files.py:346
+#, python-format
+msgid "Successfully committed to %s"
+msgstr "Commit réalisé avec succès sur %s"
+
+#: rhodecode/controllers/files.py:287 rhodecode/controllers/files.py:352
+msgid "Error occurred during commit"
+msgstr "Une erreur est survenue durant le commit"
+
+#: rhodecode/controllers/files.py:318
+#, python-format
+msgid "Added %s via RhodeCode"
+msgstr "%s ajouté par RhodeCode"
+
+#: rhodecode/controllers/files.py:332
+msgid "No content"
+msgstr "Aucun contenu"
+
+#: rhodecode/controllers/files.py:336
+msgid "No filename"
+msgstr "Aucun nom de fichier"
+
+#: rhodecode/controllers/files.py:378
+msgid "downloads disabled"
+msgstr "Les téléchargements sont désactivés"
+
+#: rhodecode/controllers/files.py:389
+#, python-format
+msgid "Unknown revision %s"
+msgstr "Révision %s inconnue."
+
+#: rhodecode/controllers/files.py:391
+msgid "Empty repository"
+msgstr "Dépôt vide."
+
+#: rhodecode/controllers/files.py:393
+msgid "Unknown archive type"
+msgstr "Type d’archive inconnu"
+
+#: rhodecode/controllers/files.py:494
+#: rhodecode/templates/changeset/changeset_range.html:13
+#: rhodecode/templates/changeset/changeset_range.html:31
+msgid "Changesets"
+msgstr "Changesets"
+
+#: rhodecode/controllers/files.py:495 rhodecode/controllers/pullrequests.py:72
+#: rhodecode/controllers/summary.py:232 rhodecode/model/scm.py:543
+msgid "Branches"
+msgstr "Branches"
+
+#: rhodecode/controllers/files.py:496 rhodecode/controllers/pullrequests.py:76
+#: rhodecode/controllers/summary.py:233 rhodecode/model/scm.py:554
+msgid "Tags"
+msgstr "Tags"
+
+#: rhodecode/controllers/forks.py:73 rhodecode/controllers/admin/repos.py:90
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+"Le dépôt %s n’est pas représenté dans la base de données. Il a "
+"probablement été créé ou renommé manuellement. Veuillez relancer "
+"l’application pour rescanner les dépôts."
+
+#: rhodecode/controllers/forks.py:133 rhodecode/controllers/settings.py:72
+#, python-format
+msgid ""
+"%s repository is not mapped to db perhaps it was created or renamed from "
+"the file system please run the application again in order to rescan "
+"repositories"
+msgstr ""
+"Le dépôt %s n’est pas représenté dans la base de données. Il a "
+"probablement été créé ou renommé manuellement. Veuillez relancer "
+"l’application pour rescanner les dépôts."
+
+#: rhodecode/controllers/forks.py:167
+#, python-format
+msgid "forked %s repository as %s"
+msgstr "dépôt %s forké en tant que %s"
+
+#: rhodecode/controllers/forks.py:181
+#, python-format
+msgid "An error occurred during repository forking %s"
+msgstr "Une erreur est survenue durant le fork du dépôt %s."
+
+#: rhodecode/controllers/journal.py:202 rhodecode/controllers/journal.py:239
+#, fuzzy
+msgid "public journal"
+msgstr "Journal public"
+
+#: rhodecode/controllers/journal.py:206 rhodecode/controllers/journal.py:243
+#: rhodecode/templates/base/base.html:220
+msgid "journal"
+msgstr "Journal"
+
+#: rhodecode/controllers/login.py:143
+msgid "You have successfully registered into rhodecode"
+msgstr "Vous vous êtes inscrits avec succès à RhodeCode"
+
+#: rhodecode/controllers/login.py:164
+msgid "Your password reset link was sent"
+msgstr "Un lien de rénitialisation de votre mot de passe vous a été envoyé."
+
+#: rhodecode/controllers/login.py:184
+msgid ""
+"Your password reset was successful, new password has been sent to your "
+"email"
+msgstr ""
+"Votre mot de passe a été réinitialisé. Votre nouveau mot de passe vous a "
+"été envoyé par e-mail."
+
+#: rhodecode/controllers/pullrequests.py:74 rhodecode/model/scm.py:549
+#, fuzzy
+msgid "Bookmarks"
+msgstr "Signets"
+
+#: rhodecode/controllers/pullrequests.py:158
+msgid "Pull request requires a title with min. 3 chars"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:160
+msgid "error during creation of pull request"
+msgstr "erreur lors de la création de la demande traction"
+
+#: rhodecode/controllers/pullrequests.py:181
+#, fuzzy
+msgid "Successfully opened new pull request"
+msgstr "L’utilisateur a été supprimé avec succès."
+
+#: rhodecode/controllers/pullrequests.py:184
+#, fuzzy
+msgid "Error occurred during sending pull request"
+msgstr "Une erreur est survenue durant la création du dépôt %s."
+
+#: rhodecode/controllers/pullrequests.py:217
+#, fuzzy
+msgid "Successfully deleted pull request"
+msgstr "L’utilisateur a été supprimé avec succès."
+
+#: rhodecode/controllers/search.py:131
+msgid "Invalid search query. Try quoting it."
+msgstr "Requête invalide. Essayer de la mettre entre guillemets."
+
+#: rhodecode/controllers/search.py:136
+msgid "There is no index to search in. Please run whoosh indexer"
+msgstr ""
+"L’index de recherche n’est pas présent. Veuillez exécuter l’indexeur de "
+"code Whoosh."
+
+#: rhodecode/controllers/search.py:140
+msgid "An error occurred during this search operation"
+msgstr "Une erreur est survenue durant l’opération de recherche."
+
+#: rhodecode/controllers/settings.py:107
+#: rhodecode/controllers/admin/repos.py:266
+#, python-format
+msgid "Repository %s updated successfully"
+msgstr "Dépôt %s mis à jour avec succès."
+
+#: rhodecode/controllers/settings.py:125
+#: rhodecode/controllers/admin/repos.py:284
+#, python-format
+msgid "error occurred during update of repository %s"
+msgstr "Une erreur est survenue lors de la mise à jour du dépôt %s."
+
+#: rhodecode/controllers/settings.py:143
+#: rhodecode/controllers/admin/repos.py:302
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+"Le dépôt %s n’est pas représenté dans la base de données. Il a "
+"probablement été déplacé ou renommé manuellement. Veuillez relancer "
+"l’application pour rescanner les dépôts."
+
+#: rhodecode/controllers/settings.py:155
+#: rhodecode/controllers/admin/repos.py:314
+#, python-format
+msgid "deleted repository %s"
+msgstr "Dépôt %s supprimé"
+
+#: rhodecode/controllers/settings.py:159
+#: rhodecode/controllers/admin/repos.py:324
+#: rhodecode/controllers/admin/repos.py:330
+#, python-format
+msgid "An error occurred during deletion of %s"
+msgstr "Erreur pendant la suppression de %s"
+
+#: rhodecode/controllers/summary.py:138
+msgid "No data loaded yet"
+msgstr "Aucune donnée actuellement disponible."
+
+#: rhodecode/controllers/summary.py:142
+#: rhodecode/templates/summary/summary.html:148
+msgid "Statistics are disabled for this repository"
+msgstr "La mise à jour des statistiques est désactivée pour ce dépôt."
+
+#: rhodecode/controllers/admin/ldap_settings.py:50
+msgid "BASE"
+msgstr "Base"
+
+#: rhodecode/controllers/admin/ldap_settings.py:51
+msgid "ONELEVEL"
+msgstr "Un niveau"
+
+#: rhodecode/controllers/admin/ldap_settings.py:52
+msgid "SUBTREE"
+msgstr "Sous-arbre"
+
+#: rhodecode/controllers/admin/ldap_settings.py:56
+msgid "NEVER"
+msgstr "NEVER"
+
+#: rhodecode/controllers/admin/ldap_settings.py:57
+msgid "ALLOW"
+msgstr "Autoriser"
+
+#: rhodecode/controllers/admin/ldap_settings.py:58
+msgid "TRY"
+msgstr "TRY"
+
+#: rhodecode/controllers/admin/ldap_settings.py:59
+msgid "DEMAND"
+msgstr "DEMAND"
+
+#: rhodecode/controllers/admin/ldap_settings.py:60
+msgid "HARD"
+msgstr "HARD"
+
+#: rhodecode/controllers/admin/ldap_settings.py:64
+msgid "No encryption"
+msgstr "Pas de chiffrement"
+
+#: rhodecode/controllers/admin/ldap_settings.py:65
+msgid "LDAPS connection"
+msgstr "Connection LDAPS"
+
+#: rhodecode/controllers/admin/ldap_settings.py:66
+msgid "START_TLS on LDAP connection"
+msgstr "START_TLS à la connexion"
+
+#: rhodecode/controllers/admin/ldap_settings.py:126
+msgid "Ldap settings updated successfully"
+msgstr "Mise à jour réussie des réglages LDAP"
+
+#: rhodecode/controllers/admin/ldap_settings.py:130
+msgid "Unable to activate ldap. The \"python-ldap\" library is missing."
+msgstr "Impossible d’activer LDAP. La bibliothèque « python-ldap » est manquante."
+
+#: rhodecode/controllers/admin/ldap_settings.py:147
+msgid "error occurred during update of ldap settings"
+msgstr "Une erreur est survenue durant la mise à jour des réglages du LDAP."
+
+#: rhodecode/controllers/admin/permissions.py:59
+msgid "None"
+msgstr "Aucun"
+
+#: rhodecode/controllers/admin/permissions.py:60
+msgid "Read"
+msgstr "Lire"
+
+#: rhodecode/controllers/admin/permissions.py:61
+msgid "Write"
+msgstr "Écrire"
+
+#: rhodecode/controllers/admin/permissions.py:62
+#: rhodecode/templates/admin/ldap/ldap.html:9
+#: rhodecode/templates/admin/permissions/permissions.html:9
+#: rhodecode/templates/admin/repos/repo_add.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:9
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:8
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:8
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
+#: rhodecode/templates/admin/settings/hooks.html:9
+#: rhodecode/templates/admin/settings/settings.html:9
+#: rhodecode/templates/admin/users/user_add.html:8
+#: rhodecode/templates/admin/users/user_edit.html:9
+#: rhodecode/templates/admin/users/user_edit.html:122
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/admin/users_groups/users_group_add.html:8
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:9
+#: rhodecode/templates/admin/users_groups/users_groups.html:9
+#: rhodecode/templates/base/base.html:197
+#: rhodecode/templates/base/base.html:337
+#: rhodecode/templates/base/base.html:339
+#: rhodecode/templates/base/base.html:341
+msgid "Admin"
+msgstr "Administration"
+
+#: rhodecode/controllers/admin/permissions.py:65
+msgid "disabled"
+msgstr "Désactivé"
+
+#: rhodecode/controllers/admin/permissions.py:67
+msgid "allowed with manual account activation"
+msgstr "Autorisé avec activation manuelle du compte"
+
+#: rhodecode/controllers/admin/permissions.py:69
+msgid "allowed with automatic account activation"
+msgstr "Autorisé avec activation automatique du compte"
+
+#: rhodecode/controllers/admin/permissions.py:71
+#: rhodecode/controllers/admin/permissions.py:74
+msgid "Disabled"
+msgstr "Interdite"
+
+#: rhodecode/controllers/admin/permissions.py:72
+#: rhodecode/controllers/admin/permissions.py:75
+msgid "Enabled"
+msgstr "Autorisée"
+
+#: rhodecode/controllers/admin/permissions.py:116
+msgid "Default permissions updated successfully"
+msgstr "Permissions par défaut mises à jour avec succès"
+
+#: rhodecode/controllers/admin/permissions.py:130
+msgid "error occurred during update of permissions"
+msgstr "erreur pendant la mise à jour des permissions"
+
+#: rhodecode/controllers/admin/repos.py:123
+msgid "--REMOVE FORK--"
+msgstr "[Pas un fork]"
+
+#: rhodecode/controllers/admin/repos.py:192
+#, python-format
+msgid "created repository %s from %s"
+msgstr "Le dépôt %s a été créé depuis %s."
+
+#: rhodecode/controllers/admin/repos.py:196
+#, python-format
+msgid "created repository %s"
+msgstr "Le dépôt %s a été créé."
+
+#: rhodecode/controllers/admin/repos.py:227
+#, python-format
+msgid "error occurred during creation of repository %s"
+msgstr "Une erreur est survenue durant la création du dépôt %s."
+
+#: rhodecode/controllers/admin/repos.py:319
+#, python-format
+msgid "Cannot delete %s it still contains attached forks"
+msgstr "Impossible de supprimer le dépôt %s : Des forks y sont attachés."
+
+#: rhodecode/controllers/admin/repos.py:348
+msgid "An error occurred during deletion of repository user"
+msgstr "Une erreur est survenue durant la suppression de l’utilisateur du dépôt."
+
+#: rhodecode/controllers/admin/repos.py:367
+msgid "An error occurred during deletion of repository users groups"
+msgstr ""
+"Une erreur est survenue durant la suppression du groupe d’utilisateurs de"
+" ce dépôt."
+
+#: rhodecode/controllers/admin/repos.py:385
+msgid "An error occurred during deletion of repository stats"
+msgstr "Une erreur est survenue durant la suppression des statistiques du dépôt."
+
+#: rhodecode/controllers/admin/repos.py:402
+msgid "An error occurred during cache invalidation"
+msgstr "Une erreur est survenue durant l’invalidation du cache."
+
+#: rhodecode/controllers/admin/repos.py:422
+#, fuzzy
+msgid "An error occurred during unlocking"
+msgstr "Une erreur est survenue durant cette opération."
+
+#: rhodecode/controllers/admin/repos.py:442
+msgid "Updated repository visibility in public journal"
+msgstr "La visibilité du dépôt dans le journal public a été mise à jour."
+
+#: rhodecode/controllers/admin/repos.py:446
+msgid "An error occurred during setting this repository in public journal"
+msgstr ""
+"Une erreur est survenue durant la configuration du journal public pour ce"
+" dépôt."
+
+#: rhodecode/controllers/admin/repos.py:451 rhodecode/model/validators.py:299
+msgid "Token mismatch"
+msgstr "Jeton d’authentification incorrect."
+
+#: rhodecode/controllers/admin/repos.py:464
+msgid "Pulled from remote location"
+msgstr "Les changements distants ont été récupérés."
+
+#: rhodecode/controllers/admin/repos.py:466
+msgid "An error occurred during pull from remote location"
+msgstr "Une erreur est survenue durant le pull depuis la source distante."
+
+#: rhodecode/controllers/admin/repos.py:482
+msgid "Nothing"
+msgstr "[Aucun dépôt]"
+
+#: rhodecode/controllers/admin/repos.py:484
+#, python-format
+msgid "Marked repo %s as fork of %s"
+msgstr "Le dépôt %s a été marké comme fork de %s"
+
+#: rhodecode/controllers/admin/repos.py:488
+msgid "An error occurred during this operation"
+msgstr "Une erreur est survenue durant cette opération."
+
+#: rhodecode/controllers/admin/repos_groups.py:116
+#, python-format
+msgid "created repos group %s"
+msgstr "Le groupe de dépôts %s a été créé."
+
+#: rhodecode/controllers/admin/repos_groups.py:129
+#, python-format
+msgid "error occurred during creation of repos group %s"
+msgstr "Une erreur est survenue durant la création du groupe de dépôts %s."
+
+#: rhodecode/controllers/admin/repos_groups.py:163
+#, python-format
+msgid "updated repos group %s"
+msgstr "Le groupe de dépôts %s a été mis à jour."
+
+#: rhodecode/controllers/admin/repos_groups.py:176
+#, python-format
+msgid "error occurred during update of repos group %s"
+msgstr "Une erreur est survenue durant la mise à jour du groupe de dépôts %s."
+
+#: rhodecode/controllers/admin/repos_groups.py:194
+#, python-format
+msgid "This group contains %s repositores and cannot be deleted"
+msgstr "Ce groupe contient %s dépôts et ne peut être supprimé."
+
+#: rhodecode/controllers/admin/repos_groups.py:202
+#, python-format
+msgid "removed repos group %s"
+msgstr "Le groupe de dépôts %s a été supprimé."
+
+#: rhodecode/controllers/admin/repos_groups.py:208
+msgid "Cannot delete this group it still contains subgroups"
+msgstr "Impossible de supprimer ce groupe : Il contient des sous-groupes."
+
+#: rhodecode/controllers/admin/repos_groups.py:213
+#: rhodecode/controllers/admin/repos_groups.py:218
+#, python-format
+msgid "error occurred during deletion of repos group %s"
+msgstr "Une erreur est survenue durant la suppression du groupe de dépôts %s."
+
+#: rhodecode/controllers/admin/repos_groups.py:238
+msgid "An error occurred during deletion of group user"
+msgstr ""
+"Une erreur est survenue durant la suppression de l’utilisateur du groupe "
+"de dépôts."
+
+#: rhodecode/controllers/admin/repos_groups.py:258
+msgid "An error occurred during deletion of group users groups"
+msgstr ""
+"Une erreur est survenue durant la suppression du groupe d’utilisateurs du"
+" groupe de dépôts."
+
+#: rhodecode/controllers/admin/settings.py:121
+#, python-format
+msgid "Repositories successfully rescanned added: %s,removed: %s"
+msgstr "Après re-scan : %s ajouté(s), %s enlevé(s)"
+
+#: rhodecode/controllers/admin/settings.py:129
+msgid "Whoosh reindex task scheduled"
+msgstr "La tâche de réindexation Whoosh a été planifiée."
+
+#: rhodecode/controllers/admin/settings.py:160
+msgid "Updated application settings"
+msgstr "Réglages mis à jour"
+
+#: rhodecode/controllers/admin/settings.py:164
+#: rhodecode/controllers/admin/settings.py:275
+msgid "error occurred during updating application settings"
+msgstr "Une erreur est survenue durant la mise à jour des options."
+
+#: rhodecode/controllers/admin/settings.py:200
+#, fuzzy
+msgid "Updated visualisation settings"
+msgstr "Réglages mis à jour"
+
+#: rhodecode/controllers/admin/settings.py:205
+#, fuzzy
+msgid "error occurred during updating visualisation settings"
+msgstr "Une erreur est survenue durant la mise à jour des options."
+
+#: rhodecode/controllers/admin/settings.py:271
+#, fuzzy
+msgid "Updated VCS settings"
+msgstr "Réglages de Mercurial mis à jour"
+
+#: rhodecode/controllers/admin/settings.py:285
+msgid "Added new hook"
+msgstr "Le nouveau hook a été ajouté."
+
+#: rhodecode/controllers/admin/settings.py:297
+msgid "Updated hooks"
+msgstr "Hooks mis à jour"
+
+#: rhodecode/controllers/admin/settings.py:301
+msgid "error occurred during hook creation"
+msgstr "Une erreur est survenue durant la création du hook."
+
+#: rhodecode/controllers/admin/settings.py:320
+msgid "Email task created"
+msgstr "La tâche d’e-mail a été créée."
+
+#: rhodecode/controllers/admin/settings.py:375
+msgid "You can't edit this user since it's crucial for entire application"
+msgstr ""
+"Vous ne pouvez pas éditer cet utilisateur ; il est nécessaire pour le bon"
+" fonctionnement de l’application."
+
+#: rhodecode/controllers/admin/settings.py:406
+msgid "Your account was updated successfully"
+msgstr "Votre compte a été mis à jour avec succès"
+
+#: rhodecode/controllers/admin/settings.py:421
+#: rhodecode/controllers/admin/users.py:191
+#, python-format
+msgid "error occurred during update of user %s"
+msgstr "Une erreur est survenue durant la mise à jour de l’utilisateur %s."
+
+#: rhodecode/controllers/admin/users.py:130
+#, python-format
+msgid "created user %s"
+msgstr "utilisateur %s créé"
+
+#: rhodecode/controllers/admin/users.py:142
+#, python-format
+msgid "error occurred during creation of user %s"
+msgstr "Une erreur est survenue durant la création de l’utilisateur %s."
+
+#: rhodecode/controllers/admin/users.py:171
+msgid "User updated successfully"
+msgstr "L’utilisateur a été mis à jour avec succès."
+
+#: rhodecode/controllers/admin/users.py:207
+msgid "successfully deleted user"
+msgstr "L’utilisateur a été supprimé avec succès."
+
+#: rhodecode/controllers/admin/users.py:212
+msgid "An error occurred during deletion of user"
+msgstr "Une erreur est survenue durant la suppression de l’utilisateur."
+
+#: rhodecode/controllers/admin/users.py:226
+msgid "You can't edit this user"
+msgstr "Vous ne pouvez pas éditer cet utilisateur"
+
+#: rhodecode/controllers/admin/users.py:266
+msgid "Granted 'repository create' permission to user"
+msgstr "La permission de création de dépôts a été accordée à l’utilisateur."
+
+#: rhodecode/controllers/admin/users.py:271
+msgid "Revoked 'repository create' permission to user"
+msgstr "La permission de création de dépôts a été révoquée à l’utilisateur."
+
+#: rhodecode/controllers/admin/users.py:277
+#, fuzzy
+msgid "Granted 'repository fork' permission to user"
+msgstr "La permission de création de dépôts a été accordée à l’utilisateur."
+
+#: rhodecode/controllers/admin/users.py:282
+#, fuzzy
+msgid "Revoked 'repository fork' permission to user"
+msgstr "La permission de création de dépôts a été révoquée à l’utilisateur."
+
+#: rhodecode/controllers/admin/users.py:288
+#: rhodecode/controllers/admin/users_groups.py:255
+#, fuzzy
+msgid "An error occurred during permissions saving"
+msgstr "Une erreur est survenue durant cette opération."
+
+#: rhodecode/controllers/admin/users.py:303
+#, python-format
+msgid "Added email %s to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:309
+#, fuzzy
+msgid "An error occurred during email saving"
+msgstr "Une erreur est survenue durant cette opération."
+
+#: rhodecode/controllers/admin/users.py:319
+#, fuzzy
+msgid "Removed email from user"
+msgstr "Le groupe de dépôts %s a été supprimé."
+
+#: rhodecode/controllers/admin/users_groups.py:84
+#, python-format
+msgid "created users group %s"
+msgstr "Le groupe d’utilisateurs %s a été créé."
+
+#: rhodecode/controllers/admin/users_groups.py:95
+#, python-format
+msgid "error occurred during creation of users group %s"
+msgstr "Une erreur est survenue durant la création du groupe d’utilisateurs %s."
+
+#: rhodecode/controllers/admin/users_groups.py:135
+#, python-format
+msgid "updated users group %s"
+msgstr "Le groupe d’utilisateurs %s a été mis à jour."
+
+#: rhodecode/controllers/admin/users_groups.py:157
+#, python-format
+msgid "error occurred during update of users group %s"
+msgstr "Une erreur est survenue durant la mise à jour du groupe d’utilisateurs %s."
+
+#: rhodecode/controllers/admin/users_groups.py:174
+msgid "successfully deleted users group"
+msgstr "Le groupe d’utilisateurs a été supprimé avec succès."
+
+#: rhodecode/controllers/admin/users_groups.py:179
+msgid "An error occurred during deletion of users group"
+msgstr "Une erreur est survenue lors de la suppression du groupe d’utilisateurs."
+
+#: rhodecode/controllers/admin/users_groups.py:233
+#, fuzzy
+msgid "Granted 'repository create' permission to users group"
+msgstr "La permission de création de dépôts a été accordée à l’utilisateur."
+
+#: rhodecode/controllers/admin/users_groups.py:238
+#, fuzzy
+msgid "Revoked 'repository create' permission to users group"
+msgstr "La permission de création de dépôts a été révoquée à l’utilisateur."
+
+#: rhodecode/controllers/admin/users_groups.py:244
+#, fuzzy
+msgid "Granted 'repository fork' permission to users group"
+msgstr "La permission de création de dépôts a été accordée à l’utilisateur."
+
+#: rhodecode/controllers/admin/users_groups.py:249
+#, fuzzy
+msgid "Revoked 'repository fork' permission to users group"
+msgstr "La permission de création de dépôts a été révoquée à l’utilisateur."
+
+#: rhodecode/lib/auth.py:499
+msgid "You need to be a registered user to perform this action"
+msgstr "Vous devez être un utilisateur enregistré pour effectuer cette action."
+
+#: rhodecode/lib/auth.py:540
+msgid "You need to be a signed in to view this page"
+msgstr "Vous devez être connecté pour visualiser cette page."
+
+#: rhodecode/lib/diffs.py:86
+msgid "Changeset was too big and was cut off, use diff menu to display this diff"
+msgstr ""
+"Cet ensemble de changements était trop gros pour être affiché et a été "
+"découpé, utilisez le menu « Diff » pour afficher les différences."
+
+#: rhodecode/lib/diffs.py:96
+msgid "No changes detected"
+msgstr "Aucun changement détecté."
+
+#: rhodecode/lib/helpers.py:372
+#, python-format
+msgid "%a, %d %b %Y %H:%M:%S"
+msgstr "%d/%m/%Y à %H:%M:%S"
+
+#: rhodecode/lib/helpers.py:484
+msgid "True"
+msgstr "Vrai"
+
+#: rhodecode/lib/helpers.py:488
+msgid "False"
+msgstr "Faux"
+
+#: rhodecode/lib/helpers.py:532
+msgid "Changeset not found"
+msgstr "Ensemble de changements non trouvé"
+
+#: rhodecode/lib/helpers.py:555
+#, python-format
+msgid "Show all combined changesets %s->%s"
+msgstr "Afficher les changements combinés %s->%s"
+
+#: rhodecode/lib/helpers.py:561
+msgid "compare view"
+msgstr "vue de comparaison"
+
+#: rhodecode/lib/helpers.py:581
+msgid "and"
+msgstr "et"
+
+#: rhodecode/lib/helpers.py:582
+#, python-format
+msgid "%s more"
+msgstr "%s de plus"
+
+#: rhodecode/lib/helpers.py:583 rhodecode/templates/changelog/changelog.html:48
+msgid "revisions"
+msgstr "révisions"
+
+#: rhodecode/lib/helpers.py:606
+msgid "fork name "
+msgstr "Nom du fork"
+
+#: rhodecode/lib/helpers.py:620
+#: rhodecode/templates/pullrequests/pullrequest_show.html:4
+#: rhodecode/templates/pullrequests/pullrequest_show.html:12
+#, python-format
+msgid "Pull request #%s"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:626
+msgid "[deleted] repository"
+msgstr "[a supprimé] le dépôt"
+
+#: rhodecode/lib/helpers.py:628 rhodecode/lib/helpers.py:638
+msgid "[created] repository"
+msgstr "[a créé] le dépôt"
+
+#: rhodecode/lib/helpers.py:630
+msgid "[created] repository as fork"
+msgstr "[a créé] le dépôt en tant que fork"
+
+#: rhodecode/lib/helpers.py:632 rhodecode/lib/helpers.py:640
+msgid "[forked] repository"
+msgstr "[a forké] le dépôt"
+
+#: rhodecode/lib/helpers.py:634 rhodecode/lib/helpers.py:642
+msgid "[updated] repository"
+msgstr "[a mis à jour] le dépôt"
+
+#: rhodecode/lib/helpers.py:636
+msgid "[delete] repository"
+msgstr "[a supprimé] le dépôt"
+
+#: rhodecode/lib/helpers.py:644
+msgid "[created] user"
+msgstr "[a créé] l’utilisateur"
+
+#: rhodecode/lib/helpers.py:646
+msgid "[updated] user"
+msgstr "[a mis à jour] l’utilisateur"
+
+#: rhodecode/lib/helpers.py:648
+msgid "[created] users group"
+msgstr "[a créé] le groupe d’utilisateurs"
+
+#: rhodecode/lib/helpers.py:650
+msgid "[updated] users group"
+msgstr "[a mis à jour] le groupe d’utilisateurs"
+
+#: rhodecode/lib/helpers.py:652
+msgid "[commented] on revision in repository"
+msgstr "[a commenté] une révision du dépôt"
+
+#: rhodecode/lib/helpers.py:654
+#, fuzzy
+msgid "[commented] on pull request for"
+msgstr "[a commenté] une révision du dépôt"
+
+#: rhodecode/lib/helpers.py:656
+#, fuzzy
+msgid "[closed] pull request for"
+msgstr "[a commenté] une révision du dépôt"
+
+#: rhodecode/lib/helpers.py:658
+msgid "[pushed] into"
+msgstr "[a pushé] dans"
+
+#: rhodecode/lib/helpers.py:660
+msgid "[committed via RhodeCode] into repository"
+msgstr "[a commité via RhodeCode] dans le dépôt"
+
+#: rhodecode/lib/helpers.py:662
+msgid "[pulled from remote] into repository"
+msgstr "[a pullé depuis un site distant] dans le dépôt"
+
+#: rhodecode/lib/helpers.py:664
+msgid "[pulled] from"
+msgstr "[a pullé] depuis"
+
+#: rhodecode/lib/helpers.py:666
+msgid "[started following] repository"
+msgstr "[suit maintenant] le dépôt"
+
+#: rhodecode/lib/helpers.py:668
+msgid "[stopped following] repository"
+msgstr "[ne suit plus] le dépôt"
+
+#: rhodecode/lib/helpers.py:840
+#, python-format
+msgid " and %s more"
+msgstr "et %s de plus"
+
+#: rhodecode/lib/helpers.py:844
+msgid "No Files"
+msgstr "Aucun fichier"
+
+#: rhodecode/lib/utils2.py:335
+#, python-format
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] "%d an"
+msgstr[1] "%d ans"
+
+#: rhodecode/lib/utils2.py:336
+#, python-format
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] "%d mois"
+msgstr[1] "%d mois"
+
+#: rhodecode/lib/utils2.py:337
+#, python-format
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] "%d jour"
+msgstr[1] "%d jours"
+
+#: rhodecode/lib/utils2.py:338
+#, python-format
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] "%d heure"
+msgstr[1] "%d heures"
+
+#: rhodecode/lib/utils2.py:339
+#, python-format
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] "%d minute"
+msgstr[1] "%d minutes"
+
+#: rhodecode/lib/utils2.py:340
+#, python-format
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] "%d seconde"
+msgstr[1] "%d secondes"
+
+#: rhodecode/lib/utils2.py:355
+#, python-format
+msgid "%s ago"
+msgstr "Il y a %s"
+
+#: rhodecode/lib/utils2.py:357
+#, python-format
+msgid "%s and %s ago"
+msgstr "Il y a %s et %s"
+
+#: rhodecode/lib/utils2.py:360
+msgid "just now"
+msgstr "à l’instant"
+
+#: rhodecode/lib/celerylib/tasks.py:269
+msgid "password reset link"
+msgstr "Réinitialisation du mot de passe"
+
+#: rhodecode/model/comment.py:110
+#, python-format
+msgid "on line %s"
+msgstr "à la ligne %s"
+
+#: rhodecode/model/comment.py:157
+msgid "[Mention]"
+msgstr "[Mention]"
+
+#: rhodecode/model/db.py:1140
+#, fuzzy
+msgid "Repository no access"
+msgstr "Dépôts"
+
+#: rhodecode/model/db.py:1141
+#, fuzzy
+msgid "Repository read access"
+msgstr "Ce dépôt existe déjà"
+
+#: rhodecode/model/db.py:1142
+#, fuzzy
+msgid "Repository write access"
+msgstr "Dépôts"
+
+#: rhodecode/model/db.py:1143
+#, fuzzy
+msgid "Repository admin access"
+msgstr "Dépôts"
+
+#: rhodecode/model/db.py:1145
+#, fuzzy
+msgid "Repositories Group no access"
+msgstr "Groupes de dépôts"
+
+#: rhodecode/model/db.py:1146
+#, fuzzy
+msgid "Repositories Group read access"
+msgstr "Groupes de dépôts"
+
+#: rhodecode/model/db.py:1147
+#, fuzzy
+msgid "Repositories Group write access"
+msgstr "Groupes de dépôts"
+
+#: rhodecode/model/db.py:1148
+#, fuzzy
+msgid "Repositories Group admin access"
+msgstr "Groupes de dépôts"
+
+#: rhodecode/model/db.py:1150
+#, fuzzy
+msgid "RhodeCode Administrator"
+msgstr "Administration des utilisateurs"
+
+#: rhodecode/model/db.py:1151
+#, fuzzy
+msgid "Repository creation disabled"
+msgstr "Création de dépôt"
+
+#: rhodecode/model/db.py:1152
+#, fuzzy
+msgid "Repository creation enabled"
+msgstr "Création de dépôt"
+
+#: rhodecode/model/db.py:1153
+#, fuzzy
+msgid "Repository forking disabled"
+msgstr "Création de dépôt"
+
+#: rhodecode/model/db.py:1154
+#, fuzzy
+msgid "Repository forking enabled"
+msgstr "Création de dépôt"
+
+#: rhodecode/model/db.py:1155
+#, fuzzy
+msgid "Register disabled"
+msgstr "Désactivé"
+
+#: rhodecode/model/db.py:1156
+msgid "Register new user with RhodeCode with manual activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1159
+msgid "Register new user with RhodeCode with auto activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1579
+msgid "Not Reviewed"
+msgstr ""
+
+#: rhodecode/model/db.py:1580
+#, fuzzy
+msgid "Approved"
+msgstr "Supprimés"
+
+#: rhodecode/model/db.py:1581
+msgid "Rejected"
+msgstr ""
+
+#: rhodecode/model/db.py:1582
+msgid "Under Review"
+msgstr ""
+
+#: rhodecode/model/forms.py:43
+msgid "Please enter a login"
+msgstr "Veuillez entrer un identifiant"
+
+#: rhodecode/model/forms.py:44
+#, python-format
+msgid "Enter a value %(min)i characters long or more"
+msgstr "Entrez une valeur d’au moins %(min)i caractères de long."
+
+#: rhodecode/model/forms.py:52
+msgid "Please enter a password"
+msgstr "Veuillez entrer un mot de passe"
+
+#: rhodecode/model/forms.py:53
+#, python-format
+msgid "Enter %(min)i characters or more"
+msgstr "Entrez au moins %(min)i caractères"
+
+#: rhodecode/model/notification.py:220
+msgid "commented on commit"
+msgstr "a posté un commentaire sur le commit"
+
+#: rhodecode/model/notification.py:221
+msgid "sent message"
+msgstr "a envoyé un message"
+
+#: rhodecode/model/notification.py:222
+msgid "mentioned you"
+msgstr "vous a mentioné"
+
+#: rhodecode/model/notification.py:223
+msgid "registered in RhodeCode"
+msgstr "s’est enregistré sur RhodeCode"
+
+#: rhodecode/model/notification.py:224
+msgid "opened new pull request"
+msgstr ""
+
+#: rhodecode/model/notification.py:225
+#, fuzzy
+msgid "commented on pull request"
+msgstr "a posté un commentaire sur le commit"
+
+#: rhodecode/model/pull_request.py:84
+#, python-format
+msgid "%(user)s wants you to review pull request #%(pr_id)s"
+msgstr ""
+
+#: rhodecode/model/scm.py:535
+#, fuzzy
+msgid "latest tip"
+msgstr "Dernière connexion"
+
+#: rhodecode/model/user.py:230
+msgid "new user registration"
+msgstr "Nouveau compte utilisateur enregistré"
+
+#: rhodecode/model/user.py:255 rhodecode/model/user.py:277
+#: rhodecode/model/user.py:299
+msgid "You can't Edit this user since it's crucial for entire application"
+msgstr ""
+"Vous ne pouvez pas éditer cet utilisateur ; il est nécessaire pour le bon"
+" fonctionnement de l’application."
+
+#: rhodecode/model/user.py:323
+msgid "You can't remove this user since it's crucial for entire application"
+msgstr ""
+"Vous ne pouvez pas supprimer cet utilisateur ; il est nécessaire pour le "
+"bon fonctionnement de l’application."
+
+#: rhodecode/model/user.py:329
+#, python-format
+msgid ""
+"user \"%s\" still owns %s repositories and cannot be removed. Switch "
+"owners or remove those repositories. %s"
+msgstr ""
+"L’utilisateur « %s » possède %s dépôts et ne peut être supprimé. Changez "
+"les propriétaires de ces dépôts. %s"
+
+#: rhodecode/model/validators.py:35 rhodecode/model/validators.py:36
+msgid "Value cannot be an empty list"
+msgstr ""
+
+#: rhodecode/model/validators.py:82
+#, fuzzy, python-format
+msgid "Username \"%(username)s\" already exists"
+msgstr "Ce nom \"%(username)s\" d’utilisateur existe déjà"
+
+#: rhodecode/model/validators.py:84
+#, python-format
+msgid "Username \"%(username)s\" is forbidden"
+msgstr ""
+
+#: rhodecode/model/validators.py:86
+msgid ""
+"Username may only contain alphanumeric characters underscores, periods or"
+" dashes and must begin with alphanumeric character"
+msgstr ""
+"Le nom d’utilisateur peut contenir uniquement des caractères alpha-"
+"numériques ainsi que les caractères suivants : « _ . - ». Il doit "
+"commencer par un caractère alpha-numérique."
+
+#: rhodecode/model/validators.py:114
+#, python-format
+msgid "Username %(username)s is not valid"
+msgstr "%(username)s Nom d'utilisateur n'est pas valide"
+
+#: rhodecode/model/validators.py:133
+#, fuzzy
+msgid "Invalid users group name"
+msgstr "nom d’utilisateur invalide"
+
+#: rhodecode/model/validators.py:134
+#, python-format
+msgid "Users group \"%(usersgroup)s\" already exists"
+msgstr "Ce groupe \"%(usersgroup)s\" d’utilisateurs existe déjà."
+
+#: rhodecode/model/validators.py:136
+msgid ""
+"users group name may only contain  alphanumeric characters underscores, "
+"periods or dashes and must begin with alphanumeric character"
+msgstr ""
+"Le nom de groupe de dépôts peut contenir uniquement des caractères alpha-"
+"numériques ainsi que les caractères suivants : « _ . - ». Il doit "
+"commencer par un caractère alpha-numérique."
+
+#: rhodecode/model/validators.py:174
+msgid "Cannot assign this group as parent"
+msgstr "Impossible d’assigner ce groupe en tant que parent."
+
+#: rhodecode/model/validators.py:175
+#, python-format
+msgid "Group \"%(group_name)s\" already exists"
+msgstr "Ce nom d’utilisateur \"%(group_name)s\" existe déjà"
+
+#: rhodecode/model/validators.py:177
+#, python-format
+msgid "Repository with name \"%(group_name)s\" already exists"
+msgstr "Dépôt avec le nom de \"%(group_name)s\" existe déjà"
+
+#: rhodecode/model/validators.py:235
+#, fuzzy
+msgid "Invalid characters (non-ascii) in password"
+msgstr "Caractères incorrects dans le mot de passe"
+
+#: rhodecode/model/validators.py:250
+msgid "Passwords do not match"
+msgstr "Les mots de passe ne correspondent pas."
+
+#: rhodecode/model/validators.py:267
+msgid "invalid password"
+msgstr "mot de passe invalide"
+
+#: rhodecode/model/validators.py:268
+msgid "invalid user name"
+msgstr "nom d’utilisateur invalide"
+
+#: rhodecode/model/validators.py:269
+msgid "Your account is disabled"
+msgstr "Votre compte est désactivé"
+
+#: rhodecode/model/validators.py:313
+#, python-format
+msgid "Repository name %(repo)s is disallowed"
+msgstr "Ce nom de dépôt %(repo)s est interdit"
+
+#: rhodecode/model/validators.py:315
+#, python-format
+msgid "Repository named %(repo)s already exists"
+msgstr "Un dépôt portant %(repo)s ce nom existe déjà."
+
+#: rhodecode/model/validators.py:316
+#, python-format
+msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
+msgstr "Ce dépôt \"%(repo)s\" existe déjà dans le groupe « \"%(group)s\" »."
+
+#: rhodecode/model/validators.py:318
+#, python-format
+msgid "Repositories group with name \"%(repo)s\" already exists"
+msgstr "Un dépôt portant \"%(repo)s\" ce nom existe déjà."
+
+#: rhodecode/model/validators.py:431
+msgid "invalid clone url"
+msgstr "URL de clonage invalide."
+
+#: rhodecode/model/validators.py:432
+#, fuzzy
+msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url"
+msgstr ""
+"URL à cloner invalide. Veuillez fournir une URL valide commençant par "
+"http(s)."
+
+#: rhodecode/model/validators.py:457
+#, fuzzy
+msgid "Fork have to be the same type as parent"
+msgstr "Le fork doit être du même type que l’original"
+
+#: rhodecode/model/validators.py:478
+msgid "This username or users group name is not valid"
+msgstr "Ce nom d’utilisateur ou de groupe n’est pas valide."
+
+#: rhodecode/model/validators.py:562
+msgid "This is not a valid path"
+msgstr "Ceci n’est pas un chemin valide"
+
+#: rhodecode/model/validators.py:577
+msgid "This e-mail address is already taken"
+msgstr "Cette adresse e-mail est déjà enregistrée"
+
+#: rhodecode/model/validators.py:597
+#, python-format
+msgid "e-mail \"%(email)s\" does not exist."
+msgstr "Cette adresse e-mail \"%(email)s\" n’existe pas"
+
+#: rhodecode/model/validators.py:634
+msgid ""
+"The LDAP Login attribute of the CN must be specified - this is the name "
+"of the attribute that is equivalent to \"username\""
+msgstr ""
+"L’attribut Login du CN doit être spécifié. Cet attribut correspond au nom"
+" d’utilisateur."
+
+#: rhodecode/model/validators.py:653
+#, python-format
+msgid "Revisions %(revs)s are already part of pull request or have set status"
+msgstr ""
+
+#: rhodecode/templates/index.html:3
+msgid "Dashboard"
+msgstr "Tableau de bord"
+
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/repo_switcher_list.html:4
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/users/user_edit_my_account.html:31
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/bookmarks/bookmarks.html:10
+#: rhodecode/templates/branches/branches.html:9
+#: rhodecode/templates/journal/journal.html:40
+#: rhodecode/templates/tags/tags.html:10
+msgid "quick filter..."
+msgstr "Filtre rapide…"
+
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/base/base.html:221
+msgid "repositories"
+msgstr "Dépôts"
+
+#: rhodecode/templates/index_base.html:13
+#: rhodecode/templates/index_base.html:15
+#: rhodecode/templates/admin/repos/repos.html:21
+msgid "ADD REPOSITORY"
+msgstr "AJOUTER UN DÉPÔT"
+
+#: rhodecode/templates/index_base.html:29
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:32
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:32
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:33
+#: rhodecode/templates/admin/users_groups/users_group_add.html:32
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:33
+msgid "Group name"
+msgstr "Nom de groupe"
+
+#: rhodecode/templates/index_base.html:30
+#: rhodecode/templates/index_base.html:71
+#: rhodecode/templates/index_base.html:142
+#: rhodecode/templates/index_base.html:168
+#: rhodecode/templates/admin/repos/repo_add_base.html:56
+#: rhodecode/templates/admin/repos/repo_edit.html:75
+#: rhodecode/templates/admin/repos/repos.html:72
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:41
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:41
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:34
+#: rhodecode/templates/forks/fork.html:59
+#: rhodecode/templates/settings/repo_settings.html:66
+#: rhodecode/templates/summary/summary.html:105
+msgid "Description"
+msgstr "Description"
+
+#: rhodecode/templates/index_base.html:40
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46
+msgid "Repositories group"
+msgstr "Groupe de dépôts"
+
+#: rhodecode/templates/index_base.html:70
+#: rhodecode/templates/index_base.html:166
+#: rhodecode/templates/admin/repos/repo_add_base.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:32
+#: rhodecode/templates/admin/repos/repos.html:70
+#: rhodecode/templates/admin/users/user_edit.html:192
+#: rhodecode/templates/admin/users/user_edit_my_account.html:59
+#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:6
+#: rhodecode/templates/bookmarks/bookmarks.html:36
+#: rhodecode/templates/bookmarks/bookmarks_data.html:6
+#: rhodecode/templates/branches/branches.html:51
+#: rhodecode/templates/files/files_browser.html:47
+#: rhodecode/templates/journal/journal.html:59
+#: rhodecode/templates/journal/journal.html:107
+#: rhodecode/templates/journal/journal.html:186
+#: rhodecode/templates/settings/repo_settings.html:31
+#: rhodecode/templates/summary/summary.html:43
+#: rhodecode/templates/summary/summary.html:123
+#: rhodecode/templates/tags/tags.html:36
+#: rhodecode/templates/tags/tags_data.html:6
+msgid "Name"
+msgstr "Nom"
+
+#: rhodecode/templates/index_base.html:72
+msgid "Last change"
+msgstr "Dernière modification"
+
+#: rhodecode/templates/index_base.html:73
+#: rhodecode/templates/index_base.html:171
+#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/journal/journal.html:188
+msgid "Tip"
+msgstr "Sommet"
+
+#: rhodecode/templates/index_base.html:74
+#: rhodecode/templates/index_base.html:173
+#: rhodecode/templates/admin/repos/repo_edit.html:121
+#: rhodecode/templates/admin/repos/repos.html:73
+msgid "Owner"
+msgstr "Propriétaire"
+
+#: rhodecode/templates/index_base.html:75
+#: rhodecode/templates/summary/summary.html:48
+#: rhodecode/templates/summary/summary.html:51
+msgid "RSS"
+msgstr "RSS"
+
+#: rhodecode/templates/index_base.html:76
+msgid "Atom"
+msgstr "Atom"
+
+#: rhodecode/templates/index_base.html:110
+#: rhodecode/templates/index_base.html:112
+#, python-format
+msgid "Subscribe to %s rss feed"
+msgstr "S’abonner au flux RSS de %s"
+
+#: rhodecode/templates/index_base.html:117
+#: rhodecode/templates/index_base.html:119
+#, python-format
+msgid "Subscribe to %s atom feed"
+msgstr "S’abonner au flux ATOM de %s"
+
+#: rhodecode/templates/index_base.html:140
+msgid "Group Name"
+msgstr "Nom du groupe"
+
+#: rhodecode/templates/index_base.html:158
+#: rhodecode/templates/index_base.html:198
+#: rhodecode/templates/admin/repos/repos.html:94
+#: rhodecode/templates/admin/users/user_edit_my_account.html:179
+#: rhodecode/templates/admin/users/users.html:107
+#: rhodecode/templates/bookmarks/bookmarks.html:60
+#: rhodecode/templates/branches/branches.html:77
+#: rhodecode/templates/journal/journal.html:211
+#: rhodecode/templates/tags/tags.html:60
+msgid "Click to sort ascending"
+msgstr "Tri ascendant"
+
+#: rhodecode/templates/index_base.html:159
+#: rhodecode/templates/index_base.html:199
+#: rhodecode/templates/admin/repos/repos.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account.html:180
+#: rhodecode/templates/admin/users/users.html:108
+#: rhodecode/templates/bookmarks/bookmarks.html:61
+#: rhodecode/templates/branches/branches.html:78
+#: rhodecode/templates/journal/journal.html:212
+#: rhodecode/templates/tags/tags.html:61
+msgid "Click to sort descending"
+msgstr "Tri descendant"
+
+#: rhodecode/templates/index_base.html:169
+msgid "Last Change"
+msgstr "Dernière modification"
+
+#: rhodecode/templates/index_base.html:200
+#: rhodecode/templates/admin/repos/repos.html:96
+#: rhodecode/templates/admin/users/user_edit_my_account.html:181
+#: rhodecode/templates/admin/users/users.html:109
+#: rhodecode/templates/bookmarks/bookmarks.html:62
+#: rhodecode/templates/branches/branches.html:79
+#: rhodecode/templates/journal/journal.html:213
+#: rhodecode/templates/tags/tags.html:62
+msgid "No records found."
+msgstr "Aucun élément n’a été trouvé."
+
+#: rhodecode/templates/index_base.html:201
+#: rhodecode/templates/admin/repos/repos.html:97
+#: rhodecode/templates/admin/users/user_edit_my_account.html:182
+#: rhodecode/templates/admin/users/users.html:110
+#: rhodecode/templates/bookmarks/bookmarks.html:63
+#: rhodecode/templates/branches/branches.html:80
+#: rhodecode/templates/journal/journal.html:214
+#: rhodecode/templates/tags/tags.html:63
+msgid "Data error."
+msgstr "Erreur d’intégrité des données."
+
+#: rhodecode/templates/index_base.html:202
+#: rhodecode/templates/admin/repos/repos.html:98
+#: rhodecode/templates/admin/users/user_edit_my_account.html:183
+#: rhodecode/templates/admin/users/users.html:111
+#: rhodecode/templates/bookmarks/bookmarks.html:64
+#: rhodecode/templates/branches/branches.html:81
+#: rhodecode/templates/journal/journal.html:215
+#: rhodecode/templates/tags/tags.html:64
+msgid "Loading..."
+msgstr "Chargement…"
+
+#: rhodecode/templates/login.html:5 rhodecode/templates/login.html:54
+msgid "Sign In"
+msgstr "Connexion"
+
+#: rhodecode/templates/login.html:21
+msgid "Sign In to"
+msgstr "Connexion à"
+
+#: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20
+#: rhodecode/templates/admin/admin_log.html:5
+#: rhodecode/templates/admin/users/user_add.html:32
+#: rhodecode/templates/admin/users/user_edit.html:50
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:26
+#: rhodecode/templates/base/base.html:83
+#: rhodecode/templates/summary/summary.html:122
+msgid "Username"
+msgstr "Nom d’utilisateur"
+
+#: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29
+#: rhodecode/templates/admin/ldap/ldap.html:46
+#: rhodecode/templates/admin/users/user_add.html:41
+#: rhodecode/templates/base/base.html:92
+msgid "Password"
+msgstr "Mot de passe"
+
+#: rhodecode/templates/login.html:50
+msgid "Remember me"
+msgstr "Se souvenir de moi"
+
+#: rhodecode/templates/login.html:60
+msgid "Forgot your password ?"
+msgstr "Mot de passe oublié ?"
+
+#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:103
+msgid "Don't have an account ?"
+msgstr "Vous n’avez pas de compte ?"
+
+#: rhodecode/templates/password_reset.html:5
+msgid "Reset your password"
+msgstr "Mot de passe oublié ?"
+
+#: rhodecode/templates/password_reset.html:11
+msgid "Reset your password to"
+msgstr "Réinitialiser votre mot de passe"
+
+#: rhodecode/templates/password_reset.html:21
+msgid "Email address"
+msgstr "Adresse e-mail"
+
+#: rhodecode/templates/password_reset.html:30
+msgid "Reset my password"
+msgstr "Réinitialiser mon mot de passe"
+
+#: rhodecode/templates/password_reset.html:31
+msgid "Password reset link will be send to matching email address"
+msgstr "Votre nouveau mot de passe sera envoyé à l’adresse correspondante."
+
+#: rhodecode/templates/register.html:5 rhodecode/templates/register.html:74
+msgid "Sign Up"
+msgstr "Inscription"
+
+#: rhodecode/templates/register.html:11
+msgid "Sign Up to"
+msgstr "Inscription à"
+
+#: rhodecode/templates/register.html:38
+msgid "Re-enter password"
+msgstr "Confirmation"
+
+#: rhodecode/templates/register.html:47
+#: rhodecode/templates/admin/users/user_add.html:59
+#: rhodecode/templates/admin/users/user_edit.html:86
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53
+msgid "First Name"
+msgstr "Prénom"
+
+#: rhodecode/templates/register.html:56
+#: rhodecode/templates/admin/users/user_add.html:68
+#: rhodecode/templates/admin/users/user_edit.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62
+msgid "Last Name"
+msgstr "Nom"
+
+#: rhodecode/templates/register.html:65
+#: rhodecode/templates/admin/users/user_add.html:77
+#: rhodecode/templates/admin/users/user_edit.html:104
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71
+#: rhodecode/templates/summary/summary.html:124
+msgid "Email"
+msgstr "E-mail"
+
+#: rhodecode/templates/register.html:76
+msgid "Your account will be activated right after registration"
+msgstr "Votre compte utilisateur sera actif dès la fin de l’enregistrement."
+
+#: rhodecode/templates/register.html:78
+msgid "Your account must wait for activation by administrator"
+msgstr "Votre compte utilisateur devra être activé par un administrateur."
+
+#: rhodecode/templates/repo_switcher_list.html:11
+#: rhodecode/templates/admin/repos/repo_add_base.html:65
+#: rhodecode/templates/admin/repos/repo_edit.html:85
+#: rhodecode/templates/settings/repo_settings.html:76
+msgid "Private repository"
+msgstr "Dépôt privé"
+
+#: rhodecode/templates/repo_switcher_list.html:16
+msgid "Public repository"
+msgstr "Dépôt public"
+
+#: rhodecode/templates/switch_to_list.html:3
+#: rhodecode/templates/branches/branches.html:14
+msgid "branches"
+msgstr "Branches"
+
+#: rhodecode/templates/switch_to_list.html:10
+#: rhodecode/templates/branches/branches_data.html:57
+msgid "There are no branches yet"
+msgstr "Aucune branche n’a été créée pour le moment."
+
+#: rhodecode/templates/switch_to_list.html:15
+#: rhodecode/templates/shortlog/shortlog_data.html:10
+#: rhodecode/templates/tags/tags.html:15
+msgid "tags"
+msgstr "Tags"
+
+#: rhodecode/templates/switch_to_list.html:22
+#: rhodecode/templates/tags/tags_data.html:33
+msgid "There are no tags yet"
+msgstr "Aucun tag n’a été créé pour le moment."
+
+#: rhodecode/templates/switch_to_list.html:28
+#: rhodecode/templates/bookmarks/bookmarks.html:15
+msgid "bookmarks"
+msgstr "Signets"
+
+#: rhodecode/templates/switch_to_list.html:35
+#: rhodecode/templates/bookmarks/bookmarks_data.html:32
+msgid "There are no bookmarks yet"
+msgstr "Aucun signet n’a été créé."
+
+#: rhodecode/templates/admin/admin.html:5
+#: rhodecode/templates/admin/admin.html:9
+msgid "Admin journal"
+msgstr "Historique d’administration"
+
+#: rhodecode/templates/admin/admin_log.html:6
+#: rhodecode/templates/admin/repos/repos.html:74
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:8
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:9
+#: rhodecode/templates/journal/journal.html:61
+#: rhodecode/templates/journal/journal.html:62
+msgid "Action"
+msgstr "Action"
+
+#: rhodecode/templates/admin/admin_log.html:7
+msgid "Repository"
+msgstr "Dépôt"
+
+#: rhodecode/templates/admin/admin_log.html:8
+#: rhodecode/templates/bookmarks/bookmarks.html:37
+#: rhodecode/templates/bookmarks/bookmarks_data.html:7
+#: rhodecode/templates/branches/branches.html:52
+#: rhodecode/templates/tags/tags.html:37
+#: rhodecode/templates/tags/tags_data.html:7
+msgid "Date"
+msgstr "Date"
+
+#: rhodecode/templates/admin/admin_log.html:9
+msgid "From IP"
+msgstr "Depuis l’adresse IP"
+
+#: rhodecode/templates/admin/admin_log.html:53
+msgid "No actions yet"
+msgstr "Aucune action n’a été enregistrée pour le moment."
+
+#: rhodecode/templates/admin/ldap/ldap.html:5
+msgid "LDAP administration"
+msgstr "Administration LDAP"
+
+#: rhodecode/templates/admin/ldap/ldap.html:11
+msgid "Ldap"
+msgstr "LDAP"
+
+#: rhodecode/templates/admin/ldap/ldap.html:28
+msgid "Connection settings"
+msgstr "Options de connexion"
+
+#: rhodecode/templates/admin/ldap/ldap.html:30
+msgid "Enable LDAP"
+msgstr "Activer le LDAP"
+
+#: rhodecode/templates/admin/ldap/ldap.html:34
+msgid "Host"
+msgstr "Serveur"
+
+#: rhodecode/templates/admin/ldap/ldap.html:38
+msgid "Port"
+msgstr "Port"
+
+#: rhodecode/templates/admin/ldap/ldap.html:42
+msgid "Account"
+msgstr "Compte"
+
+#: rhodecode/templates/admin/ldap/ldap.html:50
+msgid "Connection security"
+msgstr "Connexion sécurisée"
+
+#: rhodecode/templates/admin/ldap/ldap.html:54
+msgid "Certificate Checks"
+msgstr "Vérif. des certificats"
+
+#: rhodecode/templates/admin/ldap/ldap.html:57
+msgid "Search settings"
+msgstr "Réglages de recherche"
+
+#: rhodecode/templates/admin/ldap/ldap.html:59
+msgid "Base DN"
+msgstr "Base de recherche"
+
+#: rhodecode/templates/admin/ldap/ldap.html:63
+msgid "LDAP Filter"
+msgstr "Filtre de recherche"
+
+#: rhodecode/templates/admin/ldap/ldap.html:67
+msgid "LDAP Search Scope"
+msgstr "Portée de recherche"
+
+#: rhodecode/templates/admin/ldap/ldap.html:70
+msgid "Attribute mappings"
+msgstr "Correspondance des attributs"
+
+#: rhodecode/templates/admin/ldap/ldap.html:72
+msgid "Login Attribute"
+msgstr "Attribut pour le nom d’utilisateur"
+
+#: rhodecode/templates/admin/ldap/ldap.html:76
+msgid "First Name Attribute"
+msgstr "Attribut pour le prénom"
+
+#: rhodecode/templates/admin/ldap/ldap.html:80
+msgid "Last Name Attribute"
+msgstr "Attribut pour le nom de famille"
+
+#: rhodecode/templates/admin/ldap/ldap.html:84
+msgid "E-mail Attribute"
+msgstr "Attribut pour l’e-mail"
+
+#: rhodecode/templates/admin/ldap/ldap.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:141
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:74
+#: rhodecode/templates/admin/settings/hooks.html:73
+#: rhodecode/templates/admin/users/user_edit.html:129
+#: rhodecode/templates/admin/users/user_edit.html:174
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:79
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:135
+#: rhodecode/templates/settings/repo_settings.html:93
+msgid "Save"
+msgstr "Enregistrer"
+
+#: rhodecode/templates/admin/notifications/notifications.html:5
+#: rhodecode/templates/admin/notifications/notifications.html:9
+msgid "My Notifications"
+msgstr "Mes notifications"
+
+#: rhodecode/templates/admin/notifications/notifications.html:29
+msgid "All"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:30
+#, fuzzy
+msgid "Comments"
+msgstr "commits"
+
+#: rhodecode/templates/admin/notifications/notifications.html:31
+#: rhodecode/templates/base/base.html:254
+#: rhodecode/templates/base/base.html:256
+msgid "Pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:35
+msgid "Mark all read"
+msgstr "Tout marquer comme lu"
+
+#: rhodecode/templates/admin/notifications/notifications_data.html:39
+msgid "No notifications here yet"
+msgstr "Aucune notification pour le moment."
+
+#: rhodecode/templates/admin/notifications/show_notification.html:5
+#: rhodecode/templates/admin/notifications/show_notification.html:11
+msgid "Show notification"
+msgstr "Notification"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:9
+msgid "Notifications"
+msgstr "Notifications"
+
+#: rhodecode/templates/admin/permissions/permissions.html:5
+msgid "Permissions administration"
+msgstr "Gestion des permissions"
+
+#: rhodecode/templates/admin/permissions/permissions.html:11
+#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
+#: rhodecode/templates/admin/users/user_edit.html:139
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:100
+#: rhodecode/templates/settings/repo_settings.html:86
+msgid "Permissions"
+msgstr "Permissions"
+
+#: rhodecode/templates/admin/permissions/permissions.html:24
+msgid "Default permissions"
+msgstr "Permissions par défaut"
+
+#: rhodecode/templates/admin/permissions/permissions.html:31
+msgid "Anonymous access"
+msgstr "Accès anonyme"
+
+#: rhodecode/templates/admin/permissions/permissions.html:41
+msgid "Repository permission"
+msgstr "Permissions du dépôt"
+
+#: rhodecode/templates/admin/permissions/permissions.html:49
+msgid ""
+"All default permissions on each repository will be reset to choosen "
+"permission, note that all custom default permission on repositories will "
+"be lost"
+msgstr ""
+"Les permissions par défaut de chaque dépôt vont être remplacées par la "
+"permission choisie. Toutes les permissions par défaut des dépôts seront "
+"perdues."
+
+#: rhodecode/templates/admin/permissions/permissions.html:50
+msgid "overwrite existing settings"
+msgstr "Écraser les permissions existantes"
+
+#: rhodecode/templates/admin/permissions/permissions.html:55
+msgid "Registration"
+msgstr "Enregistrement"
+
+#: rhodecode/templates/admin/permissions/permissions.html:63
+msgid "Repository creation"
+msgstr "Création de dépôt"
+
+#: rhodecode/templates/admin/permissions/permissions.html:71
+#, fuzzy
+msgid "Repository forking"
+msgstr "Création de dépôt"
+
+#: rhodecode/templates/admin/permissions/permissions.html:78
+#: rhodecode/templates/admin/repos/repo_edit.html:241
+msgid "set"
+msgstr "Définir"
+
+#: rhodecode/templates/admin/repos/repo_add.html:5
+#: rhodecode/templates/admin/repos/repo_add_create_repository.html:5
+msgid "Add repository"
+msgstr "Ajouter un dépôt"
+
+#: rhodecode/templates/admin/repos/repo_add.html:11
+#: rhodecode/templates/admin/repos/repo_edit.html:11
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
+msgid "Repositories"
+msgstr "Dépôts"
+
+#: rhodecode/templates/admin/repos/repo_add.html:13
+msgid "add new"
+msgstr "ajouter un nouveau"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:20
+#: rhodecode/templates/summary/summary.html:95
+#: rhodecode/templates/summary/summary.html:96
+msgid "Clone from"
+msgstr "Cloner depuis"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:24
+#: rhodecode/templates/admin/repos/repo_edit.html:44
+#: rhodecode/templates/settings/repo_settings.html:43
+msgid "Optional http[s] url from which repository should be cloned."
+msgstr "URL http(s) depuis laquelle le dépôt doit être cloné."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:29
+#: rhodecode/templates/admin/repos/repo_edit.html:49
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:4
+#: rhodecode/templates/forks/fork.html:50
+#: rhodecode/templates/settings/repo_settings.html:48
+msgid "Repository group"
+msgstr "Groupe de dépôt"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:33
+#: rhodecode/templates/forks/fork.html:54
+#, fuzzy
+msgid "Optionaly select a group to put this repository into."
+msgstr "Sélectionnez un groupe (optionel) dans lequel sera placé le dépôt."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:38
+#: rhodecode/templates/admin/repos/repo_edit.html:58
+msgid "Type"
+msgstr "Type"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:42
+msgid "Type of repository to create."
+msgstr "Type de dépôt à créer."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:47
+#: rhodecode/templates/admin/repos/repo_edit.html:66
+#: rhodecode/templates/forks/fork.html:41
+#: rhodecode/templates/settings/repo_settings.html:57
+#, fuzzy
+msgid "Landing revision"
+msgstr "révision suivante"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:51
+#: rhodecode/templates/admin/repos/repo_edit.html:70
+#: rhodecode/templates/forks/fork.html:45
+#: rhodecode/templates/settings/repo_settings.html:61
+msgid "Default revision for files page, downloads, whoosh and readme"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:60
+#: rhodecode/templates/admin/repos/repo_edit.html:79
+#: rhodecode/templates/forks/fork.html:63
+#: rhodecode/templates/settings/repo_settings.html:70
+msgid "Keep it short and to the point. Use a README file for longer descriptions."
+msgstr ""
+"Gardez cette description précise et concise. Utilisez un fichier README "
+"pour des descriptions plus détaillées."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:69
+#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/forks/fork.html:72
+#: rhodecode/templates/settings/repo_settings.html:80
+msgid ""
+"Private repositories are only visible to people explicitly added as "
+"collaborators."
+msgstr ""
+"Les dépôts privés sont visibles seulement par les utilisateurs ajoutés "
+"comme collaborateurs."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:73
+msgid "add"
+msgstr "Ajouter"
+
+#: rhodecode/templates/admin/repos/repo_add_create_repository.html:9
+msgid "add new repository"
+msgstr "ajouter un nouveau dépôt"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:5
+msgid "Edit repository"
+msgstr "Éditer le dépôt"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:13
+#: rhodecode/templates/admin/users/user_edit.html:13
+#: rhodecode/templates/admin/users/user_edit.html:224
+#: rhodecode/templates/admin/users/user_edit.html:226
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:13
+#: rhodecode/templates/files/files_source.html:44
+#: rhodecode/templates/journal/journal.html:81
+msgid "edit"
+msgstr "éditer"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:40
+#: rhodecode/templates/settings/repo_settings.html:39
+msgid "Clone uri"
+msgstr "URL de clone"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:53
+#: rhodecode/templates/settings/repo_settings.html:52
+msgid "Optional select a group to put this repository into."
+msgstr "Sélectionnez un groupe (optionel) dans lequel sera placé le dépôt."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:94
+msgid "Enable statistics"
+msgstr "Activer les statistiques"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:98
+msgid "Enable statistics window on summary page."
+msgstr "Afficher les statistiques sur la page du dépôt."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:103
+msgid "Enable downloads"
+msgstr "Activer les téléchargements"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:107
+msgid "Enable download menu on summary page."
+msgstr "Afficher le menu de téléchargements sur la page du dépôt."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:112
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:66
+#, fuzzy
+msgid "Enable locking"
+msgstr "Activer"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:116
+msgid "Enable lock-by-pulling on repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:126
+msgid "Change owner of this repository."
+msgstr "Changer le propriétaire de ce dépôt."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:142
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:75
+#: rhodecode/templates/admin/settings/settings.html:113
+#: rhodecode/templates/admin/settings/settings.html:168
+#: rhodecode/templates/admin/settings/settings.html:258
+#: rhodecode/templates/admin/users/user_edit.html:130
+#: rhodecode/templates/admin/users/user_edit.html:175
+#: rhodecode/templates/admin/users/user_edit.html:278
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:136
+#: rhodecode/templates/files/files_add.html:82
+#: rhodecode/templates/files/files_edit.html:68
+#: rhodecode/templates/pullrequests/pullrequest.html:124
+#: rhodecode/templates/settings/repo_settings.html:94
+msgid "Reset"
+msgstr "Réinitialiser"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:152
+msgid "Administration"
+msgstr "Administration"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:155
+msgid "Statistics"
+msgstr "Statistiques"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:159
+msgid "Reset current statistics"
+msgstr "Réinitialiser les statistiques"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:159
+msgid "Confirm to remove current statistics"
+msgstr "Souhaitez-vous vraiment réinitialiser les statistiques de ce dépôt ?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:162
+msgid "Fetched to rev"
+msgstr "Parcouru jusqu’à la révision"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:163
+msgid "Stats gathered"
+msgstr "Statistiques obtenues"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:171
+msgid "Remote"
+msgstr "Dépôt distant"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Pull changes from remote location"
+msgstr "Récupérer les changements depuis le site distant"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Confirm to pull changes from remote side"
+msgstr "Voulez-vous vraiment récupérer les changements depuis le site distant ?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:186
+msgid "Cache"
+msgstr "Cache"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:190
+msgid "Invalidate repository cache"
+msgstr "Invalider le cache du dépôt"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:190
+msgid "Confirm to invalidate repository cache"
+msgstr "Voulez-vous vraiment invalider le cache du dépôt ?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:195
+#: rhodecode/templates/base/base.html:318
+#: rhodecode/templates/base/base.html:320
+#: rhodecode/templates/base/base.html:322
+msgid "Public journal"
+msgstr "Journal public"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:201
+msgid "Remove from public journal"
+msgstr "Supprimer du journal public"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:203
+msgid "Add to public journal"
+msgstr "Ajouter le dépôt au journal public"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:208
+msgid ""
+"All actions made on this repository will be accessible to everyone in "
+"public journal"
+msgstr ""
+"Le descriptif des actions réalisées sur ce dépôt sera visible à tous "
+"depuis le journal public."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:215
+#, fuzzy
+msgid "Locking"
+msgstr "Déverrouiller"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Unlock locked repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+#, fuzzy
+msgid "Confirm to unlock repository"
+msgstr "Voulez-vous vraiment supprimer ce dépôt ?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "lock repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+#, fuzzy
+msgid "Confirm to lock repository"
+msgstr "Voulez-vous vraiment supprimer ce dépôt ?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:224
+#, fuzzy
+msgid "Repository is not locked"
+msgstr "Dépôts"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:229
+msgid "Force locking on repository. Works only when anonymous access is disabled"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:236
+#, fuzzy
+msgid "Set as fork of"
+msgstr "Indiquer comme fork"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:245
+#, fuzzy
+msgid "Manually set this repository as a fork of another from the list"
+msgstr "Permet d’indiquer manuellement que ce dépôt est un fork d’un autre dépôt."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:251
+#: rhodecode/templates/changeset/changeset_file_comment.html:26
+msgid "Delete"
+msgstr "Supprimer"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+msgid "Remove this repository"
+msgstr "Supprimer ce dépôt"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+#: rhodecode/templates/journal/journal.html:84
+msgid "Confirm to delete this repository"
+msgstr "Voulez-vous vraiment supprimer ce dépôt ?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:259
+msgid ""
+"This repository will be renamed in a special way in order to be "
+"unaccesible for RhodeCode and VCS systems.\n"
+"                         If you need fully delete it from filesystem "
+"please do it manually"
+msgstr ""
+"Ce dépôt sera renommé de manière à le rendre inaccessible à RhodeCode et "
+"au système de gestion de versions.\n"
+"Si vous voulez le supprimer complètement, effectuez la suppression "
+"manuellement."
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:3
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3
+msgid "none"
+msgstr "Aucune"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:4
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4
+msgid "read"
+msgstr "Lecture"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:5
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5
+msgid "write"
+msgstr "Écriture"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:6
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6
+#: rhodecode/templates/admin/users/users.html:85
+#: rhodecode/templates/base/base.html:217
+msgid "admin"
+msgstr "Administration"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:7
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7
+msgid "member"
+msgstr "Membre"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
+#: rhodecode/templates/data_table/_dt_elements.html:67
+#: rhodecode/templates/journal/journal.html:132
+#: rhodecode/templates/summary/summary.html:76
+msgid "private repository"
+msgstr "Dépôt privé"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:19
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:28
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:18
+msgid "default"
+msgstr "[Par défaut]"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:33
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:58
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:23
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:42
+msgid "revoke"
+msgstr "Révoquer"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:83
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:67
+msgid "Add another member"
+msgstr "Ajouter un utilisateur"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:97
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81
+msgid "Failed to remove user"
+msgstr "Échec de suppression de l’utilisateur"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:112
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:96
+msgid "Failed to remove users group"
+msgstr "Erreur lors de la suppression du groupe d’utilisateurs."
+
+#: rhodecode/templates/admin/repos/repos.html:5
+msgid "Repositories administration"
+msgstr "Administration des dépôts"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:8
+msgid "Groups"
+msgstr "Groupes"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:12
+msgid "with"
+msgstr "comprenant"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:5
+msgid "Add repos group"
+msgstr "Créer un groupe de dépôt"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:10
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:10
+msgid "Repos groups"
+msgstr "Groupes de dépôts"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:12
+msgid "add new repos group"
+msgstr "Nouveau groupe de dépôt"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:50
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:50
+msgid "Group parent"
+msgstr "Parent du groupe"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:58
+#: rhodecode/templates/admin/users/user_add.html:94
+#: rhodecode/templates/admin/users_groups/users_group_add.html:49
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:90
+#: rhodecode/templates/pullrequests/pullrequest_show.html:113
+msgid "save"
+msgstr "Enregistrer"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:5
+msgid "Edit repos group"
+msgstr "Éditer le groupe de dépôt"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:12
+msgid "edit repos group"
+msgstr "Édition du groupe de dépôt"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:70
+msgid ""
+"Enable lock-by-pulling on group. This option will be applied to all other"
+" groups and repositories inside"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5
+msgid "Repositories groups administration"
+msgstr "Administration des groupes de dépôts"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:22
+msgid "ADD NEW GROUP"
+msgstr "AJOUTER UN NOUVEAU GROUPE"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:35
+msgid "Number of toplevel repositories"
+msgstr "Nombre de sous-dépôts"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
+#: rhodecode/templates/admin/users/users.html:87
+#: rhodecode/templates/admin/users_groups/users_groups.html:35
+msgid "action"
+msgstr "Action"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#: rhodecode/templates/admin/users/user_edit.html:255
+#: rhodecode/templates/admin/users_groups/users_groups.html:44
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#: rhodecode/templates/data_table/_dt_elements.html:103
+msgid "delete"
+msgstr "Supprimer"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#, python-format
+msgid "Confirm to delete this group: %s"
+msgstr "Voulez-vous vraiment supprimer le groupe « %s » ?"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:62
+msgid "There are no repositories groups yet"
+msgstr "Aucun groupe de dépôts n’a été créé pour le moment."
+
+#: rhodecode/templates/admin/settings/hooks.html:5
+#: rhodecode/templates/admin/settings/settings.html:5
+msgid "Settings administration"
+msgstr "Administration générale"
+
+#: rhodecode/templates/admin/settings/hooks.html:9
+#: rhodecode/templates/admin/settings/settings.html:9
+#: rhodecode/templates/settings/repo_settings.html:13
+msgid "Settings"
+msgstr "Options"
+
+#: rhodecode/templates/admin/settings/hooks.html:24
+msgid "Built in hooks - read only"
+msgstr "Hooks prédéfinis (lecture seule)"
+
+#: rhodecode/templates/admin/settings/hooks.html:40
+msgid "Custom hooks"
+msgstr "Hooks personnalisés"
+
+#: rhodecode/templates/admin/settings/hooks.html:56
+msgid "remove"
+msgstr "Enlever"
+
+#: rhodecode/templates/admin/settings/hooks.html:88
+msgid "Failed to remove hook"
+msgstr "Erreur lors de la suppression du hook."
+
+#: rhodecode/templates/admin/settings/settings.html:24
+msgid "Remap and rescan repositories"
+msgstr "Ré-associer et re-scanner les dépôts"
+
+#: rhodecode/templates/admin/settings/settings.html:32
+msgid "rescan option"
+msgstr "Option de re-scan"
+
+#: rhodecode/templates/admin/settings/settings.html:38
+msgid ""
+"In case a repository was deleted from filesystem and there are leftovers "
+"in the database check this option to scan obsolete data in database and "
+"remove it."
+msgstr ""
+"Cochez cette option pour supprimer d’éventuelles données obsolètes "
+"(concernant des dépôts manuellement supprimés) de la base de données."
+
+#: rhodecode/templates/admin/settings/settings.html:39
+msgid "destroy old data"
+msgstr "Supprimer les données obsolètes"
+
+#: rhodecode/templates/admin/settings/settings.html:41
+msgid ""
+"Rescan repositories location for new repositories. Also deletes obsolete "
+"if `destroy` flag is checked "
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:46
+msgid "Rescan repositories"
+msgstr "Re-scanner les dépôts"
+
+#: rhodecode/templates/admin/settings/settings.html:52
+msgid "Whoosh indexing"
+msgstr "Indexation Whoosh"
+
+#: rhodecode/templates/admin/settings/settings.html:60
+msgid "index build option"
+msgstr "Option d’indexation"
+
+#: rhodecode/templates/admin/settings/settings.html:65
+msgid "build from scratch"
+msgstr "Purger et reconstruire l’index"
+
+#: rhodecode/templates/admin/settings/settings.html:71
+msgid "Reindex"
+msgstr "Mettre à jour l’index"
+
+#: rhodecode/templates/admin/settings/settings.html:77
+msgid "Global application settings"
+msgstr "Réglages d’application globaux"
+
+#: rhodecode/templates/admin/settings/settings.html:86
+msgid "Application name"
+msgstr "Nom de l’application"
+
+#: rhodecode/templates/admin/settings/settings.html:95
+msgid "Realm text"
+msgstr "Texte du royaume"
+
+#: rhodecode/templates/admin/settings/settings.html:104
+msgid "GA code"
+msgstr "Code GA"
+
+#: rhodecode/templates/admin/settings/settings.html:112
+#: rhodecode/templates/admin/settings/settings.html:167
+#: rhodecode/templates/admin/settings/settings.html:257
+msgid "Save settings"
+msgstr "Enregister les options"
+
+#: rhodecode/templates/admin/settings/settings.html:119
+#, fuzzy
+msgid "Visualisation settings"
+msgstr "Réglages d’application globaux"
+
+#: rhodecode/templates/admin/settings/settings.html:128
+#, fuzzy
+msgid "Icons"
+msgstr "Options"
+
+#: rhodecode/templates/admin/settings/settings.html:133
+msgid "Show public repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:137
+#, fuzzy
+msgid "Show private repo icon on repositories"
+msgstr "Dépôt privé"
+
+#: rhodecode/templates/admin/settings/settings.html:144
+#, fuzzy
+msgid "Meta-Tagging"
+msgstr "Réglages"
+
+#: rhodecode/templates/admin/settings/settings.html:149
+msgid "Stylify recognised metatags:"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:176
+#, fuzzy
+msgid "VCS settings"
+msgstr "Réglages"
+
+#: rhodecode/templates/admin/settings/settings.html:185
+msgid "Web"
+msgstr "Web"
+
+#: rhodecode/templates/admin/settings/settings.html:190
+#, fuzzy
+msgid "require ssl for vcs operations"
+msgstr "SSL requis pour les pushs"
+
+#: rhodecode/templates/admin/settings/settings.html:192
+msgid ""
+"RhodeCode will require SSL for pushing or pulling. If SSL is missing it "
+"will return HTTP Error 406: Not Acceptable"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:198
+msgid "Hooks"
+msgstr "Hooks"
+
+#: rhodecode/templates/admin/settings/settings.html:203
+msgid "Update repository after push (hg update)"
+msgstr "Mettre à jour les dépôts après un push (hg update)"
+
+#: rhodecode/templates/admin/settings/settings.html:207
+msgid "Show repository size after push"
+msgstr "Afficher la taille du dépôt après un push"
+
+#: rhodecode/templates/admin/settings/settings.html:211
+msgid "Log user push commands"
+msgstr "Journaliser les commandes de push"
+
+#: rhodecode/templates/admin/settings/settings.html:215
+msgid "Log user pull commands"
+msgstr "Journaliser les commandes de pull"
+
+#: rhodecode/templates/admin/settings/settings.html:219
+msgid "advanced setup"
+msgstr "Avancé"
+
+#: rhodecode/templates/admin/settings/settings.html:224
+#, fuzzy
+msgid "Mercurial Extensions"
+msgstr "Dépôt Mercurial"
+
+#: rhodecode/templates/admin/settings/settings.html:229
+msgid "largefiles extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:233
+msgid "hgsubversion extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:235
+msgid ""
+"Requires hgsubversion library installed. Allows clonning from svn remote "
+"locations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:245
+msgid "Repositories location"
+msgstr "Emplacement des dépôts"
+
+#: rhodecode/templates/admin/settings/settings.html:250
+msgid ""
+"This a crucial application setting. If you are really sure you need to "
+"change this, you must restart application in order to make this setting "
+"take effect. Click this label to unlock."
+msgstr ""
+"Ce réglage ne devrait pas être modifié en temps normal. Si vous devez "
+"vraiment le faire, redémarrer l’application une fois le changement "
+"effectué. Cliquez sur ce texte pour déverrouiller."
+
+#: rhodecode/templates/admin/settings/settings.html:251
+msgid "unlock"
+msgstr "Déverrouiller"
+
+#: rhodecode/templates/admin/settings/settings.html:252
+msgid ""
+"Location where repositories are stored. After changing this value a "
+"restart, and rescan is required"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:272
+msgid "Test Email"
+msgstr "E-mail de test"
+
+#: rhodecode/templates/admin/settings/settings.html:280
+msgid "Email to"
+msgstr "Envoyer l’e-mail à"
+
+#: rhodecode/templates/admin/settings/settings.html:288
+msgid "Send"
+msgstr "Envoyer"
+
+#: rhodecode/templates/admin/settings/settings.html:294
+msgid "System Info and Packages"
+msgstr "Information système et paquets"
+
+#: rhodecode/templates/admin/settings/settings.html:297
+msgid "show"
+msgstr "Montrer"
+
+#: rhodecode/templates/admin/users/user_add.html:5
+msgid "Add user"
+msgstr "Ajouter un utilisateur"
+
+#: rhodecode/templates/admin/users/user_add.html:10
+#: rhodecode/templates/admin/users/user_edit.html:11
+msgid "Users"
+msgstr "Utilisateurs"
+
+#: rhodecode/templates/admin/users/user_add.html:12
+msgid "add new user"
+msgstr "nouvel utilisateur"
+
+#: rhodecode/templates/admin/users/user_add.html:50
+msgid "Password confirmation"
+msgstr "Confirmation"
+
+#: rhodecode/templates/admin/users/user_add.html:86
+#: rhodecode/templates/admin/users/user_edit.html:113
+#: rhodecode/templates/admin/users_groups/users_group_add.html:41
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:42
+msgid "Active"
+msgstr "Actif"
+
+#: rhodecode/templates/admin/users/user_edit.html:5
+msgid "Edit user"
+msgstr "Éditer l'utilisateur"
+
+#: rhodecode/templates/admin/users/user_edit.html:34
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10
+msgid "Change your avatar at"
+msgstr "Vous pouvez changer votre avatar sur"
+
+#: rhodecode/templates/admin/users/user_edit.html:35
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11
+msgid "Using"
+msgstr "en utilisant l’adresse"
+
+#: rhodecode/templates/admin/users/user_edit.html:43
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20
+msgid "API key"
+msgstr "Clé d’API"
+
+#: rhodecode/templates/admin/users/user_edit.html:59
+msgid "LDAP DN"
+msgstr "DN LDAP"
+
+#: rhodecode/templates/admin/users/user_edit.html:68
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:35
+msgid "New password"
+msgstr "Nouveau mot de passe"
+
+#: rhodecode/templates/admin/users/user_edit.html:77
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44
+msgid "New password confirmation"
+msgstr "Confirmation du nouveau mot de passe"
+
+#: rhodecode/templates/admin/users/user_edit.html:147
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:108
+#, fuzzy
+msgid "Inherit default permissions"
+msgstr "Permissions par défaut"
+
+#: rhodecode/templates/admin/users/user_edit.html:152
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:113
+#, python-format
+msgid ""
+"Select to inherit permissions from %s settings. With this selected below "
+"options does not have any action"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:158
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:119
+msgid "Create repositories"
+msgstr "Création de dépôts"
+
+#: rhodecode/templates/admin/users/user_edit.html:166
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:127
+#, fuzzy
+msgid "Fork repositories"
+msgstr "Dépôts"
+
+#: rhodecode/templates/admin/users/user_edit.html:186
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:22
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:39
+#, fuzzy
+msgid "Nothing here yet"
+msgstr "Aucune notification pour le moment."
+
+#: rhodecode/templates/admin/users/user_edit.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account.html:60
+#: rhodecode/templates/admin/users/user_edit_my_account.html:194
+msgid "Permission"
+msgstr "Permission"
+
+#: rhodecode/templates/admin/users/user_edit.html:194
+#, fuzzy
+msgid "Edit Permission"
+msgstr "Permissions du dépôt"
+
+#: rhodecode/templates/admin/users/user_edit.html:243
+#, fuzzy
+msgid "Email addresses"
+msgstr "Adresse e-mail"
+
+#: rhodecode/templates/admin/users/user_edit.html:256
+#, fuzzy, python-format
+msgid "Confirm to delete this email: %s"
+msgstr "Voulez-vous vraiment supprimer l’utilisateur « %s » ?"
+
+#: rhodecode/templates/admin/users/user_edit.html:270
+#, fuzzy
+msgid "New email address"
+msgstr "Adresse e-mail"
+
+#: rhodecode/templates/admin/users/user_edit.html:277
+#, fuzzy
+msgid "Add"
+msgstr "Ajouter"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:5
+#: rhodecode/templates/base/base.html:124
+msgid "My account"
+msgstr "Mon compte"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:9
+msgid "My Account"
+msgstr "Mon compte"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:35
+msgid "My permissions"
+msgstr "Mes permissions"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:38
+#: rhodecode/templates/journal/journal.html:41
+msgid "My repos"
+msgstr "Mes dépôts"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:41
+#, fuzzy
+msgid "My pull requests"
+msgstr "a posté un commentaire sur le commit"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:45
+#, fuzzy
+msgid "Add repo"
+msgstr "ajouter un nouveau"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2
+msgid "Opened by me"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:10
+#, python-format
+msgid "Pull request #%s opened on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15
+#, fuzzy
+msgid "Confirm to delete this pull request"
+msgstr "Voulez-vous vraiment supprimer ce dépôt ?"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:26
+msgid "I participate in"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:33
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:30
+#, python-format
+msgid "Pull request #%s opened by %s on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:7
+#: rhodecode/templates/bookmarks/bookmarks.html:40
+#: rhodecode/templates/bookmarks/bookmarks_data.html:9
+#: rhodecode/templates/branches/branches.html:55
+#: rhodecode/templates/journal/journal.html:60
+#: rhodecode/templates/tags/tags.html:40
+#: rhodecode/templates/tags/tags_data.html:9
+msgid "Revision"
+msgstr "Révision"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/journal/journal.html:81
+msgid "private"
+msgstr "privé"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#, python-format
+msgid "Confirm to delete this repository: %s"
+msgstr "Voulez-vous vraiment supprimer le dépôt %s ?"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:38
+#: rhodecode/templates/journal/journal.html:94
+msgid "No repositories yet"
+msgstr "Aucun dépôt pour le moment"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:40
+#: rhodecode/templates/journal/journal.html:96
+msgid "create one now"
+msgstr "En créer un maintenant"
+
+#: rhodecode/templates/admin/users/users.html:5
+msgid "Users administration"
+msgstr "Administration des utilisateurs"
+
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/base/base.html:223
+msgid "users"
+msgstr "Utilisateurs"
+
+#: rhodecode/templates/admin/users/users.html:23
+msgid "ADD NEW USER"
+msgstr "NOUVEL UTILISATEUR"
+
+#: rhodecode/templates/admin/users/users.html:77
+msgid "username"
+msgstr "Nom d’utilisateur"
+
+#: rhodecode/templates/admin/users/users.html:80
+#, fuzzy
+msgid "firstname"
+msgstr "Prénom"
+
+#: rhodecode/templates/admin/users/users.html:81
+msgid "lastname"
+msgstr "Nom de famille"
+
+#: rhodecode/templates/admin/users/users.html:82
+msgid "last login"
+msgstr "Dernière connexion"
+
+#: rhodecode/templates/admin/users/users.html:84
+#: rhodecode/templates/admin/users_groups/users_groups.html:34
+msgid "active"
+msgstr "Actif"
+
+#: rhodecode/templates/admin/users/users.html:86
+#: rhodecode/templates/base/base.html:226
+msgid "ldap"
+msgstr "LDAP"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:5
+msgid "Add users group"
+msgstr "Ajouter un groupe d’utilisateur"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:10
+#: rhodecode/templates/admin/users_groups/users_groups.html:9
+msgid "Users groups"
+msgstr "Groupes d’utilisateurs"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:12
+msgid "add new users group"
+msgstr "Ajouter un nouveau groupe"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:5
+msgid "Edit users group"
+msgstr "Éditer le groupe d’utilisateurs"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:11
+msgid "UsersGroups"
+msgstr "UsersGroups"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:50
+msgid "Members"
+msgstr "Membres"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:58
+msgid "Choosen group members"
+msgstr "Membres du groupe"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:61
+msgid "Remove all elements"
+msgstr "Tout enlever"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:75
+msgid "Available members"
+msgstr "Membres disponibles"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:79
+msgid "Add all elements"
+msgstr "Tout ajouter"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:146
+msgid "Group members"
+msgstr "Membres du groupe"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:5
+msgid "Users groups administration"
+msgstr "Gestion des groupes d’utilisateurs"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:23
+msgid "ADD NEW USER GROUP"
+msgstr "AJOUTER UN NOUVEAU GROUPE"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:32
+msgid "group name"
+msgstr "Nom du groupe"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:33
+#: rhodecode/templates/base/root.html:46
+msgid "members"
+msgstr "Membres"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:45
+#, python-format
+msgid "Confirm to delete this users group: %s"
+msgstr "Voulez-vous vraiment supprimer le groupe d‘utilisateurs « %s » ?"
+
+#: rhodecode/templates/base/base.html:41
+msgid "Submit a bug"
+msgstr "Signaler un bogue"
+
+#: rhodecode/templates/base/base.html:77
+msgid "Login to your account"
+msgstr "Connexion à votre compte"
+
+#: rhodecode/templates/base/base.html:100
+msgid "Forgot password ?"
+msgstr "Mot de passe oublié ?"
+
+#: rhodecode/templates/base/base.html:107
+msgid "Log In"
+msgstr "Connexion"
+
+#: rhodecode/templates/base/base.html:118
+msgid "Inbox"
+msgstr "Boîte de réception"
+
+#: rhodecode/templates/base/base.html:122
+#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/base/base.html:302
+#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/bookmarks/bookmarks.html:11
+#: rhodecode/templates/branches/branches.html:10
+#: rhodecode/templates/changelog/changelog.html:10
+#: rhodecode/templates/changeset/changeset.html:10
+#: rhodecode/templates/changeset/changeset_range.html:9
+#: rhodecode/templates/compare/compare_diff.html:9
+#: rhodecode/templates/files/file_diff.html:8
+#: rhodecode/templates/files/files.html:8
+#: rhodecode/templates/files/files_add.html:15
+#: rhodecode/templates/files/files_edit.html:15
+#: rhodecode/templates/followers/followers.html:9
+#: rhodecode/templates/forks/fork.html:9 rhodecode/templates/forks/forks.html:9
+#: rhodecode/templates/pullrequests/pullrequest.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8
+#: rhodecode/templates/settings/repo_settings.html:9
+#: rhodecode/templates/shortlog/shortlog.html:10
+#: rhodecode/templates/summary/summary.html:8
+#: rhodecode/templates/tags/tags.html:11
+msgid "Home"
+msgstr "Accueil"
+
+#: rhodecode/templates/base/base.html:123
+#: rhodecode/templates/base/base.html:309
+#: rhodecode/templates/base/base.html:311
+#: rhodecode/templates/base/base.html:313
+#: rhodecode/templates/journal/journal.html:4
+#: rhodecode/templates/journal/journal.html:21
+#: rhodecode/templates/journal/public_journal.html:4
+msgid "Journal"
+msgstr "Historique"
+
+#: rhodecode/templates/base/base.html:125
+msgid "Log Out"
+msgstr "Se déconnecter"
+
+#: rhodecode/templates/base/base.html:144
+msgid "Switch repository"
+msgstr "Aller au dépôt"
+
+#: rhodecode/templates/base/base.html:146
+msgid "Products"
+msgstr "Produits"
+
+#: rhodecode/templates/base/base.html:152
+#: rhodecode/templates/base/base.html:182
+msgid "loading..."
+msgstr "Chargement…"
+
+#: rhodecode/templates/base/base.html:158
+#: rhodecode/templates/base/base.html:160
+#: rhodecode/templates/base/base.html:162
+#: rhodecode/templates/data_table/_dt_elements.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:17
+#: rhodecode/templates/data_table/_dt_elements.html:19
+msgid "Summary"
+msgstr "Résumé"
+
+#: rhodecode/templates/base/base.html:166
+#: rhodecode/templates/base/base.html:168
+#: rhodecode/templates/base/base.html:170
+#: rhodecode/templates/changelog/changelog.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:23
+#: rhodecode/templates/data_table/_dt_elements.html:25
+#: rhodecode/templates/data_table/_dt_elements.html:27
+msgid "Changelog"
+msgstr "Historique"
+
+#: rhodecode/templates/base/base.html:175
+#: rhodecode/templates/base/base.html:177
+#: rhodecode/templates/base/base.html:179
+msgid "Switch to"
+msgstr "Aller"
+
+#: rhodecode/templates/base/base.html:186
+#: rhodecode/templates/base/base.html:188
+#: rhodecode/templates/base/base.html:190
+#: rhodecode/templates/data_table/_dt_elements.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:33
+#: rhodecode/templates/data_table/_dt_elements.html:35
+msgid "Files"
+msgstr "Fichiers"
+
+#: rhodecode/templates/base/base.html:195
+#: rhodecode/templates/base/base.html:199
+msgid "Options"
+msgstr "Options"
+
+#: rhodecode/templates/base/base.html:204
+#: rhodecode/templates/base/base.html:206
+#: rhodecode/templates/base/base.html:227
+msgid "settings"
+msgstr "Réglages"
+
+#: rhodecode/templates/base/base.html:209
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/forks/fork.html:13
+msgid "fork"
+msgstr "Fork"
+
+#: rhodecode/templates/base/base.html:211
+#: rhodecode/templates/changelog/changelog.html:40
+msgid "Open new pull request"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:213
+msgid "search"
+msgstr "Rechercher"
+
+#: rhodecode/templates/base/base.html:222
+msgid "repositories groups"
+msgstr "Groupes de dépôts"
+
+#: rhodecode/templates/base/base.html:224
+msgid "users groups"
+msgstr "Groupes d’utilisateurs"
+
+#: rhodecode/templates/base/base.html:225
+msgid "permissions"
+msgstr "Permissions"
+
+#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:240
+msgid "Followers"
+msgstr "Followers"
+
+#: rhodecode/templates/base/base.html:246
+#: rhodecode/templates/base/base.html:248
+msgid "Forks"
+msgstr "Forks"
+
+#: rhodecode/templates/base/base.html:327
+#: rhodecode/templates/base/base.html:329
+#: rhodecode/templates/base/base.html:331
+#: rhodecode/templates/search/search.html:52
+msgid "Search"
+msgstr "Rechercher"
+
+#: rhodecode/templates/base/root.html:42
+msgid "add another comment"
+msgstr "Nouveau commentaire"
+
+#: rhodecode/templates/base/root.html:43
+#: rhodecode/templates/journal/journal.html:120
+#: rhodecode/templates/summary/summary.html:57
+msgid "Stop following this repository"
+msgstr "Arrêter de suivre ce dépôt"
+
+#: rhodecode/templates/base/root.html:44
+#: rhodecode/templates/summary/summary.html:61
+msgid "Start following this repository"
+msgstr "Suivre ce dépôt"
+
+#: rhodecode/templates/base/root.html:45
+msgid "Group"
+msgstr "Groupe"
+
+#: rhodecode/templates/base/root.html:47
+msgid "search truncated"
+msgstr "Résultats tronqués"
+
+#: rhodecode/templates/base/root.html:48
+msgid "no matching files"
+msgstr "Aucun fichier ne correspond"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:5
+#, python-format
+msgid "%s Bookmarks"
+msgstr "Signets de %s"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:39
+#: rhodecode/templates/bookmarks/bookmarks_data.html:8
+#: rhodecode/templates/branches/branches.html:54
+#: rhodecode/templates/tags/tags.html:39
+#: rhodecode/templates/tags/tags_data.html:8
+msgid "Author"
+msgstr "Auteur"
+
+#: rhodecode/templates/branches/branches.html:5
+#, python-format
+msgid "%s Branches"
+msgstr "Branches de %s"
+
+#: rhodecode/templates/branches/branches.html:29
+#, fuzzy
+msgid "Compare branches"
+msgstr "Branches"
+
+#: rhodecode/templates/branches/branches.html:57
+#: rhodecode/templates/compare/compare_diff.html:5
+#: rhodecode/templates/compare/compare_diff.html:13
+#, fuzzy
+msgid "Compare"
+msgstr "vue de comparaison"
+
+#: rhodecode/templates/branches/branches_data.html:6
+msgid "name"
+msgstr "Prénom"
+
+#: rhodecode/templates/branches/branches_data.html:7
+msgid "date"
+msgstr "Date"
+
+#: rhodecode/templates/branches/branches_data.html:8
+#: rhodecode/templates/shortlog/shortlog_data.html:8
+msgid "author"
+msgstr "Auteur"
+
+#: rhodecode/templates/branches/branches_data.html:9
+#: rhodecode/templates/shortlog/shortlog_data.html:5
+msgid "revision"
+msgstr "Révision"
+
+#: rhodecode/templates/branches/branches_data.html:10
+#, fuzzy
+msgid "compare"
+msgstr "vue de comparaison"
+
+#: rhodecode/templates/changelog/changelog.html:6
+#, python-format
+msgid "%s Changelog"
+msgstr "Historique de %s"
+
+#: rhodecode/templates/changelog/changelog.html:15
+#, python-format
+msgid "showing %d out of %d revision"
+msgid_plural "showing %d out of %d revisions"
+msgstr[0] "Affichage de %d révision sur %d"
+msgstr[1] "Affichage de %d révisions sur %d"
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:19
+#, python-format
+msgid "compare fork with %s"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:21
+#, fuzzy
+msgid "Compare fork"
+msgstr "vue de comparaison"
+
+#: rhodecode/templates/changelog/changelog.html:46
+msgid "Show"
+msgstr "Afficher"
+
+#: rhodecode/templates/changelog/changelog.html:72
+#: rhodecode/templates/summary/summary.html:364
+msgid "show more"
+msgstr "montrer plus"
+
+#: rhodecode/templates/changelog/changelog.html:76
+msgid "Affected number of files, click to show more details"
+msgstr "Nombre de fichiers modifiés, cliquez pour plus de détails"
+
+#: rhodecode/templates/changelog/changelog.html:89
+#: rhodecode/templates/changeset/changeset.html:38
+#: rhodecode/templates/changeset/changeset_file_comment.html:20
+#: rhodecode/templates/changeset/changeset_range.html:46
+#, fuzzy
+msgid "Changeset status"
+msgstr "Changesets"
+
+#: rhodecode/templates/changelog/changelog.html:92
+msgid "Click to open associated pull request"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:102
+#: rhodecode/templates/changeset/changeset.html:78
+msgid "Parent"
+msgstr "Parent"
+
+#: rhodecode/templates/changelog/changelog.html:108
+#: rhodecode/templates/changeset/changeset.html:84
+msgid "No parents"
+msgstr "Aucun parent"
+
+#: rhodecode/templates/changelog/changelog.html:113
+#: rhodecode/templates/changeset/changeset.html:88
+msgid "merge"
+msgstr "Fusion"
+
+#: rhodecode/templates/changelog/changelog.html:116
+#: rhodecode/templates/changeset/changeset.html:91
+#: rhodecode/templates/files/files.html:29
+#: rhodecode/templates/files/files_add.html:33
+#: rhodecode/templates/files/files_edit.html:33
+#: rhodecode/templates/shortlog/shortlog_data.html:9
+msgid "branch"
+msgstr "Branche"
+
+#: rhodecode/templates/changelog/changelog.html:122
+msgid "bookmark"
+msgstr "Signet"
+
+#: rhodecode/templates/changelog/changelog.html:128
+#: rhodecode/templates/changeset/changeset.html:96
+msgid "tag"
+msgstr "Tag"
+
+#: rhodecode/templates/changelog/changelog.html:164
+msgid "Show selected changes __S -> __E"
+msgstr "Afficher les changements sélections de __S à __E"
+
+#: rhodecode/templates/changelog/changelog.html:255
+msgid "There are no changes yet"
+msgstr "Il n’y a aucun changement pour le moment"
+
+#: rhodecode/templates/changelog/changelog_details.html:4
+#: rhodecode/templates/changeset/changeset.html:66
+msgid "removed"
+msgstr "Supprimés"
+
+#: rhodecode/templates/changelog/changelog_details.html:5
+#: rhodecode/templates/changeset/changeset.html:67
+msgid "changed"
+msgstr "Modifiés"
+
+#: rhodecode/templates/changelog/changelog_details.html:6
+#: rhodecode/templates/changeset/changeset.html:68
+msgid "added"
+msgstr "Ajoutés"
+
+#: rhodecode/templates/changelog/changelog_details.html:8
+#: rhodecode/templates/changelog/changelog_details.html:9
+#: rhodecode/templates/changelog/changelog_details.html:10
+#: rhodecode/templates/changeset/changeset.html:70
+#: rhodecode/templates/changeset/changeset.html:71
+#: rhodecode/templates/changeset/changeset.html:72
+#, python-format
+msgid "affected %s files"
+msgstr "%s fichiers affectés"
+
+#: rhodecode/templates/changeset/changeset.html:6
+#, python-format
+msgid "%s Changeset"
+msgstr "Changeset de %s"
+
+#: rhodecode/templates/changeset/changeset.html:14
+msgid "Changeset"
+msgstr "Changements"
+
+#: rhodecode/templates/changeset/changeset.html:43
+#: rhodecode/templates/changeset/diff_block.html:20
+msgid "raw diff"
+msgstr "Diff brut"
+
+#: rhodecode/templates/changeset/changeset.html:44
+#: rhodecode/templates/changeset/diff_block.html:21
+msgid "download diff"
+msgstr "Télécharger le diff"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] "%d commentaire"
+msgstr[1] "%d commentaires"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "(%d inline)"
+msgid_plural "(%d inline)"
+msgstr[0] "(et %d en ligne)"
+msgstr[1] "(et %d en ligne)"
+
+#: rhodecode/templates/changeset/changeset.html:103
+#, python-format
+msgid "%s files affected with %s insertions and %s deletions:"
+msgstr "%s fichiers affectés avec %s insertions et %s suppressions :"
+
+#: rhodecode/templates/changeset/changeset.html:119
+msgid "Changeset was too big and was cut off..."
+msgstr "Cet ensemble de changements était trop important et a été découpé…"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:42
+msgid "Submitting..."
+msgstr "Envoi…"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:45
+msgid "Commenting on line {1}."
+msgstr "Commentaire sur la ligne {1}."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:46
+#: rhodecode/templates/changeset/changeset_file_comment.html:121
+#, python-format
+msgid "Comments parsed using %s syntax with %s support."
+msgstr ""
+"Les commentaires sont analysés avec la syntaxe %s, avec le support de la "
+"commande %s."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:123
+msgid "Use @username inside this text to send notification to this RhodeCode user"
+msgstr ""
+"Utilisez @nomutilisateur dans ce texte pour envoyer une notification à "
+"l’utilisateur RhodeCode en question."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:59
+#: rhodecode/templates/changeset/changeset_file_comment.html:138
+msgid "Comment"
+msgstr "Commentaire"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:60
+#: rhodecode/templates/changeset/changeset_file_comment.html:71
+msgid "Hide"
+msgstr "Masquer"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "You need to be logged in to comment."
+msgstr "Vous devez être connecté pour poster des commentaires."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "Login now"
+msgstr "Se connecter maintenant"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:118
+msgid "Leave a comment"
+msgstr "Laisser un commentaire"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "Check this to change current status of code-review for this changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+#, fuzzy
+msgid "change status"
+msgstr "Changesets"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:140
+msgid "Comment and close"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:5
+#, python-format
+msgid "%s Changesets"
+msgstr "Changesets de %s"
+
+#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/templates/compare/compare_diff.html:29
+msgid "Compare View"
+msgstr "Comparaison"
+
+#: rhodecode/templates/changeset/changeset_range.html:54
+#: rhodecode/templates/compare/compare_diff.html:41
+#: rhodecode/templates/pullrequests/pullrequest_show.html:69
+msgid "Files affected"
+msgstr "Fichiers affectés"
+
+#: rhodecode/templates/changeset/diff_block.html:19
+msgid "diff"
+msgstr "Diff"
+
+#: rhodecode/templates/changeset/diff_block.html:27
+msgid "show inline comments"
+msgstr "Afficher les commentaires"
+
+#: rhodecode/templates/compare/compare_cs.html:5
+#, fuzzy
+msgid "No changesets"
+msgstr "Dépôt vide"
+
+#: rhodecode/templates/compare/compare_diff.html:37
+#, fuzzy
+msgid "Outgoing changesets"
+msgstr "Dépôt vide"
+
+#: rhodecode/templates/data_table/_dt_elements.html:39
+#: rhodecode/templates/data_table/_dt_elements.html:41
+#: rhodecode/templates/data_table/_dt_elements.html:43
+msgid "Fork"
+msgstr "Fork"
+
+#: rhodecode/templates/data_table/_dt_elements.html:60
+#: rhodecode/templates/journal/journal.html:126
+#: rhodecode/templates/summary/summary.html:68
+msgid "Mercurial repository"
+msgstr "Dépôt Mercurial"
+
+#: rhodecode/templates/data_table/_dt_elements.html:62
+#: rhodecode/templates/journal/journal.html:128
+#: rhodecode/templates/summary/summary.html:71
+msgid "Git repository"
+msgstr "Dépôt Git"
+
+#: rhodecode/templates/data_table/_dt_elements.html:69
+#: rhodecode/templates/journal/journal.html:134
+#: rhodecode/templates/summary/summary.html:78
+msgid "public repository"
+msgstr "Dépôt public"
+
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/summary/summary.html:87
+#: rhodecode/templates/summary/summary.html:88
+msgid "Fork of"
+msgstr "Fork de"
+
+#: rhodecode/templates/data_table/_dt_elements.html:92
+msgid "No changesets yet"
+msgstr "Dépôt vide"
+
+#: rhodecode/templates/data_table/_dt_elements.html:104
+#, python-format
+msgid "Confirm to delete this user: %s"
+msgstr "Voulez-vous vraiment supprimer l’utilisateur « %s » ?"
+
+#: rhodecode/templates/email_templates/main.html:8
+msgid "This is an notification from RhodeCode."
+msgstr "Ceci est une notification de RhodeCode."
+
+#: rhodecode/templates/errors/error_document.html:46
+#, python-format
+msgid "You will be redirected to %s in %s seconds"
+msgstr "Vous serez redirigé vers %s dans %s secondes."
+
+#: rhodecode/templates/files/file_diff.html:4
+#, python-format
+msgid "%s File diff"
+msgstr "Diff de fichier de %s"
+
+#: rhodecode/templates/files/file_diff.html:12
+msgid "File diff"
+msgstr "Diff de fichier"
+
+#: rhodecode/templates/files/files.html:4
+#: rhodecode/templates/files/files.html:72
+#, fuzzy, python-format
+msgid "%s files"
+msgstr "Fichiers de %s"
+
+#: rhodecode/templates/files/files.html:12
+#: rhodecode/templates/summary/summary.html:340
+msgid "files"
+msgstr "Fichiers"
+
+#: rhodecode/templates/files/files_add.html:4
+#: rhodecode/templates/files/files_edit.html:4
+#, python-format
+msgid "%s Edit file"
+msgstr "Edition de fichier de %s"
+
+#: rhodecode/templates/files/files_add.html:19
+msgid "add file"
+msgstr "Ajouter un fichier"
+
+#: rhodecode/templates/files/files_add.html:40
+msgid "Add new file"
+msgstr "Ajouter un nouveau fichier"
+
+#: rhodecode/templates/files/files_add.html:45
+msgid "File Name"
+msgstr "Nom de fichier"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:58
+msgid "or"
+msgstr "ou"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:54
+msgid "Upload file"
+msgstr "Téléverser un fichier"
+
+#: rhodecode/templates/files/files_add.html:58
+msgid "Create new file"
+msgstr "Créer un nouveau fichier"
+
+#: rhodecode/templates/files/files_add.html:63
+#: rhodecode/templates/files/files_edit.html:39
+#: rhodecode/templates/files/files_ypjax.html:3
+msgid "Location"
+msgstr "Emplacement"
+
+#: rhodecode/templates/files/files_add.html:67
+msgid "use / to separate directories"
+msgstr "Utilisez / pour séparer les répertoires"
+
+#: rhodecode/templates/files/files_add.html:77
+#: rhodecode/templates/files/files_edit.html:63
+#: rhodecode/templates/shortlog/shortlog_data.html:6
+msgid "commit message"
+msgstr "Message de commit"
+
+#: rhodecode/templates/files/files_add.html:81
+#: rhodecode/templates/files/files_edit.html:67
+msgid "Commit changes"
+msgstr "Commiter les changements"
+
+#: rhodecode/templates/files/files_browser.html:13
+msgid "view"
+msgstr "voir"
+
+#: rhodecode/templates/files/files_browser.html:14
+msgid "previous revision"
+msgstr "révision précédente"
+
+#: rhodecode/templates/files/files_browser.html:16
+msgid "next revision"
+msgstr "révision suivante"
+
+#: rhodecode/templates/files/files_browser.html:23
+msgid "follow current branch"
+msgstr "Suivre la branche actuelle"
+
+#: rhodecode/templates/files/files_browser.html:27
+msgid "search file list"
+msgstr "Rechercher un fichier"
+
+#: rhodecode/templates/files/files_browser.html:31
+#: rhodecode/templates/shortlog/shortlog_data.html:65
+msgid "add new file"
+msgstr "Ajouter un fichier"
+
+#: rhodecode/templates/files/files_browser.html:35
+msgid "Loading file list..."
+msgstr "Chargement de la liste des fichiers…"
+
+#: rhodecode/templates/files/files_browser.html:48
+msgid "Size"
+msgstr "Taille"
+
+#: rhodecode/templates/files/files_browser.html:49
+msgid "Mimetype"
+msgstr "Type MIME"
+
+#: rhodecode/templates/files/files_browser.html:50
+msgid "Last Revision"
+msgstr "Dernière révision"
+
+#: rhodecode/templates/files/files_browser.html:51
+msgid "Last modified"
+msgstr "Dernière modification"
+
+#: rhodecode/templates/files/files_browser.html:52
+msgid "Last commiter"
+msgstr "Dernier commiteur"
+
+#: rhodecode/templates/files/files_edit.html:19
+msgid "edit file"
+msgstr "Éditer le fichier"
+
+#: rhodecode/templates/files/files_edit.html:49
+#: rhodecode/templates/files/files_source.html:38
+msgid "show annotation"
+msgstr "Afficher les annotations"
+
+#: rhodecode/templates/files/files_edit.html:50
+#: rhodecode/templates/files/files_source.html:40
+#: rhodecode/templates/files/files_source.html:68
+msgid "show as raw"
+msgstr "montrer le fichier brut"
+
+#: rhodecode/templates/files/files_edit.html:51
+#: rhodecode/templates/files/files_source.html:41
+msgid "download as raw"
+msgstr "télécharger le fichier brut"
+
+#: rhodecode/templates/files/files_edit.html:54
+msgid "source"
+msgstr "Source"
+
+#: rhodecode/templates/files/files_edit.html:59
+msgid "Editing file"
+msgstr "Édition du fichier"
+
+#: rhodecode/templates/files/files_source.html:2
+msgid "History"
+msgstr "Historique"
+
+#: rhodecode/templates/files/files_source.html:9
+#, fuzzy
+msgid "diff to revision"
+msgstr "révision suivante"
+
+#: rhodecode/templates/files/files_source.html:10
+#, fuzzy
+msgid "show at revision"
+msgstr "révision suivante"
+
+#: rhodecode/templates/files/files_source.html:14
+#, python-format
+msgid "%s author"
+msgid_plural "%s authors"
+msgstr[0] "%s Auteur"
+msgstr[1] "%s Auteurs"
+
+#: rhodecode/templates/files/files_source.html:36
+msgid "show source"
+msgstr "montrer les sources"
+
+#: rhodecode/templates/files/files_source.html:59
+#, python-format
+msgid "Binary file (%s)"
+msgstr "Fichier binaire (%s)"
+
+#: rhodecode/templates/files/files_source.html:68
+msgid "File is too big to display"
+msgstr "Ce fichier est trop gros pour être affiché."
+
+#: rhodecode/templates/files/files_source.html:124
+msgid "Selection link"
+msgstr "Lien vers la sélection"
+
+#: rhodecode/templates/files/files_ypjax.html:5
+msgid "annotation"
+msgstr "annotation"
+
+#: rhodecode/templates/files/files_ypjax.html:15
+msgid "Go back"
+msgstr "Revenir en arrière"
+
+#: rhodecode/templates/files/files_ypjax.html:16
+msgid "No files at given path"
+msgstr "Aucun fichier à cet endroit"
+
+#: rhodecode/templates/followers/followers.html:5
+#, python-format
+msgid "%s Followers"
+msgstr "Followers de %s"
+
+#: rhodecode/templates/followers/followers.html:13
+msgid "followers"
+msgstr "followers"
+
+#: rhodecode/templates/followers/followers_data.html:12
+msgid "Started following -"
+msgstr "A commencé à suivre le dépôt :"
+
+#: rhodecode/templates/forks/fork.html:5
+#, python-format
+msgid "%s Fork"
+msgstr "Fork de %s"
+
+#: rhodecode/templates/forks/fork.html:31
+msgid "Fork name"
+msgstr "Nom du fork"
+
+#: rhodecode/templates/forks/fork.html:68
+msgid "Private"
+msgstr "Privé"
+
+#: rhodecode/templates/forks/fork.html:77
+msgid "Copy permissions"
+msgstr "Copier les permissions"
+
+#: rhodecode/templates/forks/fork.html:81
+msgid "Copy permissions from forked repository"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:86
+msgid "Update after clone"
+msgstr "MÀJ après le clonage"
+
+#: rhodecode/templates/forks/fork.html:90
+msgid "Checkout source after making a clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:94
+msgid "fork this repository"
+msgstr "Forker ce dépôt"
+
+#: rhodecode/templates/forks/forks.html:5
+#, python-format
+msgid "%s Forks"
+msgstr "Forks de %s"
+
+#: rhodecode/templates/forks/forks.html:13
+msgid "forks"
+msgstr "forks"
+
+#: rhodecode/templates/forks/forks_data.html:17
+msgid "forked"
+msgstr "forké"
+
+#: rhodecode/templates/forks/forks_data.html:38
+msgid "There are no forks yet"
+msgstr "Il n’y a pas encore de forks."
+
+#: rhodecode/templates/journal/journal.html:13
+#, fuzzy
+msgid "ATOM journal feed"
+msgstr "%s — Flux %s du journal public"
+
+#: rhodecode/templates/journal/journal.html:14
+#, fuzzy
+msgid "RSS journal feed"
+msgstr "%s — Flux %s du journal public"
+
+#: rhodecode/templates/journal/journal.html:24
+#: rhodecode/templates/pullrequests/pullrequest.html:27
+msgid "Refresh"
+msgstr "Rafraîchir"
+
+#: rhodecode/templates/journal/journal.html:27
+#: rhodecode/templates/journal/public_journal.html:24
+#, fuzzy
+msgid "RSS feed"
+msgstr "Flux %s de %s"
+
+#: rhodecode/templates/journal/journal.html:30
+#: rhodecode/templates/journal/public_journal.html:27
+msgid "ATOM feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:41
+msgid "Watched"
+msgstr "Surveillé"
+
+#: rhodecode/templates/journal/journal.html:46
+msgid "ADD"
+msgstr "AJOUTER"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "following user"
+msgstr "utilisateur suivant"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "user"
+msgstr "utilisateur"
+
+#: rhodecode/templates/journal/journal.html:147
+msgid "You are not following any users or repositories"
+msgstr "Vous ne suivez aucun utilisateur ou dépôt"
+
+#: rhodecode/templates/journal/journal_data.html:47
+msgid "No entries yet"
+msgstr "Aucune entrée pour le moment"
+
+#: rhodecode/templates/journal/public_journal.html:13
+#, fuzzy
+msgid "ATOM public journal feed"
+msgstr "%s — Flux %s du journal public"
+
+#: rhodecode/templates/journal/public_journal.html:14
+#, fuzzy
+msgid "RSS public journal feed"
+msgstr "%s — Flux %s du journal public"
+
+#: rhodecode/templates/journal/public_journal.html:21
+msgid "Public Journal"
+msgstr "Journal public"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:4
+#: rhodecode/templates/pullrequests/pullrequest.html:12
+msgid "New pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:28
+msgid "refresh overview"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:66
+#, fuzzy
+msgid "Detailed compare view"
+msgstr "vue de comparaison"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:70
+#: rhodecode/templates/pullrequests/pullrequest_show.html:82
+msgid "Pull request reviewers"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:79
+#: rhodecode/templates/pullrequests/pullrequest_show.html:94
+#, fuzzy
+msgid "owner"
+msgstr "Propriétaire"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:91
+#: rhodecode/templates/pullrequests/pullrequest_show.html:109
+msgid "Add reviewer to this pull request."
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:97
+#, fuzzy
+msgid "Create new pull request"
+msgstr "Créer un nouveau fichier"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:106
+#: rhodecode/templates/pullrequests/pullrequest_show.html:25
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:33
+#, fuzzy
+msgid "Title"
+msgstr "Écriture"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:115
+#, fuzzy
+msgid "description"
+msgstr "Description"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:123
+msgid "Send pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:23
+#, python-format
+msgid "Closed %s"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:31
+#, fuzzy
+msgid "Status"
+msgstr "Changesets"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:36
+msgid "Pull request status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:44
+msgid "Still not reviewed by"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:47
+#, python-format
+msgid "%d reviewer"
+msgid_plural "%d reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:54
+#, fuzzy
+msgid "Created on"
+msgstr "En créer un maintenant"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:61
+#, fuzzy
+msgid "Compare view"
+msgstr "vue de comparaison"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:65
+#, fuzzy
+msgid "Incoming changesets"
+msgstr "Dépôt vide"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4
+#, fuzzy
+msgid "all pull requests"
+msgstr "Créer un nouveau fichier"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:12
+msgid "All pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:27
+msgid "Closed"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:6
+#, python-format
+msgid "Search \"%s\" in repository: %s"
+msgstr "dans \"%s\" le dépôt: %s"
+
+#: rhodecode/templates/search/search.html:8
+#, python-format
+msgid "Search \"%s\" in all repositories"
+msgstr "Recherche \"%s\" dans tous les référentiels"
+
+#: rhodecode/templates/search/search.html:12
+#: rhodecode/templates/search/search.html:32
+#, python-format
+msgid "Search in repository: %s"
+msgstr "dans le dépôt : %s"
+
+#: rhodecode/templates/search/search.html:14
+#: rhodecode/templates/search/search.html:34
+#, fuzzy
+msgid "Search in all repositories"
+msgstr "dans tous les dépôts"
+
+#: rhodecode/templates/search/search.html:48
+msgid "Search term"
+msgstr "Termes de la recherches"
+
+#: rhodecode/templates/search/search.html:60
+msgid "Search in"
+msgstr "Rechercher dans"
+
+#: rhodecode/templates/search/search.html:63
+msgid "File contents"
+msgstr "Le contenu des fichiers"
+
+#: rhodecode/templates/search/search.html:64
+#, fuzzy
+msgid "Commit messages"
+msgstr "Message de commit"
+
+#: rhodecode/templates/search/search.html:65
+msgid "File names"
+msgstr "Les noms de fichiers"
+
+#: rhodecode/templates/search/search_commit.html:35
+#: rhodecode/templates/search/search_content.html:21
+#: rhodecode/templates/search/search_path.html:15
+msgid "Permission denied"
+msgstr "Permission refusée"
+
+#: rhodecode/templates/settings/repo_settings.html:5
+#, python-format
+msgid "%s Settings"
+msgstr "Réglages de %s"
+
+#: rhodecode/templates/shortlog/shortlog.html:5
+#, python-format
+msgid "%s Shortlog"
+msgstr "Résumé de %s"
+
+#: rhodecode/templates/shortlog/shortlog.html:14
+msgid "shortlog"
+msgstr "Résumé"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:7
+msgid "age"
+msgstr "Âge"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:18
+msgid "No commit message"
+msgstr "Pas de message de commit"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:62
+msgid "Add or upload files directly via RhodeCode"
+msgstr "Ajouter ou téléverser des fichiers directement via RhodeCode…"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:71
+msgid "Push new repo"
+msgstr "Pusher le nouveau dépôt"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:79
+msgid "Existing repository?"
+msgstr "Le dépôt existe déjà ?"
+
+#: rhodecode/templates/summary/summary.html:4
+#, python-format
+msgid "%s Summary"
+msgstr "Résumé de %s"
+
+#: rhodecode/templates/summary/summary.html:12
+msgid "summary"
+msgstr "résumé"
+
+#: rhodecode/templates/summary/summary.html:20
+#, fuzzy, python-format
+msgid "repo %s ATOM feed"
+msgstr "S’abonner au flux ATOM de %s"
+
+#: rhodecode/templates/summary/summary.html:21
+#, fuzzy, python-format
+msgid "repo %s RSS feed"
+msgstr "S’abonner au flux RSS de %s"
+
+#: rhodecode/templates/summary/summary.html:49
+#: rhodecode/templates/summary/summary.html:52
+msgid "ATOM"
+msgstr "ATOM"
+
+#: rhodecode/templates/summary/summary.html:82
+#, python-format
+msgid "Non changable ID %s"
+msgstr "Identifiant permanent : %s"
+
+#: rhodecode/templates/summary/summary.html:87
+msgid "public"
+msgstr "publique"
+
+#: rhodecode/templates/summary/summary.html:95
+msgid "remote clone"
+msgstr "Clone distant"
+
+#: rhodecode/templates/summary/summary.html:116
+msgid "Contact"
+msgstr "Contact"
+
+#: rhodecode/templates/summary/summary.html:130
+msgid "Clone url"
+msgstr "URL de clone"
+
+#: rhodecode/templates/summary/summary.html:133
+msgid "Show by Name"
+msgstr "Afficher par nom"
+
+#: rhodecode/templates/summary/summary.html:134
+msgid "Show by ID"
+msgstr "Afficher par ID"
+
+#: rhodecode/templates/summary/summary.html:142
+msgid "Trending files"
+msgstr "Populaires"
+
+#: rhodecode/templates/summary/summary.html:150
+#: rhodecode/templates/summary/summary.html:166
+#: rhodecode/templates/summary/summary.html:194
+msgid "enable"
+msgstr "Activer"
+
+#: rhodecode/templates/summary/summary.html:158
+msgid "Download"
+msgstr "Téléchargements"
+
+#: rhodecode/templates/summary/summary.html:162
+msgid "There are no downloads yet"
+msgstr "Il n’y a pas encore de téléchargements proposés."
+
+#: rhodecode/templates/summary/summary.html:164
+msgid "Downloads are disabled for this repository"
+msgstr "Les téléchargements sont désactivés pour ce dépôt."
+
+#: rhodecode/templates/summary/summary.html:170
+msgid "Download as zip"
+msgstr "Télécharger en ZIP"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "Check this to download archive with subrepos"
+msgstr "Télécharger une archive contenant également les sous-dépôts éventuels"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "with subrepos"
+msgstr "avec les sous-dépôts"
+
+#: rhodecode/templates/summary/summary.html:186
+msgid "Commit activity by day / author"
+msgstr "Activité de commit par jour et par auteur"
+
+#: rhodecode/templates/summary/summary.html:197
+msgid "Stats gathered: "
+msgstr "Statistiques obtenues :"
+
+#: rhodecode/templates/summary/summary.html:218
+msgid "Shortlog"
+msgstr "Résumé des changements"
+
+#: rhodecode/templates/summary/summary.html:220
+msgid "Quick start"
+msgstr "Démarrage rapide"
+
+#: rhodecode/templates/summary/summary.html:233
+#, python-format
+msgid "Readme file at revision '%s'"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:236
+msgid "Permalink to this readme"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:293
+#, python-format
+msgid "Download %s as %s"
+msgstr "Télécharger %s comme archive %s"
+
+#: rhodecode/templates/summary/summary.html:650
+msgid "commits"
+msgstr "commits"
+
+#: rhodecode/templates/summary/summary.html:651
+msgid "files added"
+msgstr "fichiers ajoutés"
+
+#: rhodecode/templates/summary/summary.html:652
+msgid "files changed"
+msgstr "fichiers modifiés"
+
+#: rhodecode/templates/summary/summary.html:653
+msgid "files removed"
+msgstr "fichiers supprimés"
+
+#: rhodecode/templates/summary/summary.html:656
+msgid "commit"
+msgstr "commit"
+
+#: rhodecode/templates/summary/summary.html:657
+msgid "file added"
+msgstr "fichier ajouté"
+
+#: rhodecode/templates/summary/summary.html:658
+msgid "file changed"
+msgstr "fichié modifié"
+
+#: rhodecode/templates/summary/summary.html:659
+msgid "file removed"
+msgstr "fichier supprimé"
+
+#: rhodecode/templates/tags/tags.html:5
+#, python-format
+msgid "%s Tags"
+msgstr "Tags de %s"
+
--- a/rhodecode/i18n/how_to	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/i18n/how_to	Sun Sep 02 21:19:54 2012 +0200
@@ -4,25 +4,27 @@
 
 #this needs to be done on source codes, preferable default/stable branches
  
-python setup.py extract_messages -> get messages from project
-python setup.py init_catalog -l pl -> create a language directory for <pl> lang
-edit the new po file with poedit or any other editor
-python setup.py compile_catalog -> create translation files
+python setup.py extract_messages <- get messages from project
+python setup.py init_catalog -l pl <- create a language directory for <pl> lang
+#edit the new po file with poedit or any other editor
+msgfmt -f -c <updated_file.po> <- check format and errors
+python setup.py compile_catalog <- create translation files
 
 ############# 
 # to update #
 #############
 
-python setup.py extract_messages -> get messages from project
-python setup.py update_catalog -> to update the translations
-edit the new updated po file with poedit
-python setup.py compile_catalog -> create translation files
+python setup.py extract_messages <- get messages from project
+python setup.py update_catalog <- to update the translations
+#edit the new updated po file with poedit
+msgfmt -f -c <updated_file.po> <- check format and errors
+python setup.py compile_catalog <- create translation files
 
 
 ###################
 # change language #
 ###################
 
-`lang=en`
+`lang=pl`
 
 in the .ini file
\ No newline at end of file
Binary file rhodecode/i18n/ja/LC_MESSAGES/rhodecode.mo has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/i18n/ja/LC_MESSAGES/rhodecode.po	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,3929 @@
+# Japanese translations for RhodeCode.
+# Copyright (C) 2011 ORGANIZATION
+# This file is distributed under the same license as the RhodeCode project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+# Takumi IINO <trot.thunder@gmail.com> 2012
+# WAKAYAMA Shirou <shirou.faw@gmail.com> 2012
+#
+# Mercurial Japanese Translation.
+# - http://selenic.com/repo/hg/file/stable/i18n/ja.po
+# ========================================
+msgid ""
+msgstr ""
+"Project-Id-Version: RhodeCode 1.2.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-02 20:30+0200\n"
+"PO-Revision-Date: 2012-07-14 03:16+0900\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: ja <LL@li.org>\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: rhodecode/controllers/changelog.py:94
+msgid "All Branches"
+msgstr "すべてのブランチ"
+
+#: rhodecode/controllers/changeset.py:83
+msgid "show white space"
+msgstr "空白を表示"
+
+#: rhodecode/controllers/changeset.py:90 rhodecode/controllers/changeset.py:97
+msgid "ignore white space"
+msgstr "空白を無視"
+
+#: rhodecode/controllers/changeset.py:157
+#, python-format
+msgid "%s line context"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:333
+#: rhodecode/controllers/changeset.py:348 rhodecode/lib/diffs.py:70
+msgid "binary file"
+msgstr "バイナリファイル"
+
+#: rhodecode/controllers/changeset.py:408
+msgid ""
+"Changing status on a changeset associated witha closed pull request is "
+"not allowed"
+msgstr ""
+
+#: rhodecode/controllers/compare.py:69
+#, fuzzy
+msgid "There are no changesets yet"
+msgstr "まだ変更がありません"
+
+#: rhodecode/controllers/error.py:69
+msgid "Home page"
+msgstr "ホームページ"
+
+#: rhodecode/controllers/error.py:98
+msgid "The request could not be understood by the server due to malformed syntax."
+msgstr "形式が間違っているため、サーバーはリクエストを処理出来ませんでした"
+
+#: rhodecode/controllers/error.py:101
+msgid "Unauthorized access to resource"
+msgstr "リソースにアクセスする権限がありません"
+
+#: rhodecode/controllers/error.py:103
+msgid "You don't have permission to view this page"
+msgstr "このページを見る権限がありません"
+
+#: rhodecode/controllers/error.py:105
+msgid "The resource could not be found"
+msgstr "リソースが見つかりません"
+
+#: rhodecode/controllers/error.py:107
+msgid ""
+"The server encountered an unexpected condition which prevented it from "
+"fulfilling the request."
+msgstr ""
+
+#: rhodecode/controllers/feed.py:49
+#, python-format
+msgid "Changes on %s repository"
+msgstr "%s リポジトリでの変更"
+
+#: rhodecode/controllers/feed.py:50
+#, python-format
+msgid "%s %s feed"
+msgstr "%s %s フィード"
+
+#: rhodecode/controllers/feed.py:75
+msgid "commited on"
+msgstr "コミット"
+
+#: rhodecode/controllers/files.py:84
+#, fuzzy
+msgid "click here to add new file"
+msgstr "新しいファイルを追加"
+
+#: rhodecode/controllers/files.py:85
+#, python-format
+msgid "There are no files yet %s"
+msgstr "まだファイルがありません %s"
+
+#: rhodecode/controllers/files.py:239 rhodecode/controllers/files.py:299
+#, python-format
+msgid "This repository is has been locked by %s on %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:266
+#, python-format
+msgid "Edited %s via RhodeCode"
+msgstr "RhodeCode経由で %s を変更"
+
+#: rhodecode/controllers/files.py:271
+msgid "No changes"
+msgstr "変更点なし"
+
+#: rhodecode/controllers/files.py:282 rhodecode/controllers/files.py:346
+#, python-format
+msgid "Successfully committed to %s"
+msgstr "%s へのコミットが成功しました"
+
+#: rhodecode/controllers/files.py:287 rhodecode/controllers/files.py:352
+msgid "Error occurred during commit"
+msgstr "コミット中にエラーが発生しました"
+
+#: rhodecode/controllers/files.py:318
+#, python-format
+msgid "Added %s via RhodeCode"
+msgstr "RhodeCode経由で %s を追加"
+
+#: rhodecode/controllers/files.py:332
+msgid "No content"
+msgstr "内容がありません"
+
+#: rhodecode/controllers/files.py:336
+msgid "No filename"
+msgstr "ファイル名がありません"
+
+#: rhodecode/controllers/files.py:378
+msgid "downloads disabled"
+msgstr "ダウンロードは無効化されています"
+
+#: rhodecode/controllers/files.py:389
+#, python-format
+msgid "Unknown revision %s"
+msgstr "%s は未知のリビジョンです"
+
+#: rhodecode/controllers/files.py:391
+msgid "Empty repository"
+msgstr "空のリポジトリ"
+
+#: rhodecode/controllers/files.py:393
+msgid "Unknown archive type"
+msgstr "未知のアーカイブ種別です"
+
+#: rhodecode/controllers/files.py:494
+#: rhodecode/templates/changeset/changeset_range.html:13
+#: rhodecode/templates/changeset/changeset_range.html:31
+msgid "Changesets"
+msgstr "チェンジセット"
+
+#: rhodecode/controllers/files.py:495 rhodecode/controllers/pullrequests.py:72
+#: rhodecode/controllers/summary.py:232 rhodecode/model/scm.py:543
+msgid "Branches"
+msgstr "ブランチ"
+
+#: rhodecode/controllers/files.py:496 rhodecode/controllers/pullrequests.py:76
+#: rhodecode/controllers/summary.py:233 rhodecode/model/scm.py:554
+msgid "Tags"
+msgstr "タグ"
+
+#: rhodecode/controllers/forks.py:73 rhodecode/controllers/admin/repos.py:90
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+"%s "
+"リポジトリはDB内に見つかりませんでした。おそらくファイルシステム上で作られたか名前が変更されたためです。リポジトリをもう一度チェックするためにアプリケーションを立ち上げ直してください。"
+
+#: rhodecode/controllers/forks.py:133 rhodecode/controllers/settings.py:72
+#, python-format
+msgid ""
+"%s repository is not mapped to db perhaps it was created or renamed from "
+"the file system please run the application again in order to rescan "
+"repositories"
+msgstr ""
+"%s "
+"リポジトリはDB内に見つかりませんでした。おそらくファイルシステム上で作られたか名前が変更されたためです。リポジトリをもう一度チェックするためにアプリケーションを立ち上げ直してください。"
+
+#: rhodecode/controllers/forks.py:167
+#, python-format
+msgid "forked %s repository as %s"
+msgstr "リポジトリ %s を %s としてフォーク"
+
+#: rhodecode/controllers/forks.py:181
+#, python-format
+msgid "An error occurred during repository forking %s"
+msgstr "リポジトリ %s のフォーク中にエラーが発生しました"
+
+#: rhodecode/controllers/journal.py:202 rhodecode/controllers/journal.py:239
+msgid "public journal"
+msgstr "公開ジャーナル"
+
+#: rhodecode/controllers/journal.py:206 rhodecode/controllers/journal.py:243
+#: rhodecode/templates/base/base.html:220
+msgid "journal"
+msgstr "ジャーナル"
+
+#: rhodecode/controllers/login.py:143
+msgid "You have successfully registered into rhodecode"
+msgstr "rhodecodeへの登録を受け付けました"
+
+#: rhodecode/controllers/login.py:164
+msgid "Your password reset link was sent"
+msgstr "パスワードリセットのリンクを送信しました"
+
+#: rhodecode/controllers/login.py:184
+msgid ""
+"Your password reset was successful, new password has been sent to your "
+"email"
+msgstr "パスワードをリセットしました。新しいパスワードをあなたのメールアドレスに送りました"
+
+#: rhodecode/controllers/pullrequests.py:74 rhodecode/model/scm.py:549
+msgid "Bookmarks"
+msgstr "ブックマーク"
+
+#: rhodecode/controllers/pullrequests.py:158
+msgid "Pull request requires a title with min. 3 chars"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:160
+#, fuzzy
+msgid "error during creation of pull request"
+msgstr "ユーザー %s の作成中にエラーが発生しました"
+
+#: rhodecode/controllers/pullrequests.py:181
+msgid "Successfully opened new pull request"
+msgstr "新しいプルリクエストを作成しました"
+
+#: rhodecode/controllers/pullrequests.py:184
+msgid "Error occurred during sending pull request"
+msgstr "プルリクエストの作成中にエラーが発生しました"
+
+#: rhodecode/controllers/pullrequests.py:217
+#, fuzzy
+msgid "Successfully deleted pull request"
+msgstr "新しいプルリクエストを作成しました"
+
+#: rhodecode/controllers/search.py:131
+msgid "Invalid search query. Try quoting it."
+msgstr "無効な検索クエリーです。\\\"で囲んで下さい"
+
+#: rhodecode/controllers/search.py:136
+msgid "There is no index to search in. Please run whoosh indexer"
+msgstr "検索するためのインデックスがありません。whooshでインデックスを作成して下さい"
+
+#: rhodecode/controllers/search.py:140
+msgid "An error occurred during this search operation"
+msgstr "検索を実行する際にエラーがおきました"
+
+#: rhodecode/controllers/settings.py:107
+#: rhodecode/controllers/admin/repos.py:266
+#, python-format
+msgid "Repository %s updated successfully"
+msgstr "リポジトリ %s の更新に成功しました"
+
+#: rhodecode/controllers/settings.py:125
+#: rhodecode/controllers/admin/repos.py:284
+#, python-format
+msgid "error occurred during update of repository %s"
+msgstr "リポジトリ %s の更新中にエラーが発生しました"
+
+#: rhodecode/controllers/settings.py:143
+#: rhodecode/controllers/admin/repos.py:302
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+"%s "
+"リポジトリはDB内に見つかりませんでした。おそらくファイルシステム上で作られたか名前が変更されたためです。リポジトリをもう一度チェックするためにアプリケーションを立ち上げ直してください。"
+
+#: rhodecode/controllers/settings.py:155
+#: rhodecode/controllers/admin/repos.py:314
+#, python-format
+msgid "deleted repository %s"
+msgstr "リポジトリ %s を削除しました"
+
+#: rhodecode/controllers/settings.py:159
+#: rhodecode/controllers/admin/repos.py:324
+#: rhodecode/controllers/admin/repos.py:330
+#, python-format
+msgid "An error occurred during deletion of %s"
+msgstr "リポジトリ %s の削除中にエラーが発生しました"
+
+#: rhodecode/controllers/summary.py:138
+msgid "No data loaded yet"
+msgstr ""
+
+#: rhodecode/controllers/summary.py:142
+#: rhodecode/templates/summary/summary.html:148
+msgid "Statistics are disabled for this repository"
+msgstr "このリポジトリの統計は無効化されています"
+
+#: rhodecode/controllers/admin/ldap_settings.py:50
+msgid "BASE"
+msgstr "BASE"
+
+#: rhodecode/controllers/admin/ldap_settings.py:51
+msgid "ONELEVEL"
+msgstr "ONELEVEL"
+
+#: rhodecode/controllers/admin/ldap_settings.py:52
+msgid "SUBTREE"
+msgstr "SUBTREE"
+
+#: rhodecode/controllers/admin/ldap_settings.py:56
+msgid "NEVER"
+msgstr "NEVER"
+
+#: rhodecode/controllers/admin/ldap_settings.py:57
+msgid "ALLOW"
+msgstr "ALLOW"
+
+#: rhodecode/controllers/admin/ldap_settings.py:58
+msgid "TRY"
+msgstr "TRY"
+
+#: rhodecode/controllers/admin/ldap_settings.py:59
+msgid "DEMAND"
+msgstr "DEMAND"
+
+#: rhodecode/controllers/admin/ldap_settings.py:60
+msgid "HARD"
+msgstr "HARD"
+
+#: rhodecode/controllers/admin/ldap_settings.py:64
+msgid "No encryption"
+msgstr "暗号化なし"
+
+#: rhodecode/controllers/admin/ldap_settings.py:65
+msgid "LDAPS connection"
+msgstr "LDAPS接続"
+
+#: rhodecode/controllers/admin/ldap_settings.py:66
+msgid "START_TLS on LDAP connection"
+msgstr "LDAP接続でSTART_TLSを使用"
+
+#: rhodecode/controllers/admin/ldap_settings.py:126
+msgid "Ldap settings updated successfully"
+msgstr "LDAP設定を更新しました"
+
+#: rhodecode/controllers/admin/ldap_settings.py:130
+msgid "Unable to activate ldap. The \"python-ldap\" library is missing."
+msgstr "LDAPを有効にできませんでした。\"python-ldap\"ライブラリがありません。"
+
+#: rhodecode/controllers/admin/ldap_settings.py:147
+msgid "error occurred during update of ldap settings"
+msgstr "LDAP設定の更新中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/permissions.py:59
+msgid "None"
+msgstr "なし"
+
+#: rhodecode/controllers/admin/permissions.py:60
+msgid "Read"
+msgstr "読込"
+
+#: rhodecode/controllers/admin/permissions.py:61
+msgid "Write"
+msgstr "書込"
+
+#: rhodecode/controllers/admin/permissions.py:62
+#: rhodecode/templates/admin/ldap/ldap.html:9
+#: rhodecode/templates/admin/permissions/permissions.html:9
+#: rhodecode/templates/admin/repos/repo_add.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:9
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:8
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:8
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
+#: rhodecode/templates/admin/settings/hooks.html:9
+#: rhodecode/templates/admin/settings/settings.html:9
+#: rhodecode/templates/admin/users/user_add.html:8
+#: rhodecode/templates/admin/users/user_edit.html:9
+#: rhodecode/templates/admin/users/user_edit.html:122
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/admin/users_groups/users_group_add.html:8
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:9
+#: rhodecode/templates/admin/users_groups/users_groups.html:9
+#: rhodecode/templates/base/base.html:197
+#: rhodecode/templates/base/base.html:337
+#: rhodecode/templates/base/base.html:339
+#: rhodecode/templates/base/base.html:341
+msgid "Admin"
+msgstr "管理"
+
+#: rhodecode/controllers/admin/permissions.py:65
+msgid "disabled"
+msgstr "無効にする"
+
+#: rhodecode/controllers/admin/permissions.py:67
+msgid "allowed with manual account activation"
+msgstr "手動でアカウントを有効にする"
+
+#: rhodecode/controllers/admin/permissions.py:69
+msgid "allowed with automatic account activation"
+msgstr "自動でアカウントを有効にする"
+
+#: rhodecode/controllers/admin/permissions.py:71
+#: rhodecode/controllers/admin/permissions.py:74
+msgid "Disabled"
+msgstr "無効"
+
+#: rhodecode/controllers/admin/permissions.py:72
+#: rhodecode/controllers/admin/permissions.py:75
+msgid "Enabled"
+msgstr "有効"
+
+#: rhodecode/controllers/admin/permissions.py:116
+msgid "Default permissions updated successfully"
+msgstr "デフォルトの権限を更新しました"
+
+#: rhodecode/controllers/admin/permissions.py:130
+msgid "error occurred during update of permissions"
+msgstr "権限の更新中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:123
+msgid "--REMOVE FORK--"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:192
+#, python-format
+msgid "created repository %s from %s"
+msgstr "リポジトリ %s を %s から作成"
+
+#: rhodecode/controllers/admin/repos.py:196
+#, python-format
+msgid "created repository %s"
+msgstr "リポジトリ %s を作成しました"
+
+#: rhodecode/controllers/admin/repos.py:227
+#, python-format
+msgid "error occurred during creation of repository %s"
+msgstr "リポジトリ %s を作成中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:319
+#, python-format
+msgid "Cannot delete %s it still contains attached forks"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:348
+msgid "An error occurred during deletion of repository user"
+msgstr "リポジトリユーザーの削除中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:367
+msgid "An error occurred during deletion of repository users groups"
+msgstr "リポジトリユーザーグループの削除中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:385
+msgid "An error occurred during deletion of repository stats"
+msgstr "リポジトリステートの削除中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:402
+msgid "An error occurred during cache invalidation"
+msgstr "キャッシュの無効化時にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:422
+#, fuzzy
+msgid "An error occurred during unlocking"
+msgstr "メールの保存時にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:442
+msgid "Updated repository visibility in public journal"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:446
+msgid "An error occurred during setting this repository in public journal"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:451 rhodecode/model/validators.py:299
+msgid "Token mismatch"
+msgstr "トークンが合いません"
+
+#: rhodecode/controllers/admin/repos.py:464
+msgid "Pulled from remote location"
+msgstr "リモートから取得"
+
+#: rhodecode/controllers/admin/repos.py:466
+msgid "An error occurred during pull from remote location"
+msgstr "リモートから取得中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos.py:482
+msgid "Nothing"
+msgstr "ありません"
+
+#: rhodecode/controllers/admin/repos.py:484
+#, python-format
+msgid "Marked repo %s as fork of %s"
+msgstr "%s リポジトリを %s のフォークとして印をつける"
+
+#: rhodecode/controllers/admin/repos.py:488
+msgid "An error occurred during this operation"
+msgstr "操作中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:116
+#, python-format
+msgid "created repos group %s"
+msgstr "リポジトリグループ %s を作成しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:129
+#, python-format
+msgid "error occurred during creation of repos group %s"
+msgstr "リポジトリグループ %s を作成中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:163
+#, python-format
+msgid "updated repos group %s"
+msgstr "リポジトリグループ %s を更新しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:176
+#, python-format
+msgid "error occurred during update of repos group %s"
+msgstr "リポジトリグループ %s を更新中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:194
+#, python-format
+msgid "This group contains %s repositores and cannot be deleted"
+msgstr "このグループは %s リポジトリを含んでいるため削除出来ません"
+
+#: rhodecode/controllers/admin/repos_groups.py:202
+#, python-format
+msgid "removed repos group %s"
+msgstr "リポジトリグループ %s を削除しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:208
+msgid "Cannot delete this group it still contains subgroups"
+msgstr "サブグループを含んでいるため、このグループを削除できません"
+
+#: rhodecode/controllers/admin/repos_groups.py:213
+#: rhodecode/controllers/admin/repos_groups.py:218
+#, python-format
+msgid "error occurred during deletion of repos group %s"
+msgstr "リポジトリグループの削除中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:238
+msgid "An error occurred during deletion of group user"
+msgstr "グループユーザーを削除中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/repos_groups.py:258
+msgid "An error occurred during deletion of group users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:121
+#, python-format
+msgid "Repositories successfully rescanned added: %s,removed: %s"
+msgstr "リポジトリを再度スキャンしました。 追加: %s 削除: %s"
+
+#: rhodecode/controllers/admin/settings.py:129
+msgid "Whoosh reindex task scheduled"
+msgstr "Whooshの再インデックスタスクを予定に入れました"
+
+#: rhodecode/controllers/admin/settings.py:160
+msgid "Updated application settings"
+msgstr "アプリケーション設定を更新しました"
+
+#: rhodecode/controllers/admin/settings.py:164
+#: rhodecode/controllers/admin/settings.py:275
+msgid "error occurred during updating application settings"
+msgstr "アプリケーション設定を更新中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/settings.py:200
+#, fuzzy
+msgid "Updated visualisation settings"
+msgstr "アプリケーション設定を更新しました"
+
+#: rhodecode/controllers/admin/settings.py:205
+#, fuzzy
+msgid "error occurred during updating visualisation settings"
+msgstr "アプリケーション設定を更新中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/settings.py:271
+#, fuzzy
+msgid "Updated VCS settings"
+msgstr "Mercurialの設定を更新しました"
+
+#: rhodecode/controllers/admin/settings.py:285
+msgid "Added new hook"
+msgstr "新しいフックを追加しました"
+
+#: rhodecode/controllers/admin/settings.py:297
+msgid "Updated hooks"
+msgstr "フックを更新しました"
+
+#: rhodecode/controllers/admin/settings.py:301
+msgid "error occurred during hook creation"
+msgstr "フックの作成時にエラーが発生しました"
+
+#: rhodecode/controllers/admin/settings.py:320
+msgid "Email task created"
+msgstr "メールのタスクを作成しました"
+
+#: rhodecode/controllers/admin/settings.py:375
+msgid "You can't edit this user since it's crucial for entire application"
+msgstr "このユーザーを編集出来ません。このユーザーはアプリケーションにとって必要不可欠です。"
+
+#: rhodecode/controllers/admin/settings.py:406
+msgid "Your account was updated successfully"
+msgstr "アカウントを更新しました"
+
+#: rhodecode/controllers/admin/settings.py:421
+#: rhodecode/controllers/admin/users.py:191
+#, python-format
+msgid "error occurred during update of user %s"
+msgstr "ユーザー %s の更新中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users.py:130
+#, python-format
+msgid "created user %s"
+msgstr "ユーザー %s を作成しました"
+
+#: rhodecode/controllers/admin/users.py:142
+#, python-format
+msgid "error occurred during creation of user %s"
+msgstr "ユーザー %s の作成中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users.py:171
+msgid "User updated successfully"
+msgstr "ユーザーの更新に成功しました"
+
+#: rhodecode/controllers/admin/users.py:207
+msgid "successfully deleted user"
+msgstr "ユーザーの削除に成功しました"
+
+#: rhodecode/controllers/admin/users.py:212
+msgid "An error occurred during deletion of user"
+msgstr "ユーザーの削除中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users.py:226
+msgid "You can't edit this user"
+msgstr "このユーザーは編集できません"
+
+#: rhodecode/controllers/admin/users.py:266
+msgid "Granted 'repository create' permission to user"
+msgstr "ユーザーに 'リポジトリ作成' 権限を与えました"
+
+#: rhodecode/controllers/admin/users.py:271
+msgid "Revoked 'repository create' permission to user"
+msgstr "ユーザーの 'リポジトリ作成' 権限を取り消しました"
+
+#: rhodecode/controllers/admin/users.py:277
+#, fuzzy
+msgid "Granted 'repository fork' permission to user"
+msgstr "ユーザーに 'リポジトリ作成' 権限を与えました"
+
+#: rhodecode/controllers/admin/users.py:282
+#, fuzzy
+msgid "Revoked 'repository fork' permission to user"
+msgstr "ユーザーの 'リポジトリ作成' 権限を取り消しました"
+
+#: rhodecode/controllers/admin/users.py:288
+#: rhodecode/controllers/admin/users_groups.py:255
+#, fuzzy
+msgid "An error occurred during permissions saving"
+msgstr "メールの保存時にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users.py:303
+#, python-format
+msgid "Added email %s to user"
+msgstr "ユーザーにメール %s を追加しました"
+
+#: rhodecode/controllers/admin/users.py:309
+msgid "An error occurred during email saving"
+msgstr "メールの保存時にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users.py:319
+msgid "Removed email from user"
+msgstr "ユーザーからメールを削除しました"
+
+#: rhodecode/controllers/admin/users_groups.py:84
+#, python-format
+msgid "created users group %s"
+msgstr "ユーザーグループ %s を作成しました"
+
+#: rhodecode/controllers/admin/users_groups.py:95
+#, python-format
+msgid "error occurred during creation of users group %s"
+msgstr "ユーザーグループ %s の作成中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users_groups.py:135
+#, python-format
+msgid "updated users group %s"
+msgstr "ユーザーグループ %s を更新しました"
+
+#: rhodecode/controllers/admin/users_groups.py:157
+#, python-format
+msgid "error occurred during update of users group %s"
+msgstr "ユーザーグループ %s の更新中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users_groups.py:174
+msgid "successfully deleted users group"
+msgstr "ユーザーグループ"
+
+#: rhodecode/controllers/admin/users_groups.py:179
+msgid "An error occurred during deletion of users group"
+msgstr "ユーザーグループの削除中にエラーが発生しました"
+
+#: rhodecode/controllers/admin/users_groups.py:233
+#, fuzzy
+msgid "Granted 'repository create' permission to users group"
+msgstr "ユーザーに 'リポジトリ作成' 権限を与えました"
+
+#: rhodecode/controllers/admin/users_groups.py:238
+#, fuzzy
+msgid "Revoked 'repository create' permission to users group"
+msgstr "ユーザーの 'リポジトリ作成' 権限を取り消しました"
+
+#: rhodecode/controllers/admin/users_groups.py:244
+#, fuzzy
+msgid "Granted 'repository fork' permission to users group"
+msgstr "ユーザーに 'リポジトリ作成' 権限を与えました"
+
+#: rhodecode/controllers/admin/users_groups.py:249
+#, fuzzy
+msgid "Revoked 'repository fork' permission to users group"
+msgstr "ユーザーの 'リポジトリ作成' 権限を取り消しました"
+
+#: rhodecode/lib/auth.py:499
+msgid "You need to be a registered user to perform this action"
+msgstr "このアクションを実行するためには登録ユーザーである必要があります"
+
+#: rhodecode/lib/auth.py:540
+msgid "You need to be a signed in to view this page"
+msgstr "このページを閲覧するためにはサインインが必要です"
+
+#: rhodecode/lib/diffs.py:86
+msgid "Changeset was too big and was cut off, use diff menu to display this diff"
+msgstr ""
+
+#: rhodecode/lib/diffs.py:96
+msgid "No changes detected"
+msgstr "検出された変更はありません"
+
+#: rhodecode/lib/helpers.py:372
+#, python-format
+msgid "%a, %d %b %Y %H:%M:%S"
+msgstr "%a, %d %b %Y %H:%M:%S"
+
+#: rhodecode/lib/helpers.py:484
+msgid "True"
+msgstr "True"
+
+#: rhodecode/lib/helpers.py:488
+msgid "False"
+msgstr "False"
+
+#: rhodecode/lib/helpers.py:532
+msgid "Changeset not found"
+msgstr "リビジョンが見つかりません"
+
+#: rhodecode/lib/helpers.py:555
+#, python-format
+msgid "Show all combined changesets %s->%s"
+msgstr "%s から %s までのすべてのチェンジセットを表示"
+
+#: rhodecode/lib/helpers.py:561
+msgid "compare view"
+msgstr "比較の表示"
+
+#: rhodecode/lib/helpers.py:581
+msgid "and"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:582
+#, python-format
+msgid "%s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:583 rhodecode/templates/changelog/changelog.html:48
+msgid "revisions"
+msgstr "リビジョン"
+
+#: rhodecode/lib/helpers.py:606
+msgid "fork name "
+msgstr "フォーク名 "
+
+#: rhodecode/lib/helpers.py:620
+#: rhodecode/templates/pullrequests/pullrequest_show.html:4
+#: rhodecode/templates/pullrequests/pullrequest_show.html:12
+#, python-format
+msgid "Pull request #%s"
+msgstr "プルリクエスト #%s"
+
+#: rhodecode/lib/helpers.py:626
+msgid "[deleted] repository"
+msgstr "リポジトリを[削除]"
+
+#: rhodecode/lib/helpers.py:628 rhodecode/lib/helpers.py:638
+msgid "[created] repository"
+msgstr "リポジトリを[作成]"
+
+#: rhodecode/lib/helpers.py:630
+msgid "[created] repository as fork"
+msgstr "フォークしてリポジトリを[作成]"
+
+#: rhodecode/lib/helpers.py:632 rhodecode/lib/helpers.py:640
+msgid "[forked] repository"
+msgstr "リポジトリを[フォーク]"
+
+#: rhodecode/lib/helpers.py:634 rhodecode/lib/helpers.py:642
+msgid "[updated] repository"
+msgstr "リポジトリを[更新]"
+
+#: rhodecode/lib/helpers.py:636
+msgid "[delete] repository"
+msgstr "リポジトリを[削除]"
+
+#: rhodecode/lib/helpers.py:644
+msgid "[created] user"
+msgstr "ユーザーを[作成]"
+
+#: rhodecode/lib/helpers.py:646
+msgid "[updated] user"
+msgstr "ユーザーを[更新]"
+
+#: rhodecode/lib/helpers.py:648
+msgid "[created] users group"
+msgstr "ユーザーグループを[作成]"
+
+#: rhodecode/lib/helpers.py:650
+msgid "[updated] users group"
+msgstr "ユーザーグループを[更新]"
+
+#: rhodecode/lib/helpers.py:652
+msgid "[commented] on revision in repository"
+msgstr "リポジトリのリビジョンに[コメント]"
+
+#: rhodecode/lib/helpers.py:654
+#, fuzzy
+msgid "[commented] on pull request for"
+msgstr "プルリクエストに[コメント]"
+
+#: rhodecode/lib/helpers.py:656
+#, fuzzy
+msgid "[closed] pull request for"
+msgstr "プルリクエストに[コメント]"
+
+#: rhodecode/lib/helpers.py:658
+msgid "[pushed] into"
+msgstr "[プッシュ]"
+
+#: rhodecode/lib/helpers.py:660
+msgid "[committed via RhodeCode] into repository"
+msgstr "リポジトリに[RhodeCode経由でコミット]"
+
+#: rhodecode/lib/helpers.py:662
+msgid "[pulled from remote] into repository"
+msgstr "リポジトリに[リモートからプル]"
+
+#: rhodecode/lib/helpers.py:664
+msgid "[pulled] from"
+msgstr "[プル]"
+
+#: rhodecode/lib/helpers.py:666
+msgid "[started following] repository"
+msgstr "リポジトリの[フォローを開始]"
+
+#: rhodecode/lib/helpers.py:668
+msgid "[stopped following] repository"
+msgstr "リポジトリの[フォローを停止]"
+
+#: rhodecode/lib/helpers.py:840
+#, python-format
+msgid " and %s more"
+msgstr " と %s 以上"
+
+#: rhodecode/lib/helpers.py:844
+msgid "No Files"
+msgstr ""
+
+#: rhodecode/lib/utils2.py:335
+#, python-format
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] "%d 年"
+
+#: rhodecode/lib/utils2.py:336
+#, python-format
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] "%d ヶ月"
+
+#: rhodecode/lib/utils2.py:337
+#, python-format
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] "%d 日"
+
+#: rhodecode/lib/utils2.py:338
+#, python-format
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] "%d 時間"
+
+#: rhodecode/lib/utils2.py:339
+#, python-format
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] "%d 分"
+
+#: rhodecode/lib/utils2.py:340
+#, python-format
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] "%d 秒"
+
+#: rhodecode/lib/utils2.py:355
+#, python-format
+msgid "%s ago"
+msgstr "%s 前"
+
+#: rhodecode/lib/utils2.py:357
+#, python-format
+msgid "%s and %s ago"
+msgstr "%s と %s 前"
+
+#: rhodecode/lib/utils2.py:360
+msgid "just now"
+msgstr "ちょうどいま"
+
+#: rhodecode/lib/celerylib/tasks.py:269
+msgid "password reset link"
+msgstr "パスワードリセットのリンク"
+
+#: rhodecode/model/comment.py:110
+#, python-format
+msgid "on line %s"
+msgstr ""
+
+#: rhodecode/model/comment.py:157
+msgid "[Mention]"
+msgstr ""
+
+#: rhodecode/model/db.py:1140
+msgid "Repository no access"
+msgstr ""
+
+#: rhodecode/model/db.py:1141
+msgid "Repository read access"
+msgstr ""
+
+#: rhodecode/model/db.py:1142
+msgid "Repository write access"
+msgstr ""
+
+#: rhodecode/model/db.py:1143
+msgid "Repository admin access"
+msgstr ""
+
+#: rhodecode/model/db.py:1145
+msgid "Repositories Group no access"
+msgstr ""
+
+#: rhodecode/model/db.py:1146
+msgid "Repositories Group read access"
+msgstr ""
+
+#: rhodecode/model/db.py:1147
+msgid "Repositories Group write access"
+msgstr ""
+
+#: rhodecode/model/db.py:1148
+msgid "Repositories Group admin access"
+msgstr ""
+
+#: rhodecode/model/db.py:1150
+msgid "RhodeCode Administrator"
+msgstr ""
+
+#: rhodecode/model/db.py:1151
+msgid "Repository creation disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1152
+msgid "Repository creation enabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1153
+msgid "Repository forking disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1154
+msgid "Repository forking enabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1155
+msgid "Register disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1156
+msgid "Register new user with RhodeCode with manual activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1159
+msgid "Register new user with RhodeCode with auto activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1579
+msgid "Not Reviewed"
+msgstr "未レビュー"
+
+#: rhodecode/model/db.py:1580
+msgid "Approved"
+msgstr "承認"
+
+#: rhodecode/model/db.py:1581
+msgid "Rejected"
+msgstr "却下"
+
+#: rhodecode/model/db.py:1582
+msgid "Under Review"
+msgstr "レビュー中"
+
+#: rhodecode/model/forms.py:43
+msgid "Please enter a login"
+msgstr "ログイン名を入力してください"
+
+#: rhodecode/model/forms.py:44
+#, python-format
+msgid "Enter a value %(min)i characters long or more"
+msgstr "%(min)i 文字以上必要です"
+
+#: rhodecode/model/forms.py:52
+msgid "Please enter a password"
+msgstr "パスワードを入力してください"
+
+#: rhodecode/model/forms.py:53
+#, python-format
+msgid "Enter %(min)i characters or more"
+msgstr "%(min)i 文字以上必要です"
+
+#: rhodecode/model/notification.py:220
+msgid "commented on commit"
+msgstr "コミットに対するコメント"
+
+#: rhodecode/model/notification.py:221
+msgid "sent message"
+msgstr ""
+
+#: rhodecode/model/notification.py:222
+msgid "mentioned you"
+msgstr ""
+
+#: rhodecode/model/notification.py:223
+msgid "registered in RhodeCode"
+msgstr ""
+
+#: rhodecode/model/notification.py:224
+msgid "opened new pull request"
+msgstr ""
+
+#: rhodecode/model/notification.py:225
+msgid "commented on pull request"
+msgstr ""
+
+#: rhodecode/model/pull_request.py:84
+#, python-format
+msgid "%(user)s wants you to review pull request #%(pr_id)s"
+msgstr ""
+
+#: rhodecode/model/scm.py:535
+msgid "latest tip"
+msgstr "最新のtip"
+
+#: rhodecode/model/user.py:230
+msgid "new user registration"
+msgstr "新規ユーザー登録"
+
+#: rhodecode/model/user.py:255 rhodecode/model/user.py:277
+#: rhodecode/model/user.py:299
+msgid "You can't Edit this user since it's crucial for entire application"
+msgstr ""
+
+#: rhodecode/model/user.py:323
+msgid "You can't remove this user since it's crucial for entire application"
+msgstr ""
+
+#: rhodecode/model/user.py:329
+#, python-format
+msgid ""
+"user \"%s\" still owns %s repositories and cannot be removed. Switch "
+"owners or remove those repositories. %s"
+msgstr ""
+
+#: rhodecode/model/validators.py:35 rhodecode/model/validators.py:36
+msgid "Value cannot be an empty list"
+msgstr ""
+
+#: rhodecode/model/validators.py:82
+#, python-format
+msgid "Username \"%(username)s\" already exists"
+msgstr "ユーザー名 \"%(username)s\" はすでに使われています"
+
+#: rhodecode/model/validators.py:84
+#, python-format
+msgid "Username \"%(username)s\" is forbidden"
+msgstr "ユーザー名 \"%(username)s\" は許可されていません"
+
+#: rhodecode/model/validators.py:86
+msgid ""
+"Username may only contain alphanumeric characters underscores, periods or"
+" dashes and must begin with alphanumeric character"
+msgstr "ユーザー名はアルファベット、アンダースコア(_)、ピリオド(.)、ダッシュ(-)しか使えません。また、アルファベットから始まる必要があります"
+
+#: rhodecode/model/validators.py:114
+#, python-format
+msgid "Username %(username)s is not valid"
+msgstr "ユーザー名 %(username)s は不正です"
+
+#: rhodecode/model/validators.py:133
+msgid "Invalid users group name"
+msgstr "不正なユーザーグループ名です"
+
+#: rhodecode/model/validators.py:134
+#, python-format
+msgid "Users group \"%(usersgroup)s\" already exists"
+msgstr "ユーザーグループ \"%(usersgroup)s\" はすでに存在します"
+
+#: rhodecode/model/validators.py:136
+msgid ""
+"users group name may only contain  alphanumeric characters underscores, "
+"periods or dashes and must begin with alphanumeric character"
+msgstr ""
+"ユーザーグループ名はアルファベット、アンダースコア(_)、ピリオド(.)、ダッシュ(-)しか使えません。また、アルファベットから始まる必要があります"
+" "
+
+#: rhodecode/model/validators.py:174
+msgid "Cannot assign this group as parent"
+msgstr "このグループは親にできません"
+
+#: rhodecode/model/validators.py:175
+#, python-format
+msgid "Group \"%(group_name)s\" already exists"
+msgstr "グループ \"%(group_name)s\" はすでに存在します"
+
+#: rhodecode/model/validators.py:177
+#, python-format
+msgid "Repository with name \"%(group_name)s\" already exists"
+msgstr "グループ名 \"%(group_name)s\" を持つリポジトリはすでに存在します"
+
+#: rhodecode/model/validators.py:235
+msgid "Invalid characters (non-ascii) in password"
+msgstr "パスワードに利用出来ない文字列(non-ascii)です"
+
+#: rhodecode/model/validators.py:250
+msgid "Passwords do not match"
+msgstr "パスワードが一致しません"
+
+#: rhodecode/model/validators.py:267
+msgid "invalid password"
+msgstr "不正なパスワードです"
+
+#: rhodecode/model/validators.py:268
+msgid "invalid user name"
+msgstr "不正なユーザー名です"
+
+#: rhodecode/model/validators.py:269
+msgid "Your account is disabled"
+msgstr "アカウントは無効です"
+
+#: rhodecode/model/validators.py:313
+#, python-format
+msgid "Repository name %(repo)s is disallowed"
+msgstr "リポジトリ名 %(repo)s は許可されていません"
+
+#: rhodecode/model/validators.py:315
+#, python-format
+msgid "Repository named %(repo)s already exists"
+msgstr "リポジトリ %(repo)s はすでに存在します"
+
+#: rhodecode/model/validators.py:316
+#, python-format
+msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
+msgstr "リポジトリ \"%(repo)s\" は グループ \"%(group)s\" にすでに存在します"
+
+#: rhodecode/model/validators.py:318
+#, python-format
+msgid "Repositories group with name \"%(repo)s\" already exists"
+msgstr "リポジトリグループ名 \"%(repo)s\" はすでに存在します"
+
+#: rhodecode/model/validators.py:431
+msgid "invalid clone url"
+msgstr "無効なクローンURIです"
+
+#: rhodecode/model/validators.py:432
+msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url"
+msgstr ""
+
+#: rhodecode/model/validators.py:457
+msgid "Fork have to be the same type as parent"
+msgstr "フォークは親と同じタイプの必要があります"
+
+#: rhodecode/model/validators.py:478
+msgid "This username or users group name is not valid"
+msgstr "ユーザー名かユーザーグループが不正です"
+
+#: rhodecode/model/validators.py:562
+msgid "This is not a valid path"
+msgstr "不正なパスです"
+
+#: rhodecode/model/validators.py:577
+msgid "This e-mail address is already taken"
+msgstr "このメールアドレスはすでに取得されています"
+
+#: rhodecode/model/validators.py:597
+#, python-format
+msgid "e-mail \"%(email)s\" does not exist."
+msgstr "メールアドレス \"%(email)s\" は存在しません"
+
+#: rhodecode/model/validators.py:634
+msgid ""
+"The LDAP Login attribute of the CN must be specified - this is the name "
+"of the attribute that is equivalent to \"username\""
+msgstr "LDAPのこのCNに対するログイン属性は必須です。 - これは \"ユーザー名\" と同じです"
+
+#: rhodecode/model/validators.py:653
+#, python-format
+msgid "Revisions %(revs)s are already part of pull request or have set status"
+msgstr ""
+
+#: rhodecode/templates/index.html:3
+msgid "Dashboard"
+msgstr "ダッシュボード"
+
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/repo_switcher_list.html:4
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/users/user_edit_my_account.html:31
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/bookmarks/bookmarks.html:10
+#: rhodecode/templates/branches/branches.html:9
+#: rhodecode/templates/journal/journal.html:40
+#: rhodecode/templates/tags/tags.html:10
+msgid "quick filter..."
+msgstr "クイックフィルタ..."
+
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/base/base.html:221
+msgid "repositories"
+msgstr "リポジトリ"
+
+#: rhodecode/templates/index_base.html:13
+#: rhodecode/templates/index_base.html:15
+#: rhodecode/templates/admin/repos/repos.html:21
+msgid "ADD REPOSITORY"
+msgstr "リポジトリの追加"
+
+#: rhodecode/templates/index_base.html:29
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:32
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:32
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:33
+#: rhodecode/templates/admin/users_groups/users_group_add.html:32
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:33
+msgid "Group name"
+msgstr "グループ名"
+
+#: rhodecode/templates/index_base.html:30
+#: rhodecode/templates/index_base.html:71
+#: rhodecode/templates/index_base.html:142
+#: rhodecode/templates/index_base.html:168
+#: rhodecode/templates/admin/repos/repo_add_base.html:56
+#: rhodecode/templates/admin/repos/repo_edit.html:75
+#: rhodecode/templates/admin/repos/repos.html:72
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:41
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:41
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:34
+#: rhodecode/templates/forks/fork.html:59
+#: rhodecode/templates/settings/repo_settings.html:66
+#: rhodecode/templates/summary/summary.html:105
+msgid "Description"
+msgstr "説明"
+
+#: rhodecode/templates/index_base.html:40
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46
+msgid "Repositories group"
+msgstr "リポジトリグループ"
+
+#: rhodecode/templates/index_base.html:70
+#: rhodecode/templates/index_base.html:166
+#: rhodecode/templates/admin/repos/repo_add_base.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:32
+#: rhodecode/templates/admin/repos/repos.html:70
+#: rhodecode/templates/admin/users/user_edit.html:192
+#: rhodecode/templates/admin/users/user_edit_my_account.html:59
+#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:6
+#: rhodecode/templates/bookmarks/bookmarks.html:36
+#: rhodecode/templates/bookmarks/bookmarks_data.html:6
+#: rhodecode/templates/branches/branches.html:51
+#: rhodecode/templates/files/files_browser.html:47
+#: rhodecode/templates/journal/journal.html:59
+#: rhodecode/templates/journal/journal.html:107
+#: rhodecode/templates/journal/journal.html:186
+#: rhodecode/templates/settings/repo_settings.html:31
+#: rhodecode/templates/summary/summary.html:43
+#: rhodecode/templates/summary/summary.html:123
+#: rhodecode/templates/tags/tags.html:36
+#: rhodecode/templates/tags/tags_data.html:6
+msgid "Name"
+msgstr "名前"
+
+#: rhodecode/templates/index_base.html:72
+msgid "Last change"
+msgstr "最後の変更時刻"
+
+#: rhodecode/templates/index_base.html:73
+#: rhodecode/templates/index_base.html:171
+#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/journal/journal.html:188
+msgid "Tip"
+msgstr "Tip"
+
+#: rhodecode/templates/index_base.html:74
+#: rhodecode/templates/index_base.html:173
+#: rhodecode/templates/admin/repos/repo_edit.html:121
+#: rhodecode/templates/admin/repos/repos.html:73
+msgid "Owner"
+msgstr "所有者"
+
+#: rhodecode/templates/index_base.html:75
+#: rhodecode/templates/summary/summary.html:48
+#: rhodecode/templates/summary/summary.html:51
+msgid "RSS"
+msgstr "RSS"
+
+#: rhodecode/templates/index_base.html:76
+msgid "Atom"
+msgstr "Atom"
+
+#: rhodecode/templates/index_base.html:110
+#: rhodecode/templates/index_base.html:112
+#, python-format
+msgid "Subscribe to %s rss feed"
+msgstr "%s の RSS フィードを購読"
+
+#: rhodecode/templates/index_base.html:117
+#: rhodecode/templates/index_base.html:119
+#, python-format
+msgid "Subscribe to %s atom feed"
+msgstr "%s の ATOM フィードを購読"
+
+#: rhodecode/templates/index_base.html:140
+msgid "Group Name"
+msgstr "グループ名"
+
+#: rhodecode/templates/index_base.html:158
+#: rhodecode/templates/index_base.html:198
+#: rhodecode/templates/admin/repos/repos.html:94
+#: rhodecode/templates/admin/users/user_edit_my_account.html:179
+#: rhodecode/templates/admin/users/users.html:107
+#: rhodecode/templates/bookmarks/bookmarks.html:60
+#: rhodecode/templates/branches/branches.html:77
+#: rhodecode/templates/journal/journal.html:211
+#: rhodecode/templates/tags/tags.html:60
+msgid "Click to sort ascending"
+msgstr "昇順で並び換え"
+
+#: rhodecode/templates/index_base.html:159
+#: rhodecode/templates/index_base.html:199
+#: rhodecode/templates/admin/repos/repos.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account.html:180
+#: rhodecode/templates/admin/users/users.html:108
+#: rhodecode/templates/bookmarks/bookmarks.html:61
+#: rhodecode/templates/branches/branches.html:78
+#: rhodecode/templates/journal/journal.html:212
+#: rhodecode/templates/tags/tags.html:61
+msgid "Click to sort descending"
+msgstr "降順で並び替え"
+
+#: rhodecode/templates/index_base.html:169
+msgid "Last Change"
+msgstr "最後の変更点"
+
+#: rhodecode/templates/index_base.html:200
+#: rhodecode/templates/admin/repos/repos.html:96
+#: rhodecode/templates/admin/users/user_edit_my_account.html:181
+#: rhodecode/templates/admin/users/users.html:109
+#: rhodecode/templates/bookmarks/bookmarks.html:62
+#: rhodecode/templates/branches/branches.html:79
+#: rhodecode/templates/journal/journal.html:213
+#: rhodecode/templates/tags/tags.html:62
+msgid "No records found."
+msgstr "レコードが見つかりません"
+
+#: rhodecode/templates/index_base.html:201
+#: rhodecode/templates/admin/repos/repos.html:97
+#: rhodecode/templates/admin/users/user_edit_my_account.html:182
+#: rhodecode/templates/admin/users/users.html:110
+#: rhodecode/templates/bookmarks/bookmarks.html:63
+#: rhodecode/templates/branches/branches.html:80
+#: rhodecode/templates/journal/journal.html:214
+#: rhodecode/templates/tags/tags.html:63
+msgid "Data error."
+msgstr "データエラー"
+
+#: rhodecode/templates/index_base.html:202
+#: rhodecode/templates/admin/repos/repos.html:98
+#: rhodecode/templates/admin/users/user_edit_my_account.html:183
+#: rhodecode/templates/admin/users/users.html:111
+#: rhodecode/templates/bookmarks/bookmarks.html:64
+#: rhodecode/templates/branches/branches.html:81
+#: rhodecode/templates/journal/journal.html:215
+#: rhodecode/templates/tags/tags.html:64
+msgid "Loading..."
+msgstr "読み込み中..."
+
+#: rhodecode/templates/login.html:5 rhodecode/templates/login.html:54
+msgid "Sign In"
+msgstr "サインイン"
+
+#: rhodecode/templates/login.html:21
+msgid "Sign In to"
+msgstr ""
+
+#: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20
+#: rhodecode/templates/admin/admin_log.html:5
+#: rhodecode/templates/admin/users/user_add.html:32
+#: rhodecode/templates/admin/users/user_edit.html:50
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:26
+#: rhodecode/templates/base/base.html:83
+#: rhodecode/templates/summary/summary.html:122
+msgid "Username"
+msgstr "ユーザー名"
+
+#: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29
+#: rhodecode/templates/admin/ldap/ldap.html:46
+#: rhodecode/templates/admin/users/user_add.html:41
+#: rhodecode/templates/base/base.html:92
+msgid "Password"
+msgstr "パスワード"
+
+#: rhodecode/templates/login.html:50
+msgid "Remember me"
+msgstr "次回から自動的にサインイン"
+
+#: rhodecode/templates/login.html:60
+msgid "Forgot your password ?"
+msgstr "パスワードを忘れた場合はこちら"
+
+#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:103
+msgid "Don't have an account ?"
+msgstr "アカウントを持っていない場合はこちら"
+
+#: rhodecode/templates/password_reset.html:5
+msgid "Reset your password"
+msgstr "パスワードリセット"
+
+#: rhodecode/templates/password_reset.html:11
+msgid "Reset your password to"
+msgstr "パスワードリセット"
+
+#: rhodecode/templates/password_reset.html:21
+msgid "Email address"
+msgstr "メールアドレス"
+
+#: rhodecode/templates/password_reset.html:30
+msgid "Reset my password"
+msgstr "パスワードをリセットする"
+
+#: rhodecode/templates/password_reset.html:31
+msgid "Password reset link will be send to matching email address"
+msgstr "該当するメールアドレスにパスワードリセットのリンクを送信します"
+
+#: rhodecode/templates/register.html:5 rhodecode/templates/register.html:74
+msgid "Sign Up"
+msgstr "サインアップ"
+
+#: rhodecode/templates/register.html:11
+msgid "Sign Up to"
+msgstr "サインアップ"
+
+#: rhodecode/templates/register.html:38
+msgid "Re-enter password"
+msgstr "パスワード再入力"
+
+#: rhodecode/templates/register.html:47
+#: rhodecode/templates/admin/users/user_add.html:59
+#: rhodecode/templates/admin/users/user_edit.html:86
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53
+msgid "First Name"
+msgstr "名前"
+
+#: rhodecode/templates/register.html:56
+#: rhodecode/templates/admin/users/user_add.html:68
+#: rhodecode/templates/admin/users/user_edit.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62
+msgid "Last Name"
+msgstr "名字"
+
+#: rhodecode/templates/register.html:65
+#: rhodecode/templates/admin/users/user_add.html:77
+#: rhodecode/templates/admin/users/user_edit.html:104
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71
+#: rhodecode/templates/summary/summary.html:124
+msgid "Email"
+msgstr "メールアドレス"
+
+#: rhodecode/templates/register.html:76
+msgid "Your account will be activated right after registration"
+msgstr "アカウントは登録後にアクティブになります"
+
+#: rhodecode/templates/register.html:78
+msgid "Your account must wait for activation by administrator"
+msgstr "アカウントは管理者のアクティベーションを待つ必要があります"
+
+#: rhodecode/templates/repo_switcher_list.html:11
+#: rhodecode/templates/admin/repos/repo_add_base.html:65
+#: rhodecode/templates/admin/repos/repo_edit.html:85
+#: rhodecode/templates/settings/repo_settings.html:76
+msgid "Private repository"
+msgstr "非公開リポジトリ"
+
+#: rhodecode/templates/repo_switcher_list.html:16
+msgid "Public repository"
+msgstr "公開リポジトリ"
+
+#: rhodecode/templates/switch_to_list.html:3
+#: rhodecode/templates/branches/branches.html:14
+msgid "branches"
+msgstr "ブランチ"
+
+#: rhodecode/templates/switch_to_list.html:10
+#: rhodecode/templates/branches/branches_data.html:57
+msgid "There are no branches yet"
+msgstr "まだブランチがありません"
+
+#: rhodecode/templates/switch_to_list.html:15
+#: rhodecode/templates/shortlog/shortlog_data.html:10
+#: rhodecode/templates/tags/tags.html:15
+msgid "tags"
+msgstr "タグ"
+
+#: rhodecode/templates/switch_to_list.html:22
+#: rhodecode/templates/tags/tags_data.html:33
+msgid "There are no tags yet"
+msgstr "まだタグがありません"
+
+#: rhodecode/templates/switch_to_list.html:28
+#: rhodecode/templates/bookmarks/bookmarks.html:15
+msgid "bookmarks"
+msgstr "ブックマーク"
+
+#: rhodecode/templates/switch_to_list.html:35
+#: rhodecode/templates/bookmarks/bookmarks_data.html:32
+msgid "There are no bookmarks yet"
+msgstr "まだブックマークがありません"
+
+#: rhodecode/templates/admin/admin.html:5
+#: rhodecode/templates/admin/admin.html:9
+msgid "Admin journal"
+msgstr "管理者ジャーナル"
+
+#: rhodecode/templates/admin/admin_log.html:6
+#: rhodecode/templates/admin/repos/repos.html:74
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:8
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:9
+#: rhodecode/templates/journal/journal.html:61
+#: rhodecode/templates/journal/journal.html:62
+msgid "Action"
+msgstr "アクション"
+
+#: rhodecode/templates/admin/admin_log.html:7
+msgid "Repository"
+msgstr "リポジトリ"
+
+#: rhodecode/templates/admin/admin_log.html:8
+#: rhodecode/templates/bookmarks/bookmarks.html:37
+#: rhodecode/templates/bookmarks/bookmarks_data.html:7
+#: rhodecode/templates/branches/branches.html:52
+#: rhodecode/templates/tags/tags.html:37
+#: rhodecode/templates/tags/tags_data.html:7
+msgid "Date"
+msgstr "日時"
+
+#: rhodecode/templates/admin/admin_log.html:9
+msgid "From IP"
+msgstr "アクセス元IPアドレス"
+
+#: rhodecode/templates/admin/admin_log.html:53
+msgid "No actions yet"
+msgstr "まだアクションがありません"
+
+#: rhodecode/templates/admin/ldap/ldap.html:5
+msgid "LDAP administration"
+msgstr "LDAP管理"
+
+#: rhodecode/templates/admin/ldap/ldap.html:11
+msgid "Ldap"
+msgstr "LDAP"
+
+#: rhodecode/templates/admin/ldap/ldap.html:28
+msgid "Connection settings"
+msgstr "接続設定"
+
+#: rhodecode/templates/admin/ldap/ldap.html:30
+msgid "Enable LDAP"
+msgstr "LDAPを有効にする"
+
+#: rhodecode/templates/admin/ldap/ldap.html:34
+msgid "Host"
+msgstr "ホスト"
+
+#: rhodecode/templates/admin/ldap/ldap.html:38
+msgid "Port"
+msgstr "ポート"
+
+#: rhodecode/templates/admin/ldap/ldap.html:42
+msgid "Account"
+msgstr "アカウント"
+
+#: rhodecode/templates/admin/ldap/ldap.html:50
+msgid "Connection security"
+msgstr "接続のセキュリティ"
+
+#: rhodecode/templates/admin/ldap/ldap.html:54
+msgid "Certificate Checks"
+msgstr "証明書チェック"
+
+#: rhodecode/templates/admin/ldap/ldap.html:57
+msgid "Search settings"
+msgstr "検索設定"
+
+#: rhodecode/templates/admin/ldap/ldap.html:59
+msgid "Base DN"
+msgstr "Base DN"
+
+#: rhodecode/templates/admin/ldap/ldap.html:63
+msgid "LDAP Filter"
+msgstr "LDAPフィルター"
+
+#: rhodecode/templates/admin/ldap/ldap.html:67
+msgid "LDAP Search Scope"
+msgstr "LDAP検索範囲"
+
+#: rhodecode/templates/admin/ldap/ldap.html:70
+msgid "Attribute mappings"
+msgstr "属性マッピング"
+
+#: rhodecode/templates/admin/ldap/ldap.html:72
+msgid "Login Attribute"
+msgstr "ログイン属性"
+
+#: rhodecode/templates/admin/ldap/ldap.html:76
+msgid "First Name Attribute"
+msgstr "名前(First Name)属性"
+
+#: rhodecode/templates/admin/ldap/ldap.html:80
+msgid "Last Name Attribute"
+msgstr "名字(Last Name)属性"
+
+#: rhodecode/templates/admin/ldap/ldap.html:84
+msgid "E-mail Attribute"
+msgstr "メールアドレス属性"
+
+#: rhodecode/templates/admin/ldap/ldap.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:141
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:74
+#: rhodecode/templates/admin/settings/hooks.html:73
+#: rhodecode/templates/admin/users/user_edit.html:129
+#: rhodecode/templates/admin/users/user_edit.html:174
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:79
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:135
+#: rhodecode/templates/settings/repo_settings.html:93
+msgid "Save"
+msgstr "保存"
+
+#: rhodecode/templates/admin/notifications/notifications.html:5
+#: rhodecode/templates/admin/notifications/notifications.html:9
+msgid "My Notifications"
+msgstr "通知"
+
+#: rhodecode/templates/admin/notifications/notifications.html:29
+msgid "All"
+msgstr "すべて"
+
+#: rhodecode/templates/admin/notifications/notifications.html:30
+msgid "Comments"
+msgstr "コメント"
+
+#: rhodecode/templates/admin/notifications/notifications.html:31
+#: rhodecode/templates/base/base.html:254
+#: rhodecode/templates/base/base.html:256
+msgid "Pull requests"
+msgstr "プルリクエスト"
+
+#: rhodecode/templates/admin/notifications/notifications.html:35
+msgid "Mark all read"
+msgstr "すべて既読にする"
+
+#: rhodecode/templates/admin/notifications/notifications_data.html:39
+msgid "No notifications here yet"
+msgstr "通知はまだありません"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:5
+#: rhodecode/templates/admin/notifications/show_notification.html:11
+msgid "Show notification"
+msgstr "通知を表示"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:9
+msgid "Notifications"
+msgstr "通知"
+
+#: rhodecode/templates/admin/permissions/permissions.html:5
+msgid "Permissions administration"
+msgstr "権限管理"
+
+#: rhodecode/templates/admin/permissions/permissions.html:11
+#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
+#: rhodecode/templates/admin/users/user_edit.html:139
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:100
+#: rhodecode/templates/settings/repo_settings.html:86
+msgid "Permissions"
+msgstr "権限設定"
+
+#: rhodecode/templates/admin/permissions/permissions.html:24
+msgid "Default permissions"
+msgstr "デフォルトの権限"
+
+#: rhodecode/templates/admin/permissions/permissions.html:31
+msgid "Anonymous access"
+msgstr "匿名アクセス"
+
+#: rhodecode/templates/admin/permissions/permissions.html:41
+msgid "Repository permission"
+msgstr "リポジトリの権限"
+
+#: rhodecode/templates/admin/permissions/permissions.html:49
+msgid ""
+"All default permissions on each repository will be reset to choosen "
+"permission, note that all custom default permission on repositories will "
+"be lost"
+msgstr ""
+
+#: rhodecode/templates/admin/permissions/permissions.html:50
+msgid "overwrite existing settings"
+msgstr "現在の設定を上書きする"
+
+#: rhodecode/templates/admin/permissions/permissions.html:55
+msgid "Registration"
+msgstr "登録"
+
+#: rhodecode/templates/admin/permissions/permissions.html:63
+msgid "Repository creation"
+msgstr "リポジトリ作成"
+
+#: rhodecode/templates/admin/permissions/permissions.html:71
+#, fuzzy
+msgid "Repository forking"
+msgstr "リポジトリ作成"
+
+#: rhodecode/templates/admin/permissions/permissions.html:78
+#: rhodecode/templates/admin/repos/repo_edit.html:241
+msgid "set"
+msgstr "保存"
+
+#: rhodecode/templates/admin/repos/repo_add.html:5
+#: rhodecode/templates/admin/repos/repo_add_create_repository.html:5
+msgid "Add repository"
+msgstr "リポジトリの追加"
+
+#: rhodecode/templates/admin/repos/repo_add.html:11
+#: rhodecode/templates/admin/repos/repo_edit.html:11
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
+msgid "Repositories"
+msgstr "リポジトリ"
+
+#: rhodecode/templates/admin/repos/repo_add.html:13
+msgid "add new"
+msgstr "新規追加"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:20
+#: rhodecode/templates/summary/summary.html:95
+#: rhodecode/templates/summary/summary.html:96
+msgid "Clone from"
+msgstr "クローン元"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:24
+#: rhodecode/templates/admin/repos/repo_edit.html:44
+#: rhodecode/templates/settings/repo_settings.html:43
+msgid "Optional http[s] url from which repository should be cloned."
+msgstr "オプション:クローンするリポジトリのHTTP[S]のURLを指定します"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:29
+#: rhodecode/templates/admin/repos/repo_edit.html:49
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:4
+#: rhodecode/templates/forks/fork.html:50
+#: rhodecode/templates/settings/repo_settings.html:48
+msgid "Repository group"
+msgstr "リポジトリグループ"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:33
+#: rhodecode/templates/forks/fork.html:54
+msgid "Optionaly select a group to put this repository into."
+msgstr "オプション:このリポジトリが属するグループを選択します"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:38
+#: rhodecode/templates/admin/repos/repo_edit.html:58
+msgid "Type"
+msgstr "リポジトリのタイプ"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:42
+msgid "Type of repository to create."
+msgstr "作成するリポジトリのタイプを指定します"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:47
+#: rhodecode/templates/admin/repos/repo_edit.html:66
+#: rhodecode/templates/forks/fork.html:41
+#: rhodecode/templates/settings/repo_settings.html:57
+msgid "Landing revision"
+msgstr "ランディングリビジョン"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:51
+#: rhodecode/templates/admin/repos/repo_edit.html:70
+#: rhodecode/templates/forks/fork.html:45
+#: rhodecode/templates/settings/repo_settings.html:61
+msgid "Default revision for files page, downloads, whoosh and readme"
+msgstr "ファイルページ、ダウンロード、検索、READMEのデフォルトのリビジョンを指定します"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:60
+#: rhodecode/templates/admin/repos/repo_edit.html:79
+#: rhodecode/templates/forks/fork.html:63
+#: rhodecode/templates/settings/repo_settings.html:70
+msgid "Keep it short and to the point. Use a README file for longer descriptions."
+msgstr "短く要点を絞ってください。長い説明にはREADMEファイルを利用してください。"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:69
+#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/forks/fork.html:72
+#: rhodecode/templates/settings/repo_settings.html:80
+msgid ""
+"Private repositories are only visible to people explicitly added as "
+"collaborators."
+msgstr "非公開リポジトリはコラボレーターとして明示的に追加された人でないと見つけられません"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:73
+msgid "add"
+msgstr "追加"
+
+#: rhodecode/templates/admin/repos/repo_add_create_repository.html:9
+msgid "add new repository"
+msgstr "新しいリポジトリの追加"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:5
+msgid "Edit repository"
+msgstr "リポジトリを編集"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:13
+#: rhodecode/templates/admin/users/user_edit.html:13
+#: rhodecode/templates/admin/users/user_edit.html:224
+#: rhodecode/templates/admin/users/user_edit.html:226
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:13
+#: rhodecode/templates/files/files_source.html:44
+#: rhodecode/templates/journal/journal.html:81
+msgid "edit"
+msgstr "編集"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:40
+#: rhodecode/templates/settings/repo_settings.html:39
+msgid "Clone uri"
+msgstr "クローンURI"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:53
+#: rhodecode/templates/settings/repo_settings.html:52
+msgid "Optional select a group to put this repository into."
+msgstr "オプション: このリポジトリを配置するグループを選択します"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:94
+msgid "Enable statistics"
+msgstr "統計を有効にする"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:98
+msgid "Enable statistics window on summary page."
+msgstr "概要ページの統計ウィンドウを有効にします"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:103
+msgid "Enable downloads"
+msgstr "ダウンロードを有効にする"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:107
+msgid "Enable download menu on summary page."
+msgstr "概要ページのダウンロードメニューを有効にします"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:112
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:66
+#, fuzzy
+msgid "Enable locking"
+msgstr "有効にする"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:116
+msgid "Enable lock-by-pulling on repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:126
+msgid "Change owner of this repository."
+msgstr "リポジトリの所有者を変更"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:142
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:75
+#: rhodecode/templates/admin/settings/settings.html:113
+#: rhodecode/templates/admin/settings/settings.html:168
+#: rhodecode/templates/admin/settings/settings.html:258
+#: rhodecode/templates/admin/users/user_edit.html:130
+#: rhodecode/templates/admin/users/user_edit.html:175
+#: rhodecode/templates/admin/users/user_edit.html:278
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:136
+#: rhodecode/templates/files/files_add.html:82
+#: rhodecode/templates/files/files_edit.html:68
+#: rhodecode/templates/pullrequests/pullrequest.html:124
+#: rhodecode/templates/settings/repo_settings.html:94
+msgid "Reset"
+msgstr "リセット"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:152
+msgid "Administration"
+msgstr "管理"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:155
+msgid "Statistics"
+msgstr "統計"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:159
+msgid "Reset current statistics"
+msgstr "現在の統計情報をリセットする"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:159
+msgid "Confirm to remove current statistics"
+msgstr "現在の統計情報をリセットしてもよろしいですか"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:162
+msgid "Fetched to rev"
+msgstr "収集するリビジョン"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:163
+msgid "Stats gathered"
+msgstr "収集した統計情報"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:171
+msgid "Remote"
+msgstr "リモート"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Pull changes from remote location"
+msgstr "リモートから変更を取り込む"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Confirm to pull changes from remote side"
+msgstr "リモートから変更を取り込んでもよろしいですか?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:186
+msgid "Cache"
+msgstr "キャッシュ"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:190
+msgid "Invalidate repository cache"
+msgstr "リポジトリのキャッシュを無効化"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:190
+msgid "Confirm to invalidate repository cache"
+msgstr "リポジトリのキャッシュを無効化してもよろしいですか?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:195
+#: rhodecode/templates/base/base.html:318
+#: rhodecode/templates/base/base.html:320
+#: rhodecode/templates/base/base.html:322
+msgid "Public journal"
+msgstr "公開ジャーナル"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:201
+msgid "Remove from public journal"
+msgstr "公開ジャーナルから削除する"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:203
+msgid "Add to public journal"
+msgstr "公開ジャーナルに追加する"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:208
+msgid ""
+"All actions made on this repository will be accessible to everyone in "
+"public journal"
+msgstr "公開ジャーナルでは、このリポジトリに対して行った操作のすべてが公開されます"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:215
+#, fuzzy
+msgid "Locking"
+msgstr "変更可能にする"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Unlock locked repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+#, fuzzy
+msgid "Confirm to unlock repository"
+msgstr "このリポジトリを削除しますか?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "lock repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+#, fuzzy
+msgid "Confirm to lock repository"
+msgstr "このリポジトリを削除しますか?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:224
+#, fuzzy
+msgid "Repository is not locked"
+msgstr "リポジトリロケーション"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:229
+msgid "Force locking on repository. Works only when anonymous access is disabled"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:236
+msgid "Set as fork of"
+msgstr "フォーク元の設定"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:245
+msgid "Manually set this repository as a fork of another from the list"
+msgstr "このリポジトリをリスト中の他のリポジトリのフォークとして、手動で設定します"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:251
+#: rhodecode/templates/changeset/changeset_file_comment.html:26
+msgid "Delete"
+msgstr "削除"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+msgid "Remove this repository"
+msgstr "このリポジトリを削除"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+#: rhodecode/templates/journal/journal.html:84
+msgid "Confirm to delete this repository"
+msgstr "このリポジトリを削除しますか?"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:259
+msgid ""
+"This repository will be renamed in a special way in order to be "
+"unaccesible for RhodeCode and VCS systems.\n"
+"                         If you need fully delete it from filesystem "
+"please do it manually"
+msgstr ""
+"このリポジトリはRhodeCodeとVCSシステムからアクセスされないような名前に、特別な方法で変更されます。\n"
+"もし、ファイルシステムから完全に削除したい場合、手動で行ってください"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:3
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3
+msgid "none"
+msgstr "なし"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:4
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4
+msgid "read"
+msgstr "読込"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:5
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5
+msgid "write"
+msgstr "書込"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:6
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6
+#: rhodecode/templates/admin/users/users.html:85
+#: rhodecode/templates/base/base.html:217
+msgid "admin"
+msgstr "管理"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:7
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7
+msgid "member"
+msgstr "メンバー"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
+#: rhodecode/templates/data_table/_dt_elements.html:67
+#: rhodecode/templates/journal/journal.html:132
+#: rhodecode/templates/summary/summary.html:76
+msgid "private repository"
+msgstr "非公開リポジトリ"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:19
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:28
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:18
+msgid "default"
+msgstr "default"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:33
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:58
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:23
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:42
+msgid "revoke"
+msgstr "取消"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:83
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:67
+msgid "Add another member"
+msgstr "別のメンバーを追加"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:97
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81
+msgid "Failed to remove user"
+msgstr "ユーザーの削除に失敗しました"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:112
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:96
+msgid "Failed to remove users group"
+msgstr "ユーザーグループの削除に失敗しました"
+
+#: rhodecode/templates/admin/repos/repos.html:5
+msgid "Repositories administration"
+msgstr "リポジトリ管理"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:8
+msgid "Groups"
+msgstr "グループ"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:12
+msgid "with"
+msgstr "と"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:5
+msgid "Add repos group"
+msgstr "リポジトリグループを追加"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:10
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:10
+msgid "Repos groups"
+msgstr "リポジトリグループ"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:12
+msgid "add new repos group"
+msgstr "新しいリポジトリグループを追加"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:50
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:50
+msgid "Group parent"
+msgstr "親グループ"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:58
+#: rhodecode/templates/admin/users/user_add.html:94
+#: rhodecode/templates/admin/users_groups/users_group_add.html:49
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:90
+#: rhodecode/templates/pullrequests/pullrequest_show.html:113
+msgid "save"
+msgstr "保存"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:5
+msgid "Edit repos group"
+msgstr "リポジトリグループを編集"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:12
+msgid "edit repos group"
+msgstr "リポジトリグループを編集"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:70
+msgid ""
+"Enable lock-by-pulling on group. This option will be applied to all other"
+" groups and repositories inside"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5
+msgid "Repositories groups administration"
+msgstr "リポジトリグループ管理"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:22
+msgid "ADD NEW GROUP"
+msgstr "新しいグループを追加"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:35
+msgid "Number of toplevel repositories"
+msgstr "トップレベルリポジトリの数"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
+#: rhodecode/templates/admin/users/users.html:87
+#: rhodecode/templates/admin/users_groups/users_groups.html:35
+msgid "action"
+msgstr "アクション"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#: rhodecode/templates/admin/users/user_edit.html:255
+#: rhodecode/templates/admin/users_groups/users_groups.html:44
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#: rhodecode/templates/data_table/_dt_elements.html:103
+msgid "delete"
+msgstr "削除"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#, python-format
+msgid "Confirm to delete this group: %s"
+msgstr "グループ %s を削除してもよろしいですか"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:62
+msgid "There are no repositories groups yet"
+msgstr "まだリポジトリグループがありません"
+
+#: rhodecode/templates/admin/settings/hooks.html:5
+#: rhodecode/templates/admin/settings/settings.html:5
+msgid "Settings administration"
+msgstr "設定管理"
+
+#: rhodecode/templates/admin/settings/hooks.html:9
+#: rhodecode/templates/admin/settings/settings.html:9
+#: rhodecode/templates/settings/repo_settings.html:13
+msgid "Settings"
+msgstr "設定"
+
+#: rhodecode/templates/admin/settings/hooks.html:24
+msgid "Built in hooks - read only"
+msgstr "組み込みフック - 読み込み専用"
+
+#: rhodecode/templates/admin/settings/hooks.html:40
+msgid "Custom hooks"
+msgstr "カスタムフック"
+
+#: rhodecode/templates/admin/settings/hooks.html:56
+msgid "remove"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/hooks.html:88
+msgid "Failed to remove hook"
+msgstr "フックの削除に失敗しました"
+
+#: rhodecode/templates/admin/settings/settings.html:24
+msgid "Remap and rescan repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:32
+msgid "rescan option"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:38
+msgid ""
+"In case a repository was deleted from filesystem and there are leftovers "
+"in the database check this option to scan obsolete data in database and "
+"remove it."
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:39
+msgid "destroy old data"
+msgstr "古いデータを削除する"
+
+#: rhodecode/templates/admin/settings/settings.html:41
+msgid ""
+"Rescan repositories location for new repositories. Also deletes obsolete "
+"if `destroy` flag is checked "
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:46
+msgid "Rescan repositories"
+msgstr "リポジトリを再チェック"
+
+#: rhodecode/templates/admin/settings/settings.html:52
+msgid "Whoosh indexing"
+msgstr "Whooshインデックス"
+
+#: rhodecode/templates/admin/settings/settings.html:60
+msgid "index build option"
+msgstr "インデックス作成時の設定"
+
+#: rhodecode/templates/admin/settings/settings.html:65
+msgid "build from scratch"
+msgstr "一度削除してから再度インデックスを作成"
+
+#: rhodecode/templates/admin/settings/settings.html:71
+msgid "Reindex"
+msgstr "再インデックス"
+
+#: rhodecode/templates/admin/settings/settings.html:77
+msgid "Global application settings"
+msgstr "アプリケーション全体の設定"
+
+#: rhodecode/templates/admin/settings/settings.html:86
+msgid "Application name"
+msgstr "アプリケーション名"
+
+#: rhodecode/templates/admin/settings/settings.html:95
+msgid "Realm text"
+msgstr "Realmテキスト"
+
+#: rhodecode/templates/admin/settings/settings.html:104
+msgid "GA code"
+msgstr "GAコード"
+
+#: rhodecode/templates/admin/settings/settings.html:112
+#: rhodecode/templates/admin/settings/settings.html:167
+#: rhodecode/templates/admin/settings/settings.html:257
+msgid "Save settings"
+msgstr "設定を保存"
+
+#: rhodecode/templates/admin/settings/settings.html:119
+#, fuzzy
+msgid "Visualisation settings"
+msgstr "アプリケーション全体の設定"
+
+#: rhodecode/templates/admin/settings/settings.html:128
+#, fuzzy
+msgid "Icons"
+msgstr "オプション"
+
+#: rhodecode/templates/admin/settings/settings.html:133
+msgid "Show public repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:137
+#, fuzzy
+msgid "Show private repo icon on repositories"
+msgstr "非公開リポジトリ"
+
+#: rhodecode/templates/admin/settings/settings.html:144
+#, fuzzy
+msgid "Meta-Tagging"
+msgstr "設定"
+
+#: rhodecode/templates/admin/settings/settings.html:149
+msgid "Stylify recognised metatags:"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:176
+#, fuzzy
+msgid "VCS settings"
+msgstr "設定"
+
+#: rhodecode/templates/admin/settings/settings.html:185
+msgid "Web"
+msgstr "Web"
+
+#: rhodecode/templates/admin/settings/settings.html:190
+#, fuzzy
+msgid "require ssl for vcs operations"
+msgstr "プッシュにSSLを必須とする"
+
+#: rhodecode/templates/admin/settings/settings.html:192
+msgid ""
+"RhodeCode will require SSL for pushing or pulling. If SSL is missing it "
+"will return HTTP Error 406: Not Acceptable"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:198
+msgid "Hooks"
+msgstr "フック"
+
+#: rhodecode/templates/admin/settings/settings.html:203
+msgid "Update repository after push (hg update)"
+msgstr "プッシュ後にリポジトリをを更新する (hg update)"
+
+#: rhodecode/templates/admin/settings/settings.html:207
+msgid "Show repository size after push"
+msgstr "プッシュ後にリポジトリのサイズを表示する"
+
+#: rhodecode/templates/admin/settings/settings.html:211
+msgid "Log user push commands"
+msgstr "ユーザーのプッシュコマンドを記録する"
+
+#: rhodecode/templates/admin/settings/settings.html:215
+msgid "Log user pull commands"
+msgstr "ユーザーのプルコマンドを記録する"
+
+#: rhodecode/templates/admin/settings/settings.html:219
+msgid "advanced setup"
+msgstr "高度な設定"
+
+#: rhodecode/templates/admin/settings/settings.html:224
+#, fuzzy
+msgid "Mercurial Extensions"
+msgstr "Mercurialリポジトリ"
+
+#: rhodecode/templates/admin/settings/settings.html:229
+msgid "largefiles extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:233
+msgid "hgsubversion extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:235
+msgid ""
+"Requires hgsubversion library installed. Allows clonning from svn remote "
+"locations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:245
+msgid "Repositories location"
+msgstr "リポジトリロケーション"
+
+#: rhodecode/templates/admin/settings/settings.html:250
+msgid ""
+"This a crucial application setting. If you are really sure you need to "
+"change this, you must restart application in order to make this setting "
+"take effect. Click this label to unlock."
+msgstr "これはアプリケーションの重要な設定です。本当に変更が必要でしょうか。もし、変更した場合、変更を反映さ競るためにアプリケーションを再起動する必要があります。変更可能にするにはこのラベルをクリックして下さい"
+
+#: rhodecode/templates/admin/settings/settings.html:251
+msgid "unlock"
+msgstr "変更可能にする"
+
+#: rhodecode/templates/admin/settings/settings.html:252
+msgid ""
+"Location where repositories are stored. After changing this value a "
+"restart, and rescan is required"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:272
+msgid "Test Email"
+msgstr "テストメール"
+
+#: rhodecode/templates/admin/settings/settings.html:280
+msgid "Email to"
+msgstr "送信先"
+
+#: rhodecode/templates/admin/settings/settings.html:288
+msgid "Send"
+msgstr "送る"
+
+#: rhodecode/templates/admin/settings/settings.html:294
+msgid "System Info and Packages"
+msgstr "システム情報とパッケージ"
+
+#: rhodecode/templates/admin/settings/settings.html:297
+msgid "show"
+msgstr "表示"
+
+#: rhodecode/templates/admin/users/user_add.html:5
+msgid "Add user"
+msgstr "ユーザーを追加"
+
+#: rhodecode/templates/admin/users/user_add.html:10
+#: rhodecode/templates/admin/users/user_edit.html:11
+msgid "Users"
+msgstr "ユーザー"
+
+#: rhodecode/templates/admin/users/user_add.html:12
+msgid "add new user"
+msgstr "新しいユーザーを追加"
+
+#: rhodecode/templates/admin/users/user_add.html:50
+msgid "Password confirmation"
+msgstr "パスワード再入力"
+
+#: rhodecode/templates/admin/users/user_add.html:86
+#: rhodecode/templates/admin/users/user_edit.html:113
+#: rhodecode/templates/admin/users_groups/users_group_add.html:41
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:42
+msgid "Active"
+msgstr "アクティブ"
+
+#: rhodecode/templates/admin/users/user_edit.html:5
+msgid "Edit user"
+msgstr "ユーザー編集"
+
+#: rhodecode/templates/admin/users/user_edit.html:34
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10
+msgid "Change your avatar at"
+msgstr "アイコンを変えられます : "
+
+#: rhodecode/templates/admin/users/user_edit.html:35
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11
+msgid "Using"
+msgstr "メールアドレス:"
+
+#: rhodecode/templates/admin/users/user_edit.html:43
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20
+msgid "API key"
+msgstr "APIキー"
+
+#: rhodecode/templates/admin/users/user_edit.html:59
+msgid "LDAP DN"
+msgstr "LDAP DN"
+
+#: rhodecode/templates/admin/users/user_edit.html:68
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:35
+msgid "New password"
+msgstr "新しいパスワード"
+
+#: rhodecode/templates/admin/users/user_edit.html:77
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44
+msgid "New password confirmation"
+msgstr "新しいパスワード 再入力"
+
+#: rhodecode/templates/admin/users/user_edit.html:147
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:108
+#, fuzzy
+msgid "Inherit default permissions"
+msgstr "デフォルトの権限"
+
+#: rhodecode/templates/admin/users/user_edit.html:152
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:113
+#, python-format
+msgid ""
+"Select to inherit permissions from %s settings. With this selected below "
+"options does not have any action"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:158
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:119
+msgid "Create repositories"
+msgstr "リポジトリを作成する"
+
+#: rhodecode/templates/admin/users/user_edit.html:166
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:127
+#, fuzzy
+msgid "Fork repositories"
+msgstr "リポジトリ"
+
+#: rhodecode/templates/admin/users/user_edit.html:186
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:22
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:39
+#, fuzzy
+msgid "Nothing here yet"
+msgstr "通知はまだありません"
+
+#: rhodecode/templates/admin/users/user_edit.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account.html:60
+#: rhodecode/templates/admin/users/user_edit_my_account.html:194
+msgid "Permission"
+msgstr "権限"
+
+#: rhodecode/templates/admin/users/user_edit.html:194
+#, fuzzy
+msgid "Edit Permission"
+msgstr "リポジトリの権限"
+
+#: rhodecode/templates/admin/users/user_edit.html:243
+msgid "Email addresses"
+msgstr "メールアドレス"
+
+#: rhodecode/templates/admin/users/user_edit.html:256
+#, python-format
+msgid "Confirm to delete this email: %s"
+msgstr "このメールを削除してよろしいですか: %s"
+
+#: rhodecode/templates/admin/users/user_edit.html:270
+msgid "New email address"
+msgstr "新しいメールアドレス"
+
+#: rhodecode/templates/admin/users/user_edit.html:277
+msgid "Add"
+msgstr "追加"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:5
+#: rhodecode/templates/base/base.html:124
+msgid "My account"
+msgstr "アカウント"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:9
+msgid "My Account"
+msgstr "アカウント"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:35
+msgid "My permissions"
+msgstr "権限"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:38
+#: rhodecode/templates/journal/journal.html:41
+msgid "My repos"
+msgstr "リポジトリ"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:41
+#, fuzzy
+msgid "My pull requests"
+msgstr "すべてのプルリクエスト"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:45
+#, fuzzy
+msgid "Add repo"
+msgstr "新規追加"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2
+msgid "Opened by me"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:10
+#, fuzzy, python-format
+msgid "Pull request #%s opened on %s"
+msgstr "プルリクエスト #%s"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15
+#, fuzzy
+msgid "Confirm to delete this pull request"
+msgstr "このリポジトリを削除しますか?"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:26
+msgid "I participate in"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:33
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:30
+#, python-format
+msgid "Pull request #%s opened by %s on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:7
+#: rhodecode/templates/bookmarks/bookmarks.html:40
+#: rhodecode/templates/bookmarks/bookmarks_data.html:9
+#: rhodecode/templates/branches/branches.html:55
+#: rhodecode/templates/journal/journal.html:60
+#: rhodecode/templates/tags/tags.html:40
+#: rhodecode/templates/tags/tags_data.html:9
+msgid "Revision"
+msgstr "リビジョン"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/journal/journal.html:81
+msgid "private"
+msgstr "非公開"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#, python-format
+msgid "Confirm to delete this repository: %s"
+msgstr "このリポジトリを削除しますか? : %s"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:38
+#: rhodecode/templates/journal/journal.html:94
+msgid "No repositories yet"
+msgstr "まだリポジトリがありません"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:40
+#: rhodecode/templates/journal/journal.html:96
+msgid "create one now"
+msgstr "今すぐ作成する"
+
+#: rhodecode/templates/admin/users/users.html:5
+msgid "Users administration"
+msgstr "ユーザー管理"
+
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/base/base.html:223
+msgid "users"
+msgstr "ユーザー"
+
+#: rhodecode/templates/admin/users/users.html:23
+msgid "ADD NEW USER"
+msgstr "新しいユーザーを追加"
+
+#: rhodecode/templates/admin/users/users.html:77
+msgid "username"
+msgstr "ユーザー名"
+
+#: rhodecode/templates/admin/users/users.html:80
+#, fuzzy
+msgid "firstname"
+msgstr "名前"
+
+#: rhodecode/templates/admin/users/users.html:81
+msgid "lastname"
+msgstr "名字"
+
+#: rhodecode/templates/admin/users/users.html:82
+msgid "last login"
+msgstr "最終ログイン日"
+
+#: rhodecode/templates/admin/users/users.html:84
+#: rhodecode/templates/admin/users_groups/users_groups.html:34
+msgid "active"
+msgstr "アクティブ"
+
+#: rhodecode/templates/admin/users/users.html:86
+#: rhodecode/templates/base/base.html:226
+msgid "ldap"
+msgstr "LDAP"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:5
+msgid "Add users group"
+msgstr "ユーザーグループを追加"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:10
+#: rhodecode/templates/admin/users_groups/users_groups.html:9
+msgid "Users groups"
+msgstr "ユーザーグループ"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:12
+msgid "add new users group"
+msgstr "新しいユーザーグループを追加"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:5
+msgid "Edit users group"
+msgstr "ユーザーグループを編集"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:11
+msgid "UsersGroups"
+msgstr "ユーザーグループ"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:50
+msgid "Members"
+msgstr "メンバー"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:58
+msgid "Choosen group members"
+msgstr "グループメンバーを選ぶ"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:61
+msgid "Remove all elements"
+msgstr "全ての要素を削除"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:75
+msgid "Available members"
+msgstr "有効なメンバー"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:79
+msgid "Add all elements"
+msgstr "全ての要素を追加"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:146
+msgid "Group members"
+msgstr "グループメンバー"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:5
+msgid "Users groups administration"
+msgstr "ユーザーグループ管理"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:23
+msgid "ADD NEW USER GROUP"
+msgstr "新しいユーザーグループを追加"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:32
+msgid "group name"
+msgstr "グループ名"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:33
+#: rhodecode/templates/base/root.html:46
+msgid "members"
+msgstr "メンバー"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:45
+#, python-format
+msgid "Confirm to delete this users group: %s"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:41
+msgid "Submit a bug"
+msgstr "バグレポート"
+
+#: rhodecode/templates/base/base.html:77
+msgid "Login to your account"
+msgstr "ログイン"
+
+#: rhodecode/templates/base/base.html:100
+msgid "Forgot password ?"
+msgstr "パスワードを忘れた場合はこちら"
+
+#: rhodecode/templates/base/base.html:107
+msgid "Log In"
+msgstr "ログイン"
+
+#: rhodecode/templates/base/base.html:118
+msgid "Inbox"
+msgstr "受信箱"
+
+#: rhodecode/templates/base/base.html:122
+#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/base/base.html:302
+#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/bookmarks/bookmarks.html:11
+#: rhodecode/templates/branches/branches.html:10
+#: rhodecode/templates/changelog/changelog.html:10
+#: rhodecode/templates/changeset/changeset.html:10
+#: rhodecode/templates/changeset/changeset_range.html:9
+#: rhodecode/templates/compare/compare_diff.html:9
+#: rhodecode/templates/files/file_diff.html:8
+#: rhodecode/templates/files/files.html:8
+#: rhodecode/templates/files/files_add.html:15
+#: rhodecode/templates/files/files_edit.html:15
+#: rhodecode/templates/followers/followers.html:9
+#: rhodecode/templates/forks/fork.html:9 rhodecode/templates/forks/forks.html:9
+#: rhodecode/templates/pullrequests/pullrequest.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8
+#: rhodecode/templates/settings/repo_settings.html:9
+#: rhodecode/templates/shortlog/shortlog.html:10
+#: rhodecode/templates/summary/summary.html:8
+#: rhodecode/templates/tags/tags.html:11
+msgid "Home"
+msgstr "ホーム"
+
+#: rhodecode/templates/base/base.html:123
+#: rhodecode/templates/base/base.html:309
+#: rhodecode/templates/base/base.html:311
+#: rhodecode/templates/base/base.html:313
+#: rhodecode/templates/journal/journal.html:4
+#: rhodecode/templates/journal/journal.html:21
+#: rhodecode/templates/journal/public_journal.html:4
+msgid "Journal"
+msgstr "ジャーナル"
+
+#: rhodecode/templates/base/base.html:125
+msgid "Log Out"
+msgstr "ログアウト"
+
+#: rhodecode/templates/base/base.html:144
+msgid "Switch repository"
+msgstr "リポジトリの切り替え"
+
+#: rhodecode/templates/base/base.html:146
+msgid "Products"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:152
+#: rhodecode/templates/base/base.html:182
+msgid "loading..."
+msgstr "読み込み中..."
+
+#: rhodecode/templates/base/base.html:158
+#: rhodecode/templates/base/base.html:160
+#: rhodecode/templates/base/base.html:162
+#: rhodecode/templates/data_table/_dt_elements.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:17
+#: rhodecode/templates/data_table/_dt_elements.html:19
+msgid "Summary"
+msgstr "要約"
+
+#: rhodecode/templates/base/base.html:166
+#: rhodecode/templates/base/base.html:168
+#: rhodecode/templates/base/base.html:170
+#: rhodecode/templates/changelog/changelog.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:23
+#: rhodecode/templates/data_table/_dt_elements.html:25
+#: rhodecode/templates/data_table/_dt_elements.html:27
+msgid "Changelog"
+msgstr "履歴"
+
+#: rhodecode/templates/base/base.html:175
+#: rhodecode/templates/base/base.html:177
+#: rhodecode/templates/base/base.html:179
+msgid "Switch to"
+msgstr "ブランチの切り替え"
+
+#: rhodecode/templates/base/base.html:186
+#: rhodecode/templates/base/base.html:188
+#: rhodecode/templates/base/base.html:190
+#: rhodecode/templates/data_table/_dt_elements.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:33
+#: rhodecode/templates/data_table/_dt_elements.html:35
+msgid "Files"
+msgstr "ファイル"
+
+#: rhodecode/templates/base/base.html:195
+#: rhodecode/templates/base/base.html:199
+msgid "Options"
+msgstr "オプション"
+
+#: rhodecode/templates/base/base.html:204
+#: rhodecode/templates/base/base.html:206
+#: rhodecode/templates/base/base.html:227
+msgid "settings"
+msgstr "設定"
+
+#: rhodecode/templates/base/base.html:209
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/forks/fork.html:13
+msgid "fork"
+msgstr "フォーク"
+
+#: rhodecode/templates/base/base.html:211
+#: rhodecode/templates/changelog/changelog.html:40
+msgid "Open new pull request"
+msgstr "新しいプルリクエストを作成"
+
+#: rhodecode/templates/base/base.html:213
+msgid "search"
+msgstr "検索"
+
+#: rhodecode/templates/base/base.html:222
+msgid "repositories groups"
+msgstr "リポジトリグループ"
+
+#: rhodecode/templates/base/base.html:224
+msgid "users groups"
+msgstr "ユーザーグループ"
+
+#: rhodecode/templates/base/base.html:225
+msgid "permissions"
+msgstr "権限"
+
+#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:240
+msgid "Followers"
+msgstr "フォロワー"
+
+#: rhodecode/templates/base/base.html:246
+#: rhodecode/templates/base/base.html:248
+msgid "Forks"
+msgstr "フォーク"
+
+#: rhodecode/templates/base/base.html:327
+#: rhodecode/templates/base/base.html:329
+#: rhodecode/templates/base/base.html:331
+#: rhodecode/templates/search/search.html:52
+msgid "Search"
+msgstr "検索"
+
+#: rhodecode/templates/base/root.html:42
+msgid "add another comment"
+msgstr "別のコメントを追加"
+
+#: rhodecode/templates/base/root.html:43
+#: rhodecode/templates/journal/journal.html:120
+#: rhodecode/templates/summary/summary.html:57
+msgid "Stop following this repository"
+msgstr "このリポジトリのフォローをやめる"
+
+#: rhodecode/templates/base/root.html:44
+#: rhodecode/templates/summary/summary.html:61
+msgid "Start following this repository"
+msgstr "このリポジトリのフォローする"
+
+#: rhodecode/templates/base/root.html:45
+msgid "Group"
+msgstr "グループ"
+
+#: rhodecode/templates/base/root.html:47
+msgid "search truncated"
+msgstr "検索結果は省略されています"
+
+#: rhodecode/templates/base/root.html:48
+msgid "no matching files"
+msgstr "マッチするファイルはありません"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:5
+#, python-format
+msgid "%s Bookmarks"
+msgstr "%s ブックマーク"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:39
+#: rhodecode/templates/bookmarks/bookmarks_data.html:8
+#: rhodecode/templates/branches/branches.html:54
+#: rhodecode/templates/tags/tags.html:39
+#: rhodecode/templates/tags/tags_data.html:8
+msgid "Author"
+msgstr "作成者"
+
+#: rhodecode/templates/branches/branches.html:5
+#, python-format
+msgid "%s Branches"
+msgstr "%s ブランチ"
+
+#: rhodecode/templates/branches/branches.html:29
+msgid "Compare branches"
+msgstr "ブランチの比較"
+
+#: rhodecode/templates/branches/branches.html:57
+#: rhodecode/templates/compare/compare_diff.html:5
+#: rhodecode/templates/compare/compare_diff.html:13
+msgid "Compare"
+msgstr "比較"
+
+#: rhodecode/templates/branches/branches_data.html:6
+msgid "name"
+msgstr "名前"
+
+#: rhodecode/templates/branches/branches_data.html:7
+msgid "date"
+msgstr "日付"
+
+#: rhodecode/templates/branches/branches_data.html:8
+#: rhodecode/templates/shortlog/shortlog_data.html:8
+msgid "author"
+msgstr "作成者"
+
+#: rhodecode/templates/branches/branches_data.html:9
+#: rhodecode/templates/shortlog/shortlog_data.html:5
+msgid "revision"
+msgstr "リビジョン"
+
+#: rhodecode/templates/branches/branches_data.html:10
+msgid "compare"
+msgstr "比較"
+
+#: rhodecode/templates/changelog/changelog.html:6
+#, python-format
+msgid "%s Changelog"
+msgstr "%s チェンジログ"
+
+#: rhodecode/templates/changelog/changelog.html:15
+#, python-format
+msgid "showing %d out of %d revision"
+msgid_plural "showing %d out of %d revisions"
+msgstr[0] ""
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:19
+#, python-format
+msgid "compare fork with %s"
+msgstr "%s とフォークを比較"
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:21
+msgid "Compare fork"
+msgstr "フォークを比較"
+
+#: rhodecode/templates/changelog/changelog.html:46
+msgid "Show"
+msgstr "表示"
+
+#: rhodecode/templates/changelog/changelog.html:72
+#: rhodecode/templates/summary/summary.html:364
+msgid "show more"
+msgstr "もっと表示"
+
+#: rhodecode/templates/changelog/changelog.html:76
+msgid "Affected number of files, click to show more details"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:89
+#: rhodecode/templates/changeset/changeset.html:38
+#: rhodecode/templates/changeset/changeset_file_comment.html:20
+#: rhodecode/templates/changeset/changeset_range.html:46
+msgid "Changeset status"
+msgstr "リビジョンステータス"
+
+#: rhodecode/templates/changelog/changelog.html:92
+msgid "Click to open associated pull request"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:102
+#: rhodecode/templates/changeset/changeset.html:78
+msgid "Parent"
+msgstr "親リビジョン"
+
+#: rhodecode/templates/changelog/changelog.html:108
+#: rhodecode/templates/changeset/changeset.html:84
+msgid "No parents"
+msgstr "親リビジョンはありません"
+
+#: rhodecode/templates/changelog/changelog.html:113
+#: rhodecode/templates/changeset/changeset.html:88
+msgid "merge"
+msgstr "マージ"
+
+#: rhodecode/templates/changelog/changelog.html:116
+#: rhodecode/templates/changeset/changeset.html:91
+#: rhodecode/templates/files/files.html:29
+#: rhodecode/templates/files/files_add.html:33
+#: rhodecode/templates/files/files_edit.html:33
+#: rhodecode/templates/shortlog/shortlog_data.html:9
+msgid "branch"
+msgstr "ブランチ"
+
+#: rhodecode/templates/changelog/changelog.html:122
+msgid "bookmark"
+msgstr "ブックマーク"
+
+#: rhodecode/templates/changelog/changelog.html:128
+#: rhodecode/templates/changeset/changeset.html:96
+msgid "tag"
+msgstr "タグ"
+
+#: rhodecode/templates/changelog/changelog.html:164
+msgid "Show selected changes __S -> __E"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:255
+msgid "There are no changes yet"
+msgstr "まだ変更がありません"
+
+#: rhodecode/templates/changelog/changelog_details.html:4
+#: rhodecode/templates/changeset/changeset.html:66
+msgid "removed"
+msgstr "削除"
+
+#: rhodecode/templates/changelog/changelog_details.html:5
+#: rhodecode/templates/changeset/changeset.html:67
+msgid "changed"
+msgstr "変更"
+
+#: rhodecode/templates/changelog/changelog_details.html:6
+#: rhodecode/templates/changeset/changeset.html:68
+msgid "added"
+msgstr "追加"
+
+#: rhodecode/templates/changelog/changelog_details.html:8
+#: rhodecode/templates/changelog/changelog_details.html:9
+#: rhodecode/templates/changelog/changelog_details.html:10
+#: rhodecode/templates/changeset/changeset.html:70
+#: rhodecode/templates/changeset/changeset.html:71
+#: rhodecode/templates/changeset/changeset.html:72
+#, python-format
+msgid "affected %s files"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset.html:6
+#, python-format
+msgid "%s Changeset"
+msgstr "%s チェンジセット"
+
+#: rhodecode/templates/changeset/changeset.html:14
+msgid "Changeset"
+msgstr "チェンジセット"
+
+#: rhodecode/templates/changeset/changeset.html:43
+#: rhodecode/templates/changeset/diff_block.html:20
+msgid "raw diff"
+msgstr "差分を表示"
+
+#: rhodecode/templates/changeset/changeset.html:44
+#: rhodecode/templates/changeset/diff_block.html:21
+msgid "download diff"
+msgstr "差分をダウンロード"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] "%d コメント"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "(%d inline)"
+msgid_plural "(%d inline)"
+msgstr[0] "(%d インライン)"
+
+#: rhodecode/templates/changeset/changeset.html:103
+#, python-format
+msgid "%s files affected with %s insertions and %s deletions:"
+msgstr "%s ファイルに影響。 %s 個の追加と %s 個の削除:"
+
+#: rhodecode/templates/changeset/changeset.html:119
+msgid "Changeset was too big and was cut off..."
+msgstr "チェンジセットが大きすぎるため、省略しました"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:42
+msgid "Submitting..."
+msgstr "サブミット中..."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:45
+msgid "Commenting on line {1}."
+msgstr "{1} 行目にコメント"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:46
+#: rhodecode/templates/changeset/changeset_file_comment.html:121
+#, python-format
+msgid "Comments parsed using %s syntax with %s support."
+msgstr "コメントには %s 構文 ( %s サポートつき ) が利用出来ます"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:123
+msgid "Use @username inside this text to send notification to this RhodeCode user"
+msgstr "テキスト内で @username を使うと、この RhodeCode のユーザーに通知を送信します"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:59
+#: rhodecode/templates/changeset/changeset_file_comment.html:138
+msgid "Comment"
+msgstr "コメント"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:60
+#: rhodecode/templates/changeset/changeset_file_comment.html:71
+msgid "Hide"
+msgstr "隠す"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "You need to be logged in to comment."
+msgstr "コメントするにはログインが必要です"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "Login now"
+msgstr "今すぐログインする"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:118
+msgid "Leave a comment"
+msgstr "コメントを残す"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "Check this to change current status of code-review for this changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "change status"
+msgstr "ステータスを変更する"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:140
+msgid "Comment and close"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:5
+#, python-format
+msgid "%s Changesets"
+msgstr "%s チェンジセット"
+
+#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/templates/compare/compare_diff.html:29
+msgid "Compare View"
+msgstr "比較ビュー"
+
+#: rhodecode/templates/changeset/changeset_range.html:54
+#: rhodecode/templates/compare/compare_diff.html:41
+#: rhodecode/templates/pullrequests/pullrequest_show.html:69
+msgid "Files affected"
+msgstr ""
+
+#: rhodecode/templates/changeset/diff_block.html:19
+msgid "diff"
+msgstr "差分"
+
+#: rhodecode/templates/changeset/diff_block.html:27
+msgid "show inline comments"
+msgstr "インラインコメントを表示"
+
+#: rhodecode/templates/compare/compare_cs.html:5
+msgid "No changesets"
+msgstr "チェンジセットはありません"
+
+#: rhodecode/templates/compare/compare_diff.html:37
+msgid "Outgoing changesets"
+msgstr "送信可能なチェンジセット"
+
+#: rhodecode/templates/data_table/_dt_elements.html:39
+#: rhodecode/templates/data_table/_dt_elements.html:41
+#: rhodecode/templates/data_table/_dt_elements.html:43
+msgid "Fork"
+msgstr "フォーク"
+
+#: rhodecode/templates/data_table/_dt_elements.html:60
+#: rhodecode/templates/journal/journal.html:126
+#: rhodecode/templates/summary/summary.html:68
+msgid "Mercurial repository"
+msgstr "Mercurialリポジトリ"
+
+#: rhodecode/templates/data_table/_dt_elements.html:62
+#: rhodecode/templates/journal/journal.html:128
+#: rhodecode/templates/summary/summary.html:71
+msgid "Git repository"
+msgstr "Gitリポジトリ"
+
+#: rhodecode/templates/data_table/_dt_elements.html:69
+#: rhodecode/templates/journal/journal.html:134
+#: rhodecode/templates/summary/summary.html:78
+msgid "public repository"
+msgstr "公開リポジトリ"
+
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/summary/summary.html:87
+#: rhodecode/templates/summary/summary.html:88
+msgid "Fork of"
+msgstr "フォーク元: "
+
+#: rhodecode/templates/data_table/_dt_elements.html:92
+msgid "No changesets yet"
+msgstr "まだチェンジセットがありません"
+
+#: rhodecode/templates/data_table/_dt_elements.html:104
+#, python-format
+msgid "Confirm to delete this user: %s"
+msgstr "このユーザーを本当に削除してよろしいですか?: %s"
+
+#: rhodecode/templates/email_templates/main.html:8
+msgid "This is an notification from RhodeCode."
+msgstr "RhodeCodeからの通知があります"
+
+#: rhodecode/templates/errors/error_document.html:46
+#, python-format
+msgid "You will be redirected to %s in %s seconds"
+msgstr ""
+
+#: rhodecode/templates/files/file_diff.html:4
+#, python-format
+msgid "%s File diff"
+msgstr "%s ファイル差分"
+
+#: rhodecode/templates/files/file_diff.html:12
+msgid "File diff"
+msgstr "ファイル差分"
+
+#: rhodecode/templates/files/files.html:4
+#: rhodecode/templates/files/files.html:72
+#, fuzzy, python-format
+msgid "%s files"
+msgstr "%s ファイル"
+
+#: rhodecode/templates/files/files.html:12
+#: rhodecode/templates/summary/summary.html:340
+msgid "files"
+msgstr "ファイル"
+
+#: rhodecode/templates/files/files_add.html:4
+#: rhodecode/templates/files/files_edit.html:4
+#, python-format
+msgid "%s Edit file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:19
+msgid "add file"
+msgstr "ファイルを追加"
+
+#: rhodecode/templates/files/files_add.html:40
+msgid "Add new file"
+msgstr "新しいファイルを追加"
+
+#: rhodecode/templates/files/files_add.html:45
+msgid "File Name"
+msgstr "ファイル名"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:58
+msgid "or"
+msgstr "または"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:54
+msgid "Upload file"
+msgstr "アップロード"
+
+#: rhodecode/templates/files/files_add.html:58
+msgid "Create new file"
+msgstr "新しいファイルを作成"
+
+#: rhodecode/templates/files/files_add.html:63
+#: rhodecode/templates/files/files_edit.html:39
+#: rhodecode/templates/files/files_ypjax.html:3
+msgid "Location"
+msgstr "場所"
+
+#: rhodecode/templates/files/files_add.html:67
+msgid "use / to separate directories"
+msgstr "ディレクトリの区切りには / を使います"
+
+#: rhodecode/templates/files/files_add.html:77
+#: rhodecode/templates/files/files_edit.html:63
+#: rhodecode/templates/shortlog/shortlog_data.html:6
+msgid "commit message"
+msgstr "コミットメッセージ"
+
+#: rhodecode/templates/files/files_add.html:81
+#: rhodecode/templates/files/files_edit.html:67
+msgid "Commit changes"
+msgstr "変更をコミット"
+
+#: rhodecode/templates/files/files_browser.html:13
+msgid "view"
+msgstr "表示"
+
+#: rhodecode/templates/files/files_browser.html:14
+msgid "previous revision"
+msgstr "前のリビジョン"
+
+#: rhodecode/templates/files/files_browser.html:16
+msgid "next revision"
+msgstr "次のリビジョン"
+
+#: rhodecode/templates/files/files_browser.html:23
+msgid "follow current branch"
+msgstr "このブランチで追跡"
+
+#: rhodecode/templates/files/files_browser.html:27
+msgid "search file list"
+msgstr "ファイル一覧を検索"
+
+#: rhodecode/templates/files/files_browser.html:31
+#: rhodecode/templates/shortlog/shortlog_data.html:65
+msgid "add new file"
+msgstr "新しいファイルを追加"
+
+#: rhodecode/templates/files/files_browser.html:35
+msgid "Loading file list..."
+msgstr "ファイル一覧を読み込み中..."
+
+#: rhodecode/templates/files/files_browser.html:48
+msgid "Size"
+msgstr "サイズ"
+
+#: rhodecode/templates/files/files_browser.html:49
+msgid "Mimetype"
+msgstr "Mimetype"
+
+#: rhodecode/templates/files/files_browser.html:50
+msgid "Last Revision"
+msgstr "最後のリビジョン"
+
+#: rhodecode/templates/files/files_browser.html:51
+msgid "Last modified"
+msgstr "最終更新日"
+
+#: rhodecode/templates/files/files_browser.html:52
+msgid "Last commiter"
+msgstr "最後の作成者"
+
+#: rhodecode/templates/files/files_edit.html:19
+msgid "edit file"
+msgstr "ファイルを編集"
+
+#: rhodecode/templates/files/files_edit.html:49
+#: rhodecode/templates/files/files_source.html:38
+msgid "show annotation"
+msgstr "アノテーションを表示"
+
+#: rhodecode/templates/files/files_edit.html:50
+#: rhodecode/templates/files/files_source.html:40
+#: rhodecode/templates/files/files_source.html:68
+msgid "show as raw"
+msgstr "元のファイルを表示"
+
+#: rhodecode/templates/files/files_edit.html:51
+#: rhodecode/templates/files/files_source.html:41
+msgid "download as raw"
+msgstr "元のファイルをダウンロード"
+
+#: rhodecode/templates/files/files_edit.html:54
+msgid "source"
+msgstr "ソース"
+
+#: rhodecode/templates/files/files_edit.html:59
+msgid "Editing file"
+msgstr "ファイルを編集"
+
+#: rhodecode/templates/files/files_source.html:2
+msgid "History"
+msgstr "変更履歴"
+
+#: rhodecode/templates/files/files_source.html:9
+msgid "diff to revision"
+msgstr "このリビジョンの差分を見る"
+
+#: rhodecode/templates/files/files_source.html:10
+msgid "show at revision"
+msgstr "このリビジョンを見る"
+
+#: rhodecode/templates/files/files_source.html:14
+#, python-format
+msgid "%s author"
+msgid_plural "%s authors"
+msgstr[0] "%s 作成者"
+
+#: rhodecode/templates/files/files_source.html:36
+msgid "show source"
+msgstr "ソースを表示"
+
+#: rhodecode/templates/files/files_source.html:59
+#, python-format
+msgid "Binary file (%s)"
+msgstr "バイナリファイル (%s)"
+
+#: rhodecode/templates/files/files_source.html:68
+msgid "File is too big to display"
+msgstr "表示するには大きすぎるファイルです"
+
+#: rhodecode/templates/files/files_source.html:124
+msgid "Selection link"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:5
+msgid "annotation"
+msgstr "アノテーション"
+
+#: rhodecode/templates/files/files_ypjax.html:15
+msgid "Go back"
+msgstr "戻る"
+
+#: rhodecode/templates/files/files_ypjax.html:16
+msgid "No files at given path"
+msgstr "そのパスにはファイルはありません"
+
+#: rhodecode/templates/followers/followers.html:5
+#, python-format
+msgid "%s Followers"
+msgstr "%s フォロワー"
+
+#: rhodecode/templates/followers/followers.html:13
+msgid "followers"
+msgstr "フォロワー"
+
+#: rhodecode/templates/followers/followers_data.html:12
+msgid "Started following -"
+msgstr "フォロー開始日 -"
+
+#: rhodecode/templates/forks/fork.html:5
+#, python-format
+msgid "%s Fork"
+msgstr "%s フォーク"
+
+#: rhodecode/templates/forks/fork.html:31
+msgid "Fork name"
+msgstr "フォーク名"
+
+#: rhodecode/templates/forks/fork.html:68
+msgid "Private"
+msgstr "非公開"
+
+#: rhodecode/templates/forks/fork.html:77
+msgid "Copy permissions"
+msgstr "権限のコピー"
+
+#: rhodecode/templates/forks/fork.html:81
+msgid "Copy permissions from forked repository"
+msgstr "フォーク元リポジトリから権限をコピーします"
+
+#: rhodecode/templates/forks/fork.html:86
+msgid "Update after clone"
+msgstr "クローン後にupdateする"
+
+#: rhodecode/templates/forks/fork.html:90
+msgid "Checkout source after making a clone"
+msgstr "クローンした後にソースをチェックアウトします"
+
+#: rhodecode/templates/forks/fork.html:94
+msgid "fork this repository"
+msgstr "このリポジトリをフォーク"
+
+#: rhodecode/templates/forks/forks.html:5
+#, python-format
+msgid "%s Forks"
+msgstr "%s フォーク"
+
+#: rhodecode/templates/forks/forks.html:13
+msgid "forks"
+msgstr "フォーク"
+
+#: rhodecode/templates/forks/forks_data.html:17
+msgid "forked"
+msgstr "フォークしました"
+
+#: rhodecode/templates/forks/forks_data.html:38
+msgid "There are no forks yet"
+msgstr "まだフォークがありません"
+
+#: rhodecode/templates/journal/journal.html:13
+msgid "ATOM journal feed"
+msgstr "ATOM ジャーナルフィード"
+
+#: rhodecode/templates/journal/journal.html:14
+msgid "RSS journal feed"
+msgstr "RSS ジャーナルフィード"
+
+#: rhodecode/templates/journal/journal.html:24
+#: rhodecode/templates/pullrequests/pullrequest.html:27
+msgid "Refresh"
+msgstr "更新"
+
+#: rhodecode/templates/journal/journal.html:27
+#: rhodecode/templates/journal/public_journal.html:24
+msgid "RSS feed"
+msgstr "RSSフィード"
+
+#: rhodecode/templates/journal/journal.html:30
+#: rhodecode/templates/journal/public_journal.html:27
+msgid "ATOM feed"
+msgstr "ATOMフィード"
+
+#: rhodecode/templates/journal/journal.html:41
+msgid "Watched"
+msgstr "ウォッチ"
+
+#: rhodecode/templates/journal/journal.html:46
+msgid "ADD"
+msgstr "追加"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "following user"
+msgstr "フォローしているユーザー"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "user"
+msgstr "ユーザー"
+
+#: rhodecode/templates/journal/journal.html:147
+msgid "You are not following any users or repositories"
+msgstr "まだどのユーザーもリポジトリもフォローしていません"
+
+#: rhodecode/templates/journal/journal_data.html:47
+msgid "No entries yet"
+msgstr "まだエントリがありません"
+
+#: rhodecode/templates/journal/public_journal.html:13
+msgid "ATOM public journal feed"
+msgstr "ATOM 公開ジャーナルフィード"
+
+#: rhodecode/templates/journal/public_journal.html:14
+msgid "RSS public journal feed"
+msgstr "RSS 公開ジャーナルフィード"
+
+#: rhodecode/templates/journal/public_journal.html:21
+msgid "Public Journal"
+msgstr "公開ジャーナル"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:4
+#: rhodecode/templates/pullrequests/pullrequest.html:12
+msgid "New pull request"
+msgstr "新しいプルリクエスト"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:28
+msgid "refresh overview"
+msgstr "概要の更新"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:66
+msgid "Detailed compare view"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:70
+#: rhodecode/templates/pullrequests/pullrequest_show.html:82
+msgid "Pull request reviewers"
+msgstr "プルリクエストレビュアー"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:79
+#: rhodecode/templates/pullrequests/pullrequest_show.html:94
+#, fuzzy
+msgid "owner"
+msgstr "所有者"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:91
+#: rhodecode/templates/pullrequests/pullrequest_show.html:109
+#, fuzzy
+msgid "Add reviewer to this pull request."
+msgstr "新しいプルリクエスト"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:97
+msgid "Create new pull request"
+msgstr "新しいプルリクエストを作成"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:106
+#: rhodecode/templates/pullrequests/pullrequest_show.html:25
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:33
+msgid "Title"
+msgstr "タイトル"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:115
+msgid "description"
+msgstr "説明"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:123
+msgid "Send pull request"
+msgstr "プルリクエストを送る"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:23
+#, python-format
+msgid "Closed %s"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:31
+#, fuzzy
+msgid "Status"
+msgstr "ステータスを変更する"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:36
+msgid "Pull request status"
+msgstr "プルリクエストステータス"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:44
+#, fuzzy
+msgid "Still not reviewed by"
+msgstr "未レビュー"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:47
+#, fuzzy, python-format
+msgid "%d reviewer"
+msgid_plural "%d reviewers"
+msgstr[0] "レビュー中"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:54
+msgid "Created on"
+msgstr "作成日"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:61
+msgid "Compare view"
+msgstr "比較ビュー"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:65
+msgid "Incoming changesets"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4
+#, fuzzy
+msgid "all pull requests"
+msgstr "すべてのプルリクエスト"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:12
+msgid "All pull requests"
+msgstr "すべてのプルリクエスト"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:27
+msgid "Closed"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:6
+#, python-format
+msgid "Search \"%s\" in repository: %s"
+msgstr "\"%s\" を %s リポジトリから検索"
+
+#: rhodecode/templates/search/search.html:8
+#, python-format
+msgid "Search \"%s\" in all repositories"
+msgstr "\"%s\" を全てのリポジトリから検索"
+
+#: rhodecode/templates/search/search.html:12
+#: rhodecode/templates/search/search.html:32
+#, python-format
+msgid "Search in repository: %s"
+msgstr "%s リポジトリから検索"
+
+#: rhodecode/templates/search/search.html:14
+#: rhodecode/templates/search/search.html:34
+msgid "Search in all repositories"
+msgstr "全てのリポジトリから検索"
+
+#: rhodecode/templates/search/search.html:48
+msgid "Search term"
+msgstr "検索キーワード"
+
+#: rhodecode/templates/search/search.html:60
+msgid "Search in"
+msgstr "検索対象"
+
+#: rhodecode/templates/search/search.html:63
+msgid "File contents"
+msgstr "ファイル内容"
+
+#: rhodecode/templates/search/search.html:64
+#, fuzzy
+msgid "Commit messages"
+msgstr "コミットメッセージ"
+
+#: rhodecode/templates/search/search.html:65
+msgid "File names"
+msgstr "ファイル名"
+
+#: rhodecode/templates/search/search_commit.html:35
+#: rhodecode/templates/search/search_content.html:21
+#: rhodecode/templates/search/search_path.html:15
+msgid "Permission denied"
+msgstr "権限がありません"
+
+#: rhodecode/templates/settings/repo_settings.html:5
+#, python-format
+msgid "%s Settings"
+msgstr "%s 設定"
+
+#: rhodecode/templates/shortlog/shortlog.html:5
+#, python-format
+msgid "%s Shortlog"
+msgstr "%s 短いログ"
+
+#: rhodecode/templates/shortlog/shortlog.html:14
+msgid "shortlog"
+msgstr "ログ"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:7
+msgid "age"
+msgstr "経過時間"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:18
+msgid "No commit message"
+msgstr "コミットメッセージが有りません"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:62
+msgid "Add or upload files directly via RhodeCode"
+msgstr "RhodeCode経由で直接ファイルを追加またはアップロード"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:71
+msgid "Push new repo"
+msgstr "新しいリポジトリをプッシュ"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:79
+msgid "Existing repository?"
+msgstr "存在するリポジトリをプッシュ"
+
+#: rhodecode/templates/summary/summary.html:4
+#, python-format
+msgid "%s Summary"
+msgstr "%s 要約"
+
+#: rhodecode/templates/summary/summary.html:12
+msgid "summary"
+msgstr "要約"
+
+#: rhodecode/templates/summary/summary.html:20
+#, python-format
+msgid "repo %s ATOM feed"
+msgstr "リポジトリ %s ATOM フィード"
+
+#: rhodecode/templates/summary/summary.html:21
+#, python-format
+msgid "repo %s RSS feed"
+msgstr "リポジトリ %s RSS フィード"
+
+#: rhodecode/templates/summary/summary.html:49
+#: rhodecode/templates/summary/summary.html:52
+msgid "ATOM"
+msgstr "ATOM"
+
+#: rhodecode/templates/summary/summary.html:82
+#, python-format
+msgid "Non changable ID %s"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:87
+msgid "public"
+msgstr "公開"
+
+#: rhodecode/templates/summary/summary.html:95
+msgid "remote clone"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:116
+msgid "Contact"
+msgstr "コンタクト"
+
+#: rhodecode/templates/summary/summary.html:130
+msgid "Clone url"
+msgstr "クローンURL"
+
+#: rhodecode/templates/summary/summary.html:133
+msgid "Show by Name"
+msgstr "名前で表示"
+
+#: rhodecode/templates/summary/summary.html:134
+msgid "Show by ID"
+msgstr "IDで表示"
+
+#: rhodecode/templates/summary/summary.html:142
+msgid "Trending files"
+msgstr "トレンドファイル"
+
+#: rhodecode/templates/summary/summary.html:150
+#: rhodecode/templates/summary/summary.html:166
+#: rhodecode/templates/summary/summary.html:194
+msgid "enable"
+msgstr "有効にする"
+
+#: rhodecode/templates/summary/summary.html:158
+msgid "Download"
+msgstr "ダウンロード"
+
+#: rhodecode/templates/summary/summary.html:162
+msgid "There are no downloads yet"
+msgstr "まだダウンロードがありません"
+
+#: rhodecode/templates/summary/summary.html:164
+msgid "Downloads are disabled for this repository"
+msgstr "このリポジトリのダウンロードは無効化されています"
+
+#: rhodecode/templates/summary/summary.html:170
+msgid "Download as zip"
+msgstr "ZIPとしてダウンロード"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "Check this to download archive with subrepos"
+msgstr "チェックするとダウンロードアーカイブにサブリポジトリが含まれます"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "with subrepos"
+msgstr "サブリポジトリを含む"
+
+#: rhodecode/templates/summary/summary.html:186
+msgid "Commit activity by day / author"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:197
+msgid "Stats gathered: "
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:218
+msgid "Shortlog"
+msgstr "ログ"
+
+#: rhodecode/templates/summary/summary.html:220
+msgid "Quick start"
+msgstr "クイックスタート"
+
+#: rhodecode/templates/summary/summary.html:233
+#, python-format
+msgid "Readme file at revision '%s'"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:236
+msgid "Permalink to this readme"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:293
+#, python-format
+msgid "Download %s as %s"
+msgstr "%s を %sとしてダウンロード"
+
+#: rhodecode/templates/summary/summary.html:650
+msgid "commits"
+msgstr "コミット"
+
+#: rhodecode/templates/summary/summary.html:651
+msgid "files added"
+msgstr "追加されたファイル"
+
+#: rhodecode/templates/summary/summary.html:652
+msgid "files changed"
+msgstr "変更されたファイル"
+
+#: rhodecode/templates/summary/summary.html:653
+msgid "files removed"
+msgstr "削除されたファイル"
+
+#: rhodecode/templates/summary/summary.html:656
+msgid "commit"
+msgstr "コミット"
+
+#: rhodecode/templates/summary/summary.html:657
+msgid "file added"
+msgstr "追加されたファイル"
+
+#: rhodecode/templates/summary/summary.html:658
+msgid "file changed"
+msgstr "変更されたファイル"
+
+#: rhodecode/templates/summary/summary.html:659
+msgid "file removed"
+msgstr "削除されたファイル"
+
+#: rhodecode/templates/tags/tags.html:5
+#, python-format
+msgid "%s Tags"
+msgstr "%s タグ"
+
Binary file rhodecode/i18n/pt_BR/LC_MESSAGES/rhodecode.mo has changed
--- a/rhodecode/i18n/pt_BR/LC_MESSAGES/rhodecode.po	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/i18n/pt_BR/LC_MESSAGES/rhodecode.po	Sun Sep 02 21:19:54 2012 +0200
@@ -1,14 +1,14 @@
 # Portuguese (Brazil) translations for RhodeCode.
-# Copyright (C) 2011 Augusto Herrmann
+# Copyright (C) 2011-2012 Augusto Herrmann
 # This file is distributed under the same license as the RhodeCode project.
-# Augusto Herrmann <augusto.herrmann@gmail.com>, 2011.
+# Augusto Herrmann <augusto.herrmann@gmail.com>, 2012.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: RhodeCode 1.2.0\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2011-09-14 15:50-0300\n"
-"PO-Revision-Date: 2011-09-14 15:53-0300\n"
+"POT-Creation-Date: 2012-09-02 20:30+0200\n"
+"PO-Revision-Date: 2012-05-22 16:47-0300\n"
 "Last-Translator: Augusto Herrmann <augusto.herrmann@gmail.com>\n"
 "Language-Team: pt_BR <LL@li.org>\n"
 "Plural-Forms: nplurals=2; plural=(n > 1)\n"
@@ -17,21 +17,38 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: Babel 0.9.6\n"
 
-#: rhodecode/controllers/changeset.py:108
-#: rhodecode/controllers/changeset.py:149
-#: rhodecode/controllers/changeset.py:216
-#: rhodecode/controllers/changeset.py:229
+#: rhodecode/controllers/changelog.py:94
+msgid "All Branches"
+msgstr "Todos os Ramos"
+
+#: rhodecode/controllers/changeset.py:83
+msgid "show white space"
+msgstr "mostrar espaços em branco"
+
+#: rhodecode/controllers/changeset.py:90 rhodecode/controllers/changeset.py:97
+msgid "ignore white space"
+msgstr "ignorar espaços em branco"
+
+#: rhodecode/controllers/changeset.py:157
+#, python-format
+msgid "%s line context"
+msgstr "contexto de %s linhas"
+
+#: rhodecode/controllers/changeset.py:333
+#: rhodecode/controllers/changeset.py:348 rhodecode/lib/diffs.py:70
 msgid "binary file"
 msgstr "arquivo binário"
 
-#: rhodecode/controllers/changeset.py:123
-#: rhodecode/controllers/changeset.py:168
-msgid "Changeset is to big and was cut off, see raw changeset instead"
-msgstr "Conjunto de mudanças é grande demais e foi cortado, em vez disso veja o conjunto de mudanças bruto"
-
-#: rhodecode/controllers/changeset.py:159
-msgid "Diff is to big and was cut off, see raw diff instead"
-msgstr "Diff é grande demais e foi cortado, em vez disso veja diff bruto"
+#: rhodecode/controllers/changeset.py:408
+msgid ""
+"Changing status on a changeset associated witha closed pull request is "
+"not allowed"
+msgstr ""
+
+#: rhodecode/controllers/compare.py:69
+#, fuzzy
+msgid "There are no changesets yet"
+msgstr "Ainda não há alteações"
 
 #: rhodecode/controllers/error.py:69
 msgid "Home page"
@@ -39,7 +56,9 @@
 
 #: rhodecode/controllers/error.py:98
 msgid "The request could not be understood by the server due to malformed syntax."
-msgstr "A requisição não pôde ser compreendida pelo servidor devido à sintaxe mal formada"
+msgstr ""
+"A requisição não pôde ser compreendida pelo servidor devido à sintaxe mal"
+" formada"
 
 #: rhodecode/controllers/error.py:101
 msgid "Unauthorized access to resource"
@@ -54,250 +73,325 @@
 msgstr "O recurso não pôde ser encontrado"
 
 #: rhodecode/controllers/error.py:107
-msgid "The server encountered an unexpected condition which prevented it from fulfilling the request."
-msgstr "O servidor encontrou uma condição inesperada que o impediu de satisfazer a requisição"
-
-#: rhodecode/controllers/feed.py:48
+msgid ""
+"The server encountered an unexpected condition which prevented it from "
+"fulfilling the request."
+msgstr ""
+"O servidor encontrou uma condição inesperada que o impediu de satisfazer "
+"a requisição"
+
+#: rhodecode/controllers/feed.py:49
 #, python-format
 msgid "Changes on %s repository"
 msgstr "Alterações no repositório %s"
 
-#: rhodecode/controllers/feed.py:49
+#: rhodecode/controllers/feed.py:50
 #, python-format
 msgid "%s %s feed"
 msgstr "%s - feed %s"
 
-#: rhodecode/controllers/files.py:72
-msgid "There are no files yet"
-msgstr "Ainda não há arquivos"
-
-#: rhodecode/controllers/files.py:262
+#: rhodecode/controllers/feed.py:75
+#, fuzzy
+msgid "commited on"
+msgstr "commit"
+
+#: rhodecode/controllers/files.py:84
+#, fuzzy
+msgid "click here to add new file"
+msgstr "adicionar novo arquivo"
+
+#: rhodecode/controllers/files.py:85
+#, python-format
+msgid "There are no files yet %s"
+msgstr "Ainda não há arquivos %s"
+
+#: rhodecode/controllers/files.py:239 rhodecode/controllers/files.py:299
+#, python-format
+msgid "This repository is has been locked by %s on %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:266
 #, python-format
 msgid "Edited %s via RhodeCode"
 msgstr "Editado %s via RhodeCode"
 
-#: rhodecode/controllers/files.py:267
-#: rhodecode/templates/files/file_diff.html:40
+#: rhodecode/controllers/files.py:271
 msgid "No changes"
 msgstr "Sem alterações"
 
-#: rhodecode/controllers/files.py:278
+#: rhodecode/controllers/files.py:282 rhodecode/controllers/files.py:346
 #, python-format
 msgid "Successfully committed to %s"
 msgstr "Commit realizado com sucesso para %s"
 
-#: rhodecode/controllers/files.py:283
+#: rhodecode/controllers/files.py:287 rhodecode/controllers/files.py:352
 msgid "Error occurred during commit"
 msgstr "Ocorreu um erro ao realizar commit"
 
-#: rhodecode/controllers/files.py:308
+#: rhodecode/controllers/files.py:318
+#, python-format
+msgid "Added %s via RhodeCode"
+msgstr "Adicionado %s via RhodeCode"
+
+#: rhodecode/controllers/files.py:332
+msgid "No content"
+msgstr "Nenhum conteúdo"
+
+#: rhodecode/controllers/files.py:336
+msgid "No filename"
+msgstr "Nenhum nomes de arquivo"
+
+#: rhodecode/controllers/files.py:378
 msgid "downloads disabled"
 msgstr "downloads desabilitados"
 
-#: rhodecode/controllers/files.py:313
+#: rhodecode/controllers/files.py:389
 #, python-format
 msgid "Unknown revision %s"
 msgstr "Revisão desconhecida %s"
 
-#: rhodecode/controllers/files.py:315
+#: rhodecode/controllers/files.py:391
 msgid "Empty repository"
 msgstr "Repositório vazio"
 
-#: rhodecode/controllers/files.py:317
+#: rhodecode/controllers/files.py:393
 msgid "Unknown archive type"
 msgstr "Arquivo de tipo desconhecido"
 
-#: rhodecode/controllers/files.py:385
-#: rhodecode/controllers/files.py:398
-msgid "Binary file"
-msgstr "Arquivo binário"
-
-#: rhodecode/controllers/files.py:417
-#: rhodecode/templates/changeset/changeset_range.html:4
-#: rhodecode/templates/changeset/changeset_range.html:12
-#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/controllers/files.py:494
+#: rhodecode/templates/changeset/changeset_range.html:13
+#: rhodecode/templates/changeset/changeset_range.html:31
 msgid "Changesets"
 msgstr "Conjuntos de mudanças"
 
-#: rhodecode/controllers/files.py:418
-#: rhodecode/controllers/summary.py:175
-#: rhodecode/templates/branches/branches.html:5
-#: rhodecode/templates/summary/summary.html:690
+#: rhodecode/controllers/files.py:495 rhodecode/controllers/pullrequests.py:72
+#: rhodecode/controllers/summary.py:232 rhodecode/model/scm.py:543
 msgid "Branches"
 msgstr "Ramos"
 
-#: rhodecode/controllers/files.py:419
-#: rhodecode/controllers/summary.py:176
-#: rhodecode/templates/summary/summary.html:679
-#: rhodecode/templates/tags/tags.html:5
+#: rhodecode/controllers/files.py:496 rhodecode/controllers/pullrequests.py:76
+#: rhodecode/controllers/summary.py:233 rhodecode/model/scm.py:554
 msgid "Tags"
 msgstr "Etiquetas"
 
-#: rhodecode/controllers/journal.py:50
+#: rhodecode/controllers/forks.py:73 rhodecode/controllers/admin/repos.py:90
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+"repositório %s não está mapeado ao bd. Talvez ele tenha sido criado ou "
+"renomeado a partir do sistema de arquivos. Por favor execute a aplicação "
+"outra vez para varrer novamente por repositórios"
+
+#: rhodecode/controllers/forks.py:133 rhodecode/controllers/settings.py:72
 #, python-format
-msgid "%s public journal %s feed"
-msgstr "diário público de %s - feed %s"
-
-#: rhodecode/controllers/journal.py:178
-#: rhodecode/controllers/journal.py:212
-#: rhodecode/templates/admin/repos/repo_edit.html:171
-#: rhodecode/templates/base/base.html:50
-msgid "Public journal"
+msgid ""
+"%s repository is not mapped to db perhaps it was created or renamed from "
+"the file system please run the application again in order to rescan "
+"repositories"
+msgstr ""
+"repositório %s não está mapeado ao bd. Talvez ele tenha sido criado ou "
+"renomeado a partir do sistema de arquivos. Por favor execute a aplicação "
+"outra vez para varrer novamente por repositórios"
+
+#: rhodecode/controllers/forks.py:167
+#, python-format
+msgid "forked %s repository as %s"
+msgstr "bifurcado repositório %s como %s"
+
+#: rhodecode/controllers/forks.py:181
+#, python-format
+msgid "An error occurred during repository forking %s"
+msgstr "Ocorreu um erro ao bifurcar o repositório %s"
+
+#: rhodecode/controllers/journal.py:202 rhodecode/controllers/journal.py:239
+#, fuzzy
+msgid "public journal"
 msgstr "Diário público"
 
-#: rhodecode/controllers/login.py:111
+#: rhodecode/controllers/journal.py:206 rhodecode/controllers/journal.py:243
+#: rhodecode/templates/base/base.html:220
+msgid "journal"
+msgstr "diário"
+
+#: rhodecode/controllers/login.py:143
 msgid "You have successfully registered into rhodecode"
 msgstr "Você se registrou com sucesso no rhodecode"
 
-#: rhodecode/controllers/login.py:133
+#: rhodecode/controllers/login.py:164
 msgid "Your password reset link was sent"
 msgstr "Seu link de reinicialização de senha foi enviado"
 
-#: rhodecode/controllers/login.py:155
-msgid "Your password reset was successful, new password has been sent to your email"
-msgstr "Sua reinicialização de senha foi bem sucedida, sua senha foi enviada ao seu e-mail"
-
-#: rhodecode/controllers/search.py:109
+#: rhodecode/controllers/login.py:184
+msgid ""
+"Your password reset was successful, new password has been sent to your "
+"email"
+msgstr ""
+"Sua reinicialização de senha foi bem sucedida, sua senha foi enviada ao "
+"seu e-mail"
+
+#: rhodecode/controllers/pullrequests.py:74 rhodecode/model/scm.py:549
+msgid "Bookmarks"
+msgstr "Marcadores"
+
+#: rhodecode/controllers/pullrequests.py:158
+msgid "Pull request requires a title with min. 3 chars"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:160
+#, fuzzy
+msgid "error during creation of pull request"
+msgstr "ocorreu um erro ao criar o usuário %s"
+
+#: rhodecode/controllers/pullrequests.py:181
+#, fuzzy
+msgid "Successfully opened new pull request"
+msgstr "usuário excluído com sucesso"
+
+#: rhodecode/controllers/pullrequests.py:184
+#, fuzzy
+msgid "Error occurred during sending pull request"
+msgstr "ocorreu um erro ao criar o repositório %s"
+
+#: rhodecode/controllers/pullrequests.py:217
+#, fuzzy
+msgid "Successfully deleted pull request"
+msgstr "usuário excluído com sucesso"
+
+#: rhodecode/controllers/search.py:131
 msgid "Invalid search query. Try quoting it."
 msgstr "Consulta de busca inválida. Tente usar aspas."
 
-#: rhodecode/controllers/search.py:114
+#: rhodecode/controllers/search.py:136
 msgid "There is no index to search in. Please run whoosh indexer"
 msgstr "Não há índice onde pesquisa. Por favor execute o indexador whoosh"
 
-#: rhodecode/controllers/search.py:118
+#: rhodecode/controllers/search.py:140
 msgid "An error occurred during this search operation"
 msgstr "Ocorreu um erro durante essa operação de busca"
 
-#: rhodecode/controllers/settings.py:61
-#: rhodecode/controllers/settings.py:171
-#, python-format
-msgid "%s repository is not mapped to db perhaps it was created or renamed from the file system please run the application again in order to rescan repositories"
-msgstr "repositório %s não está mapeado ao bd. Talvez ele tenha sido criado ou renomeado a partir do sistema de arquivos. Por favor execute a aplicação outra vez para varrer novamente por repositórios"
-
-#: rhodecode/controllers/settings.py:109
-#: rhodecode/controllers/admin/repos.py:239
+#: rhodecode/controllers/settings.py:107
+#: rhodecode/controllers/admin/repos.py:266
 #, python-format
 msgid "Repository %s updated successfully"
 msgstr "Repositório %s atualizado com sucesso"
 
-#: rhodecode/controllers/settings.py:126
-#: rhodecode/controllers/admin/repos.py:257
+#: rhodecode/controllers/settings.py:125
+#: rhodecode/controllers/admin/repos.py:284
 #, python-format
 msgid "error occurred during update of repository %s"
 msgstr "ocorreu um erro ao atualizar o repositório %s"
 
-#: rhodecode/controllers/settings.py:144
-#: rhodecode/controllers/admin/repos.py:275
+#: rhodecode/controllers/settings.py:143
+#: rhodecode/controllers/admin/repos.py:302
 #, python-format
-msgid "%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"
-msgstr "repositório %s não está mapeado ao bd. Talvez ele tenha sido movido ou renomeado a partir do sistema de arquivos. Por favor execute a aplicação outra vez para varrer novamente por repositórios"
-
-#: rhodecode/controllers/settings.py:156
-#: rhodecode/controllers/admin/repos.py:287
+msgid ""
+"%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"
+msgstr ""
+"repositório %s não está mapeado ao bd. Talvez ele tenha sido movido ou "
+"renomeado a partir do sistema de arquivos. Por favor execute a aplicação "
+"outra vez para varrer novamente por repositórios"
+
+#: rhodecode/controllers/settings.py:155
+#: rhodecode/controllers/admin/repos.py:314
 #, python-format
 msgid "deleted repository %s"
 msgstr "excluído o repositório %s"
 
 #: rhodecode/controllers/settings.py:159
-#: rhodecode/controllers/admin/repos.py:297
-#: rhodecode/controllers/admin/repos.py:303
+#: rhodecode/controllers/admin/repos.py:324
+#: rhodecode/controllers/admin/repos.py:330
 #, python-format
 msgid "An error occurred during deletion of %s"
 msgstr "Ocorreu um erro durante a exclusão de %s"
 
-#: rhodecode/controllers/settings.py:193
-#, python-format
-msgid "forked %s repository as %s"
-msgstr "bifurcado repositório %s como %s"
-
-#: rhodecode/controllers/settings.py:211
-#, python-format
-msgid "An error occurred during repository forking %s"
-msgstr "Ocorreu um erro ao bifurcar o repositório %s"
-
-#: rhodecode/controllers/summary.py:123
+#: rhodecode/controllers/summary.py:138
 msgid "No data loaded yet"
 msgstr "Ainda não há dados carregados"
 
-#: rhodecode/controllers/summary.py:126
+#: rhodecode/controllers/summary.py:142
+#: rhodecode/templates/summary/summary.html:148
 msgid "Statistics are disabled for this repository"
 msgstr "As estatísticas estão desabillitadas para este repositório"
 
-#: rhodecode/controllers/admin/ldap_settings.py:49
+#: rhodecode/controllers/admin/ldap_settings.py:50
 msgid "BASE"
 msgstr "BASE"
 
-#: rhodecode/controllers/admin/ldap_settings.py:50
+#: rhodecode/controllers/admin/ldap_settings.py:51
 msgid "ONELEVEL"
 msgstr "UMNÍVEL"
 
-#: rhodecode/controllers/admin/ldap_settings.py:51
+#: rhodecode/controllers/admin/ldap_settings.py:52
 msgid "SUBTREE"
 msgstr "SUBÁRVORE"
 
-#: rhodecode/controllers/admin/ldap_settings.py:55
+#: rhodecode/controllers/admin/ldap_settings.py:56
 msgid "NEVER"
 msgstr "NUNCA"
 
-#: rhodecode/controllers/admin/ldap_settings.py:56
+#: rhodecode/controllers/admin/ldap_settings.py:57
 msgid "ALLOW"
 msgstr "PERMITIR"
 
-#: rhodecode/controllers/admin/ldap_settings.py:57
-msgid "TRY"
-msgstr "TENTAR"
-
 #: rhodecode/controllers/admin/ldap_settings.py:58
-msgid "DEMAND"
-msgstr "EXIGIR"
+msgid "TRY"
+msgstr "TENTAR"
 
 #: rhodecode/controllers/admin/ldap_settings.py:59
+msgid "DEMAND"
+msgstr "EXIGIR"
+
+#: rhodecode/controllers/admin/ldap_settings.py:60
 msgid "HARD"
 msgstr "DIFÍCIL"
 
-#: rhodecode/controllers/admin/ldap_settings.py:63
+#: rhodecode/controllers/admin/ldap_settings.py:64
 msgid "No encryption"
 msgstr "Sem criptografia"
 
-#: rhodecode/controllers/admin/ldap_settings.py:64
+#: rhodecode/controllers/admin/ldap_settings.py:65
 msgid "LDAPS connection"
 msgstr "Conexão LDAPS"
 
-#: rhodecode/controllers/admin/ldap_settings.py:65
+#: rhodecode/controllers/admin/ldap_settings.py:66
 msgid "START_TLS on LDAP connection"
 msgstr "START_TLS na conexão LDAP"
 
-#: rhodecode/controllers/admin/ldap_settings.py:115
+#: rhodecode/controllers/admin/ldap_settings.py:126
 msgid "Ldap settings updated successfully"
 msgstr "Configurações de LDAP atualizadas com sucesso"
 
-#: rhodecode/controllers/admin/ldap_settings.py:120
+#: rhodecode/controllers/admin/ldap_settings.py:130
 msgid "Unable to activate ldap. The \"python-ldap\" library is missing."
 msgstr "Não foi possível ativar LDAP. A biblioteca \"python-ldap\" está faltando."
 
-#: rhodecode/controllers/admin/ldap_settings.py:134
+#: rhodecode/controllers/admin/ldap_settings.py:147
 msgid "error occurred during update of ldap settings"
 msgstr "ocorreu um erro ao atualizar as configurações de LDAP"
 
-#: rhodecode/controllers/admin/permissions.py:56
+#: rhodecode/controllers/admin/permissions.py:59
 msgid "None"
 msgstr "Nenhum"
 
-#: rhodecode/controllers/admin/permissions.py:57
+#: rhodecode/controllers/admin/permissions.py:60
 msgid "Read"
 msgstr "Ler"
 
-#: rhodecode/controllers/admin/permissions.py:58
+#: rhodecode/controllers/admin/permissions.py:61
 msgid "Write"
 msgstr "Gravar"
 
-#: rhodecode/controllers/admin/permissions.py:59
+#: rhodecode/controllers/admin/permissions.py:62
 #: rhodecode/templates/admin/ldap/ldap.html:9
 #: rhodecode/templates/admin/permissions/permissions.html:9
 #: rhodecode/templates/admin/repos/repo_add.html:9
 #: rhodecode/templates/admin/repos/repo_edit.html:9
-#: rhodecode/templates/admin/repos/repos.html:10
+#: rhodecode/templates/admin/repos/repos.html:9
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
@@ -305,547 +399,929 @@
 #: rhodecode/templates/admin/settings/settings.html:9
 #: rhodecode/templates/admin/users/user_add.html:8
 #: rhodecode/templates/admin/users/user_edit.html:9
-#: rhodecode/templates/admin/users/user_edit.html:110
+#: rhodecode/templates/admin/users/user_edit.html:122
 #: rhodecode/templates/admin/users/users.html:9
 #: rhodecode/templates/admin/users_groups/users_group_add.html:8
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:9
 #: rhodecode/templates/admin/users_groups/users_groups.html:9
-#: rhodecode/templates/base/base.html:279
-#: rhodecode/templates/base/base.html:366
-#: rhodecode/templates/base/base.html:368
-#: rhodecode/templates/base/base.html:370
+#: rhodecode/templates/base/base.html:197
+#: rhodecode/templates/base/base.html:337
+#: rhodecode/templates/base/base.html:339
+#: rhodecode/templates/base/base.html:341
 msgid "Admin"
 msgstr "Administrador"
 
-#: rhodecode/controllers/admin/permissions.py:62
+#: rhodecode/controllers/admin/permissions.py:65
 msgid "disabled"
 msgstr "desabilitado"
 
-#: rhodecode/controllers/admin/permissions.py:64
+#: rhodecode/controllers/admin/permissions.py:67
 msgid "allowed with manual account activation"
 msgstr "permitido com ativação manual de conta"
 
-#: rhodecode/controllers/admin/permissions.py:66
+#: rhodecode/controllers/admin/permissions.py:69
 msgid "allowed with automatic account activation"
 msgstr "permitido com ativação automática de conta"
 
-#: rhodecode/controllers/admin/permissions.py:68
+#: rhodecode/controllers/admin/permissions.py:71
+#: rhodecode/controllers/admin/permissions.py:74
 msgid "Disabled"
 msgstr "Desabilitado"
 
-#: rhodecode/controllers/admin/permissions.py:69
+#: rhodecode/controllers/admin/permissions.py:72
+#: rhodecode/controllers/admin/permissions.py:75
 msgid "Enabled"
 msgstr "Habilitado"
 
-#: rhodecode/controllers/admin/permissions.py:102
+#: rhodecode/controllers/admin/permissions.py:116
 msgid "Default permissions updated successfully"
 msgstr "Permissões padrões atualizadas com sucesso"
 
-#: rhodecode/controllers/admin/permissions.py:119
+#: rhodecode/controllers/admin/permissions.py:130
 msgid "error occurred during update of permissions"
 msgstr "ocorreu um erro ao atualizar as permissões"
 
-#: rhodecode/controllers/admin/repos.py:96
-#, python-format
-msgid "%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"
-msgstr "repositório %s não está mapeado ao bd. Talvez ele tenha sido criado ou renomeado a partir do sistema de arquivos. Por favor execute a aplicação outra vez para varrer novamente por repositórios"
-
-#: rhodecode/controllers/admin/repos.py:172
+#: rhodecode/controllers/admin/repos.py:123
+msgid "--REMOVE FORK--"
+msgstr "--REMOVER BIFURCAÇÂO--"
+
+#: rhodecode/controllers/admin/repos.py:192
 #, python-format
 msgid "created repository %s from %s"
 msgstr "repositório %s criado a partir de %s"
 
-#: rhodecode/controllers/admin/repos.py:176
+#: rhodecode/controllers/admin/repos.py:196
 #, python-format
 msgid "created repository %s"
 msgstr "repositório %s criado"
 
-#: rhodecode/controllers/admin/repos.py:205
+#: rhodecode/controllers/admin/repos.py:227
 #, python-format
 msgid "error occurred during creation of repository %s"
 msgstr "ocorreu um erro ao criar o repositório %s"
 
-#: rhodecode/controllers/admin/repos.py:292
+#: rhodecode/controllers/admin/repos.py:319
 #, python-format
 msgid "Cannot delete %s it still contains attached forks"
 msgstr "Nao é possível excluir %s pois ele ainda contém bifurcações vinculadas"
 
-#: rhodecode/controllers/admin/repos.py:320
+#: rhodecode/controllers/admin/repos.py:348
 msgid "An error occurred during deletion of repository user"
 msgstr "Ocorreu um erro ao excluir usuário de repositório"
 
-#: rhodecode/controllers/admin/repos.py:335
+#: rhodecode/controllers/admin/repos.py:367
 msgid "An error occurred during deletion of repository users groups"
 msgstr "Ocorreu um erro ao excluir grupo de usuário de repositório"
 
-#: rhodecode/controllers/admin/repos.py:352
+#: rhodecode/controllers/admin/repos.py:385
 msgid "An error occurred during deletion of repository stats"
 msgstr "Ocorreu um erro ao excluir estatísticas de repositório"
 
-#: rhodecode/controllers/admin/repos.py:367
+#: rhodecode/controllers/admin/repos.py:402
 msgid "An error occurred during cache invalidation"
 msgstr "Ocorreu um erro ao invalidar o cache"
 
-#: rhodecode/controllers/admin/repos.py:387
+#: rhodecode/controllers/admin/repos.py:422
+#, fuzzy
+msgid "An error occurred during unlocking"
+msgstr "Ocorreu um erro durante essa operação"
+
+#: rhodecode/controllers/admin/repos.py:442
 msgid "Updated repository visibility in public journal"
 msgstr "Atualizada a visibilidade do repositório no diário público"
 
-#: rhodecode/controllers/admin/repos.py:390
+#: rhodecode/controllers/admin/repos.py:446
 msgid "An error occurred during setting this repository in public journal"
 msgstr "Ocorreu um erro ao ajustar esse repositório no diário público"
 
-#: rhodecode/controllers/admin/repos.py:395
-#: rhodecode/model/forms.py:53
+#: rhodecode/controllers/admin/repos.py:451 rhodecode/model/validators.py:299
 msgid "Token mismatch"
 msgstr "Descompasso de Token"
 
-#: rhodecode/controllers/admin/repos.py:408
+#: rhodecode/controllers/admin/repos.py:464
 msgid "Pulled from remote location"
 msgstr "Realizado pull de localização remota"
 
-#: rhodecode/controllers/admin/repos.py:410
+#: rhodecode/controllers/admin/repos.py:466
 msgid "An error occurred during pull from remote location"
 msgstr "Ocorreu um erro ao realizar pull de localização remota"
 
-#: rhodecode/controllers/admin/repos_groups.py:83
+#: rhodecode/controllers/admin/repos.py:482
+msgid "Nothing"
+msgstr "Nada"
+
+#: rhodecode/controllers/admin/repos.py:484
+#, python-format
+msgid "Marked repo %s as fork of %s"
+msgstr "Marcado repositório %s como bifurcação de %s"
+
+#: rhodecode/controllers/admin/repos.py:488
+msgid "An error occurred during this operation"
+msgstr "Ocorreu um erro durante essa operação"
+
+#: rhodecode/controllers/admin/repos_groups.py:116
 #, python-format
 msgid "created repos group %s"
 msgstr "criado grupo de repositórios %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:96
+#: rhodecode/controllers/admin/repos_groups.py:129
 #, python-format
 msgid "error occurred during creation of repos group %s"
 msgstr "ccorreu um erro ao criar grupo de repositório %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:130
+#: rhodecode/controllers/admin/repos_groups.py:163
 #, python-format
 msgid "updated repos group %s"
 msgstr "atualizado grupo de repositórios %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:143
+#: rhodecode/controllers/admin/repos_groups.py:176
 #, python-format
 msgid "error occurred during update of repos group %s"
 msgstr "ocorreu um erro ao atualizar grupo de repositórios %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:164
+#: rhodecode/controllers/admin/repos_groups.py:194
 #, python-format
 msgid "This group contains %s repositores and cannot be deleted"
 msgstr "Esse grupo contém %s repositórios e não pode ser excluído"
 
-#: rhodecode/controllers/admin/repos_groups.py:171
+#: rhodecode/controllers/admin/repos_groups.py:202
 #, python-format
 msgid "removed repos group %s"
 msgstr "removido grupo de repositórios %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:175
+#: rhodecode/controllers/admin/repos_groups.py:208
+msgid "Cannot delete this group it still contains subgroups"
+msgstr "Nao é possível excluir este grupo pois ele ainda contém subgrupos"
+
+#: rhodecode/controllers/admin/repos_groups.py:213
+#: rhodecode/controllers/admin/repos_groups.py:218
 #, python-format
 msgid "error occurred during deletion of repos group %s"
 msgstr "ccorreu um erro ao excluir grupo de repositórios %s"
 
-#: rhodecode/controllers/admin/settings.py:109
+#: rhodecode/controllers/admin/repos_groups.py:238
+msgid "An error occurred during deletion of group user"
+msgstr "Ocorreu um erro ao excluir o usuário de grupo"
+
+#: rhodecode/controllers/admin/repos_groups.py:258
+msgid "An error occurred during deletion of group users groups"
+msgstr "Ocorreu um erro ao excluir o grupo do grupo de usuários"
+
+#: rhodecode/controllers/admin/settings.py:121
 #, python-format
 msgid "Repositories successfully rescanned added: %s,removed: %s"
 msgstr "Repositórios varridos com sucesso adicionados: %s, removidos: %s"
 
-#: rhodecode/controllers/admin/settings.py:118
+#: rhodecode/controllers/admin/settings.py:129
 msgid "Whoosh reindex task scheduled"
 msgstr "Tarefa de reindexação do whoosh agendada"
 
-#: rhodecode/controllers/admin/settings.py:143
+#: rhodecode/controllers/admin/settings.py:160
 msgid "Updated application settings"
 msgstr "Configurações da aplicação atualizadas"
 
-#: rhodecode/controllers/admin/settings.py:148
-#: rhodecode/controllers/admin/settings.py:215
+#: rhodecode/controllers/admin/settings.py:164
+#: rhodecode/controllers/admin/settings.py:275
 msgid "error occurred during updating application settings"
 msgstr "ocorreu um erro ao atualizar as configurações da aplicação"
 
-#: rhodecode/controllers/admin/settings.py:210
-msgid "Updated mercurial settings"
+#: rhodecode/controllers/admin/settings.py:200
+#, fuzzy
+msgid "Updated visualisation settings"
+msgstr "Configurações da aplicação atualizadas"
+
+#: rhodecode/controllers/admin/settings.py:205
+#, fuzzy
+msgid "error occurred during updating visualisation settings"
+msgstr "ocorreu um erro ao atualizar as configurações da aplicação"
+
+#: rhodecode/controllers/admin/settings.py:271
+#, fuzzy
+msgid "Updated VCS settings"
 msgstr "Atualizadas as configurações do mercurial"
 
-#: rhodecode/controllers/admin/settings.py:236
+#: rhodecode/controllers/admin/settings.py:285
 msgid "Added new hook"
 msgstr "Adicionado novo gancho"
 
-#: rhodecode/controllers/admin/settings.py:247
+#: rhodecode/controllers/admin/settings.py:297
 msgid "Updated hooks"
 msgstr "Atualizados os ganchos"
 
-#: rhodecode/controllers/admin/settings.py:251
+#: rhodecode/controllers/admin/settings.py:301
 msgid "error occurred during hook creation"
 msgstr "ocorreu um erro ao criar gancho"
 
-#: rhodecode/controllers/admin/settings.py:310
+#: rhodecode/controllers/admin/settings.py:320
+msgid "Email task created"
+msgstr "Tarefa de e-mail criada"
+
+#: rhodecode/controllers/admin/settings.py:375
 msgid "You can't edit this user since it's crucial for entire application"
 msgstr "Você não pode editar esse usuário pois ele é crucial para toda a aplicação"
 
-#: rhodecode/controllers/admin/settings.py:339
+#: rhodecode/controllers/admin/settings.py:406
 msgid "Your account was updated successfully"
 msgstr "Sua conta foi atualizada com sucesso"
 
-#: rhodecode/controllers/admin/settings.py:359
-#: rhodecode/controllers/admin/users.py:130
+#: rhodecode/controllers/admin/settings.py:421
+#: rhodecode/controllers/admin/users.py:191
 #, python-format
 msgid "error occurred during update of user %s"
 msgstr "ocorreu um erro ao atualizar o usuário %s"
 
-#: rhodecode/controllers/admin/users.py:78
+#: rhodecode/controllers/admin/users.py:130
 #, python-format
 msgid "created user %s"
 msgstr "usuário %s criado"
 
-#: rhodecode/controllers/admin/users.py:90
+#: rhodecode/controllers/admin/users.py:142
 #, python-format
 msgid "error occurred during creation of user %s"
 msgstr "ocorreu um erro ao criar o usuário %s"
 
-#: rhodecode/controllers/admin/users.py:116
+#: rhodecode/controllers/admin/users.py:171
 msgid "User updated successfully"
 msgstr "Usuário atualizado com sucesso"
 
-#: rhodecode/controllers/admin/users.py:146
+#: rhodecode/controllers/admin/users.py:207
 msgid "successfully deleted user"
 msgstr "usuário excluído com sucesso"
 
-#: rhodecode/controllers/admin/users.py:150
+#: rhodecode/controllers/admin/users.py:212
 msgid "An error occurred during deletion of user"
 msgstr "Ocorreu um erro ao excluir o usuário"
 
-#: rhodecode/controllers/admin/users.py:166
+#: rhodecode/controllers/admin/users.py:226
 msgid "You can't edit this user"
 msgstr "Você não pode editar esse usuário"
 
-#: rhodecode/controllers/admin/users.py:195
-#: rhodecode/controllers/admin/users_groups.py:202
+#: rhodecode/controllers/admin/users.py:266
 msgid "Granted 'repository create' permission to user"
 msgstr "Concedida permissão de 'criar repositório' ao usuário"
 
-#: rhodecode/controllers/admin/users.py:204
-#: rhodecode/controllers/admin/users_groups.py:211
+#: rhodecode/controllers/admin/users.py:271
 msgid "Revoked 'repository create' permission to user"
 msgstr "Revogada permissão de 'criar repositório' ao usuário"
 
-#: rhodecode/controllers/admin/users_groups.py:74
+#: rhodecode/controllers/admin/users.py:277
+#, fuzzy
+msgid "Granted 'repository fork' permission to user"
+msgstr "Concedida permissão de 'criar repositório' ao usuário"
+
+#: rhodecode/controllers/admin/users.py:282
+#, fuzzy
+msgid "Revoked 'repository fork' permission to user"
+msgstr "Revogada permissão de 'criar repositório' ao usuário"
+
+#: rhodecode/controllers/admin/users.py:288
+#: rhodecode/controllers/admin/users_groups.py:255
+#, fuzzy
+msgid "An error occurred during permissions saving"
+msgstr "Ocorreu um erro durante essa operação"
+
+#: rhodecode/controllers/admin/users.py:303
+#, python-format
+msgid "Added email %s to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:309
+#, fuzzy
+msgid "An error occurred during email saving"
+msgstr "Ocorreu um erro durante essa operação"
+
+#: rhodecode/controllers/admin/users.py:319
+#, fuzzy
+msgid "Removed email from user"
+msgstr "removido grupo de repositórios %s"
+
+#: rhodecode/controllers/admin/users_groups.py:84
 #, python-format
 msgid "created users group %s"
 msgstr "criado grupo de usuários %s"
 
-#: rhodecode/controllers/admin/users_groups.py:86
+#: rhodecode/controllers/admin/users_groups.py:95
 #, python-format
 msgid "error occurred during creation of users group %s"
 msgstr "ocorreu um erro ao criar o grupo de usuários %s"
 
-#: rhodecode/controllers/admin/users_groups.py:119
+#: rhodecode/controllers/admin/users_groups.py:135
 #, python-format
 msgid "updated users group %s"
 msgstr "grupo de usuários %s atualizado"
 
-#: rhodecode/controllers/admin/users_groups.py:138
+#: rhodecode/controllers/admin/users_groups.py:157
 #, python-format
 msgid "error occurred during update of users group %s"
 msgstr "ocorreu um erro ao atualizar o grupo de usuários %s"
 
-#: rhodecode/controllers/admin/users_groups.py:154
+#: rhodecode/controllers/admin/users_groups.py:174
 msgid "successfully deleted users group"
 msgstr "grupo de usuários excluído com sucesso"
 
-#: rhodecode/controllers/admin/users_groups.py:158
+#: rhodecode/controllers/admin/users_groups.py:179
 msgid "An error occurred during deletion of users group"
 msgstr "Ocorreu um erro ao excluir o grupo de usuários"
 
-#: rhodecode/lib/__init__.py:279
-msgid "year"
-msgstr "ano"
-
-#: rhodecode/lib/__init__.py:280
-msgid "month"
-msgstr "mês"
-
-#: rhodecode/lib/__init__.py:281
-msgid "day"
-msgstr "dia"
-
-#: rhodecode/lib/__init__.py:282
-msgid "hour"
-msgstr "hora"
-
-#: rhodecode/lib/__init__.py:283
-msgid "minute"
-msgstr "minuto"
-
-#: rhodecode/lib/__init__.py:284
-msgid "second"
-msgstr "segundo"
-
-#: rhodecode/lib/__init__.py:293
-msgid "ago"
-msgstr "atrás"
-
-#: rhodecode/lib/__init__.py:296
-msgid "just now"
-msgstr "agora há pouco"
-
-#: rhodecode/lib/auth.py:377
+#: rhodecode/controllers/admin/users_groups.py:233
+#, fuzzy
+msgid "Granted 'repository create' permission to users group"
+msgstr "Concedida permissão de 'criar repositório' ao usuário"
+
+#: rhodecode/controllers/admin/users_groups.py:238
+#, fuzzy
+msgid "Revoked 'repository create' permission to users group"
+msgstr "Revogada permissão de 'criar repositório' ao usuário"
+
+#: rhodecode/controllers/admin/users_groups.py:244
+#, fuzzy
+msgid "Granted 'repository fork' permission to users group"
+msgstr "Concedida permissão de 'criar repositório' ao usuário"
+
+#: rhodecode/controllers/admin/users_groups.py:249
+#, fuzzy
+msgid "Revoked 'repository fork' permission to users group"
+msgstr "Revogada permissão de 'criar repositório' ao usuário"
+
+#: rhodecode/lib/auth.py:499
 msgid "You need to be a registered user to perform this action"
 msgstr "Você precisa ser um usuário registrado para realizar essa ação"
 
-#: rhodecode/lib/auth.py:421
+#: rhodecode/lib/auth.py:540
 msgid "You need to be a signed in to view this page"
 msgstr "Você precisa estar logado para ver essa página"
 
-#: rhodecode/lib/helpers.py:307
+#: rhodecode/lib/diffs.py:86
+msgid "Changeset was too big and was cut off, use diff menu to display this diff"
+msgstr ""
+"Conjunto de mudanças é grande demais e foi cortado, use o menu de "
+"diferenças para ver as diferenças"
+
+#: rhodecode/lib/diffs.py:96
+msgid "No changes detected"
+msgstr "Nenhuma alteração detectada"
+
+#: rhodecode/lib/helpers.py:372
+#, python-format
+msgid "%a, %d %b %Y %H:%M:%S"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:484
 msgid "True"
 msgstr "Verdadeiro"
 
-#: rhodecode/lib/helpers.py:311
+#: rhodecode/lib/helpers.py:488
 msgid "False"
 msgstr "Falso"
 
-#: rhodecode/lib/helpers.py:352
+#: rhodecode/lib/helpers.py:532
+msgid "Changeset not found"
+msgstr "Conjunto de alterações não encontrado"
+
+#: rhodecode/lib/helpers.py:555
 #, python-format
 msgid "Show all combined changesets %s->%s"
 msgstr "Ver todos os conjuntos de mudanças combinados %s->%s"
 
-#: rhodecode/lib/helpers.py:356
+#: rhodecode/lib/helpers.py:561
 msgid "compare view"
 msgstr "comparar exibir"
 
-#: rhodecode/lib/helpers.py:365
+#: rhodecode/lib/helpers.py:581
 msgid "and"
 msgstr "e"
 
-#: rhodecode/lib/helpers.py:365
+#: rhodecode/lib/helpers.py:582
 #, python-format
 msgid "%s more"
 msgstr "%s mais"
 
-#: rhodecode/lib/helpers.py:367
-#: rhodecode/templates/changelog/changelog.html:14
-#: rhodecode/templates/changelog/changelog.html:39
+#: rhodecode/lib/helpers.py:583 rhodecode/templates/changelog/changelog.html:48
 msgid "revisions"
 msgstr "revisões"
 
-#: rhodecode/lib/helpers.py:385
+#: rhodecode/lib/helpers.py:606
 msgid "fork name "
 msgstr "nome da bifurcação"
 
-#: rhodecode/lib/helpers.py:388
+#: rhodecode/lib/helpers.py:620
+#: rhodecode/templates/pullrequests/pullrequest_show.html:4
+#: rhodecode/templates/pullrequests/pullrequest_show.html:12
+#, python-format
+msgid "Pull request #%s"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:626
 msgid "[deleted] repository"
 msgstr "repositório [excluído]"
 
-#: rhodecode/lib/helpers.py:389
-#: rhodecode/lib/helpers.py:393
+#: rhodecode/lib/helpers.py:628 rhodecode/lib/helpers.py:638
 msgid "[created] repository"
 msgstr "repositório [criado]"
 
-#: rhodecode/lib/helpers.py:390
-#: rhodecode/lib/helpers.py:394
+#: rhodecode/lib/helpers.py:630
+msgid "[created] repository as fork"
+msgstr "repositório [criado] como uma bifurcação"
+
+#: rhodecode/lib/helpers.py:632 rhodecode/lib/helpers.py:640
 msgid "[forked] repository"
 msgstr "repositório [bifurcado]"
 
-#: rhodecode/lib/helpers.py:391
-#: rhodecode/lib/helpers.py:395
+#: rhodecode/lib/helpers.py:634 rhodecode/lib/helpers.py:642
 msgid "[updated] repository"
 msgstr "repositório [atualizado]"
 
-#: rhodecode/lib/helpers.py:392
+#: rhodecode/lib/helpers.py:636
 msgid "[delete] repository"
 msgstr "[excluir] repositório"
 
-#: rhodecode/lib/helpers.py:396
+#: rhodecode/lib/helpers.py:644
+#, fuzzy
+msgid "[created] user"
+msgstr "usuário %s criado"
+
+#: rhodecode/lib/helpers.py:646
+#, fuzzy
+msgid "[updated] user"
+msgstr "grupo de usuários %s atualizado"
+
+#: rhodecode/lib/helpers.py:648
+#, fuzzy
+msgid "[created] users group"
+msgstr "criado grupo de usuários %s"
+
+#: rhodecode/lib/helpers.py:650
+#, fuzzy
+msgid "[updated] users group"
+msgstr "grupo de usuários %s atualizado"
+
+#: rhodecode/lib/helpers.py:652
+#, fuzzy
+msgid "[commented] on revision in repository"
+msgstr "repositório [criado]"
+
+#: rhodecode/lib/helpers.py:654
+#, fuzzy
+msgid "[commented] on pull request for"
+msgstr "repositório [criado]"
+
+#: rhodecode/lib/helpers.py:656
+#, fuzzy
+msgid "[closed] pull request for"
+msgstr "repositório [criado]"
+
+#: rhodecode/lib/helpers.py:658
 msgid "[pushed] into"
 msgstr "[realizado push] para"
 
-#: rhodecode/lib/helpers.py:397
-msgid "[committed via RhodeCode] into"
+#: rhodecode/lib/helpers.py:660
+#, fuzzy
+msgid "[committed via RhodeCode] into repository"
 msgstr "[realizado commit via RhodeCode] para"
 
-#: rhodecode/lib/helpers.py:398
-msgid "[pulled from remote] into"
+#: rhodecode/lib/helpers.py:662
+#, fuzzy
+msgid "[pulled from remote] into repository"
 msgstr "[realizado pull remoto] para"
 
-#: rhodecode/lib/helpers.py:399
+#: rhodecode/lib/helpers.py:664
 msgid "[pulled] from"
 msgstr "[realizado pull] a partir de"
 
-#: rhodecode/lib/helpers.py:400
+#: rhodecode/lib/helpers.py:666
 msgid "[started following] repository"
 msgstr "[passou a seguir] o repositório"
 
-#: rhodecode/lib/helpers.py:401
+#: rhodecode/lib/helpers.py:668
 msgid "[stopped following] repository"
 msgstr "[parou de seguir] o repositório"
 
-#: rhodecode/lib/helpers.py:577
+#: rhodecode/lib/helpers.py:840
 #, python-format
 msgid " and %s more"
 msgstr " e mais %s"
 
-#: rhodecode/lib/helpers.py:581
+#: rhodecode/lib/helpers.py:844
 msgid "No Files"
 msgstr "Nenhum Arquivo"
 
-#: rhodecode/model/forms.py:66
-msgid "Invalid username"
-msgstr "Nome de usuário inválido"
-
-#: rhodecode/model/forms.py:75
-msgid "This username already exists"
-msgstr "Esse nome de usuário já existe"
-
-#: rhodecode/model/forms.py:79
-msgid "Username may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character"
-msgstr "Nome de usuário pode conter somente caracteres alfanuméricos, sublinha, pontos e hífens e deve iniciar com caractere alfanumérico"
-
-#: rhodecode/model/forms.py:94
-msgid "Invalid group name"
-msgstr "Nome de grupo inválido"
-
-#: rhodecode/model/forms.py:104
-msgid "This users group already exists"
-msgstr "Esse grupo de usuários já existe"
-
-#: rhodecode/model/forms.py:110
-msgid "Group name may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character"
-msgstr "Nome de grupo pode conter somente caracteres alfanuméricos, sublinha, pontos e hífens e deve iniciar com caractere alfanumérico"
-
-#: rhodecode/model/forms.py:132
-msgid "Cannot assign this group as parent"
-msgstr "Não é possível associar esse grupo como progenitor"
-
-#: rhodecode/model/forms.py:148
-msgid "This group already exists"
-msgstr "Esse grupo já existe"
-
-#: rhodecode/model/forms.py:164
-#: rhodecode/model/forms.py:172
-#: rhodecode/model/forms.py:180
-msgid "Invalid characters in password"
-msgstr "Caracteres inválidos na senha"
-
-#: rhodecode/model/forms.py:191
-msgid "Passwords do not match"
-msgstr "Senhas não conferem"
-
-#: rhodecode/model/forms.py:196
-msgid "invalid password"
-msgstr "senha inválida"
-
-#: rhodecode/model/forms.py:197
-msgid "invalid user name"
-msgstr "nome de usuário inválido"
-
-#: rhodecode/model/forms.py:198
-msgid "Your account is disabled"
-msgstr "Sua conta está desabilitada"
-
-#: rhodecode/model/forms.py:233
-msgid "This username is not valid"
-msgstr "Esse nome de usuário não é válido"
-
-#: rhodecode/model/forms.py:245
-msgid "This repository name is disallowed"
-msgstr "Esse nome de repositório não é permitido"
-
-#: rhodecode/model/forms.py:266
+#: rhodecode/lib/utils2.py:335
+#, python-format
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] "%d ano"
+msgstr[1] "%d anos"
+
+#: rhodecode/lib/utils2.py:336
+#, python-format
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] "%d mês"
+msgstr[1] "%d meses"
+
+#: rhodecode/lib/utils2.py:337
+#, python-format
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] "%d dia"
+msgstr[1] "%d dias"
+
+#: rhodecode/lib/utils2.py:338
+#, python-format
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] "%d hora"
+msgstr[1] "%d horas"
+
+#: rhodecode/lib/utils2.py:339
+#, python-format
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] "%d minuto"
+msgstr[1] "%d minutos"
+
+#: rhodecode/lib/utils2.py:340
+#, python-format
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] "%d segundo"
+msgstr[1] "%d segundos"
+
+#: rhodecode/lib/utils2.py:355
+#, python-format
+msgid "%s ago"
+msgstr "%s atrás"
+
+#: rhodecode/lib/utils2.py:357
+#, python-format
+msgid "%s and %s ago"
+msgstr "%s e %s atrás"
+
+#: rhodecode/lib/utils2.py:360
+msgid "just now"
+msgstr "agora há pouco"
+
+#: rhodecode/lib/celerylib/tasks.py:269
+msgid "password reset link"
+msgstr "link de reinicialização de senha"
+
+#: rhodecode/model/comment.py:110
 #, python-format
-msgid "This repository already exists in group \"%s\""
-msgstr "Esse repositório já existe no grupo \"%s\""
-
-#: rhodecode/model/forms.py:274
-msgid "This repository already exists"
+msgid "on line %s"
+msgstr "na linha %s"
+
+#: rhodecode/model/comment.py:157
+msgid "[Mention]"
+msgstr "[Menção]"
+
+#: rhodecode/model/db.py:1140
+#, fuzzy
+msgid "Repository no access"
+msgstr "repositórios"
+
+#: rhodecode/model/db.py:1141
+#, fuzzy
+msgid "Repository read access"
 msgstr "Esse repositório já existe"
 
-#: rhodecode/model/forms.py:312
-#: rhodecode/model/forms.py:319
-msgid "invalid clone url"
-msgstr "URL de clonagem inválida"
-
-#: rhodecode/model/forms.py:322
-msgid "Invalid clone url, provide a valid clone http\\s url"
-msgstr "URL de clonagem inválida, forneça uma URL válida de clonagem http\\s"
-
-#: rhodecode/model/forms.py:334
-msgid "Fork have to be the same type as original"
-msgstr "Bifurcação precisa ser do mesmo tipo que o original"
-
-#: rhodecode/model/forms.py:341
-msgid "This username or users group name is not valid"
-msgstr "Esse nome de usuário ou nome de grupo de usuários não é válido"
-
-#: rhodecode/model/forms.py:403
-msgid "This is not a valid path"
-msgstr "Esse não é um caminho válido"
-
-#: rhodecode/model/forms.py:416
-msgid "This e-mail address is already taken"
-msgstr "Esse endereço de e-mail já está tomado"
-
-#: rhodecode/model/forms.py:427
-msgid "This e-mail address doesn't exist."
-msgstr "Esse endereço de e-mail não existe."
-
-#: rhodecode/model/forms.py:447
-msgid "The LDAP Login attribute of the CN must be specified - this is the name of the attribute that is equivalent to 'username'"
-msgstr "O atributo de login LDAP do CN deve ser especificado - isto é o nome do atributo que é equivalente ao 'nome de usuário'"
-
-#: rhodecode/model/forms.py:466
+#: rhodecode/model/db.py:1142
+#, fuzzy
+msgid "Repository write access"
+msgstr "repositórios"
+
+#: rhodecode/model/db.py:1143
+#, fuzzy
+msgid "Repository admin access"
+msgstr "repositórios"
+
+#: rhodecode/model/db.py:1145
+#, fuzzy
+msgid "Repositories Group no access"
+msgstr "grupos de repositórios"
+
+#: rhodecode/model/db.py:1146
+#, fuzzy
+msgid "Repositories Group read access"
+msgstr "grupos de repositórios"
+
+#: rhodecode/model/db.py:1147
+#, fuzzy
+msgid "Repositories Group write access"
+msgstr "grupos de repositórios"
+
+#: rhodecode/model/db.py:1148
+#, fuzzy
+msgid "Repositories Group admin access"
+msgstr "grupos de repositórios"
+
+#: rhodecode/model/db.py:1150
+#, fuzzy
+msgid "RhodeCode Administrator"
+msgstr "Administração de usuários"
+
+#: rhodecode/model/db.py:1151
+#, fuzzy
+msgid "Repository creation disabled"
+msgstr "Criação de repositório"
+
+#: rhodecode/model/db.py:1152
+#, fuzzy
+msgid "Repository creation enabled"
+msgstr "Criação de repositório"
+
+#: rhodecode/model/db.py:1153
+#, fuzzy
+msgid "Repository forking disabled"
+msgstr "Criação de repositório"
+
+#: rhodecode/model/db.py:1154
+#, fuzzy
+msgid "Repository forking enabled"
+msgstr "Criação de repositório"
+
+#: rhodecode/model/db.py:1155
+#, fuzzy
+msgid "Register disabled"
+msgstr "desabilitado"
+
+#: rhodecode/model/db.py:1156
+msgid "Register new user with RhodeCode with manual activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1159
+msgid "Register new user with RhodeCode with auto activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1579
+msgid "Not Reviewed"
+msgstr ""
+
+#: rhodecode/model/db.py:1580
+#, fuzzy
+msgid "Approved"
+msgstr "removidos"
+
+#: rhodecode/model/db.py:1581
+msgid "Rejected"
+msgstr ""
+
+#: rhodecode/model/db.py:1582
+msgid "Under Review"
+msgstr ""
+
+#: rhodecode/model/forms.py:43
 msgid "Please enter a login"
 msgstr "Por favor entre um login"
 
-#: rhodecode/model/forms.py:467
+#: rhodecode/model/forms.py:44
 #, python-format
 msgid "Enter a value %(min)i characters long or more"
 msgstr "Entre um valor com %(min)i caracteres ou mais"
 
-#: rhodecode/model/forms.py:475
+#: rhodecode/model/forms.py:52
 msgid "Please enter a password"
 msgstr "Por favor entre com uma senha"
 
-#: rhodecode/model/forms.py:476
+#: rhodecode/model/forms.py:53
 #, python-format
 msgid "Enter %(min)i characters or more"
 msgstr "Entre com %(min)i caracteres ou mais"
 
-#: rhodecode/model/user.py:145
-msgid "[RhodeCode] New User registration"
-msgstr "[RhodeCode] Registro de Novo Usuário"
-
-#: rhodecode/model/user.py:157
-#: rhodecode/model/user.py:179
+#: rhodecode/model/notification.py:220
+msgid "commented on commit"
+msgstr "comentado no commit"
+
+#: rhodecode/model/notification.py:221
+msgid "sent message"
+msgstr "mensagem enviada"
+
+#: rhodecode/model/notification.py:222
+msgid "mentioned you"
+msgstr "mencionou você"
+
+#: rhodecode/model/notification.py:223
+msgid "registered in RhodeCode"
+msgstr "registrado no RhodeCode"
+
+#: rhodecode/model/notification.py:224
+msgid "opened new pull request"
+msgstr ""
+
+#: rhodecode/model/notification.py:225
+#, fuzzy
+msgid "commented on pull request"
+msgstr "comentado no commit"
+
+#: rhodecode/model/pull_request.py:84
+#, python-format
+msgid "%(user)s wants you to review pull request #%(pr_id)s"
+msgstr ""
+
+#: rhodecode/model/scm.py:535
+#, fuzzy
+msgid "latest tip"
+msgstr "último login"
+
+#: rhodecode/model/user.py:230
+msgid "new user registration"
+msgstr "registro de novo usuário"
+
+#: rhodecode/model/user.py:255 rhodecode/model/user.py:277
+#: rhodecode/model/user.py:299
 msgid "You can't Edit this user since it's crucial for entire application"
-msgstr "Você não pode Editar esse usuário, pois ele é crucial para toda a aplicação"
-
-#: rhodecode/model/user.py:201
+msgstr ""
+"Você não pode Editar esse usuário, pois ele é crucial para toda a "
+"aplicação"
+
+#: rhodecode/model/user.py:323
 msgid "You can't remove this user since it's crucial for entire application"
-msgstr "Você não pode remover esse usuário, pois ele é crucial para toda a aplicação"
-
-#: rhodecode/model/user.py:204
+msgstr ""
+"Você não pode remover esse usuário, pois ele é crucial para toda a "
+"aplicação"
+
+#: rhodecode/model/user.py:329
+#, python-format
+msgid ""
+"user \"%s\" still owns %s repositories and cannot be removed. Switch "
+"owners or remove those repositories. %s"
+msgstr ""
+"usuário \"%s\" ainda é dono de %s repositórios e não pode ser removido. "
+"Troque os donos ou remova esses repositórios. %s"
+
+#: rhodecode/model/validators.py:35 rhodecode/model/validators.py:36
+msgid "Value cannot be an empty list"
+msgstr ""
+
+#: rhodecode/model/validators.py:82
+#, fuzzy, python-format
+msgid "Username \"%(username)s\" already exists"
+msgstr "Esse nome de usuário já existe"
+
+#: rhodecode/model/validators.py:84
 #, python-format
-msgid "This user still owns %s repositories and cannot be removed. Switch owners or remove those repositories"
-msgstr "Esse usuário ainda é dono de %s repositórios e não pode ser removido. Troque os donos ou remova esses repositórios"
-
-#: rhodecode/templates/index.html:4
+msgid "Username \"%(username)s\" is forbidden"
+msgstr ""
+
+#: rhodecode/model/validators.py:86
+msgid ""
+"Username may only contain alphanumeric characters underscores, periods or"
+" dashes and must begin with alphanumeric character"
+msgstr ""
+"Nome de usuário pode conter somente caracteres alfanuméricos, sublinha, "
+"pontos e hífens e deve iniciar com caractere alfanumérico"
+
+#: rhodecode/model/validators.py:114
+#, fuzzy, python-format
+msgid "Username %(username)s is not valid"
+msgstr "Esse nome de usuário ou nome de grupo de usuários não é válido"
+
+#: rhodecode/model/validators.py:133
+#, fuzzy
+msgid "Invalid users group name"
+msgstr "nome de usuário inválido"
+
+#: rhodecode/model/validators.py:134
+#, fuzzy, python-format
+msgid "Users group \"%(usersgroup)s\" already exists"
+msgstr "Esse grupo de usuários já existe"
+
+#: rhodecode/model/validators.py:136
+msgid ""
+"users group name may only contain  alphanumeric characters underscores, "
+"periods or dashes and must begin with alphanumeric character"
+msgstr ""
+"Nome de grupo de repositório pode conter somente caracteres "
+"alfanuméricos, sublinha, pontos e hífens e deve iniciar com caractere "
+"alfanumérico"
+
+#: rhodecode/model/validators.py:174
+msgid "Cannot assign this group as parent"
+msgstr "Não é possível associar esse grupo como progenitor"
+
+#: rhodecode/model/validators.py:175
+#, fuzzy, python-format
+msgid "Group \"%(group_name)s\" already exists"
+msgstr "Esse nome de usuário já existe"
+
+#: rhodecode/model/validators.py:177
+#, fuzzy, python-format
+msgid "Repository with name \"%(group_name)s\" already exists"
+msgstr "Já existe um repositório com esse nome"
+
+#: rhodecode/model/validators.py:235
+#, fuzzy
+msgid "Invalid characters (non-ascii) in password"
+msgstr "Caracteres inválidos na senha"
+
+#: rhodecode/model/validators.py:250
+msgid "Passwords do not match"
+msgstr "Senhas não conferem"
+
+#: rhodecode/model/validators.py:267
+msgid "invalid password"
+msgstr "senha inválida"
+
+#: rhodecode/model/validators.py:268
+msgid "invalid user name"
+msgstr "nome de usuário inválido"
+
+#: rhodecode/model/validators.py:269
+msgid "Your account is disabled"
+msgstr "Sua conta está desabilitada"
+
+#: rhodecode/model/validators.py:313
+#, fuzzy, python-format
+msgid "Repository name %(repo)s is disallowed"
+msgstr "Esse nome de repositório não é permitido"
+
+#: rhodecode/model/validators.py:315
+#, fuzzy, python-format
+msgid "Repository named %(repo)s already exists"
+msgstr "Já existe um repositório com esse nome"
+
+#: rhodecode/model/validators.py:316
+#, fuzzy, python-format
+msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
+msgstr "Esse repositório já existe em um grupo \"%s\""
+
+#: rhodecode/model/validators.py:318
+#, fuzzy, python-format
+msgid "Repositories group with name \"%(repo)s\" already exists"
+msgstr "Já existe um repositório com esse nome"
+
+#: rhodecode/model/validators.py:431
+msgid "invalid clone url"
+msgstr "URL de clonagem inválida"
+
+#: rhodecode/model/validators.py:432
+#, fuzzy
+msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url"
+msgstr "URL de clonagem inválida, forneça uma URL válida de clonagem http\\s"
+
+#: rhodecode/model/validators.py:457
+#, fuzzy
+msgid "Fork have to be the same type as parent"
+msgstr "Bifurcação precisa ser do mesmo tipo que o original"
+
+#: rhodecode/model/validators.py:478
+msgid "This username or users group name is not valid"
+msgstr "Esse nome de usuário ou nome de grupo de usuários não é válido"
+
+#: rhodecode/model/validators.py:562
+msgid "This is not a valid path"
+msgstr "Esse não é um caminho válido"
+
+#: rhodecode/model/validators.py:577
+msgid "This e-mail address is already taken"
+msgstr "Esse endereço de e-mail já está tomado"
+
+#: rhodecode/model/validators.py:597
+#, fuzzy, python-format
+msgid "e-mail \"%(email)s\" does not exist."
+msgstr "Esse endereço de e-mail não existe."
+
+#: rhodecode/model/validators.py:634
+msgid ""
+"The LDAP Login attribute of the CN must be specified - this is the name "
+"of the attribute that is equivalent to \"username\""
+msgstr ""
+"O atributo de login LDAP do CN deve ser especificado - isto é o nome do "
+"atributo que é equivalente ao 'nome de usuário'"
+
+#: rhodecode/model/validators.py:653
+#, python-format
+msgid "Revisions %(revs)s are already part of pull request or have set status"
+msgstr ""
+
+#: rhodecode/templates/index.html:3
 msgid "Dashboard"
 msgstr "Painel de Controle"
 
-#: rhodecode/templates/index_base.html:22
-#: rhodecode/templates/admin/users/user_edit_my_account.html:102
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/repo_switcher_list.html:4
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/users/user_edit_my_account.html:31
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/bookmarks/bookmarks.html:10
+#: rhodecode/templates/branches/branches.html:9
+#: rhodecode/templates/journal/journal.html:40
+#: rhodecode/templates/tags/tags.html:10
 msgid "quick filter..."
 msgstr "filtro rápido..."
 
-#: rhodecode/templates/index_base.html:23
-#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/base/base.html:221
 msgid "repositories"
 msgstr "repositórios"
 
+#: rhodecode/templates/index_base.html:13
+#: rhodecode/templates/index_base.html:15
+#: rhodecode/templates/admin/repos/repos.html:21
+msgid "ADD REPOSITORY"
+msgstr "ADICIONAR REPOSITÓRIO"
+
 #: rhodecode/templates/index_base.html:29
-#: rhodecode/templates/admin/repos/repos.html:22
-msgid "ADD NEW REPOSITORY"
-msgstr "ADICIONAR NOVO REPOSITÓRIO"
-
-#: rhodecode/templates/index_base.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:33
@@ -854,159 +1330,158 @@
 msgid "Group name"
 msgstr "Nome do grupo"
 
-#: rhodecode/templates/index_base.html:42
-#: rhodecode/templates/index_base.html:73
-#: rhodecode/templates/admin/repos/repo_add_base.html:44
-#: rhodecode/templates/admin/repos/repo_edit.html:64
-#: rhodecode/templates/admin/repos/repos.html:31
+#: rhodecode/templates/index_base.html:30
+#: rhodecode/templates/index_base.html:71
+#: rhodecode/templates/index_base.html:142
+#: rhodecode/templates/index_base.html:168
+#: rhodecode/templates/admin/repos/repo_add_base.html:56
+#: rhodecode/templates/admin/repos/repo_edit.html:75
+#: rhodecode/templates/admin/repos/repos.html:72
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:34
-#: rhodecode/templates/settings/repo_fork.html:40
-#: rhodecode/templates/settings/repo_settings.html:40
-#: rhodecode/templates/summary/summary.html:92
+#: rhodecode/templates/forks/fork.html:59
+#: rhodecode/templates/settings/repo_settings.html:66
+#: rhodecode/templates/summary/summary.html:105
 msgid "Description"
 msgstr "Descrição"
 
-#: rhodecode/templates/index_base.html:53
+#: rhodecode/templates/index_base.html:40
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46
 msgid "Repositories group"
 msgstr "Grupo de repositórios"
 
-#: rhodecode/templates/index_base.html:72
+#: rhodecode/templates/index_base.html:70
+#: rhodecode/templates/index_base.html:166
 #: rhodecode/templates/admin/repos/repo_add_base.html:9
 #: rhodecode/templates/admin/repos/repo_edit.html:32
-#: rhodecode/templates/admin/repos/repos.html:30
-#: rhodecode/templates/admin/users/user_edit_my_account.html:117
-#: rhodecode/templates/files/files_browser.html:157
+#: rhodecode/templates/admin/repos/repos.html:70
+#: rhodecode/templates/admin/users/user_edit.html:192
+#: rhodecode/templates/admin/users/user_edit_my_account.html:59
+#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:6
+#: rhodecode/templates/bookmarks/bookmarks.html:36
+#: rhodecode/templates/bookmarks/bookmarks_data.html:6
+#: rhodecode/templates/branches/branches.html:51
+#: rhodecode/templates/files/files_browser.html:47
+#: rhodecode/templates/journal/journal.html:59
+#: rhodecode/templates/journal/journal.html:107
+#: rhodecode/templates/journal/journal.html:186
 #: rhodecode/templates/settings/repo_settings.html:31
-#: rhodecode/templates/summary/summary.html:31
-#: rhodecode/templates/summary/summary.html:107
+#: rhodecode/templates/summary/summary.html:43
+#: rhodecode/templates/summary/summary.html:123
+#: rhodecode/templates/tags/tags.html:36
+#: rhodecode/templates/tags/tags_data.html:6
 msgid "Name"
 msgstr "Nome"
 
-#: rhodecode/templates/index_base.html:74
-#: rhodecode/templates/admin/repos/repos.html:32
-#: rhodecode/templates/summary/summary.html:114
+#: rhodecode/templates/index_base.html:72
 msgid "Last change"
 msgstr "Última alteração"
 
+#: rhodecode/templates/index_base.html:73
+#: rhodecode/templates/index_base.html:171
+#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/journal/journal.html:188
+msgid "Tip"
+msgstr "Ponta"
+
+#: rhodecode/templates/index_base.html:74
+#: rhodecode/templates/index_base.html:173
+#: rhodecode/templates/admin/repos/repo_edit.html:121
+#: rhodecode/templates/admin/repos/repos.html:73
+msgid "Owner"
+msgstr "Dono"
+
 #: rhodecode/templates/index_base.html:75
-#: rhodecode/templates/admin/repos/repos.html:33
-msgid "Tip"
-msgstr "Ponta"
+#: rhodecode/templates/summary/summary.html:48
+#: rhodecode/templates/summary/summary.html:51
+msgid "RSS"
+msgstr "RSS"
 
 #: rhodecode/templates/index_base.html:76
-#: rhodecode/templates/admin/repos/repo_edit.html:97
-msgid "Owner"
-msgstr "Dono"
-
-#: rhodecode/templates/index_base.html:77
-#: rhodecode/templates/journal/public_journal.html:20
-#: rhodecode/templates/summary/summary.html:180
-#: rhodecode/templates/summary/summary.html:183
-msgid "RSS"
-msgstr "RSS"
-
-#: rhodecode/templates/index_base.html:78
-#: rhodecode/templates/journal/public_journal.html:23
-#: rhodecode/templates/summary/summary.html:181
-#: rhodecode/templates/summary/summary.html:184
 msgid "Atom"
 msgstr "Atom"
 
-#: rhodecode/templates/index_base.html:87
-#: rhodecode/templates/index_base.html:89
-#: rhodecode/templates/index_base.html:91
-#: rhodecode/templates/base/base.html:209
-#: rhodecode/templates/base/base.html:211
-#: rhodecode/templates/base/base.html:213
-#: rhodecode/templates/summary/summary.html:4
-msgid "Summary"
-msgstr "Sumário"
-
-#: rhodecode/templates/index_base.html:95
-#: rhodecode/templates/index_base.html:97
-#: rhodecode/templates/index_base.html:99
-#: rhodecode/templates/base/base.html:225
-#: rhodecode/templates/base/base.html:227
-#: rhodecode/templates/base/base.html:229
-#: rhodecode/templates/changelog/changelog.html:6
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "Changelog"
-msgstr "Registro de alterações"
-
-#: rhodecode/templates/index_base.html:103
-#: rhodecode/templates/index_base.html:105
-#: rhodecode/templates/index_base.html:107
-#: rhodecode/templates/base/base.html:268
-#: rhodecode/templates/base/base.html:270
-#: rhodecode/templates/base/base.html:272
-#: rhodecode/templates/files/files.html:4
-msgid "Files"
-msgstr "Arquivos"
-
-#: rhodecode/templates/index_base.html:116
-#: rhodecode/templates/admin/repos/repos.html:42
-#: rhodecode/templates/admin/users/user_edit_my_account.html:127
-#: rhodecode/templates/summary/summary.html:48
-msgid "Mercurial repository"
-msgstr "Repositório Mercurial"
-
-#: rhodecode/templates/index_base.html:118
-#: rhodecode/templates/admin/repos/repos.html:44
-#: rhodecode/templates/admin/users/user_edit_my_account.html:129
-#: rhodecode/templates/summary/summary.html:51
-msgid "Git repository"
-msgstr "Repositório Git"
-
-#: rhodecode/templates/index_base.html:123
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
-#: rhodecode/templates/journal/journal.html:53
-#: rhodecode/templates/summary/summary.html:56
-msgid "private repository"
-msgstr "repositório privado"
-
-#: rhodecode/templates/index_base.html:125
-#: rhodecode/templates/journal/journal.html:55
-#: rhodecode/templates/summary/summary.html:58
-msgid "public repository"
-msgstr "repositório público"
-
-#: rhodecode/templates/index_base.html:133
-#: rhodecode/templates/base/base.html:291
-#: rhodecode/templates/settings/repo_fork.html:13
-msgid "fork"
-msgstr "bifurcação"
-
-#: rhodecode/templates/index_base.html:134
-#: rhodecode/templates/admin/repos/repos.html:60
-#: rhodecode/templates/admin/users/user_edit_my_account.html:143
-#: rhodecode/templates/summary/summary.html:69
-#: rhodecode/templates/summary/summary.html:71
-msgid "Fork of"
-msgstr "Bifurcação de"
-
-#: rhodecode/templates/index_base.html:155
-#: rhodecode/templates/admin/repos/repos.html:73
-msgid "No changesets yet"
-msgstr "Ainda não há conjuntos de mudanças"
-
-#: rhodecode/templates/index_base.html:161
-#: rhodecode/templates/index_base.html:163
+#: rhodecode/templates/index_base.html:110
+#: rhodecode/templates/index_base.html:112
 #, python-format
 msgid "Subscribe to %s rss feed"
 msgstr "Assinar o feed rss de %s"
 
-#: rhodecode/templates/index_base.html:168
-#: rhodecode/templates/index_base.html:170
+#: rhodecode/templates/index_base.html:117
+#: rhodecode/templates/index_base.html:119
 #, python-format
 msgid "Subscribe to %s atom feed"
 msgstr "Assinar o feed atom de %s"
 
-#: rhodecode/templates/login.html:5
-#: rhodecode/templates/login.html:54
-#: rhodecode/templates/base/base.html:38
+#: rhodecode/templates/index_base.html:140
+msgid "Group Name"
+msgstr "Nome do Grupo"
+
+#: rhodecode/templates/index_base.html:158
+#: rhodecode/templates/index_base.html:198
+#: rhodecode/templates/admin/repos/repos.html:94
+#: rhodecode/templates/admin/users/user_edit_my_account.html:179
+#: rhodecode/templates/admin/users/users.html:107
+#: rhodecode/templates/bookmarks/bookmarks.html:60
+#: rhodecode/templates/branches/branches.html:77
+#: rhodecode/templates/journal/journal.html:211
+#: rhodecode/templates/tags/tags.html:60
+msgid "Click to sort ascending"
+msgstr "Clique para ordenar em ordem crescente"
+
+#: rhodecode/templates/index_base.html:159
+#: rhodecode/templates/index_base.html:199
+#: rhodecode/templates/admin/repos/repos.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account.html:180
+#: rhodecode/templates/admin/users/users.html:108
+#: rhodecode/templates/bookmarks/bookmarks.html:61
+#: rhodecode/templates/branches/branches.html:78
+#: rhodecode/templates/journal/journal.html:212
+#: rhodecode/templates/tags/tags.html:61
+msgid "Click to sort descending"
+msgstr "Clique para ordenar em ordem descrescente"
+
+#: rhodecode/templates/index_base.html:169
+msgid "Last Change"
+msgstr "Última Alteração"
+
+#: rhodecode/templates/index_base.html:200
+#: rhodecode/templates/admin/repos/repos.html:96
+#: rhodecode/templates/admin/users/user_edit_my_account.html:181
+#: rhodecode/templates/admin/users/users.html:109
+#: rhodecode/templates/bookmarks/bookmarks.html:62
+#: rhodecode/templates/branches/branches.html:79
+#: rhodecode/templates/journal/journal.html:213
+#: rhodecode/templates/tags/tags.html:62
+msgid "No records found."
+msgstr "Nenhum registro encontrado."
+
+#: rhodecode/templates/index_base.html:201
+#: rhodecode/templates/admin/repos/repos.html:97
+#: rhodecode/templates/admin/users/user_edit_my_account.html:182
+#: rhodecode/templates/admin/users/users.html:110
+#: rhodecode/templates/bookmarks/bookmarks.html:63
+#: rhodecode/templates/branches/branches.html:80
+#: rhodecode/templates/journal/journal.html:214
+#: rhodecode/templates/tags/tags.html:63
+msgid "Data error."
+msgstr "Erro de dados."
+
+#: rhodecode/templates/index_base.html:202
+#: rhodecode/templates/admin/repos/repos.html:98
+#: rhodecode/templates/admin/users/user_edit_my_account.html:183
+#: rhodecode/templates/admin/users/users.html:111
+#: rhodecode/templates/bookmarks/bookmarks.html:64
+#: rhodecode/templates/branches/branches.html:81
+#: rhodecode/templates/journal/journal.html:215
+#: rhodecode/templates/tags/tags.html:64
+msgid "Loading..."
+msgstr "Carregando..."
+
+#: rhodecode/templates/login.html:5 rhodecode/templates/login.html:54
 msgid "Sign In"
 msgstr "Entrar"
 
@@ -1014,31 +1489,32 @@
 msgid "Sign In to"
 msgstr "Entrar em"
 
-#: rhodecode/templates/login.html:31
-#: rhodecode/templates/register.html:20
+#: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20
 #: rhodecode/templates/admin/admin_log.html:5
 #: rhodecode/templates/admin/users/user_add.html:32
-#: rhodecode/templates/admin/users/user_edit.html:47
-#: rhodecode/templates/admin/users/user_edit_my_account.html:45
-#: rhodecode/templates/base/base.html:15
-#: rhodecode/templates/summary/summary.html:106
+#: rhodecode/templates/admin/users/user_edit.html:50
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:26
+#: rhodecode/templates/base/base.html:83
+#: rhodecode/templates/summary/summary.html:122
 msgid "Username"
 msgstr "Nome de usuário"
 
-#: rhodecode/templates/login.html:40
-#: rhodecode/templates/register.html:29
+#: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29
 #: rhodecode/templates/admin/ldap/ldap.html:46
 #: rhodecode/templates/admin/users/user_add.html:41
-#: rhodecode/templates/base/base.html:24
+#: rhodecode/templates/base/base.html:92
 msgid "Password"
 msgstr "Senha"
 
+#: rhodecode/templates/login.html:50
+msgid "Remember me"
+msgstr "Lembre-se de mim"
+
 #: rhodecode/templates/login.html:60
 msgid "Forgot your password ?"
 msgstr "Esqueceu sua senha ?"
 
-#: rhodecode/templates/login.html:63
-#: rhodecode/templates/base/base.html:35
+#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:103
 msgid "Don't have an account ?"
 msgstr "Não possui uma conta ?"
 
@@ -1060,10 +1536,11 @@
 
 #: rhodecode/templates/password_reset.html:31
 msgid "Password reset link will be send to matching email address"
-msgstr "Link de reinicialização de senha será enviado ao endereço de e-mail correspondente"
-
-#: rhodecode/templates/register.html:5
-#: rhodecode/templates/register.html:74
+msgstr ""
+"Link de reinicialização de senha será enviado ao endereço de e-mail "
+"correspondente"
+
+#: rhodecode/templates/register.html:5 rhodecode/templates/register.html:74
 msgid "Sign Up"
 msgstr "Inscrever-se"
 
@@ -1076,24 +1553,24 @@
 msgstr "Repita a senha"
 
 #: rhodecode/templates/register.html:47
-#: rhodecode/templates/admin/users/user_add.html:50
-#: rhodecode/templates/admin/users/user_edit.html:74
-#: rhodecode/templates/admin/users/user_edit_my_account.html:63
+#: rhodecode/templates/admin/users/user_add.html:59
+#: rhodecode/templates/admin/users/user_edit.html:86
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53
 msgid "First Name"
 msgstr "Primeiro Nome"
 
 #: rhodecode/templates/register.html:56
-#: rhodecode/templates/admin/users/user_add.html:59
-#: rhodecode/templates/admin/users/user_edit.html:83
-#: rhodecode/templates/admin/users/user_edit_my_account.html:72
+#: rhodecode/templates/admin/users/user_add.html:68
+#: rhodecode/templates/admin/users/user_edit.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62
 msgid "Last Name"
 msgstr "Último Nome"
 
 #: rhodecode/templates/register.html:65
-#: rhodecode/templates/admin/users/user_add.html:68
-#: rhodecode/templates/admin/users/user_edit.html:92
-#: rhodecode/templates/admin/users/user_edit_my_account.html:81
-#: rhodecode/templates/summary/summary.html:108
+#: rhodecode/templates/admin/users/user_add.html:77
+#: rhodecode/templates/admin/users/user_edit.html:104
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71
+#: rhodecode/templates/summary/summary.html:124
 msgid "Email"
 msgstr "E-mail"
 
@@ -1105,20 +1582,59 @@
 msgid "Your account must wait for activation by administrator"
 msgstr "Sua conta precisa esperar ativação por um administrador"
 
-#: rhodecode/templates/repo_switcher_list.html:14
+#: rhodecode/templates/repo_switcher_list.html:11
+#: rhodecode/templates/admin/repos/repo_add_base.html:65
+#: rhodecode/templates/admin/repos/repo_edit.html:85
+#: rhodecode/templates/settings/repo_settings.html:76
 msgid "Private repository"
 msgstr "Repositório privado"
 
-#: rhodecode/templates/repo_switcher_list.html:19
+#: rhodecode/templates/repo_switcher_list.html:16
 msgid "Public repository"
 msgstr "Repositório público"
 
+#: rhodecode/templates/switch_to_list.html:3
+#: rhodecode/templates/branches/branches.html:14
+msgid "branches"
+msgstr "ramos"
+
+#: rhodecode/templates/switch_to_list.html:10
+#: rhodecode/templates/branches/branches_data.html:57
+msgid "There are no branches yet"
+msgstr "Ainda não há ramos"
+
+#: rhodecode/templates/switch_to_list.html:15
+#: rhodecode/templates/shortlog/shortlog_data.html:10
+#: rhodecode/templates/tags/tags.html:15
+msgid "tags"
+msgstr "etiquetas"
+
+#: rhodecode/templates/switch_to_list.html:22
+#: rhodecode/templates/tags/tags_data.html:33
+msgid "There are no tags yet"
+msgstr "Ainda não há etiquetas"
+
+#: rhodecode/templates/switch_to_list.html:28
+#: rhodecode/templates/bookmarks/bookmarks.html:15
+msgid "bookmarks"
+msgstr "marcadores"
+
+#: rhodecode/templates/switch_to_list.html:35
+#: rhodecode/templates/bookmarks/bookmarks_data.html:32
+msgid "There are no bookmarks yet"
+msgstr "Ainda não há marcadores"
+
 #: rhodecode/templates/admin/admin.html:5
 #: rhodecode/templates/admin/admin.html:9
 msgid "Admin journal"
 msgstr "Diário do administrador"
 
 #: rhodecode/templates/admin/admin_log.html:6
+#: rhodecode/templates/admin/repos/repos.html:74
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:8
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:9
+#: rhodecode/templates/journal/journal.html:61
+#: rhodecode/templates/journal/journal.html:62
 msgid "Action"
 msgstr "Ação"
 
@@ -1127,6 +1643,11 @@
 msgstr "Repositório"
 
 #: rhodecode/templates/admin/admin_log.html:8
+#: rhodecode/templates/bookmarks/bookmarks.html:37
+#: rhodecode/templates/bookmarks/bookmarks_data.html:7
+#: rhodecode/templates/branches/branches.html:52
+#: rhodecode/templates/tags/tags.html:37
+#: rhodecode/templates/tags/tags_data.html:7
 msgid "Date"
 msgstr "Data"
 
@@ -1134,7 +1655,7 @@
 msgid "From IP"
 msgstr "A partir do IP"
 
-#: rhodecode/templates/admin/admin_log.html:52
+#: rhodecode/templates/admin/admin_log.html:53
 msgid "No actions yet"
 msgstr "Ainda não há ações"
 
@@ -1211,23 +1732,64 @@
 msgstr "Atributo de E-mail"
 
 #: rhodecode/templates/admin/ldap/ldap.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:141
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:74
 #: rhodecode/templates/admin/settings/hooks.html:73
-#: rhodecode/templates/admin/users/user_edit.html:117
-#: rhodecode/templates/admin/users/user_edit.html:142
-#: rhodecode/templates/admin/users/user_edit_my_account.html:89
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:263
+#: rhodecode/templates/admin/users/user_edit.html:129
+#: rhodecode/templates/admin/users/user_edit.html:174
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:79
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:135
+#: rhodecode/templates/settings/repo_settings.html:93
 msgid "Save"
 msgstr "Salvar"
 
+#: rhodecode/templates/admin/notifications/notifications.html:5
+#: rhodecode/templates/admin/notifications/notifications.html:9
+msgid "My Notifications"
+msgstr "Minhas Notificações"
+
+#: rhodecode/templates/admin/notifications/notifications.html:29
+msgid "All"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:30
+#, fuzzy
+msgid "Comments"
+msgstr "commits"
+
+#: rhodecode/templates/admin/notifications/notifications.html:31
+#: rhodecode/templates/base/base.html:254
+#: rhodecode/templates/base/base.html:256
+msgid "Pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:35
+msgid "Mark all read"
+msgstr "Marcar tudo como lido"
+
+#: rhodecode/templates/admin/notifications/notifications_data.html:39
+msgid "No notifications here yet"
+msgstr "Ainda não há notificações aqui"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:5
+#: rhodecode/templates/admin/notifications/show_notification.html:11
+msgid "Show notification"
+msgstr "Mostrar notificação"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:9
+msgid "Notifications"
+msgstr "Notificações"
+
 #: rhodecode/templates/admin/permissions/permissions.html:5
 msgid "Permissions administration"
 msgstr "Administração de permissões"
 
 #: rhodecode/templates/admin/permissions/permissions.html:11
-#: rhodecode/templates/admin/repos/repo_edit.html:109
-#: rhodecode/templates/admin/users/user_edit.html:127
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:248
-#: rhodecode/templates/settings/repo_settings.html:58
+#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
+#: rhodecode/templates/admin/users/user_edit.html:139
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:100
+#: rhodecode/templates/settings/repo_settings.html:86
 msgid "Permissions"
 msgstr "Permissões"
 
@@ -1244,8 +1806,14 @@
 msgstr "Permissão de repositório"
 
 #: rhodecode/templates/admin/permissions/permissions.html:49
-msgid "All default permissions on each repository will be reset to choosen permission, note that all custom default permission on repositories will be lost"
-msgstr "Todas as permissões padrão em cada repositório serão reinicializadas para as permissões escolhidas. Note que todas as permissões padrão customizadas nos repositórios serão perdidas"
+msgid ""
+"All default permissions on each repository will be reset to choosen "
+"permission, note that all custom default permission on repositories will "
+"be lost"
+msgstr ""
+"Todas as permissões padrão em cada repositório serão reinicializadas para"
+" as permissões escolhidas. Note que todas as permissões padrão "
+"customizadas nos repositórios serão perdidas"
 
 #: rhodecode/templates/admin/permissions/permissions.html:50
 msgid "overwrite existing settings"
@@ -1260,6 +1828,12 @@
 msgstr "Criação de repositório"
 
 #: rhodecode/templates/admin/permissions/permissions.html:71
+#, fuzzy
+msgid "Repository forking"
+msgstr "Criação de repositório"
+
+#: rhodecode/templates/admin/permissions/permissions.html:78
+#: rhodecode/templates/admin/repos/repo_edit.html:241
 msgid "set"
 msgstr "ajustar"
 
@@ -1270,7 +1844,6 @@
 
 #: rhodecode/templates/admin/repos/repo_add.html:11
 #: rhodecode/templates/admin/repos/repo_edit.html:11
-#: rhodecode/templates/admin/repos/repos.html:10
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
 msgid "Repositories"
 msgstr "Repositórios"
@@ -1280,30 +1853,76 @@
 msgstr "adicionar novo"
 
 #: rhodecode/templates/admin/repos/repo_add_base.html:20
-#: rhodecode/templates/summary/summary.html:80
-#: rhodecode/templates/summary/summary.html:82
+#: rhodecode/templates/summary/summary.html:95
+#: rhodecode/templates/summary/summary.html:96
 msgid "Clone from"
 msgstr "Clonar de"
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:28
-#: rhodecode/templates/admin/repos/repo_edit.html:48
+#: rhodecode/templates/admin/repos/repo_add_base.html:24
+#: rhodecode/templates/admin/repos/repo_edit.html:44
+#: rhodecode/templates/settings/repo_settings.html:43
+msgid "Optional http[s] url from which repository should be cloned."
+msgstr "URL opcional http[s] da qual o repositório deve ser clonado."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:29
+#: rhodecode/templates/admin/repos/repo_edit.html:49
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:4
+#: rhodecode/templates/forks/fork.html:50
+#: rhodecode/templates/settings/repo_settings.html:48
 msgid "Repository group"
 msgstr "Grupo de repositórios"
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:36
-#: rhodecode/templates/admin/repos/repo_edit.html:56
+#: rhodecode/templates/admin/repos/repo_add_base.html:33
+#: rhodecode/templates/forks/fork.html:54
+#, fuzzy
+msgid "Optionaly select a group to put this repository into."
+msgstr "Opcionalmente selecione um grupo no qual colocar esse repositório."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:38
+#: rhodecode/templates/admin/repos/repo_edit.html:58
 msgid "Type"
 msgstr "Tipo"
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:52
-#: rhodecode/templates/admin/repos/repo_edit.html:73
-#: rhodecode/templates/settings/repo_fork.html:48
-#: rhodecode/templates/settings/repo_settings.html:49
-msgid "Private"
-msgstr "Privado"
-
-#: rhodecode/templates/admin/repos/repo_add_base.html:59
+#: rhodecode/templates/admin/repos/repo_add_base.html:42
+msgid "Type of repository to create."
+msgstr "Tipo de repositório a criar."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:47
+#: rhodecode/templates/admin/repos/repo_edit.html:66
+#: rhodecode/templates/forks/fork.html:41
+#: rhodecode/templates/settings/repo_settings.html:57
+#, fuzzy
+msgid "Landing revision"
+msgstr "próxima revisão"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:51
+#: rhodecode/templates/admin/repos/repo_edit.html:70
+#: rhodecode/templates/forks/fork.html:45
+#: rhodecode/templates/settings/repo_settings.html:61
+msgid "Default revision for files page, downloads, whoosh and readme"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:60
+#: rhodecode/templates/admin/repos/repo_edit.html:79
+#: rhodecode/templates/forks/fork.html:63
+#: rhodecode/templates/settings/repo_settings.html:70
+msgid "Keep it short and to the point. Use a README file for longer descriptions."
+msgstr ""
+"Seja sucinto e objetivo. Use um arquivo README para descrições mais "
+"longas."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:69
+#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/forks/fork.html:72
+#: rhodecode/templates/settings/repo_settings.html:80
+msgid ""
+"Private repositories are only visible to people explicitly added as "
+"collaborators."
+msgstr ""
+"Repositórios privados são visíveis somente por pessoas explicitamente "
+"adicionadas como colaboradores."
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:73
 msgid "add"
 msgstr "adicionar"
 
@@ -1317,183 +1936,283 @@
 
 #: rhodecode/templates/admin/repos/repo_edit.html:13
 #: rhodecode/templates/admin/users/user_edit.html:13
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
+#: rhodecode/templates/admin/users/user_edit.html:224
+#: rhodecode/templates/admin/users/user_edit.html:226
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:13
-#: rhodecode/templates/files/files_annotate.html:49
-#: rhodecode/templates/files/files_source.html:20
+#: rhodecode/templates/files/files_source.html:44
+#: rhodecode/templates/journal/journal.html:81
 msgid "edit"
 msgstr "editar"
 
 #: rhodecode/templates/admin/repos/repo_edit.html:40
+#: rhodecode/templates/settings/repo_settings.html:39
 msgid "Clone uri"
 msgstr "URI de clonagem"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:81
+#: rhodecode/templates/admin/repos/repo_edit.html:53
+#: rhodecode/templates/settings/repo_settings.html:52
+msgid "Optional select a group to put this repository into."
+msgstr "Opcionalmente selecione um grupo no qual colocar esse repositório."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:94
 msgid "Enable statistics"
 msgstr "Habilitar estatísticas"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:98
+msgid "Enable statistics window on summary page."
+msgstr "Habilitar janela de estatísticas na página de sumário."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:103
 msgid "Enable downloads"
 msgstr "Habilitar downloads"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:127
+#: rhodecode/templates/admin/repos/repo_edit.html:107
+msgid "Enable download menu on summary page."
+msgstr "Habilitar menu de descarregar na página de sumário."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:112
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:66
+#, fuzzy
+msgid "Enable locking"
+msgstr "habilitar"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:116
+msgid "Enable lock-by-pulling on repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:126
+msgid "Change owner of this repository."
+msgstr "Mudar o dono desse repositório."
+
+#: rhodecode/templates/admin/repos/repo_edit.html:142
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:75
+#: rhodecode/templates/admin/settings/settings.html:113
+#: rhodecode/templates/admin/settings/settings.html:168
+#: rhodecode/templates/admin/settings/settings.html:258
+#: rhodecode/templates/admin/users/user_edit.html:130
+#: rhodecode/templates/admin/users/user_edit.html:175
+#: rhodecode/templates/admin/users/user_edit.html:278
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:136
+#: rhodecode/templates/files/files_add.html:82
+#: rhodecode/templates/files/files_edit.html:68
+#: rhodecode/templates/pullrequests/pullrequest.html:124
+#: rhodecode/templates/settings/repo_settings.html:94
+msgid "Reset"
+msgstr "Limpar"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:152
 msgid "Administration"
 msgstr "Administração"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:130
+#: rhodecode/templates/admin/repos/repo_edit.html:155
 msgid "Statistics"
 msgstr "Estatísticas"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Reset current statistics"
 msgstr "Reinicializar estatísticas atuais"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Confirm to remove current statistics"
 msgstr "Confirma remover atuais estatísticas"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:137
+#: rhodecode/templates/admin/repos/repo_edit.html:162
 msgid "Fetched to rev"
 msgstr "Trazida à rev"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:138
-msgid "Percentage of stats gathered"
-msgstr "Porcentagem das estatísticas totalizadas"
-
-#: rhodecode/templates/admin/repos/repo_edit.html:147
+#: rhodecode/templates/admin/repos/repo_edit.html:163
+msgid "Stats gathered"
+msgstr "Estatísticas coletadas"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:171
 msgid "Remote"
 msgstr "Remoto"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:151
+#: rhodecode/templates/admin/repos/repo_edit.html:175
 msgid "Pull changes from remote location"
 msgstr "Realizar pull de alterações a partir de localização remota"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:151
+#: rhodecode/templates/admin/repos/repo_edit.html:175
 msgid "Confirm to pull changes from remote side"
 msgstr "Confirma realizar pull de alterações a partir de lado remoto"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:162
+#: rhodecode/templates/admin/repos/repo_edit.html:186
 msgid "Cache"
 msgstr "Cache"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Invalidate repository cache"
 msgstr "Invalidar cache do repositório"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Confirm to invalidate repository cache"
 msgstr "Confirma invalidar cache do repositório"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:177
+#: rhodecode/templates/admin/repos/repo_edit.html:195
+#: rhodecode/templates/base/base.html:318
+#: rhodecode/templates/base/base.html:320
+#: rhodecode/templates/base/base.html:322
+msgid "Public journal"
+msgstr "Diário público"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:201
 msgid "Remove from public journal"
 msgstr "Remover do diário público"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:179
+#: rhodecode/templates/admin/repos/repo_edit.html:203
 msgid "Add to public journal"
 msgstr "Adicionar ao diário público"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:185
+#: rhodecode/templates/admin/repos/repo_edit.html:208
+msgid ""
+"All actions made on this repository will be accessible to everyone in "
+"public journal"
+msgstr ""
+"Todas as ações feitas nesse repositório serão acessíveis a todos no "
+"diário público"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:215
+#, fuzzy
+msgid "Locking"
+msgstr "destravar"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Unlock locked repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+#, fuzzy
+msgid "Confirm to unlock repository"
+msgstr "Confirma excluir este repositório"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "lock repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+#, fuzzy
+msgid "Confirm to lock repository"
+msgstr "Confirma excluir este repositório"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:224
+#, fuzzy
+msgid "Repository is not locked"
+msgstr "repositórios"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:229
+msgid "Force locking on repository. Works only when anonymous access is disabled"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:236
+#, fuzzy
+msgid "Set as fork of"
+msgstr "Marcar como bifurcação"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:245
+#, fuzzy
+msgid "Manually set this repository as a fork of another from the list"
+msgstr "Marcar manualmente este repositório como sendo uma bifurcação de outro"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:251
+#: rhodecode/templates/changeset/changeset_file_comment.html:26
 msgid "Delete"
 msgstr "Excluir"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
+#: rhodecode/templates/admin/repos/repo_edit.html:255
 msgid "Remove this repository"
 msgstr "Remover deste repositório"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
-#: rhodecode/templates/admin/repos/repos.html:79
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+#: rhodecode/templates/journal/journal.html:84
 msgid "Confirm to delete this repository"
 msgstr "Confirma excluir este repositório"
 
+#: rhodecode/templates/admin/repos/repo_edit.html:259
+msgid ""
+"This repository will be renamed in a special way in order to be "
+"unaccesible for RhodeCode and VCS systems.\n"
+"                         If you need fully delete it from filesystem "
+"please do it manually"
+msgstr ""
+"Este repositório será renomeado de uma maneira especial, de forma a ser "
+"inacessível ao RhodeCode e sistemas de controle de versão.\n"
+"                         Se você precisa exclui-lo completamente do "
+"sistema de arquivos, por favor faça-o manualmente"
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:3
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3
 msgid "none"
 msgstr "nenhum"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:4
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4
 msgid "read"
 msgstr "ler"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:5
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5
 msgid "write"
 msgstr "escrever"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:6
-#: rhodecode/templates/admin/users/users.html:38
-#: rhodecode/templates/base/base.html:296
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6
+#: rhodecode/templates/admin/users/users.html:85
+#: rhodecode/templates/base/base.html:217
 msgid "admin"
 msgstr "administrador"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:7
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7
 msgid "member"
 msgstr "membro"
 
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
+#: rhodecode/templates/data_table/_dt_elements.html:67
+#: rhodecode/templates/journal/journal.html:132
+#: rhodecode/templates/summary/summary.html:76
+msgid "private repository"
+msgstr "repositório privado"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:19
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:28
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:18
+#, fuzzy
+msgid "default"
+msgstr "excluir"
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:33
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:53
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:58
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:23
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:42
 msgid "revoke"
 msgstr "revogar"
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:75
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:83
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:67
 msgid "Add another member"
 msgstr "Adicionar outro membro"
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:89
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:97
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81
 msgid "Failed to remove user"
 msgstr "Falha ao reomver usuário"
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:104
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:112
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:96
 msgid "Failed to remove users group"
 msgstr "Falha ao remover grupo de usuários"
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:205
-msgid "Group"
-msgstr "Grupo"
-
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:206
-#: rhodecode/templates/admin/users_groups/users_groups.html:33
-msgid "members"
-msgstr "membros"
-
 #: rhodecode/templates/admin/repos/repos.html:5
 msgid "Repositories administration"
 msgstr "Administração de repositórios"
 
-#: rhodecode/templates/admin/repos/repos.html:34
-#: rhodecode/templates/summary/summary.html:100
-msgid "Contact"
-msgstr "Contato"
-
-#: rhodecode/templates/admin/repos/repos.html:35
-#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
-#: rhodecode/templates/admin/users/user_edit_my_account.html:119
-#: rhodecode/templates/admin/users/users.html:40
-#: rhodecode/templates/admin/users_groups/users_groups.html:35
-msgid "action"
-msgstr "ação"
-
-#: rhodecode/templates/admin/repos/repos.html:51
-#: rhodecode/templates/admin/users/user_edit_my_account.html:134
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
-msgid "private"
-msgstr "privado"
-
-#: rhodecode/templates/admin/repos/repos.html:53
-#: rhodecode/templates/admin/repos/repos.html:59
-#: rhodecode/templates/admin/users/user_edit_my_account.html:136
-#: rhodecode/templates/admin/users/user_edit_my_account.html:142
-#: rhodecode/templates/summary/summary.html:68
-msgid "public"
-msgstr "público"
-
-#: rhodecode/templates/admin/repos/repos.html:79
-#: rhodecode/templates/admin/users/users.html:55
-msgid "delete"
-msgstr "excluir"
-
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:8
 msgid "Groups"
 msgstr "Grupos"
 
-#: rhodecode/templates/admin/repos_groups/repos_groups.html:13
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:12
 msgid "with"
 msgstr "com"
 
@@ -1516,10 +2235,10 @@
 msgstr "Progenitor do grupo"
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:58
-#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
-#: rhodecode/templates/admin/users/user_add.html:85
+#: rhodecode/templates/admin/users/user_add.html:94
 #: rhodecode/templates/admin/users_groups/users_group_add.html:49
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:90
+#: rhodecode/templates/pullrequests/pullrequest_show.html:113
 msgid "save"
 msgstr "salvar"
 
@@ -1531,6 +2250,12 @@
 msgid "edit repos group"
 msgstr "editar grupo de repositórios"
 
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:70
+msgid ""
+"Enable lock-by-pulling on group. This option will be applied to all other"
+" groups and repositories inside"
+msgstr ""
+
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5
 msgid "Repositories groups administration"
 msgstr "Administração de grupos de repositórios"
@@ -1540,12 +2265,27 @@
 msgstr "ADICIONAR NOVO GRUPO"
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:35
-msgid "Number of repositories"
-msgstr "Número de repositórios"
+msgid "Number of toplevel repositories"
+msgstr "Número de repositórios de nível superior"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
+#: rhodecode/templates/admin/users/users.html:87
+#: rhodecode/templates/admin/users_groups/users_groups.html:35
+msgid "action"
+msgstr "ação"
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
-msgid "Confirm to delete this group"
-msgstr "Confirme para excluir este grupo"
+#: rhodecode/templates/admin/users/user_edit.html:255
+#: rhodecode/templates/admin/users_groups/users_groups.html:44
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#: rhodecode/templates/data_table/_dt_elements.html:103
+msgid "delete"
+msgstr "excluir"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#, python-format
+msgid "Confirm to delete this group: %s"
+msgstr "Confirme para excluir esse grupo: %s"
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:62
 msgid "There are no repositories groups yet"
@@ -1558,7 +2298,6 @@
 
 #: rhodecode/templates/admin/settings/hooks.html:9
 #: rhodecode/templates/admin/settings/settings.html:9
-#: rhodecode/templates/settings/repo_settings.html:5
 #: rhodecode/templates/settings/repo_settings.html:13
 msgid "Settings"
 msgstr "Configurações"
@@ -1588,119 +2327,208 @@
 msgstr "opção de varredura"
 
 #: rhodecode/templates/admin/settings/settings.html:38
-msgid "In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it."
-msgstr "Caso um repositório tenha sido excluído do sistema de arquivos e haja restos no banco de dados, marque esta opção para varrer dados obsoletos no banco e removê-los."
+msgid ""
+"In case a repository was deleted from filesystem and there are leftovers "
+"in the database check this option to scan obsolete data in database and "
+"remove it."
+msgstr ""
+"Caso um repositório tenha sido excluído do sistema de arquivos e haja "
+"restos no banco de dados, marque esta opção para varrer dados obsoletos "
+"no banco e removê-los."
 
 #: rhodecode/templates/admin/settings/settings.html:39
 msgid "destroy old data"
 msgstr "destruir dados antigos"
 
-#: rhodecode/templates/admin/settings/settings.html:45
+#: rhodecode/templates/admin/settings/settings.html:41
+msgid ""
+"Rescan repositories location for new repositories. Also deletes obsolete "
+"if `destroy` flag is checked "
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:46
 msgid "Rescan repositories"
 msgstr "Varrer repositórios"
 
-#: rhodecode/templates/admin/settings/settings.html:51
+#: rhodecode/templates/admin/settings/settings.html:52
 msgid "Whoosh indexing"
 msgstr "Indexação do Whoosh"
 
-#: rhodecode/templates/admin/settings/settings.html:59
+#: rhodecode/templates/admin/settings/settings.html:60
 msgid "index build option"
 msgstr "opção de construção de índice"
 
-#: rhodecode/templates/admin/settings/settings.html:64
+#: rhodecode/templates/admin/settings/settings.html:65
 msgid "build from scratch"
 msgstr "construir do início"
 
-#: rhodecode/templates/admin/settings/settings.html:70
+#: rhodecode/templates/admin/settings/settings.html:71
 msgid "Reindex"
 msgstr "Reindexar"
 
-#: rhodecode/templates/admin/settings/settings.html:76
+#: rhodecode/templates/admin/settings/settings.html:77
 msgid "Global application settings"
 msgstr "Configurações globais da aplicação"
 
-#: rhodecode/templates/admin/settings/settings.html:85
+#: rhodecode/templates/admin/settings/settings.html:86
 msgid "Application name"
 msgstr "Nome da aplicação"
 
-#: rhodecode/templates/admin/settings/settings.html:94
+#: rhodecode/templates/admin/settings/settings.html:95
 msgid "Realm text"
 msgstr "Texto de esfera"
 
-#: rhodecode/templates/admin/settings/settings.html:103
+#: rhodecode/templates/admin/settings/settings.html:104
 msgid "GA code"
 msgstr "Código GA"
 
-#: rhodecode/templates/admin/settings/settings.html:111
-#: rhodecode/templates/admin/settings/settings.html:177
-msgid "Save settings"
-msgstr "Salvar configurações"
-
 #: rhodecode/templates/admin/settings/settings.html:112
-#: rhodecode/templates/admin/settings/settings.html:178
-#: rhodecode/templates/admin/users/user_edit.html:118
-#: rhodecode/templates/admin/users/user_edit.html:143
-#: rhodecode/templates/admin/users/user_edit_my_account.html:90
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:264
-#: rhodecode/templates/files/files_edit.html:50
-msgid "Reset"
-msgstr "Limpar"
-
-#: rhodecode/templates/admin/settings/settings.html:118
-msgid "Mercurial settings"
-msgstr "Configurações do Mercurial"
-
-#: rhodecode/templates/admin/settings/settings.html:127
+#: rhodecode/templates/admin/settings/settings.html:167
+#: rhodecode/templates/admin/settings/settings.html:257
+msgid "Save settings"
+msgstr "Salvar configurações"
+
+#: rhodecode/templates/admin/settings/settings.html:119
+#, fuzzy
+msgid "Visualisation settings"
+msgstr "Configurações globais da aplicação"
+
+#: rhodecode/templates/admin/settings/settings.html:128
+#, fuzzy
+msgid "Icons"
+msgstr "Opções"
+
+#: rhodecode/templates/admin/settings/settings.html:133
+msgid "Show public repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:137
+#, fuzzy
+msgid "Show private repo icon on repositories"
+msgstr "repositório privado"
+
+#: rhodecode/templates/admin/settings/settings.html:144
+#, fuzzy
+msgid "Meta-Tagging"
+msgstr "configurações"
+
+#: rhodecode/templates/admin/settings/settings.html:149
+msgid "Stylify recognised metatags:"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:176
+#, fuzzy
+msgid "VCS settings"
+msgstr "configurações"
+
+#: rhodecode/templates/admin/settings/settings.html:185
 msgid "Web"
 msgstr "Web"
 
-#: rhodecode/templates/admin/settings/settings.html:132
-msgid "require ssl for pushing"
+#: rhodecode/templates/admin/settings/settings.html:190
+#, fuzzy
+msgid "require ssl for vcs operations"
 msgstr "exigir ssl para realizar push"
 
-#: rhodecode/templates/admin/settings/settings.html:139
+#: rhodecode/templates/admin/settings/settings.html:192
+msgid ""
+"RhodeCode will require SSL for pushing or pulling. If SSL is missing it "
+"will return HTTP Error 406: Not Acceptable"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:198
 msgid "Hooks"
 msgstr "Ganchos"
 
-#: rhodecode/templates/admin/settings/settings.html:142
+#: rhodecode/templates/admin/settings/settings.html:203
+msgid "Update repository after push (hg update)"
+msgstr "Atualizar repositório após realizar push (hg update)"
+
+#: rhodecode/templates/admin/settings/settings.html:207
+msgid "Show repository size after push"
+msgstr "Mostrar tamanho do repositório após o push"
+
+#: rhodecode/templates/admin/settings/settings.html:211
+msgid "Log user push commands"
+msgstr "Armazenar registro de comandos de push dos usuários"
+
+#: rhodecode/templates/admin/settings/settings.html:215
+msgid "Log user pull commands"
+msgstr "Armazenar registro de comandos de pull dos usuários"
+
+#: rhodecode/templates/admin/settings/settings.html:219
 msgid "advanced setup"
 msgstr "confirguações avançadas"
 
-#: rhodecode/templates/admin/settings/settings.html:147
-msgid "Update repository after push (hg update)"
-msgstr "Atualizar repositório após realizar push (hg update)"
-
-#: rhodecode/templates/admin/settings/settings.html:151
-msgid "Show repository size after push"
-msgstr "Mostrar tamanho do repositório após o push"
-
-#: rhodecode/templates/admin/settings/settings.html:155
-msgid "Log user push commands"
-msgstr "Armazenar registro de comandos de push dos usuários"
-
-#: rhodecode/templates/admin/settings/settings.html:159
-msgid "Log user pull commands"
-msgstr "Armazenar registro de comandos de pull dos usuários"
-
-#: rhodecode/templates/admin/settings/settings.html:166
+#: rhodecode/templates/admin/settings/settings.html:224
+#, fuzzy
+msgid "Mercurial Extensions"
+msgstr "Repositório Mercurial"
+
+#: rhodecode/templates/admin/settings/settings.html:229
+msgid "largefiles extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:233
+msgid "hgsubversion extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:235
+msgid ""
+"Requires hgsubversion library installed. Allows clonning from svn remote "
+"locations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:245
 msgid "Repositories location"
 msgstr "Localização dos repositórios"
 
-#: rhodecode/templates/admin/settings/settings.html:171
-msgid "This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock."
-msgstr "Essa é uma configuração crucial da aplicação. Se você realmente tem certeza de que quer mudar isto, você precisa reiniciar a aplicação para que essa configuração tenha efeito. Clique este rótulo para destravar."
-
-#: rhodecode/templates/admin/settings/settings.html:172
+#: rhodecode/templates/admin/settings/settings.html:250
+msgid ""
+"This a crucial application setting. If you are really sure you need to "
+"change this, you must restart application in order to make this setting "
+"take effect. Click this label to unlock."
+msgstr ""
+"Essa é uma configuração crucial da aplicação. Se você realmente tem "
+"certeza de que quer mudar isto, você precisa reiniciar a aplicação para "
+"que essa configuração tenha efeito. Clique este rótulo para destravar."
+
+#: rhodecode/templates/admin/settings/settings.html:251
 msgid "unlock"
 msgstr "destravar"
 
+#: rhodecode/templates/admin/settings/settings.html:252
+msgid ""
+"Location where repositories are stored. After changing this value a "
+"restart, and rescan is required"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:272
+msgid "Test Email"
+msgstr "Testar E-mail"
+
+#: rhodecode/templates/admin/settings/settings.html:280
+msgid "Email to"
+msgstr "E-mail para"
+
+#: rhodecode/templates/admin/settings/settings.html:288
+msgid "Send"
+msgstr "Enviar"
+
+#: rhodecode/templates/admin/settings/settings.html:294
+msgid "System Info and Packages"
+msgstr "Informações de Sistema e Pacotes"
+
+#: rhodecode/templates/admin/settings/settings.html:297
+msgid "show"
+msgstr "mostrar"
+
 #: rhodecode/templates/admin/users/user_add.html:5
 msgid "Add user"
 msgstr "Adicionar usuário"
 
 #: rhodecode/templates/admin/users/user_add.html:10
 #: rhodecode/templates/admin/users/user_edit.html:11
-#: rhodecode/templates/admin/users/users.html:9
 msgid "Users"
 msgstr "Usuários"
 
@@ -1708,8 +2536,12 @@
 msgid "add new user"
 msgstr "adicionar novo usuário"
 
-#: rhodecode/templates/admin/users/user_add.html:77
-#: rhodecode/templates/admin/users/user_edit.html:101
+#: rhodecode/templates/admin/users/user_add.html:50
+msgid "Password confirmation"
+msgstr "Confirmação de senha"
+
+#: rhodecode/templates/admin/users/user_add.html:86
+#: rhodecode/templates/admin/users/user_edit.html:113
 #: rhodecode/templates/admin/users_groups/users_group_add.html:41
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:42
 msgid "Active"
@@ -1719,36 +2551,100 @@
 msgid "Edit user"
 msgstr "Editar usuário"
 
-#: rhodecode/templates/admin/users/user_edit.html:33
-#: rhodecode/templates/admin/users/user_edit_my_account.html:32
+#: rhodecode/templates/admin/users/user_edit.html:34
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10
 msgid "Change your avatar at"
 msgstr "Altere o seu avatar em"
 
-#: rhodecode/templates/admin/users/user_edit.html:34
-#: rhodecode/templates/admin/users/user_edit_my_account.html:33
+#: rhodecode/templates/admin/users/user_edit.html:35
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11
 msgid "Using"
 msgstr "Usando"
 
-#: rhodecode/templates/admin/users/user_edit.html:40
-#: rhodecode/templates/admin/users/user_edit_my_account.html:39
+#: rhodecode/templates/admin/users/user_edit.html:43
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20
 msgid "API key"
 msgstr "Chave de API"
 
-#: rhodecode/templates/admin/users/user_edit.html:56
+#: rhodecode/templates/admin/users/user_edit.html:59
 msgid "LDAP DN"
 msgstr "DN LDAP"
 
-#: rhodecode/templates/admin/users/user_edit.html:65
-#: rhodecode/templates/admin/users/user_edit_my_account.html:54
+#: rhodecode/templates/admin/users/user_edit.html:68
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:35
 msgid "New password"
 msgstr "Nova senha"
 
-#: rhodecode/templates/admin/users/user_edit.html:135
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:256
+#: rhodecode/templates/admin/users/user_edit.html:77
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44
+msgid "New password confirmation"
+msgstr "Confirmação de nova senha"
+
+#: rhodecode/templates/admin/users/user_edit.html:147
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:108
+#, fuzzy
+msgid "Inherit default permissions"
+msgstr "Permissões padrão"
+
+#: rhodecode/templates/admin/users/user_edit.html:152
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:113
+#, python-format
+msgid ""
+"Select to inherit permissions from %s settings. With this selected below "
+"options does not have any action"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:158
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:119
 msgid "Create repositories"
 msgstr "Criar repositórios"
 
+#: rhodecode/templates/admin/users/user_edit.html:166
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:127
+#, fuzzy
+msgid "Fork repositories"
+msgstr "repositórios"
+
+#: rhodecode/templates/admin/users/user_edit.html:186
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:22
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:39
+#, fuzzy
+msgid "Nothing here yet"
+msgstr "Ainda não há notificações aqui"
+
+#: rhodecode/templates/admin/users/user_edit.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account.html:60
+#: rhodecode/templates/admin/users/user_edit_my_account.html:194
+msgid "Permission"
+msgstr "Permissão"
+
+#: rhodecode/templates/admin/users/user_edit.html:194
+#, fuzzy
+msgid "Edit Permission"
+msgstr "Permissão de repositório"
+
+#: rhodecode/templates/admin/users/user_edit.html:243
+#, fuzzy
+msgid "Email addresses"
+msgstr "Endereço de e-mail"
+
+#: rhodecode/templates/admin/users/user_edit.html:256
+#, fuzzy, python-format
+msgid "Confirm to delete this email: %s"
+msgstr "Confirma excluir este usuário: %s"
+
+#: rhodecode/templates/admin/users/user_edit.html:270
+#, fuzzy
+msgid "New email address"
+msgstr "Endereço de e-mail"
+
+#: rhodecode/templates/admin/users/user_edit.html:277
+#, fuzzy
+msgid "Add"
+msgstr "adicionar"
+
 #: rhodecode/templates/admin/users/user_edit_my_account.html:5
+#: rhodecode/templates/base/base.html:124
 msgid "My account"
 msgstr "Minha conta"
 
@@ -1756,26 +2652,77 @@
 msgid "My Account"
 msgstr "Minha Conta"
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:101
-msgid "My repositories"
+#: rhodecode/templates/admin/users/user_edit_my_account.html:35
+msgid "My permissions"
+msgstr "Minhas permissões"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:38
+#: rhodecode/templates/journal/journal.html:41
+msgid "My repos"
 msgstr "Meus repositórios"
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:107
-msgid "ADD REPOSITORY"
-msgstr "ADICIONAR REPOSITÓRIO"
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:118
-#: rhodecode/templates/branches/branches_data.html:7
-#: rhodecode/templates/shortlog/shortlog_data.html:8
-#: rhodecode/templates/tags/tags_data.html:7
-msgid "revision"
-msgstr "revisão"
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:41
+#, fuzzy
+msgid "My pull requests"
+msgstr "comentado no commit"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:45
+#, fuzzy
+msgid "Add repo"
+msgstr "adicionar novo"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2
+msgid "Opened by me"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:10
+#, python-format
+msgid "Pull request #%s opened on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15
+#, fuzzy
+msgid "Confirm to delete this pull request"
+msgstr "Confirma excluir este repositório"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:26
+msgid "I participate in"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:33
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:30
+#, python-format
+msgid "Pull request #%s opened by %s on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:7
+#: rhodecode/templates/bookmarks/bookmarks.html:40
+#: rhodecode/templates/bookmarks/bookmarks_data.html:9
+#: rhodecode/templates/branches/branches.html:55
+#: rhodecode/templates/journal/journal.html:60
+#: rhodecode/templates/tags/tags.html:40
+#: rhodecode/templates/tags/tags_data.html:9
+msgid "Revision"
+msgstr "Revisão"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/journal/journal.html:81
+msgid "private"
+msgstr "privado"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#, python-format
+msgid "Confirm to delete this repository: %s"
+msgstr "Confirma excluir esse repositório: %s"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:38
+#: rhodecode/templates/journal/journal.html:94
 msgid "No repositories yet"
 msgstr "Ainda não há repositórios"
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:40
+#: rhodecode/templates/journal/journal.html:96
 msgid "create one now"
 msgstr "criar um agora"
 
@@ -1783,42 +2730,42 @@
 msgid "Users administration"
 msgstr "Administração de usuários"
 
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/base/base.html:223
+msgid "users"
+msgstr "usuários"
+
 #: rhodecode/templates/admin/users/users.html:23
 msgid "ADD NEW USER"
 msgstr "ADICIONAR NOVO USUÁRIO"
 
-#: rhodecode/templates/admin/users/users.html:33
+#: rhodecode/templates/admin/users/users.html:77
 msgid "username"
 msgstr "nome de usuário"
 
-#: rhodecode/templates/admin/users/users.html:34
-#: rhodecode/templates/branches/branches_data.html:5
-#: rhodecode/templates/tags/tags_data.html:5
-msgid "name"
-msgstr "nome"
-
-#: rhodecode/templates/admin/users/users.html:35
+#: rhodecode/templates/admin/users/users.html:80
+#, fuzzy
+msgid "firstname"
+msgstr "Primeiro Nome"
+
+#: rhodecode/templates/admin/users/users.html:81
 msgid "lastname"
 msgstr "sobrenome"
 
-#: rhodecode/templates/admin/users/users.html:36
+#: rhodecode/templates/admin/users/users.html:82
 msgid "last login"
 msgstr "último login"
 
-#: rhodecode/templates/admin/users/users.html:37
+#: rhodecode/templates/admin/users/users.html:84
 #: rhodecode/templates/admin/users_groups/users_groups.html:34
 msgid "active"
 msgstr "ativo"
 
-#: rhodecode/templates/admin/users/users.html:39
-#: rhodecode/templates/base/base.html:305
+#: rhodecode/templates/admin/users/users.html:86
+#: rhodecode/templates/base/base.html:226
 msgid "ldap"
 msgstr "ldap"
 
-#: rhodecode/templates/admin/users/users.html:56
-msgid "Confirm to delete this user"
-msgstr "Conforma excluir este usuário"
-
 #: rhodecode/templates/admin/users_groups/users_group_add.html:5
 msgid "Add users group"
 msgstr "Adicionar grupo de usuários"
@@ -1860,6 +2807,10 @@
 msgid "Add all elements"
 msgstr "Adicionar todos os elementos"
 
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:146
+msgid "Group members"
+msgstr "Membros do grupo"
+
 #: rhodecode/templates/admin/users_groups/users_groups.html:5
 msgid "Users groups administration"
 msgstr "Administração de grupos de usuários"
@@ -1872,399 +2823,627 @@
 msgid "group name"
 msgstr "nome do grupo"
 
-#: rhodecode/templates/base/base.html:32
+#: rhodecode/templates/admin/users_groups/users_groups.html:33
+#: rhodecode/templates/base/root.html:46
+msgid "members"
+msgstr "membros"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:45
+#, python-format
+msgid "Confirm to delete this users group: %s"
+msgstr "Confirme para excluir este grupo de usuários: %s"
+
+#: rhodecode/templates/base/base.html:41
+msgid "Submit a bug"
+msgstr "Encaminhe um bug"
+
+#: rhodecode/templates/base/base.html:77
+msgid "Login to your account"
+msgstr "Entrar com sua conta"
+
+#: rhodecode/templates/base/base.html:100
 msgid "Forgot password ?"
 msgstr "Esqueceu a senha ?"
 
-#: rhodecode/templates/base/base.html:57
-#: rhodecode/templates/base/base.html:338
-#: rhodecode/templates/base/base.html:340
-#: rhodecode/templates/base/base.html:342
+#: rhodecode/templates/base/base.html:107
+msgid "Log In"
+msgstr "Entrar"
+
+#: rhodecode/templates/base/base.html:118
+msgid "Inbox"
+msgstr "Caixa de Entrada"
+
+#: rhodecode/templates/base/base.html:122
+#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/base/base.html:302
+#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/bookmarks/bookmarks.html:11
+#: rhodecode/templates/branches/branches.html:10
+#: rhodecode/templates/changelog/changelog.html:10
+#: rhodecode/templates/changeset/changeset.html:10
+#: rhodecode/templates/changeset/changeset_range.html:9
+#: rhodecode/templates/compare/compare_diff.html:9
+#: rhodecode/templates/files/file_diff.html:8
+#: rhodecode/templates/files/files.html:8
+#: rhodecode/templates/files/files_add.html:15
+#: rhodecode/templates/files/files_edit.html:15
+#: rhodecode/templates/followers/followers.html:9
+#: rhodecode/templates/forks/fork.html:9 rhodecode/templates/forks/forks.html:9
+#: rhodecode/templates/pullrequests/pullrequest.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8
+#: rhodecode/templates/settings/repo_settings.html:9
+#: rhodecode/templates/shortlog/shortlog.html:10
+#: rhodecode/templates/summary/summary.html:8
+#: rhodecode/templates/tags/tags.html:11
 msgid "Home"
 msgstr "Início"
 
-#: rhodecode/templates/base/base.html:61
-#: rhodecode/templates/base/base.html:347
-#: rhodecode/templates/base/base.html:349
-#: rhodecode/templates/base/base.html:351
+#: rhodecode/templates/base/base.html:123
+#: rhodecode/templates/base/base.html:309
+#: rhodecode/templates/base/base.html:311
+#: rhodecode/templates/base/base.html:313
 #: rhodecode/templates/journal/journal.html:4
-#: rhodecode/templates/journal/journal.html:17
+#: rhodecode/templates/journal/journal.html:21
 #: rhodecode/templates/journal/public_journal.html:4
 msgid "Journal"
 msgstr "Diário"
 
-#: rhodecode/templates/base/base.html:66
-msgid "Login"
-msgstr "Entrar"
-
-#: rhodecode/templates/base/base.html:68
+#: rhodecode/templates/base/base.html:125
 msgid "Log Out"
 msgstr "Sair"
 
-#: rhodecode/templates/base/base.html:107
-msgid "Submit a bug"
-msgstr "Encaminhe um bug"
-
-#: rhodecode/templates/base/base.html:141
+#: rhodecode/templates/base/base.html:144
 msgid "Switch repository"
 msgstr "Trocar repositório"
 
-#: rhodecode/templates/base/base.html:143
+#: rhodecode/templates/base/base.html:146
 msgid "Products"
 msgstr "Produtos"
 
-#: rhodecode/templates/base/base.html:149
+#: rhodecode/templates/base/base.html:152
+#: rhodecode/templates/base/base.html:182
 msgid "loading..."
 msgstr "carregando..."
 
-#: rhodecode/templates/base/base.html:234
-#: rhodecode/templates/base/base.html:236
-#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:158
+#: rhodecode/templates/base/base.html:160
+#: rhodecode/templates/base/base.html:162
+#: rhodecode/templates/data_table/_dt_elements.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:17
+#: rhodecode/templates/data_table/_dt_elements.html:19
+msgid "Summary"
+msgstr "Sumário"
+
+#: rhodecode/templates/base/base.html:166
+#: rhodecode/templates/base/base.html:168
+#: rhodecode/templates/base/base.html:170
+#: rhodecode/templates/changelog/changelog.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:23
+#: rhodecode/templates/data_table/_dt_elements.html:25
+#: rhodecode/templates/data_table/_dt_elements.html:27
+msgid "Changelog"
+msgstr "Registro de alterações"
+
+#: rhodecode/templates/base/base.html:175
+#: rhodecode/templates/base/base.html:177
+#: rhodecode/templates/base/base.html:179
 msgid "Switch to"
 msgstr "Trocar para"
 
-#: rhodecode/templates/base/base.html:242
-#: rhodecode/templates/branches/branches.html:13
-msgid "branches"
-msgstr "ramos"
-
-#: rhodecode/templates/base/base.html:249
-#: rhodecode/templates/branches/branches_data.html:52
-msgid "There are no branches yet"
-msgstr "Ainda não há ramos"
-
-#: rhodecode/templates/base/base.html:254
-#: rhodecode/templates/shortlog/shortlog_data.html:10
-#: rhodecode/templates/tags/tags.html:14
-msgid "tags"
-msgstr "etiquetas"
-
-#: rhodecode/templates/base/base.html:261
-#: rhodecode/templates/tags/tags_data.html:32
-msgid "There are no tags yet"
-msgstr "Ainda não há etiquetas"
-
-#: rhodecode/templates/base/base.html:277
-#: rhodecode/templates/base/base.html:281
-#: rhodecode/templates/files/files_annotate.html:40
-#: rhodecode/templates/files/files_source.html:11
+#: rhodecode/templates/base/base.html:186
+#: rhodecode/templates/base/base.html:188
+#: rhodecode/templates/base/base.html:190
+#: rhodecode/templates/data_table/_dt_elements.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:33
+#: rhodecode/templates/data_table/_dt_elements.html:35
+msgid "Files"
+msgstr "Arquivos"
+
+#: rhodecode/templates/base/base.html:195
+#: rhodecode/templates/base/base.html:199
 msgid "Options"
 msgstr "Opções"
 
-#: rhodecode/templates/base/base.html:286
-#: rhodecode/templates/base/base.html:288
-#: rhodecode/templates/base/base.html:306
+#: rhodecode/templates/base/base.html:204
+#: rhodecode/templates/base/base.html:206
+#: rhodecode/templates/base/base.html:227
 msgid "settings"
 msgstr "configurações"
 
-#: rhodecode/templates/base/base.html:292
+#: rhodecode/templates/base/base.html:209
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/forks/fork.html:13
+msgid "fork"
+msgstr "bifurcação"
+
+#: rhodecode/templates/base/base.html:211
+#: rhodecode/templates/changelog/changelog.html:40
+msgid "Open new pull request"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:213
 msgid "search"
 msgstr "pesquisar"
 
-#: rhodecode/templates/base/base.html:299
-msgid "journal"
-msgstr "diário"
-
-#: rhodecode/templates/base/base.html:301
+#: rhodecode/templates/base/base.html:222
 msgid "repositories groups"
 msgstr "grupos de repositórios"
 
-#: rhodecode/templates/base/base.html:302
-msgid "users"
-msgstr "usuários"
-
-#: rhodecode/templates/base/base.html:303
+#: rhodecode/templates/base/base.html:224
 msgid "users groups"
 msgstr "grupos de usuários"
 
-#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/base/base.html:225
 msgid "permissions"
 msgstr "permissões"
 
-#: rhodecode/templates/base/base.html:317
-#: rhodecode/templates/base/base.html:319
-#: rhodecode/templates/followers/followers.html:5
+#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:240
 msgid "Followers"
 msgstr "Seguidores"
 
-#: rhodecode/templates/base/base.html:325
-#: rhodecode/templates/base/base.html:327
-#: rhodecode/templates/forks/forks.html:5
+#: rhodecode/templates/base/base.html:246
+#: rhodecode/templates/base/base.html:248
 msgid "Forks"
 msgstr "Bifurcações"
 
-#: rhodecode/templates/base/base.html:356
-#: rhodecode/templates/base/base.html:358
-#: rhodecode/templates/base/base.html:360
-#: rhodecode/templates/search/search.html:4
-#: rhodecode/templates/search/search.html:24
-#: rhodecode/templates/search/search.html:46
+#: rhodecode/templates/base/base.html:327
+#: rhodecode/templates/base/base.html:329
+#: rhodecode/templates/base/base.html:331
+#: rhodecode/templates/search/search.html:52
 msgid "Search"
 msgstr "Pesquisar"
 
-#: rhodecode/templates/base/root.html:57
-#: rhodecode/templates/journal/journal.html:48
-#: rhodecode/templates/summary/summary.html:36
+#: rhodecode/templates/base/root.html:42
+msgid "add another comment"
+msgstr "adicionar outro comentário"
+
+#: rhodecode/templates/base/root.html:43
+#: rhodecode/templates/journal/journal.html:120
+#: rhodecode/templates/summary/summary.html:57
 msgid "Stop following this repository"
 msgstr "Parar de seguir este repositório"
 
-#: rhodecode/templates/base/root.html:66
-#: rhodecode/templates/summary/summary.html:40
+#: rhodecode/templates/base/root.html:44
+#: rhodecode/templates/summary/summary.html:61
 msgid "Start following this repository"
 msgstr "Passar a seguir este repositório"
 
-#: rhodecode/templates/branches/branches_data.html:4
-#: rhodecode/templates/tags/tags_data.html:4
+#: rhodecode/templates/base/root.html:45
+msgid "Group"
+msgstr "Grupo"
+
+#: rhodecode/templates/base/root.html:47
+msgid "search truncated"
+msgstr "pesquisa truncada"
+
+#: rhodecode/templates/base/root.html:48
+msgid "no matching files"
+msgstr "nenhum arquivo corresponde"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:5
+#, fuzzy, python-format
+msgid "%s Bookmarks"
+msgstr "marcadores"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:39
+#: rhodecode/templates/bookmarks/bookmarks_data.html:8
+#: rhodecode/templates/branches/branches.html:54
+#: rhodecode/templates/tags/tags.html:39
+#: rhodecode/templates/tags/tags_data.html:8
+msgid "Author"
+msgstr "Autor"
+
+#: rhodecode/templates/branches/branches.html:5
+#, fuzzy, python-format
+msgid "%s Branches"
+msgstr "ramos"
+
+#: rhodecode/templates/branches/branches.html:29
+#, fuzzy
+msgid "Compare branches"
+msgstr "ramos"
+
+#: rhodecode/templates/branches/branches.html:57
+#: rhodecode/templates/compare/compare_diff.html:5
+#: rhodecode/templates/compare/compare_diff.html:13
+#, fuzzy
+msgid "Compare"
+msgstr "comparar exibir"
+
+#: rhodecode/templates/branches/branches_data.html:6
+msgid "name"
+msgstr "nome"
+
+#: rhodecode/templates/branches/branches_data.html:7
 msgid "date"
 msgstr "data"
 
-#: rhodecode/templates/branches/branches_data.html:6
-#: rhodecode/templates/shortlog/shortlog_data.html:7
-#: rhodecode/templates/tags/tags_data.html:6
-msgid "author"
-msgstr "autor"
-
 #: rhodecode/templates/branches/branches_data.html:8
-#: rhodecode/templates/shortlog/shortlog_data.html:11
-#: rhodecode/templates/tags/tags_data.html:8
-msgid "links"
-msgstr "inks"
-
-#: rhodecode/templates/branches/branches_data.html:23
-#: rhodecode/templates/branches/branches_data.html:43
-#: rhodecode/templates/shortlog/shortlog_data.html:39
-#: rhodecode/templates/tags/tags_data.html:24
-msgid "changeset"
-msgstr "conjunto de mudanças"
-
-#: rhodecode/templates/branches/branches_data.html:25
-#: rhodecode/templates/branches/branches_data.html:45
-#: rhodecode/templates/files/files.html:12
-#: rhodecode/templates/shortlog/shortlog_data.html:41
-#: rhodecode/templates/summary/summary.html:233
-#: rhodecode/templates/tags/tags_data.html:26
-msgid "files"
-msgstr "arquivos"
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "showing "
-msgstr "mostrando "
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "out of"
-msgstr "de"
+#: rhodecode/templates/shortlog/shortlog_data.html:8
+msgid "author"
+msgstr "autor"
+
+#: rhodecode/templates/branches/branches_data.html:9
+#: rhodecode/templates/shortlog/shortlog_data.html:5
+msgid "revision"
+msgstr "revisão"
+
+#: rhodecode/templates/branches/branches_data.html:10
+#, fuzzy
+msgid "compare"
+msgstr "comparar exibir"
+
+#: rhodecode/templates/changelog/changelog.html:6
+#, fuzzy, python-format
+msgid "%s Changelog"
+msgstr "Registro de alterações"
+
+#: rhodecode/templates/changelog/changelog.html:15
+#, python-format
+msgid "showing %d out of %d revision"
+msgid_plural "showing %d out of %d revisions"
+msgstr[0] "mostrando %d de %d revisão"
+msgstr[1] "mostrando %d de %d revisões"
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:19
+#, python-format
+msgid "compare fork with %s"
+msgstr ""
 
 #: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:21
+#, fuzzy
+msgid "Compare fork"
+msgstr "comparar exibir"
+
+#: rhodecode/templates/changelog/changelog.html:46
 msgid "Show"
 msgstr "Mostrar"
 
-#: rhodecode/templates/changelog/changelog.html:50
-#: rhodecode/templates/changeset/changeset.html:42
-#: rhodecode/templates/summary/summary.html:609
-msgid "commit"
-msgstr "commit"
-
-#: rhodecode/templates/changelog/changelog.html:63
+#: rhodecode/templates/changelog/changelog.html:72
+#: rhodecode/templates/summary/summary.html:364
+msgid "show more"
+msgstr "mostrar mais"
+
+#: rhodecode/templates/changelog/changelog.html:76
 msgid "Affected number of files, click to show more details"
 msgstr "Número de arquivos afetados, clique para mostrar mais detalhes"
 
-#: rhodecode/templates/changelog/changelog.html:67
-#: rhodecode/templates/changeset/changeset.html:66
-msgid "merge"
-msgstr "mesclar"
-
-#: rhodecode/templates/changelog/changelog.html:72
-#: rhodecode/templates/changeset/changeset.html:72
+#: rhodecode/templates/changelog/changelog.html:89
+#: rhodecode/templates/changeset/changeset.html:38
+#: rhodecode/templates/changeset/changeset_file_comment.html:20
+#: rhodecode/templates/changeset/changeset_range.html:46
+#, fuzzy
+msgid "Changeset status"
+msgstr "Conjuntos de mudanças"
+
+#: rhodecode/templates/changelog/changelog.html:92
+msgid "Click to open associated pull request"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:102
+#: rhodecode/templates/changeset/changeset.html:78
 msgid "Parent"
 msgstr "Progenitor"
 
-#: rhodecode/templates/changelog/changelog.html:77
-#: rhodecode/templates/changeset/changeset.html:77
+#: rhodecode/templates/changelog/changelog.html:108
+#: rhodecode/templates/changeset/changeset.html:84
 msgid "No parents"
 msgstr "Sem progenitores"
 
-#: rhodecode/templates/changelog/changelog.html:82
-#: rhodecode/templates/changeset/changeset.html:80
+#: rhodecode/templates/changelog/changelog.html:113
+#: rhodecode/templates/changeset/changeset.html:88
+msgid "merge"
+msgstr "mesclar"
+
+#: rhodecode/templates/changelog/changelog.html:116
+#: rhodecode/templates/changeset/changeset.html:91
 #: rhodecode/templates/files/files.html:29
-#: rhodecode/templates/files/files_annotate.html:25
+#: rhodecode/templates/files/files_add.html:33
 #: rhodecode/templates/files/files_edit.html:33
 #: rhodecode/templates/shortlog/shortlog_data.html:9
 msgid "branch"
 msgstr "ramo"
 
-#: rhodecode/templates/changelog/changelog.html:86
-#: rhodecode/templates/changeset/changeset.html:83
+#: rhodecode/templates/changelog/changelog.html:122
+msgid "bookmark"
+msgstr "marcador"
+
+#: rhodecode/templates/changelog/changelog.html:128
+#: rhodecode/templates/changeset/changeset.html:96
 msgid "tag"
 msgstr "etiqueta"
 
-#: rhodecode/templates/changelog/changelog.html:122
+#: rhodecode/templates/changelog/changelog.html:164
 msgid "Show selected changes __S -> __E"
 msgstr "Mostrar alterações selecionadas __S -> __E"
 
-#: rhodecode/templates/changelog/changelog.html:172
-#: rhodecode/templates/shortlog/shortlog_data.html:61
+#: rhodecode/templates/changelog/changelog.html:255
 msgid "There are no changes yet"
 msgstr "Ainda não há alteações"
 
-#: rhodecode/templates/changelog/changelog_details.html:2
-#: rhodecode/templates/changeset/changeset.html:55
+#: rhodecode/templates/changelog/changelog_details.html:4
+#: rhodecode/templates/changeset/changeset.html:66
 msgid "removed"
 msgstr "removidos"
 
-#: rhodecode/templates/changelog/changelog_details.html:3
-#: rhodecode/templates/changeset/changeset.html:56
+#: rhodecode/templates/changelog/changelog_details.html:5
+#: rhodecode/templates/changeset/changeset.html:67
 msgid "changed"
 msgstr "alterados"
 
-#: rhodecode/templates/changelog/changelog_details.html:4
-#: rhodecode/templates/changeset/changeset.html:57
+#: rhodecode/templates/changelog/changelog_details.html:6
+#: rhodecode/templates/changeset/changeset.html:68
 msgid "added"
 msgstr "adicionados"
 
-#: rhodecode/templates/changelog/changelog_details.html:6
-#: rhodecode/templates/changelog/changelog_details.html:7
 #: rhodecode/templates/changelog/changelog_details.html:8
-#: rhodecode/templates/changeset/changeset.html:59
-#: rhodecode/templates/changeset/changeset.html:60
-#: rhodecode/templates/changeset/changeset.html:61
+#: rhodecode/templates/changelog/changelog_details.html:9
+#: rhodecode/templates/changelog/changelog_details.html:10
+#: rhodecode/templates/changeset/changeset.html:70
+#: rhodecode/templates/changeset/changeset.html:71
+#: rhodecode/templates/changeset/changeset.html:72
 #, python-format
 msgid "affected %s files"
 msgstr "%s arquivos afetados"
 
 #: rhodecode/templates/changeset/changeset.html:6
+#, fuzzy, python-format
+msgid "%s Changeset"
+msgstr "Conjunto de Mudanças"
+
 #: rhodecode/templates/changeset/changeset.html:14
-#: rhodecode/templates/changeset/changeset.html:31
 msgid "Changeset"
 msgstr "Conjunto de Mudanças"
 
-#: rhodecode/templates/changeset/changeset.html:32
-#: rhodecode/templates/changeset/changeset.html:121
-#: rhodecode/templates/changeset/changeset_range.html:78
-#: rhodecode/templates/files/file_diff.html:32
-#: rhodecode/templates/files/file_diff.html:42
+#: rhodecode/templates/changeset/changeset.html:43
+#: rhodecode/templates/changeset/diff_block.html:20
 msgid "raw diff"
 msgstr "diff bruto"
 
-#: rhodecode/templates/changeset/changeset.html:34
-#: rhodecode/templates/changeset/changeset.html:123
-#: rhodecode/templates/changeset/changeset_range.html:80
-#: rhodecode/templates/files/file_diff.html:34
+#: rhodecode/templates/changeset/changeset.html:44
+#: rhodecode/templates/changeset/diff_block.html:21
 msgid "download diff"
 msgstr "descarregar diff"
 
-#: rhodecode/templates/changeset/changeset.html:90
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] "%d comentário"
+msgstr[1] "%d comentários"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
 #, python-format
-msgid "%s files affected with %s additions and %s deletions."
-msgstr "%s arquivos afetados com %s adições e %s exclusões"
-
-#: rhodecode/templates/changeset/changeset.html:101
+msgid "(%d inline)"
+msgid_plural "(%d inline)"
+msgstr[0] "(%d em linha)"
+msgstr[1] "(%d em linha)"
+
+#: rhodecode/templates/changeset/changeset.html:103
+#, python-format
+msgid "%s files affected with %s insertions and %s deletions:"
+msgstr "%s arquivos afetados com %s inserções e %s exclusões"
+
+#: rhodecode/templates/changeset/changeset.html:119
 msgid "Changeset was too big and was cut off..."
 msgstr "Conjunto de mudanças era grande demais e foi cortado..."
 
-#: rhodecode/templates/changeset/changeset.html:119
-#: rhodecode/templates/changeset/changeset_range.html:76
-#: rhodecode/templates/files/file_diff.html:30
+#: rhodecode/templates/changeset/changeset_file_comment.html:42
+msgid "Submitting..."
+msgstr "Enviando..."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:45
+msgid "Commenting on line {1}."
+msgstr "Comentando a linha {1}."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:46
+#: rhodecode/templates/changeset/changeset_file_comment.html:121
+#, python-format
+msgid "Comments parsed using %s syntax with %s support."
+msgstr "Comentários interpretados usando a sintaxe %s com suporte a %s."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:123
+msgid "Use @username inside this text to send notification to this RhodeCode user"
+msgstr ""
+"Use @nomedeusuário dentro desse texto para enviar notificação a este "
+"usuário do RhodeCode"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:59
+#: rhodecode/templates/changeset/changeset_file_comment.html:138
+msgid "Comment"
+msgstr "Comentário"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:60
+#: rhodecode/templates/changeset/changeset_file_comment.html:71
+msgid "Hide"
+msgstr "Ocultar"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "You need to be logged in to comment."
+msgstr "Você precisa estar logado para comentar."
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "Login now"
+msgstr "Entrar agora"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:118
+msgid "Leave a comment"
+msgstr "Deixar um comentário"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "Check this to change current status of code-review for this changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+#, fuzzy
+msgid "change status"
+msgstr "Conjuntos de mudanças"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:140
+msgid "Comment and close"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:5
+#, fuzzy, python-format
+msgid "%s Changesets"
+msgstr "Conjuntos de mudanças"
+
+#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/templates/compare/compare_diff.html:29
+msgid "Compare View"
+msgstr "Exibir Comparação"
+
+#: rhodecode/templates/changeset/changeset_range.html:54
+#: rhodecode/templates/compare/compare_diff.html:41
+#: rhodecode/templates/pullrequests/pullrequest_show.html:69
+msgid "Files affected"
+msgstr "Arquivos afetados"
+
+#: rhodecode/templates/changeset/diff_block.html:19
 msgid "diff"
 msgstr "diff"
 
-#: rhodecode/templates/changeset/changeset.html:132
-#: rhodecode/templates/changeset/changeset_range.html:89
-msgid "No changes in this file"
-msgstr "Nenhuma alteração nesse arquivo"
-
-#: rhodecode/templates/changeset/changeset_range.html:30
-msgid "Compare View"
-msgstr "Exibir Comparação"
-
-#: rhodecode/templates/changeset/changeset_range.html:52
-msgid "Files affected"
-msgstr "Arquivos afetados"
-
-#: rhodecode/templates/errors/error_document.html:44
+#: rhodecode/templates/changeset/diff_block.html:27
+msgid "show inline comments"
+msgstr "mostrar comentários em linha"
+
+#: rhodecode/templates/compare/compare_cs.html:5
+#, fuzzy
+msgid "No changesets"
+msgstr "Nenhum conjunto de alterações ainda."
+
+#: rhodecode/templates/compare/compare_diff.html:37
+#, fuzzy
+msgid "Outgoing changesets"
+msgstr "Nenhum conjunto de alterações ainda."
+
+#: rhodecode/templates/data_table/_dt_elements.html:39
+#: rhodecode/templates/data_table/_dt_elements.html:41
+#: rhodecode/templates/data_table/_dt_elements.html:43
+msgid "Fork"
+msgstr "Bifurcação"
+
+#: rhodecode/templates/data_table/_dt_elements.html:60
+#: rhodecode/templates/journal/journal.html:126
+#: rhodecode/templates/summary/summary.html:68
+msgid "Mercurial repository"
+msgstr "Repositório Mercurial"
+
+#: rhodecode/templates/data_table/_dt_elements.html:62
+#: rhodecode/templates/journal/journal.html:128
+#: rhodecode/templates/summary/summary.html:71
+msgid "Git repository"
+msgstr "Repositório Git"
+
+#: rhodecode/templates/data_table/_dt_elements.html:69
+#: rhodecode/templates/journal/journal.html:134
+#: rhodecode/templates/summary/summary.html:78
+msgid "public repository"
+msgstr "repositório público"
+
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/summary/summary.html:87
+#: rhodecode/templates/summary/summary.html:88
+msgid "Fork of"
+msgstr "Bifurcação de"
+
+#: rhodecode/templates/data_table/_dt_elements.html:92
+msgid "No changesets yet"
+msgstr "Nenhum conjunto de alterações ainda."
+
+#: rhodecode/templates/data_table/_dt_elements.html:104
+#, python-format
+msgid "Confirm to delete this user: %s"
+msgstr "Confirma excluir este usuário: %s"
+
+#: rhodecode/templates/email_templates/main.html:8
+msgid "This is an notification from RhodeCode."
+msgstr "Esta é uma notificação do RhodeCode."
+
+#: rhodecode/templates/errors/error_document.html:46
 #, python-format
 msgid "You will be redirected to %s in %s seconds"
 msgstr "Você será redirecionado para %s em %s segundos"
 
 #: rhodecode/templates/files/file_diff.html:4
+#, fuzzy, python-format
+msgid "%s File diff"
+msgstr "Diff do arquivo"
+
 #: rhodecode/templates/files/file_diff.html:12
 msgid "File diff"
 msgstr "Diff do arquivo"
 
-#: rhodecode/templates/files/file_diff.html:42
-msgid "Diff is to big to display"
-msgstr "Diff é grande demais para exibir"
-
-#: rhodecode/templates/files/files.html:37
-#: rhodecode/templates/files/files_annotate.html:31
+#: rhodecode/templates/files/files.html:4
+#: rhodecode/templates/files/files.html:72
+#, fuzzy, python-format
+msgid "%s files"
+msgstr "arquivos"
+
+#: rhodecode/templates/files/files.html:12
+#: rhodecode/templates/summary/summary.html:340
+msgid "files"
+msgstr "arquivos"
+
+#: rhodecode/templates/files/files_add.html:4
+#: rhodecode/templates/files/files_edit.html:4
+#, fuzzy, python-format
+msgid "%s Edit file"
+msgstr "editar arquivo"
+
+#: rhodecode/templates/files/files_add.html:19
+msgid "add file"
+msgstr "adicionar arquivo"
+
+#: rhodecode/templates/files/files_add.html:40
+msgid "Add new file"
+msgstr "Adicionar novo arquivo"
+
+#: rhodecode/templates/files/files_add.html:45
+msgid "File Name"
+msgstr "Nome de Arquivo"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:58
+msgid "or"
+msgstr "ou"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:54
+msgid "Upload file"
+msgstr "Enviar arquivo"
+
+#: rhodecode/templates/files/files_add.html:58
+msgid "Create new file"
+msgstr "Criar novo arquivo"
+
+#: rhodecode/templates/files/files_add.html:63
 #: rhodecode/templates/files/files_edit.html:39
+#: rhodecode/templates/files/files_ypjax.html:3
 msgid "Location"
 msgstr "Local"
 
-#: rhodecode/templates/files/files.html:46
-msgid "Go back"
-msgstr "Voltar"
-
-#: rhodecode/templates/files/files.html:47
-msgid "No files at given path"
-msgstr "Nenhum arquivo no caminho especificado"
-
-#: rhodecode/templates/files/files_annotate.html:4
-msgid "File annotate"
-msgstr "Anotar arquivo"
-
-#: rhodecode/templates/files/files_annotate.html:12
-msgid "annotate"
-msgstr "anotar"
-
-#: rhodecode/templates/files/files_annotate.html:33
-#: rhodecode/templates/files/files_browser.html:160
-#: rhodecode/templates/files/files_source.html:2
-msgid "Revision"
-msgstr "Revisão"
-
-#: rhodecode/templates/files/files_annotate.html:36
-#: rhodecode/templates/files/files_browser.html:158
-#: rhodecode/templates/files/files_source.html:7
-msgid "Size"
-msgstr "Tamanho"
-
-#: rhodecode/templates/files/files_annotate.html:38
-#: rhodecode/templates/files/files_browser.html:159
-#: rhodecode/templates/files/files_source.html:9
-msgid "Mimetype"
-msgstr "Mimetype"
-
-#: rhodecode/templates/files/files_annotate.html:41
-msgid "show source"
-msgstr "mostrar fonte"
-
-#: rhodecode/templates/files/files_annotate.html:43
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:14
-#: rhodecode/templates/files/files_source.html:51
-msgid "show as raw"
-msgstr "mostrar como bruto"
-
-#: rhodecode/templates/files/files_annotate.html:45
-#: rhodecode/templates/files/files_source.html:16
-msgid "download as raw"
-msgstr "descarregar como bruto"
-
-#: rhodecode/templates/files/files_annotate.html:54
-#: rhodecode/templates/files/files_source.html:25
-msgid "History"
-msgstr "Histórico"
-
-#: rhodecode/templates/files/files_annotate.html:73
-#: rhodecode/templates/files/files_source.html:46
-#, python-format
-msgid "Binary file (%s)"
-msgstr "Arquivo binário (%s)"
-
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:51
-msgid "File is too big to display"
-msgstr "Arquivo é grande demais para exibir"
+#: rhodecode/templates/files/files_add.html:67
+msgid "use / to separate directories"
+msgstr "use / para separar diretórios"
+
+#: rhodecode/templates/files/files_add.html:77
+#: rhodecode/templates/files/files_edit.html:63
+#: rhodecode/templates/shortlog/shortlog_data.html:6
+msgid "commit message"
+msgstr "mensagem de commit"
+
+#: rhodecode/templates/files/files_add.html:81
+#: rhodecode/templates/files/files_edit.html:67
+msgid "Commit changes"
+msgstr "Realizar commit das alterações"
 
 #: rhodecode/templates/files/files_browser.html:13
 msgid "view"
@@ -2286,59 +3465,165 @@
 msgid "search file list"
 msgstr "pesquisar lista de arquivos"
 
-#: rhodecode/templates/files/files_browser.html:32
+#: rhodecode/templates/files/files_browser.html:31
+#: rhodecode/templates/shortlog/shortlog_data.html:65
+msgid "add new file"
+msgstr "adicionar novo arquivo"
+
+#: rhodecode/templates/files/files_browser.html:35
 msgid "Loading file list..."
 msgstr "Carregando lista de arquivos..."
 
-#: rhodecode/templates/files/files_browser.html:111
-msgid "search truncated"
-msgstr "pesquisa truncada"
-
-#: rhodecode/templates/files/files_browser.html:122
-msgid "no matching files"
-msgstr "nenhum arquivo corresponde"
-
-#: rhodecode/templates/files/files_browser.html:161
+#: rhodecode/templates/files/files_browser.html:48
+msgid "Size"
+msgstr "Tamanho"
+
+#: rhodecode/templates/files/files_browser.html:49
+msgid "Mimetype"
+msgstr "Mimetype"
+
+#: rhodecode/templates/files/files_browser.html:50
+msgid "Last Revision"
+msgstr "Última revisão"
+
+#: rhodecode/templates/files/files_browser.html:51
 msgid "Last modified"
 msgstr "Última alteração"
 
-#: rhodecode/templates/files/files_browser.html:162
+#: rhodecode/templates/files/files_browser.html:52
 msgid "Last commiter"
 msgstr "Último commiter"
 
-#: rhodecode/templates/files/files_edit.html:4
-msgid "Edit file"
-msgstr "Editar arquivo"
-
 #: rhodecode/templates/files/files_edit.html:19
 msgid "edit file"
 msgstr "editar arquivo"
 
-#: rhodecode/templates/files/files_edit.html:45
-#: rhodecode/templates/shortlog/shortlog_data.html:5
-msgid "commit message"
-msgstr "mensagem de commit"
+#: rhodecode/templates/files/files_edit.html:49
+#: rhodecode/templates/files/files_source.html:38
+msgid "show annotation"
+msgstr "mostrar anotação"
+
+#: rhodecode/templates/files/files_edit.html:50
+#: rhodecode/templates/files/files_source.html:40
+#: rhodecode/templates/files/files_source.html:68
+msgid "show as raw"
+msgstr "mostrar como bruto"
 
 #: rhodecode/templates/files/files_edit.html:51
-msgid "Commit changes"
-msgstr "Realizar commit das alterações"
-
-#: rhodecode/templates/files/files_source.html:12
-msgid "show annotation"
-msgstr "mostrar anotação"
-
-#: rhodecode/templates/files/files_source.html:153
+#: rhodecode/templates/files/files_source.html:41
+msgid "download as raw"
+msgstr "descarregar como bruto"
+
+#: rhodecode/templates/files/files_edit.html:54
+msgid "source"
+msgstr "fonte"
+
+#: rhodecode/templates/files/files_edit.html:59
+msgid "Editing file"
+msgstr "Editando arquivo"
+
+#: rhodecode/templates/files/files_source.html:2
+msgid "History"
+msgstr "Histórico"
+
+#: rhodecode/templates/files/files_source.html:9
+#, fuzzy
+msgid "diff to revision"
+msgstr "próxima revisão"
+
+#: rhodecode/templates/files/files_source.html:10
+#, fuzzy
+msgid "show at revision"
+msgstr "próxima revisão"
+
+#: rhodecode/templates/files/files_source.html:14
+#, fuzzy, python-format
+msgid "%s author"
+msgid_plural "%s authors"
+msgstr[0] "autor"
+msgstr[1] "autors"
+
+#: rhodecode/templates/files/files_source.html:36
+msgid "show source"
+msgstr "mostrar fonte"
+
+#: rhodecode/templates/files/files_source.html:59
+#, python-format
+msgid "Binary file (%s)"
+msgstr "Arquivo binário (%s)"
+
+#: rhodecode/templates/files/files_source.html:68
+msgid "File is too big to display"
+msgstr "Arquivo é grande demais para exibir"
+
+#: rhodecode/templates/files/files_source.html:124
 msgid "Selection link"
 msgstr "Link da seleção"
 
+#: rhodecode/templates/files/files_ypjax.html:5
+msgid "annotation"
+msgstr "anotação"
+
+#: rhodecode/templates/files/files_ypjax.html:15
+msgid "Go back"
+msgstr "Voltar"
+
+#: rhodecode/templates/files/files_ypjax.html:16
+msgid "No files at given path"
+msgstr "Nenhum arquivo no caminho especificado"
+
+#: rhodecode/templates/followers/followers.html:5
+#, fuzzy, python-format
+msgid "%s Followers"
+msgstr "seguidores"
+
 #: rhodecode/templates/followers/followers.html:13
 msgid "followers"
 msgstr "seguidores"
 
 #: rhodecode/templates/followers/followers_data.html:12
-msgid "Started following"
+#, fuzzy
+msgid "Started following -"
 msgstr "Passou a seguir"
 
+#: rhodecode/templates/forks/fork.html:5
+#, fuzzy, python-format
+msgid "%s Fork"
+msgstr "bifurcação"
+
+#: rhodecode/templates/forks/fork.html:31
+msgid "Fork name"
+msgstr "Nome da bifurcação"
+
+#: rhodecode/templates/forks/fork.html:68
+msgid "Private"
+msgstr "Privado"
+
+#: rhodecode/templates/forks/fork.html:77
+msgid "Copy permissions"
+msgstr "Copiar permissões"
+
+#: rhodecode/templates/forks/fork.html:81
+msgid "Copy permissions from forked repository"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:86
+msgid "Update after clone"
+msgstr "Atualizar após clonar"
+
+#: rhodecode/templates/forks/fork.html:90
+msgid "Checkout source after making a clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:94
+msgid "fork this repository"
+msgstr "bifurcar este repositório"
+
+#: rhodecode/templates/forks/forks.html:5
+#, fuzzy, python-format
+msgid "%s Forks"
+msgstr "bifurcações"
+
 #: rhodecode/templates/forks/forks.html:13
 msgid "forks"
 msgstr "bifurcações"
@@ -2347,184 +3632,413 @@
 msgid "forked"
 msgstr "bifurcado"
 
-#: rhodecode/templates/forks/forks_data.html:34
+#: rhodecode/templates/forks/forks_data.html:38
 msgid "There are no forks yet"
 msgstr "Ainda não há bifurcações"
 
-#: rhodecode/templates/journal/journal.html:34
-msgid "Following"
-msgstr "Seguindo"
-
-#: rhodecode/templates/journal/journal.html:41
-msgid "following user"
-msgstr "seguindo usuário"
+#: rhodecode/templates/journal/journal.html:13
+#, fuzzy
+msgid "ATOM journal feed"
+msgstr "diário público de %s - feed %s"
+
+#: rhodecode/templates/journal/journal.html:14
+#, fuzzy
+msgid "RSS journal feed"
+msgstr "diário público de %s - feed %s"
+
+#: rhodecode/templates/journal/journal.html:24
+#: rhodecode/templates/pullrequests/pullrequest.html:27
+msgid "Refresh"
+msgstr "Atualizar"
+
+#: rhodecode/templates/journal/journal.html:27
+#: rhodecode/templates/journal/public_journal.html:24
+#, fuzzy
+msgid "RSS feed"
+msgstr "%s - feed %s"
+
+#: rhodecode/templates/journal/journal.html:30
+#: rhodecode/templates/journal/public_journal.html:27
+msgid "ATOM feed"
+msgstr ""
 
 #: rhodecode/templates/journal/journal.html:41
+msgid "Watched"
+msgstr "Seguindo"
+
+#: rhodecode/templates/journal/journal.html:46
+msgid "ADD"
+msgstr "ADICIONAR"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "following user"
+msgstr "seguindo usuário"
+
+#: rhodecode/templates/journal/journal.html:114
 msgid "user"
 msgstr "usuário"
 
-#: rhodecode/templates/journal/journal.html:65
+#: rhodecode/templates/journal/journal.html:147
 msgid "You are not following any users or repositories"
 msgstr "Você não está seguindo quaisquer usuários ou repositórios"
 
-#: rhodecode/templates/journal/journal_data.html:46
+#: rhodecode/templates/journal/journal_data.html:47
 msgid "No entries yet"
 msgstr "Ainda não há entradas"
 
-#: rhodecode/templates/journal/public_journal.html:17
+#: rhodecode/templates/journal/public_journal.html:13
+#, fuzzy
+msgid "ATOM public journal feed"
+msgstr "diário público de %s - feed %s"
+
+#: rhodecode/templates/journal/public_journal.html:14
+#, fuzzy
+msgid "RSS public journal feed"
+msgstr "diário público de %s - feed %s"
+
+#: rhodecode/templates/journal/public_journal.html:21
 msgid "Public Journal"
 msgstr "Diário Público"
 
-#: rhodecode/templates/search/search.html:7
-#: rhodecode/templates/search/search.html:26
-msgid "in repository: "
+#: rhodecode/templates/pullrequests/pullrequest.html:4
+#: rhodecode/templates/pullrequests/pullrequest.html:12
+msgid "New pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:28
+msgid "refresh overview"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:66
+#, fuzzy
+msgid "Detailed compare view"
+msgstr "comparar exibir"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:70
+#: rhodecode/templates/pullrequests/pullrequest_show.html:82
+msgid "Pull request reviewers"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:79
+#: rhodecode/templates/pullrequests/pullrequest_show.html:94
+#, fuzzy
+msgid "owner"
+msgstr "Dono"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:91
+#: rhodecode/templates/pullrequests/pullrequest_show.html:109
+msgid "Add reviewer to this pull request."
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:97
+#, fuzzy
+msgid "Create new pull request"
+msgstr "Criar novo arquivo"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:106
+#: rhodecode/templates/pullrequests/pullrequest_show.html:25
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:33
+#, fuzzy
+msgid "Title"
+msgstr "escrever"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:115
+#, fuzzy
+msgid "description"
+msgstr "Descrição"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:123
+msgid "Send pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:23
+#, python-format
+msgid "Closed %s"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:31
+#, fuzzy
+msgid "Status"
+msgstr "Conjuntos de mudanças"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:36
+msgid "Pull request status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:44
+msgid "Still not reviewed by"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:47
+#, python-format
+msgid "%d reviewer"
+msgid_plural "%d reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:54
+#, fuzzy
+msgid "Created on"
+msgstr "criar um agora"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:61
+#, fuzzy
+msgid "Compare view"
+msgstr "comparar exibir"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:65
+#, fuzzy
+msgid "Incoming changesets"
+msgstr "Nenhum conjunto de alterações ainda."
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4
+#, fuzzy
+msgid "all pull requests"
+msgstr "Criar novo arquivo"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:12
+msgid "All pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:27
+msgid "Closed"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:6
+#, fuzzy, python-format
+msgid "Search \"%s\" in repository: %s"
 msgstr "no repositório"
 
-#: rhodecode/templates/search/search.html:9
-#: rhodecode/templates/search/search.html:28
-msgid "in all repositories"
+#: rhodecode/templates/search/search.html:8
+#, fuzzy, python-format
+msgid "Search \"%s\" in all repositories"
 msgstr "em todos os repositórios"
 
-#: rhodecode/templates/search/search.html:42
+#: rhodecode/templates/search/search.html:12
+#: rhodecode/templates/search/search.html:32
+#, fuzzy, python-format
+msgid "Search in repository: %s"
+msgstr "no repositório"
+
+#: rhodecode/templates/search/search.html:14
+#: rhodecode/templates/search/search.html:34
+#, fuzzy
+msgid "Search in all repositories"
+msgstr "em todos os repositórios"
+
+#: rhodecode/templates/search/search.html:48
 msgid "Search term"
 msgstr "Termo de pesquisa"
 
-#: rhodecode/templates/search/search.html:54
+#: rhodecode/templates/search/search.html:60
 msgid "Search in"
 msgstr "Pesquisando em"
 
-#: rhodecode/templates/search/search.html:57
+#: rhodecode/templates/search/search.html:63
 msgid "File contents"
 msgstr "Conteúdo dos arquivos"
 
-#: rhodecode/templates/search/search.html:59
+#: rhodecode/templates/search/search.html:64
+#, fuzzy
+msgid "Commit messages"
+msgstr "mensagem de commit"
+
+#: rhodecode/templates/search/search.html:65
 msgid "File names"
 msgstr "Nomes dos arquivos"
 
-#: rhodecode/templates/search/search_content.html:20
+#: rhodecode/templates/search/search_commit.html:35
+#: rhodecode/templates/search/search_content.html:21
 #: rhodecode/templates/search/search_path.html:15
 msgid "Permission denied"
 msgstr "Permissão negada"
 
-#: rhodecode/templates/settings/repo_fork.html:5
-msgid "Fork"
-msgstr "Bifurcação"
-
-#: rhodecode/templates/settings/repo_fork.html:31
-msgid "Fork name"
-msgstr "Nome da bifurcação"
-
-#: rhodecode/templates/settings/repo_fork.html:55
-msgid "fork this repository"
-msgstr "bifurcar este repositório"
+#: rhodecode/templates/settings/repo_settings.html:5
+#, fuzzy, python-format
+msgid "%s Settings"
+msgstr "configurações"
 
 #: rhodecode/templates/shortlog/shortlog.html:5
-#: rhodecode/templates/summary/summary.html:666
-msgid "Shortlog"
-msgstr "Log resumido"
+#, fuzzy, python-format
+msgid "%s Shortlog"
+msgstr "log resumido"
 
 #: rhodecode/templates/shortlog/shortlog.html:14
 msgid "shortlog"
 msgstr "log resumido"
 
-#: rhodecode/templates/shortlog/shortlog_data.html:6
+#: rhodecode/templates/shortlog/shortlog_data.html:7
 msgid "age"
 msgstr "idade"
 
+#: rhodecode/templates/shortlog/shortlog_data.html:18
+msgid "No commit message"
+msgstr "Nenhuma mensagem de commit"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:62
+msgid "Add or upload files directly via RhodeCode"
+msgstr "Adicionar ou enviar arquivos diretamente pelo RhodeCode"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:71
+msgid "Push new repo"
+msgstr "Fazer push de novo repositório"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:79
+msgid "Existing repository?"
+msgstr "Repositório existente?"
+
+#: rhodecode/templates/summary/summary.html:4
+#, fuzzy, python-format
+msgid "%s Summary"
+msgstr "sumário"
+
 #: rhodecode/templates/summary/summary.html:12
 msgid "summary"
 msgstr "sumário"
 
-#: rhodecode/templates/summary/summary.html:79
+#: rhodecode/templates/summary/summary.html:20
+#, fuzzy, python-format
+msgid "repo %s ATOM feed"
+msgstr "Assinar o feed atom de %s"
+
+#: rhodecode/templates/summary/summary.html:21
+#, fuzzy, python-format
+msgid "repo %s RSS feed"
+msgstr "Assinar o feed rss de %s"
+
+#: rhodecode/templates/summary/summary.html:49
+#: rhodecode/templates/summary/summary.html:52
+msgid "ATOM"
+msgstr "ATOM"
+
+#: rhodecode/templates/summary/summary.html:82
+#, python-format
+msgid "Non changable ID %s"
+msgstr "ID não alterável %s"
+
+#: rhodecode/templates/summary/summary.html:87
+msgid "public"
+msgstr "público"
+
+#: rhodecode/templates/summary/summary.html:95
 msgid "remote clone"
 msgstr "clone remoto"
 
-#: rhodecode/templates/summary/summary.html:121
-msgid "by"
-msgstr "por"
-
-#: rhodecode/templates/summary/summary.html:128
+#: rhodecode/templates/summary/summary.html:116
+msgid "Contact"
+msgstr "Contato"
+
+#: rhodecode/templates/summary/summary.html:130
 msgid "Clone url"
 msgstr "URL de clonagem"
 
-#: rhodecode/templates/summary/summary.html:137
-msgid "Trending source files"
-msgstr "Tendências nos arquivos fonte"
-
-#: rhodecode/templates/summary/summary.html:146
+#: rhodecode/templates/summary/summary.html:133
+msgid "Show by Name"
+msgstr "Mostrar por Nome"
+
+#: rhodecode/templates/summary/summary.html:134
+msgid "Show by ID"
+msgstr "Mostrar por ID"
+
+#: rhodecode/templates/summary/summary.html:142
+msgid "Trending files"
+msgstr "Tendências em arquivos"
+
+#: rhodecode/templates/summary/summary.html:150
+#: rhodecode/templates/summary/summary.html:166
+#: rhodecode/templates/summary/summary.html:194
+msgid "enable"
+msgstr "habilitar"
+
+#: rhodecode/templates/summary/summary.html:158
 msgid "Download"
 msgstr "Download"
 
-#: rhodecode/templates/summary/summary.html:150
+#: rhodecode/templates/summary/summary.html:162
 msgid "There are no downloads yet"
 msgstr "Ainda não há downloads"
 
-#: rhodecode/templates/summary/summary.html:152
+#: rhodecode/templates/summary/summary.html:164
 msgid "Downloads are disabled for this repository"
 msgstr "Downloads estão desabilitados para este repositório"
 
-#: rhodecode/templates/summary/summary.html:154
-#: rhodecode/templates/summary/summary.html:320
-msgid "enable"
-msgstr "habilitar"
-
-#: rhodecode/templates/summary/summary.html:162
-#: rhodecode/templates/summary/summary.html:297
+#: rhodecode/templates/summary/summary.html:170
+#, fuzzy
+msgid "Download as zip"
+msgstr "descarregar como bruto"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "Check this to download archive with subrepos"
+msgstr "Marque isto para descarregar arquivo com subrepositórios"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "with subrepos"
+msgstr "com subrepositórios"
+
+#: rhodecode/templates/summary/summary.html:186
+msgid "Commit activity by day / author"
+msgstr "Atividade de commit por dia / autor"
+
+#: rhodecode/templates/summary/summary.html:197
+msgid "Stats gathered: "
+msgstr "Estatísticas coletadas:"
+
+#: rhodecode/templates/summary/summary.html:218
+msgid "Shortlog"
+msgstr "Log resumido"
+
+#: rhodecode/templates/summary/summary.html:220
+msgid "Quick start"
+msgstr "Início rápido"
+
+#: rhodecode/templates/summary/summary.html:233
+#, python-format
+msgid "Readme file at revision '%s'"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:236
+msgid "Permalink to this readme"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:293
 #, python-format
 msgid "Download %s as %s"
 msgstr "Descarregar %s como %s"
 
-#: rhodecode/templates/summary/summary.html:168
-msgid "Check this to download archive with subrepos"
-msgstr "Marque isto para descarregar arquivo com subrepositórios"
-
-#: rhodecode/templates/summary/summary.html:168
-msgid "with subrepos"
-msgstr "com subrepositórios"
-
-#: rhodecode/templates/summary/summary.html:176
-msgid "Feeds"
-msgstr "Feeds"
-
-#: rhodecode/templates/summary/summary.html:257
-#: rhodecode/templates/summary/summary.html:684
-#: rhodecode/templates/summary/summary.html:695
-msgid "show more"
-msgstr "mostrar mais"
-
-#: rhodecode/templates/summary/summary.html:312
-msgid "Commit activity by day / author"
-msgstr "Atividade de commit por dia / autor"
-
-#: rhodecode/templates/summary/summary.html:324
-msgid "Loaded in"
-msgstr "Carregado em"
-
-#: rhodecode/templates/summary/summary.html:603
+#: rhodecode/templates/summary/summary.html:650
 msgid "commits"
 msgstr "commits"
 
-#: rhodecode/templates/summary/summary.html:604
+#: rhodecode/templates/summary/summary.html:651
 msgid "files added"
 msgstr "arquivos adicionados"
 
-#: rhodecode/templates/summary/summary.html:605
+#: rhodecode/templates/summary/summary.html:652
 msgid "files changed"
 msgstr "arquivos alterados"
 
-#: rhodecode/templates/summary/summary.html:606
+#: rhodecode/templates/summary/summary.html:653
 msgid "files removed"
 msgstr "arquivos removidos"
 
-#: rhodecode/templates/summary/summary.html:610
+#: rhodecode/templates/summary/summary.html:656
+msgid "commit"
+msgstr "commit"
+
+#: rhodecode/templates/summary/summary.html:657
 msgid "file added"
 msgstr "arquivo adicionado"
 
-#: rhodecode/templates/summary/summary.html:611
+#: rhodecode/templates/summary/summary.html:658
 msgid "file changed"
 msgstr "arquivo alterado"
 
-#: rhodecode/templates/summary/summary.html:612
+#: rhodecode/templates/summary/summary.html:659
 msgid "file removed"
 msgstr "arquivo removido"
 
+#: rhodecode/templates/tags/tags.html:5
+#, fuzzy, python-format
+msgid "%s Tags"
+msgstr "%s atrás"
+
--- a/rhodecode/i18n/rhodecode.pot	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/i18n/rhodecode.pot	Sun Sep 02 21:19:54 2012 +0200
@@ -1,14 +1,14 @@
 # Translations template for RhodeCode.
-# Copyright (C) 2011 ORGANIZATION
+# Copyright (C) 2012 ORGANIZATION
 # This file is distributed under the same license as the RhodeCode project.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
 #
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: RhodeCode 1.2.0\n"
+"Project-Id-Version: RhodeCode 1.4.0b\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2011-09-14 15:50-0300\n"
+"POT-Creation-Date: 2012-09-02 20:30+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,17 +17,36 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: Babel 0.9.6\n"
 
-#: rhodecode/controllers/changeset.py:108 rhodecode/controllers/changeset.py:149
-#: rhodecode/controllers/changeset.py:216 rhodecode/controllers/changeset.py:229
+#: rhodecode/controllers/changelog.py:94
+msgid "All Branches"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:83
+msgid "show white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:90 rhodecode/controllers/changeset.py:97
+msgid "ignore white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:157
+#, python-format
+msgid "%s line context"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:333 rhodecode/controllers/changeset.py:348
+#: rhodecode/lib/diffs.py:70
 msgid "binary file"
 msgstr ""
 
-#: rhodecode/controllers/changeset.py:123 rhodecode/controllers/changeset.py:168
-msgid "Changeset is to big and was cut off, see raw changeset instead"
-msgstr ""
-
-#: rhodecode/controllers/changeset.py:159
-msgid "Diff is to big and was cut off, see raw diff instead"
+#: rhodecode/controllers/changeset.py:408
+msgid ""
+"Changing status on a changeset associated witha closed pull request is not "
+"allowed"
+msgstr ""
+
+#: rhodecode/controllers/compare.py:69
+msgid "There are no changesets yet"
 msgstr ""
 
 #: rhodecode/controllers/error.py:69
@@ -56,240 +75,290 @@
 "fulfilling the request."
 msgstr ""
 
-#: rhodecode/controllers/feed.py:48
+#: rhodecode/controllers/feed.py:49
 #, python-format
 msgid "Changes on %s repository"
 msgstr ""
 
-#: rhodecode/controllers/feed.py:49
+#: rhodecode/controllers/feed.py:50
 #, python-format
 msgid "%s %s feed"
 msgstr ""
 
-#: rhodecode/controllers/files.py:72
-msgid "There are no files yet"
-msgstr ""
-
-#: rhodecode/controllers/files.py:262
+#: rhodecode/controllers/feed.py:75
+msgid "commited on"
+msgstr ""
+
+#: rhodecode/controllers/files.py:84
+msgid "click here to add new file"
+msgstr ""
+
+#: rhodecode/controllers/files.py:85
+#, python-format
+msgid "There are no files yet %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:239 rhodecode/controllers/files.py:299
+#, python-format
+msgid "This repository is has been locked by %s on %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:266
 #, python-format
 msgid "Edited %s via RhodeCode"
 msgstr ""
 
-#: rhodecode/controllers/files.py:267 rhodecode/templates/files/file_diff.html:40
+#: rhodecode/controllers/files.py:271
 msgid "No changes"
 msgstr ""
 
-#: rhodecode/controllers/files.py:278
+#: rhodecode/controllers/files.py:282 rhodecode/controllers/files.py:346
 #, python-format
 msgid "Successfully committed to %s"
 msgstr ""
 
-#: rhodecode/controllers/files.py:283
+#: rhodecode/controllers/files.py:287 rhodecode/controllers/files.py:352
 msgid "Error occurred during commit"
 msgstr ""
 
-#: rhodecode/controllers/files.py:308
+#: rhodecode/controllers/files.py:318
+#, python-format
+msgid "Added %s via RhodeCode"
+msgstr ""
+
+#: rhodecode/controllers/files.py:332
+msgid "No content"
+msgstr ""
+
+#: rhodecode/controllers/files.py:336
+msgid "No filename"
+msgstr ""
+
+#: rhodecode/controllers/files.py:378
 msgid "downloads disabled"
 msgstr ""
 
-#: rhodecode/controllers/files.py:313
+#: rhodecode/controllers/files.py:389
 #, python-format
 msgid "Unknown revision %s"
 msgstr ""
 
-#: rhodecode/controllers/files.py:315
+#: rhodecode/controllers/files.py:391
 msgid "Empty repository"
 msgstr ""
 
-#: rhodecode/controllers/files.py:317
+#: rhodecode/controllers/files.py:393
 msgid "Unknown archive type"
 msgstr ""
 
-#: rhodecode/controllers/files.py:385 rhodecode/controllers/files.py:398
-msgid "Binary file"
-msgstr ""
-
-#: rhodecode/controllers/files.py:417
-#: rhodecode/templates/changeset/changeset_range.html:4
-#: rhodecode/templates/changeset/changeset_range.html:12
-#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/controllers/files.py:494
+#: rhodecode/templates/changeset/changeset_range.html:13
+#: rhodecode/templates/changeset/changeset_range.html:31
 msgid "Changesets"
 msgstr ""
 
-#: rhodecode/controllers/files.py:418 rhodecode/controllers/summary.py:175
-#: rhodecode/templates/branches/branches.html:5
-#: rhodecode/templates/summary/summary.html:690
+#: rhodecode/controllers/files.py:495 rhodecode/controllers/pullrequests.py:72
+#: rhodecode/controllers/summary.py:232 rhodecode/model/scm.py:543
 msgid "Branches"
 msgstr ""
 
-#: rhodecode/controllers/files.py:419 rhodecode/controllers/summary.py:176
-#: rhodecode/templates/summary/summary.html:679
-#: rhodecode/templates/tags/tags.html:5
+#: rhodecode/controllers/files.py:496 rhodecode/controllers/pullrequests.py:76
+#: rhodecode/controllers/summary.py:233 rhodecode/model/scm.py:554
 msgid "Tags"
 msgstr ""
 
-#: rhodecode/controllers/journal.py:50
+#: rhodecode/controllers/forks.py:73 rhodecode/controllers/admin/repos.py:90
 #, python-format
-msgid "%s public journal %s feed"
-msgstr ""
-
-#: rhodecode/controllers/journal.py:178 rhodecode/controllers/journal.py:212
-#: rhodecode/templates/admin/repos/repo_edit.html:171
-#: rhodecode/templates/base/base.html:50
-msgid "Public journal"
-msgstr ""
-
-#: rhodecode/controllers/login.py:111
-msgid "You have successfully registered into rhodecode"
-msgstr ""
-
-#: rhodecode/controllers/login.py:133
-msgid "Your password reset link was sent"
-msgstr ""
-
-#: rhodecode/controllers/login.py:155
-msgid "Your password reset was successful, new password has been sent to your email"
-msgstr ""
-
-#: rhodecode/controllers/search.py:109
-msgid "Invalid search query. Try quoting it."
-msgstr ""
-
-#: rhodecode/controllers/search.py:114
-msgid "There is no index to search in. Please run whoosh indexer"
-msgstr ""
-
-#: rhodecode/controllers/search.py:118
-msgid "An error occurred during this search operation"
-msgstr ""
-
-#: rhodecode/controllers/settings.py:61 rhodecode/controllers/settings.py:171
+msgid ""
+"%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"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:133 rhodecode/controllers/settings.py:72
 #, python-format
 msgid ""
 "%s repository is not mapped to db perhaps it was created or renamed from the "
 "file system please run the application again in order to rescan repositories"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:109 rhodecode/controllers/admin/repos.py:239
+#: rhodecode/controllers/forks.py:167
+#, python-format
+msgid "forked %s repository as %s"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:181
+#, python-format
+msgid "An error occurred during repository forking %s"
+msgstr ""
+
+#: rhodecode/controllers/journal.py:202 rhodecode/controllers/journal.py:239
+msgid "public journal"
+msgstr ""
+
+#: rhodecode/controllers/journal.py:206 rhodecode/controllers/journal.py:243
+#: rhodecode/templates/base/base.html:220
+msgid "journal"
+msgstr ""
+
+#: rhodecode/controllers/login.py:143
+msgid "You have successfully registered into rhodecode"
+msgstr ""
+
+#: rhodecode/controllers/login.py:164
+msgid "Your password reset link was sent"
+msgstr ""
+
+#: rhodecode/controllers/login.py:184
+msgid "Your password reset was successful, new password has been sent to your email"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:74 rhodecode/model/scm.py:549
+msgid "Bookmarks"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:158
+msgid "Pull request requires a title with min. 3 chars"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:160
+msgid "error during creation of pull request"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:181
+msgid "Successfully opened new pull request"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:184
+msgid "Error occurred during sending pull request"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:217
+msgid "Successfully deleted pull request"
+msgstr ""
+
+#: rhodecode/controllers/search.py:131
+msgid "Invalid search query. Try quoting it."
+msgstr ""
+
+#: rhodecode/controllers/search.py:136
+msgid "There is no index to search in. Please run whoosh indexer"
+msgstr ""
+
+#: rhodecode/controllers/search.py:140
+msgid "An error occurred during this search operation"
+msgstr ""
+
+#: rhodecode/controllers/settings.py:107 rhodecode/controllers/admin/repos.py:266
 #, python-format
 msgid "Repository %s updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:126 rhodecode/controllers/admin/repos.py:257
+#: rhodecode/controllers/settings.py:125 rhodecode/controllers/admin/repos.py:284
 #, python-format
 msgid "error occurred during update of repository %s"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:144 rhodecode/controllers/admin/repos.py:275
+#: rhodecode/controllers/settings.py:143 rhodecode/controllers/admin/repos.py:302
 #, python-format
 msgid ""
 "%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"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:156 rhodecode/controllers/admin/repos.py:287
+#: rhodecode/controllers/settings.py:155 rhodecode/controllers/admin/repos.py:314
 #, python-format
 msgid "deleted repository %s"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:159 rhodecode/controllers/admin/repos.py:297
-#: rhodecode/controllers/admin/repos.py:303
+#: rhodecode/controllers/settings.py:159 rhodecode/controllers/admin/repos.py:324
+#: rhodecode/controllers/admin/repos.py:330
 #, python-format
 msgid "An error occurred during deletion of %s"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:193
-#, python-format
-msgid "forked %s repository as %s"
-msgstr ""
-
-#: rhodecode/controllers/settings.py:211
-#, python-format
-msgid "An error occurred during repository forking %s"
-msgstr ""
-
-#: rhodecode/controllers/summary.py:123
+#: rhodecode/controllers/summary.py:138
 msgid "No data loaded yet"
 msgstr ""
 
-#: rhodecode/controllers/summary.py:126
+#: rhodecode/controllers/summary.py:142
+#: rhodecode/templates/summary/summary.html:148
 msgid "Statistics are disabled for this repository"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:49
-msgid "BASE"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:50
-msgid "ONELEVEL"
+msgid "BASE"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:51
+msgid "ONELEVEL"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:52
 msgid "SUBTREE"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:55
-msgid "NEVER"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:56
-msgid "ALLOW"
+msgid "NEVER"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:57
-msgid "TRY"
+msgid "ALLOW"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:58
-msgid "DEMAND"
+msgid "TRY"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:59
+msgid "DEMAND"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:60
 msgid "HARD"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:63
-msgid "No encryption"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:64
-msgid "LDAPS connection"
+msgid "No encryption"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:65
+msgid "LDAPS connection"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:66
 msgid "START_TLS on LDAP connection"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:115
+#: rhodecode/controllers/admin/ldap_settings.py:126
 msgid "Ldap settings updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:120
+#: rhodecode/controllers/admin/ldap_settings.py:130
 msgid "Unable to activate ldap. The \"python-ldap\" library is missing."
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:134
+#: rhodecode/controllers/admin/ldap_settings.py:147
 msgid "error occurred during update of ldap settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:56
-msgid "None"
-msgstr ""
-
-#: rhodecode/controllers/admin/permissions.py:57
-msgid "Read"
-msgstr ""
-
-#: rhodecode/controllers/admin/permissions.py:58
-msgid "Write"
-msgstr ""
-
 #: rhodecode/controllers/admin/permissions.py:59
+msgid "None"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:60
+msgid "Read"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:61
+msgid "Write"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:62
 #: rhodecode/templates/admin/ldap/ldap.html:9
 #: rhodecode/templates/admin/permissions/permissions.html:9
 #: rhodecode/templates/admin/repos/repo_add.html:9
 #: rhodecode/templates/admin/repos/repo_edit.html:9
-#: rhodecode/templates/admin/repos/repos.html:10
+#: rhodecode/templates/admin/repos/repos.html:9
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
@@ -297,546 +366,868 @@
 #: rhodecode/templates/admin/settings/settings.html:9
 #: rhodecode/templates/admin/users/user_add.html:8
 #: rhodecode/templates/admin/users/user_edit.html:9
-#: rhodecode/templates/admin/users/user_edit.html:110
+#: rhodecode/templates/admin/users/user_edit.html:122
 #: rhodecode/templates/admin/users/users.html:9
 #: rhodecode/templates/admin/users_groups/users_group_add.html:8
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:9
 #: rhodecode/templates/admin/users_groups/users_groups.html:9
-#: rhodecode/templates/base/base.html:279 rhodecode/templates/base/base.html:366
-#: rhodecode/templates/base/base.html:368 rhodecode/templates/base/base.html:370
+#: rhodecode/templates/base/base.html:197 rhodecode/templates/base/base.html:337
+#: rhodecode/templates/base/base.html:339 rhodecode/templates/base/base.html:341
 msgid "Admin"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:62
+#: rhodecode/controllers/admin/permissions.py:65
 msgid "disabled"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:64
+#: rhodecode/controllers/admin/permissions.py:67
 msgid "allowed with manual account activation"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:66
-msgid "allowed with automatic account activation"
-msgstr ""
-
-#: rhodecode/controllers/admin/permissions.py:68
-msgid "Disabled"
-msgstr ""
-
 #: rhodecode/controllers/admin/permissions.py:69
+msgid "allowed with automatic account activation"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:71
+#: rhodecode/controllers/admin/permissions.py:74
+msgid "Disabled"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:72
+#: rhodecode/controllers/admin/permissions.py:75
 msgid "Enabled"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:102
+#: rhodecode/controllers/admin/permissions.py:116
 msgid "Default permissions updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:119
+#: rhodecode/controllers/admin/permissions.py:130
 msgid "error occurred during update of permissions"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:96
-#, python-format
-msgid ""
-"%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"
-msgstr ""
-
-#: rhodecode/controllers/admin/repos.py:172
+#: rhodecode/controllers/admin/repos.py:123
+msgid "--REMOVE FORK--"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:192
 #, python-format
 msgid "created repository %s from %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:176
+#: rhodecode/controllers/admin/repos.py:196
 #, python-format
 msgid "created repository %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:205
+#: rhodecode/controllers/admin/repos.py:227
 #, python-format
 msgid "error occurred during creation of repository %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:292
+#: rhodecode/controllers/admin/repos.py:319
 #, python-format
 msgid "Cannot delete %s it still contains attached forks"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:320
+#: rhodecode/controllers/admin/repos.py:348
 msgid "An error occurred during deletion of repository user"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:335
-msgid "An error occurred during deletion of repository users groups"
-msgstr ""
-
-#: rhodecode/controllers/admin/repos.py:352
-msgid "An error occurred during deletion of repository stats"
-msgstr ""
-
 #: rhodecode/controllers/admin/repos.py:367
+msgid "An error occurred during deletion of repository users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:385
+msgid "An error occurred during deletion of repository stats"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:402
 msgid "An error occurred during cache invalidation"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:387
+#: rhodecode/controllers/admin/repos.py:422
+msgid "An error occurred during unlocking"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:442
 msgid "Updated repository visibility in public journal"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:390
+#: rhodecode/controllers/admin/repos.py:446
 msgid "An error occurred during setting this repository in public journal"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:395 rhodecode/model/forms.py:53
+#: rhodecode/controllers/admin/repos.py:451 rhodecode/model/validators.py:299
 msgid "Token mismatch"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:408
+#: rhodecode/controllers/admin/repos.py:464
 msgid "Pulled from remote location"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:410
+#: rhodecode/controllers/admin/repos.py:466
 msgid "An error occurred during pull from remote location"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:83
+#: rhodecode/controllers/admin/repos.py:482
+msgid "Nothing"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:484
+#, python-format
+msgid "Marked repo %s as fork of %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:488
+msgid "An error occurred during this operation"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:116
 #, python-format
 msgid "created repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:96
+#: rhodecode/controllers/admin/repos_groups.py:129
 #, python-format
 msgid "error occurred during creation of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:130
+#: rhodecode/controllers/admin/repos_groups.py:163
 #, python-format
 msgid "updated repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:143
+#: rhodecode/controllers/admin/repos_groups.py:176
 #, python-format
 msgid "error occurred during update of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:164
+#: rhodecode/controllers/admin/repos_groups.py:194
 #, python-format
 msgid "This group contains %s repositores and cannot be deleted"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:171
+#: rhodecode/controllers/admin/repos_groups.py:202
 #, python-format
 msgid "removed repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:175
+#: rhodecode/controllers/admin/repos_groups.py:208
+msgid "Cannot delete this group it still contains subgroups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:213
+#: rhodecode/controllers/admin/repos_groups.py:218
 #, python-format
 msgid "error occurred during deletion of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:109
+#: rhodecode/controllers/admin/repos_groups.py:238
+msgid "An error occurred during deletion of group user"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:258
+msgid "An error occurred during deletion of group users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:121
 #, python-format
 msgid "Repositories successfully rescanned added: %s,removed: %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:118
+#: rhodecode/controllers/admin/settings.py:129
 msgid "Whoosh reindex task scheduled"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:143
+#: rhodecode/controllers/admin/settings.py:160
 msgid "Updated application settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:148
-#: rhodecode/controllers/admin/settings.py:215
+#: rhodecode/controllers/admin/settings.py:164
+#: rhodecode/controllers/admin/settings.py:275
 msgid "error occurred during updating application settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:210
-msgid "Updated mercurial settings"
-msgstr ""
-
-#: rhodecode/controllers/admin/settings.py:236
+#: rhodecode/controllers/admin/settings.py:200
+msgid "Updated visualisation settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:205
+msgid "error occurred during updating visualisation settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:271
+msgid "Updated VCS settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:285
 msgid "Added new hook"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:247
+#: rhodecode/controllers/admin/settings.py:297
 msgid "Updated hooks"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:251
+#: rhodecode/controllers/admin/settings.py:301
 msgid "error occurred during hook creation"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:310
+#: rhodecode/controllers/admin/settings.py:320
+msgid "Email task created"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:375
 msgid "You can't edit this user since it's crucial for entire application"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:339
+#: rhodecode/controllers/admin/settings.py:406
 msgid "Your account was updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:359
+#: rhodecode/controllers/admin/settings.py:421
+#: rhodecode/controllers/admin/users.py:191
+#, python-format
+msgid "error occurred during update of user %s"
+msgstr ""
+
 #: rhodecode/controllers/admin/users.py:130
 #, python-format
-msgid "error occurred during update of user %s"
-msgstr ""
-
-#: rhodecode/controllers/admin/users.py:78
-#, python-format
 msgid "created user %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:90
+#: rhodecode/controllers/admin/users.py:142
 #, python-format
 msgid "error occurred during creation of user %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:116
+#: rhodecode/controllers/admin/users.py:171
 msgid "User updated successfully"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:146
+#: rhodecode/controllers/admin/users.py:207
 msgid "successfully deleted user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:150
+#: rhodecode/controllers/admin/users.py:212
 msgid "An error occurred during deletion of user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:166
+#: rhodecode/controllers/admin/users.py:226
 msgid "You can't edit this user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:195
-#: rhodecode/controllers/admin/users_groups.py:202
+#: rhodecode/controllers/admin/users.py:266
 msgid "Granted 'repository create' permission to user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:204
-#: rhodecode/controllers/admin/users_groups.py:211
+#: rhodecode/controllers/admin/users.py:271
 msgid "Revoked 'repository create' permission to user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:74
+#: rhodecode/controllers/admin/users.py:277
+msgid "Granted 'repository fork' permission to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:282
+msgid "Revoked 'repository fork' permission to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:288
+#: rhodecode/controllers/admin/users_groups.py:255
+msgid "An error occurred during permissions saving"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:303
+#, python-format
+msgid "Added email %s to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:309
+msgid "An error occurred during email saving"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:319
+msgid "Removed email from user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:84
 #, python-format
 msgid "created users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:86
+#: rhodecode/controllers/admin/users_groups.py:95
 #, python-format
 msgid "error occurred during creation of users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:119
+#: rhodecode/controllers/admin/users_groups.py:135
 #, python-format
 msgid "updated users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:138
+#: rhodecode/controllers/admin/users_groups.py:157
 #, python-format
 msgid "error occurred during update of users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:154
+#: rhodecode/controllers/admin/users_groups.py:174
 msgid "successfully deleted users group"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:158
+#: rhodecode/controllers/admin/users_groups.py:179
 msgid "An error occurred during deletion of users group"
 msgstr ""
 
-#: rhodecode/lib/__init__.py:279
-msgid "year"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:280
-msgid "month"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:281
-msgid "day"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:282
-msgid "hour"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:283
-msgid "minute"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:284
-msgid "second"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:293
-msgid "ago"
-msgstr ""
-
-#: rhodecode/lib/__init__.py:296
-msgid "just now"
-msgstr ""
-
-#: rhodecode/lib/auth.py:377
+#: rhodecode/controllers/admin/users_groups.py:233
+msgid "Granted 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:238
+msgid "Revoked 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:244
+msgid "Granted 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:249
+msgid "Revoked 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/lib/auth.py:499
 msgid "You need to be a registered user to perform this action"
 msgstr ""
 
-#: rhodecode/lib/auth.py:421
+#: rhodecode/lib/auth.py:540
 msgid "You need to be a signed in to view this page"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:307
+#: rhodecode/lib/diffs.py:86
+msgid "Changeset was too big and was cut off, use diff menu to display this diff"
+msgstr ""
+
+#: rhodecode/lib/diffs.py:96
+msgid "No changes detected"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:372
+#, python-format
+msgid "%a, %d %b %Y %H:%M:%S"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:484
 msgid "True"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:311
+#: rhodecode/lib/helpers.py:488
 msgid "False"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:352
+#: rhodecode/lib/helpers.py:532
+msgid "Changeset not found"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:555
 #, python-format
 msgid "Show all combined changesets %s->%s"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:356
+#: rhodecode/lib/helpers.py:561
 msgid "compare view"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:365
-msgid "and"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:365
-#, python-format
-msgid "%s more"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:367 rhodecode/templates/changelog/changelog.html:14
-#: rhodecode/templates/changelog/changelog.html:39
-msgid "revisions"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:385
-msgid "fork name "
-msgstr ""
-
-#: rhodecode/lib/helpers.py:388
-msgid "[deleted] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:389 rhodecode/lib/helpers.py:393
-msgid "[created] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:390 rhodecode/lib/helpers.py:394
-msgid "[forked] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:391 rhodecode/lib/helpers.py:395
-msgid "[updated] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:392
-msgid "[delete] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:396
-msgid "[pushed] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:397
-msgid "[committed via RhodeCode] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:398
-msgid "[pulled from remote] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:399
-msgid "[pulled] from"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:400
-msgid "[started following] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:401
-msgid "[stopped following] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:577
-#, python-format
-msgid " and %s more"
-msgstr ""
-
 #: rhodecode/lib/helpers.py:581
+msgid "and"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:582
+#, python-format
+msgid "%s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:583 rhodecode/templates/changelog/changelog.html:48
+msgid "revisions"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:606
+msgid "fork name "
+msgstr ""
+
+#: rhodecode/lib/helpers.py:620
+#: rhodecode/templates/pullrequests/pullrequest_show.html:4
+#: rhodecode/templates/pullrequests/pullrequest_show.html:12
+#, python-format
+msgid "Pull request #%s"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:626
+msgid "[deleted] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:628 rhodecode/lib/helpers.py:638
+msgid "[created] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:630
+msgid "[created] repository as fork"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:632 rhodecode/lib/helpers.py:640
+msgid "[forked] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:634 rhodecode/lib/helpers.py:642
+msgid "[updated] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:636
+msgid "[delete] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:644
+msgid "[created] user"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:646
+msgid "[updated] user"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:648
+msgid "[created] users group"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:650
+msgid "[updated] users group"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:652
+msgid "[commented] on revision in repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:654
+msgid "[commented] on pull request for"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:656
+msgid "[closed] pull request for"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:658
+msgid "[pushed] into"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:660
+msgid "[committed via RhodeCode] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:662
+msgid "[pulled from remote] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:664
+msgid "[pulled] from"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:666
+msgid "[started following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:668
+msgid "[stopped following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:840
+#, python-format
+msgid " and %s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:844
 msgid "No Files"
 msgstr ""
 
-#: rhodecode/model/forms.py:66
-msgid "Invalid username"
-msgstr ""
-
-#: rhodecode/model/forms.py:75
-msgid "This username already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:79
+#: rhodecode/lib/utils2.py:335
+#, python-format
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:336
+#, python-format
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:337
+#, python-format
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:338
+#, python-format
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:339
+#, python-format
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:340
+#, python-format
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/lib/utils2.py:355
+#, python-format
+msgid "%s ago"
+msgstr ""
+
+#: rhodecode/lib/utils2.py:357
+#, python-format
+msgid "%s and %s ago"
+msgstr ""
+
+#: rhodecode/lib/utils2.py:360
+msgid "just now"
+msgstr ""
+
+#: rhodecode/lib/celerylib/tasks.py:269
+msgid "password reset link"
+msgstr ""
+
+#: rhodecode/model/comment.py:110
+#, python-format
+msgid "on line %s"
+msgstr ""
+
+#: rhodecode/model/comment.py:157
+msgid "[Mention]"
+msgstr ""
+
+#: rhodecode/model/db.py:1140
+msgid "Repository no access"
+msgstr ""
+
+#: rhodecode/model/db.py:1141
+msgid "Repository read access"
+msgstr ""
+
+#: rhodecode/model/db.py:1142
+msgid "Repository write access"
+msgstr ""
+
+#: rhodecode/model/db.py:1143
+msgid "Repository admin access"
+msgstr ""
+
+#: rhodecode/model/db.py:1145
+msgid "Repositories Group no access"
+msgstr ""
+
+#: rhodecode/model/db.py:1146
+msgid "Repositories Group read access"
+msgstr ""
+
+#: rhodecode/model/db.py:1147
+msgid "Repositories Group write access"
+msgstr ""
+
+#: rhodecode/model/db.py:1148
+msgid "Repositories Group admin access"
+msgstr ""
+
+#: rhodecode/model/db.py:1150
+msgid "RhodeCode Administrator"
+msgstr ""
+
+#: rhodecode/model/db.py:1151
+msgid "Repository creation disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1152
+msgid "Repository creation enabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1153
+msgid "Repository forking disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1154
+msgid "Repository forking enabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1155
+msgid "Register disabled"
+msgstr ""
+
+#: rhodecode/model/db.py:1156
+msgid "Register new user with RhodeCode with manual activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1159
+msgid "Register new user with RhodeCode with auto activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1579
+msgid "Not Reviewed"
+msgstr ""
+
+#: rhodecode/model/db.py:1580
+msgid "Approved"
+msgstr ""
+
+#: rhodecode/model/db.py:1581
+msgid "Rejected"
+msgstr ""
+
+#: rhodecode/model/db.py:1582
+msgid "Under Review"
+msgstr ""
+
+#: rhodecode/model/forms.py:43
+msgid "Please enter a login"
+msgstr ""
+
+#: rhodecode/model/forms.py:44
+#, python-format
+msgid "Enter a value %(min)i characters long or more"
+msgstr ""
+
+#: rhodecode/model/forms.py:52
+msgid "Please enter a password"
+msgstr ""
+
+#: rhodecode/model/forms.py:53
+#, python-format
+msgid "Enter %(min)i characters or more"
+msgstr ""
+
+#: rhodecode/model/notification.py:220
+msgid "commented on commit"
+msgstr ""
+
+#: rhodecode/model/notification.py:221
+msgid "sent message"
+msgstr ""
+
+#: rhodecode/model/notification.py:222
+msgid "mentioned you"
+msgstr ""
+
+#: rhodecode/model/notification.py:223
+msgid "registered in RhodeCode"
+msgstr ""
+
+#: rhodecode/model/notification.py:224
+msgid "opened new pull request"
+msgstr ""
+
+#: rhodecode/model/notification.py:225
+msgid "commented on pull request"
+msgstr ""
+
+#: rhodecode/model/pull_request.py:84
+#, python-format
+msgid "%(user)s wants you to review pull request #%(pr_id)s"
+msgstr ""
+
+#: rhodecode/model/scm.py:535
+msgid "latest tip"
+msgstr ""
+
+#: rhodecode/model/user.py:230
+msgid "new user registration"
+msgstr ""
+
+#: rhodecode/model/user.py:255 rhodecode/model/user.py:277
+#: rhodecode/model/user.py:299
+msgid "You can't Edit this user since it's crucial for entire application"
+msgstr ""
+
+#: rhodecode/model/user.py:323
+msgid "You can't remove this user since it's crucial for entire application"
+msgstr ""
+
+#: rhodecode/model/user.py:329
+#, python-format
+msgid ""
+"user \"%s\" still owns %s repositories and cannot be removed. Switch owners "
+"or remove those repositories. %s"
+msgstr ""
+
+#: rhodecode/model/validators.py:35 rhodecode/model/validators.py:36
+msgid "Value cannot be an empty list"
+msgstr ""
+
+#: rhodecode/model/validators.py:82
+#, python-format
+msgid "Username \"%(username)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:84
+#, python-format
+msgid "Username \"%(username)s\" is forbidden"
+msgstr ""
+
+#: rhodecode/model/validators.py:86
 msgid ""
 "Username may only contain alphanumeric characters underscores, periods or "
 "dashes and must begin with alphanumeric character"
 msgstr ""
 
-#: rhodecode/model/forms.py:94
-msgid "Invalid group name"
-msgstr ""
-
-#: rhodecode/model/forms.py:104
-msgid "This users group already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:110
+#: rhodecode/model/validators.py:114
+#, python-format
+msgid "Username %(username)s is not valid"
+msgstr ""
+
+#: rhodecode/model/validators.py:133
+msgid "Invalid users group name"
+msgstr ""
+
+#: rhodecode/model/validators.py:134
+#, python-format
+msgid "Users group \"%(usersgroup)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:136
 msgid ""
-"Group name may only contain alphanumeric characters underscores, periods or "
-"dashes and must begin with alphanumeric character"
-msgstr ""
-
-#: rhodecode/model/forms.py:132
+"users group name may only contain  alphanumeric characters underscores, "
+"periods or dashes and must begin with alphanumeric character"
+msgstr ""
+
+#: rhodecode/model/validators.py:174
 msgid "Cannot assign this group as parent"
 msgstr ""
 
-#: rhodecode/model/forms.py:148
-msgid "This group already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:164 rhodecode/model/forms.py:172
-#: rhodecode/model/forms.py:180
-msgid "Invalid characters in password"
-msgstr ""
-
-#: rhodecode/model/forms.py:191
+#: rhodecode/model/validators.py:175
+#, python-format
+msgid "Group \"%(group_name)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:177
+#, python-format
+msgid "Repository with name \"%(group_name)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:235
+msgid "Invalid characters (non-ascii) in password"
+msgstr ""
+
+#: rhodecode/model/validators.py:250
 msgid "Passwords do not match"
 msgstr ""
 
-#: rhodecode/model/forms.py:196
+#: rhodecode/model/validators.py:267
 msgid "invalid password"
 msgstr ""
 
-#: rhodecode/model/forms.py:197
+#: rhodecode/model/validators.py:268
 msgid "invalid user name"
 msgstr ""
 
-#: rhodecode/model/forms.py:198
+#: rhodecode/model/validators.py:269
 msgid "Your account is disabled"
 msgstr ""
 
-#: rhodecode/model/forms.py:233
-msgid "This username is not valid"
-msgstr ""
-
-#: rhodecode/model/forms.py:245
-msgid "This repository name is disallowed"
-msgstr ""
-
-#: rhodecode/model/forms.py:266
+#: rhodecode/model/validators.py:313
+#, python-format
+msgid "Repository name %(repo)s is disallowed"
+msgstr ""
+
+#: rhodecode/model/validators.py:315
 #, python-format
-msgid "This repository already exists in group \"%s\""
-msgstr ""
-
-#: rhodecode/model/forms.py:274
-msgid "This repository already exists"
-msgstr ""
-
-#: rhodecode/model/forms.py:312 rhodecode/model/forms.py:319
+msgid "Repository named %(repo)s already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:316
+#, python-format
+msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
+msgstr ""
+
+#: rhodecode/model/validators.py:318
+#, python-format
+msgid "Repositories group with name \"%(repo)s\" already exists"
+msgstr ""
+
+#: rhodecode/model/validators.py:431
 msgid "invalid clone url"
 msgstr ""
 
-#: rhodecode/model/forms.py:322
-msgid "Invalid clone url, provide a valid clone http\\s url"
-msgstr ""
-
-#: rhodecode/model/forms.py:334
-msgid "Fork have to be the same type as original"
-msgstr ""
-
-#: rhodecode/model/forms.py:341
+#: rhodecode/model/validators.py:432
+msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url"
+msgstr ""
+
+#: rhodecode/model/validators.py:457
+msgid "Fork have to be the same type as parent"
+msgstr ""
+
+#: rhodecode/model/validators.py:478
 msgid "This username or users group name is not valid"
 msgstr ""
 
-#: rhodecode/model/forms.py:403
+#: rhodecode/model/validators.py:562
 msgid "This is not a valid path"
 msgstr ""
 
-#: rhodecode/model/forms.py:416
+#: rhodecode/model/validators.py:577
 msgid "This e-mail address is already taken"
 msgstr ""
 
-#: rhodecode/model/forms.py:427
-msgid "This e-mail address doesn't exist."
-msgstr ""
-
-#: rhodecode/model/forms.py:447
+#: rhodecode/model/validators.py:597
+#, python-format
+msgid "e-mail \"%(email)s\" does not exist."
+msgstr ""
+
+#: rhodecode/model/validators.py:634
 msgid ""
 "The LDAP Login attribute of the CN must be specified - this is the name of "
-"the attribute that is equivalent to 'username'"
-msgstr ""
-
-#: rhodecode/model/forms.py:466
-msgid "Please enter a login"
-msgstr ""
-
-#: rhodecode/model/forms.py:467
-#, python-format
-msgid "Enter a value %(min)i characters long or more"
-msgstr ""
-
-#: rhodecode/model/forms.py:475
-msgid "Please enter a password"
-msgstr ""
-
-#: rhodecode/model/forms.py:476
+"the attribute that is equivalent to \"username\""
+msgstr ""
+
+#: rhodecode/model/validators.py:653
 #, python-format
-msgid "Enter %(min)i characters or more"
-msgstr ""
-
-#: rhodecode/model/user.py:145
-msgid "[RhodeCode] New User registration"
-msgstr ""
-
-#: rhodecode/model/user.py:157 rhodecode/model/user.py:179
-msgid "You can't Edit this user since it's crucial for entire application"
-msgstr ""
-
-#: rhodecode/model/user.py:201
-msgid "You can't remove this user since it's crucial for entire application"
-msgstr ""
-
-#: rhodecode/model/user.py:204
-#, python-format
-msgid ""
-"This user still owns %s repositories and cannot be removed. Switch owners or "
-"remove those repositories"
-msgstr ""
-
-#: rhodecode/templates/index.html:4
+msgid "Revisions %(revs)s are already part of pull request or have set status"
+msgstr ""
+
+#: rhodecode/templates/index.html:3
 msgid "Dashboard"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:22
-#: rhodecode/templates/admin/users/user_edit_my_account.html:102
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/repo_switcher_list.html:4
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/users/user_edit_my_account.html:31
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/bookmarks/bookmarks.html:10
+#: rhodecode/templates/branches/branches.html:9
+#: rhodecode/templates/journal/journal.html:40
+#: rhodecode/templates/tags/tags.html:10
 msgid "quick filter..."
 msgstr ""
 
-#: rhodecode/templates/index_base.html:23 rhodecode/templates/base/base.html:300
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/base/base.html:221
 msgid "repositories"
 msgstr ""
 
+#: rhodecode/templates/index_base.html:13 rhodecode/templates/index_base.html:15
+#: rhodecode/templates/admin/repos/repos.html:21
+msgid "ADD REPOSITORY"
+msgstr ""
+
 #: rhodecode/templates/index_base.html:29
-#: rhodecode/templates/admin/repos/repos.html:22
-msgid "ADD NEW REPOSITORY"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:33
@@ -845,145 +1236,148 @@
 msgid "Group name"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:42 rhodecode/templates/index_base.html:73
-#: rhodecode/templates/admin/repos/repo_add_base.html:44
-#: rhodecode/templates/admin/repos/repo_edit.html:64
-#: rhodecode/templates/admin/repos/repos.html:31
+#: rhodecode/templates/index_base.html:30 rhodecode/templates/index_base.html:71
+#: rhodecode/templates/index_base.html:142 rhodecode/templates/index_base.html:168
+#: rhodecode/templates/admin/repos/repo_add_base.html:56
+#: rhodecode/templates/admin/repos/repo_edit.html:75
+#: rhodecode/templates/admin/repos/repos.html:72
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:34
-#: rhodecode/templates/settings/repo_fork.html:40
-#: rhodecode/templates/settings/repo_settings.html:40
-#: rhodecode/templates/summary/summary.html:92
+#: rhodecode/templates/forks/fork.html:59
+#: rhodecode/templates/settings/repo_settings.html:66
+#: rhodecode/templates/summary/summary.html:105
 msgid "Description"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:53
+#: rhodecode/templates/index_base.html:40
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46
 msgid "Repositories group"
 msgstr ""
 
+#: rhodecode/templates/index_base.html:70 rhodecode/templates/index_base.html:166
+#: rhodecode/templates/admin/repos/repo_add_base.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:32
+#: rhodecode/templates/admin/repos/repos.html:70
+#: rhodecode/templates/admin/users/user_edit.html:192
+#: rhodecode/templates/admin/users/user_edit_my_account.html:59
+#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:6
+#: rhodecode/templates/bookmarks/bookmarks.html:36
+#: rhodecode/templates/bookmarks/bookmarks_data.html:6
+#: rhodecode/templates/branches/branches.html:51
+#: rhodecode/templates/files/files_browser.html:47
+#: rhodecode/templates/journal/journal.html:59
+#: rhodecode/templates/journal/journal.html:107
+#: rhodecode/templates/journal/journal.html:186
+#: rhodecode/templates/settings/repo_settings.html:31
+#: rhodecode/templates/summary/summary.html:43
+#: rhodecode/templates/summary/summary.html:123
+#: rhodecode/templates/tags/tags.html:36 rhodecode/templates/tags/tags_data.html:6
+msgid "Name"
+msgstr ""
+
 #: rhodecode/templates/index_base.html:72
-#: rhodecode/templates/admin/repos/repo_add_base.html:9
-#: rhodecode/templates/admin/repos/repo_edit.html:32
-#: rhodecode/templates/admin/repos/repos.html:30
-#: rhodecode/templates/admin/users/user_edit_my_account.html:117
-#: rhodecode/templates/files/files_browser.html:157
-#: rhodecode/templates/settings/repo_settings.html:31
-#: rhodecode/templates/summary/summary.html:31
-#: rhodecode/templates/summary/summary.html:107
-msgid "Name"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:74
-#: rhodecode/templates/admin/repos/repos.html:32
-#: rhodecode/templates/summary/summary.html:114
 msgid "Last change"
 msgstr ""
 
+#: rhodecode/templates/index_base.html:73 rhodecode/templates/index_base.html:171
+#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/journal/journal.html:188
+msgid "Tip"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:74 rhodecode/templates/index_base.html:173
+#: rhodecode/templates/admin/repos/repo_edit.html:121
+#: rhodecode/templates/admin/repos/repos.html:73
+msgid "Owner"
+msgstr ""
+
 #: rhodecode/templates/index_base.html:75
-#: rhodecode/templates/admin/repos/repos.html:33
-msgid "Tip"
+#: rhodecode/templates/summary/summary.html:48
+#: rhodecode/templates/summary/summary.html:51
+msgid "RSS"
 msgstr ""
 
 #: rhodecode/templates/index_base.html:76
-#: rhodecode/templates/admin/repos/repo_edit.html:97
-msgid "Owner"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:77
-#: rhodecode/templates/journal/public_journal.html:20
-#: rhodecode/templates/summary/summary.html:180
-#: rhodecode/templates/summary/summary.html:183
-msgid "RSS"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:78
-#: rhodecode/templates/journal/public_journal.html:23
-#: rhodecode/templates/summary/summary.html:181
-#: rhodecode/templates/summary/summary.html:184
 msgid "Atom"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:87 rhodecode/templates/index_base.html:89
-#: rhodecode/templates/index_base.html:91 rhodecode/templates/base/base.html:209
-#: rhodecode/templates/base/base.html:211 rhodecode/templates/base/base.html:213
-#: rhodecode/templates/summary/summary.html:4
-msgid "Summary"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:95 rhodecode/templates/index_base.html:97
-#: rhodecode/templates/index_base.html:99 rhodecode/templates/base/base.html:225
-#: rhodecode/templates/base/base.html:227 rhodecode/templates/base/base.html:229
-#: rhodecode/templates/changelog/changelog.html:6
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "Changelog"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:103 rhodecode/templates/index_base.html:105
-#: rhodecode/templates/index_base.html:107 rhodecode/templates/base/base.html:268
-#: rhodecode/templates/base/base.html:270 rhodecode/templates/base/base.html:272
-#: rhodecode/templates/files/files.html:4
-msgid "Files"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:116
-#: rhodecode/templates/admin/repos/repos.html:42
-#: rhodecode/templates/admin/users/user_edit_my_account.html:127
-#: rhodecode/templates/summary/summary.html:48
-msgid "Mercurial repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:118
-#: rhodecode/templates/admin/repos/repos.html:44
-#: rhodecode/templates/admin/users/user_edit_my_account.html:129
-#: rhodecode/templates/summary/summary.html:51
-msgid "Git repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:123
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
-#: rhodecode/templates/journal/journal.html:53
-#: rhodecode/templates/summary/summary.html:56
-msgid "private repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:125
-#: rhodecode/templates/journal/journal.html:55
-#: rhodecode/templates/summary/summary.html:58
-msgid "public repository"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:133 rhodecode/templates/base/base.html:291
-#: rhodecode/templates/settings/repo_fork.html:13
-msgid "fork"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:134
-#: rhodecode/templates/admin/repos/repos.html:60
-#: rhodecode/templates/admin/users/user_edit_my_account.html:143
-#: rhodecode/templates/summary/summary.html:69
-#: rhodecode/templates/summary/summary.html:71
-msgid "Fork of"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:155
-#: rhodecode/templates/admin/repos/repos.html:73
-msgid "No changesets yet"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:161 rhodecode/templates/index_base.html:163
+#: rhodecode/templates/index_base.html:110 rhodecode/templates/index_base.html:112
 #, python-format
 msgid "Subscribe to %s rss feed"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:168 rhodecode/templates/index_base.html:170
+#: rhodecode/templates/index_base.html:117 rhodecode/templates/index_base.html:119
 #, python-format
 msgid "Subscribe to %s atom feed"
 msgstr ""
 
+#: rhodecode/templates/index_base.html:140
+msgid "Group Name"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:158 rhodecode/templates/index_base.html:198
+#: rhodecode/templates/admin/repos/repos.html:94
+#: rhodecode/templates/admin/users/user_edit_my_account.html:179
+#: rhodecode/templates/admin/users/users.html:107
+#: rhodecode/templates/bookmarks/bookmarks.html:60
+#: rhodecode/templates/branches/branches.html:77
+#: rhodecode/templates/journal/journal.html:211
+#: rhodecode/templates/tags/tags.html:60
+msgid "Click to sort ascending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:159 rhodecode/templates/index_base.html:199
+#: rhodecode/templates/admin/repos/repos.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account.html:180
+#: rhodecode/templates/admin/users/users.html:108
+#: rhodecode/templates/bookmarks/bookmarks.html:61
+#: rhodecode/templates/branches/branches.html:78
+#: rhodecode/templates/journal/journal.html:212
+#: rhodecode/templates/tags/tags.html:61
+msgid "Click to sort descending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:169
+msgid "Last Change"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:200
+#: rhodecode/templates/admin/repos/repos.html:96
+#: rhodecode/templates/admin/users/user_edit_my_account.html:181
+#: rhodecode/templates/admin/users/users.html:109
+#: rhodecode/templates/bookmarks/bookmarks.html:62
+#: rhodecode/templates/branches/branches.html:79
+#: rhodecode/templates/journal/journal.html:213
+#: rhodecode/templates/tags/tags.html:62
+msgid "No records found."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:201
+#: rhodecode/templates/admin/repos/repos.html:97
+#: rhodecode/templates/admin/users/user_edit_my_account.html:182
+#: rhodecode/templates/admin/users/users.html:110
+#: rhodecode/templates/bookmarks/bookmarks.html:63
+#: rhodecode/templates/branches/branches.html:80
+#: rhodecode/templates/journal/journal.html:214
+#: rhodecode/templates/tags/tags.html:63
+msgid "Data error."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:202
+#: rhodecode/templates/admin/repos/repos.html:98
+#: rhodecode/templates/admin/users/user_edit_my_account.html:183
+#: rhodecode/templates/admin/users/users.html:111
+#: rhodecode/templates/bookmarks/bookmarks.html:64
+#: rhodecode/templates/branches/branches.html:81
+#: rhodecode/templates/journal/journal.html:215
+#: rhodecode/templates/tags/tags.html:64
+msgid "Loading..."
+msgstr ""
+
 #: rhodecode/templates/login.html:5 rhodecode/templates/login.html:54
-#: rhodecode/templates/base/base.html:38
 msgid "Sign In"
 msgstr ""
 
@@ -994,25 +1388,29 @@
 #: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20
 #: rhodecode/templates/admin/admin_log.html:5
 #: rhodecode/templates/admin/users/user_add.html:32
-#: rhodecode/templates/admin/users/user_edit.html:47
-#: rhodecode/templates/admin/users/user_edit_my_account.html:45
-#: rhodecode/templates/base/base.html:15
-#: rhodecode/templates/summary/summary.html:106
+#: rhodecode/templates/admin/users/user_edit.html:50
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:26
+#: rhodecode/templates/base/base.html:83
+#: rhodecode/templates/summary/summary.html:122
 msgid "Username"
 msgstr ""
 
 #: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29
 #: rhodecode/templates/admin/ldap/ldap.html:46
 #: rhodecode/templates/admin/users/user_add.html:41
-#: rhodecode/templates/base/base.html:24
+#: rhodecode/templates/base/base.html:92
 msgid "Password"
 msgstr ""
 
+#: rhodecode/templates/login.html:50
+msgid "Remember me"
+msgstr ""
+
 #: rhodecode/templates/login.html:60
 msgid "Forgot your password ?"
 msgstr ""
 
-#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:35
+#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:103
 msgid "Don't have an account ?"
 msgstr ""
 
@@ -1049,24 +1447,24 @@
 msgstr ""
 
 #: rhodecode/templates/register.html:47
-#: rhodecode/templates/admin/users/user_add.html:50
-#: rhodecode/templates/admin/users/user_edit.html:74
-#: rhodecode/templates/admin/users/user_edit_my_account.html:63
+#: rhodecode/templates/admin/users/user_add.html:59
+#: rhodecode/templates/admin/users/user_edit.html:86
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53
 msgid "First Name"
 msgstr ""
 
 #: rhodecode/templates/register.html:56
-#: rhodecode/templates/admin/users/user_add.html:59
-#: rhodecode/templates/admin/users/user_edit.html:83
-#: rhodecode/templates/admin/users/user_edit_my_account.html:72
+#: rhodecode/templates/admin/users/user_add.html:68
+#: rhodecode/templates/admin/users/user_edit.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62
 msgid "Last Name"
 msgstr ""
 
 #: rhodecode/templates/register.html:65
-#: rhodecode/templates/admin/users/user_add.html:68
-#: rhodecode/templates/admin/users/user_edit.html:92
-#: rhodecode/templates/admin/users/user_edit_my_account.html:81
-#: rhodecode/templates/summary/summary.html:108
+#: rhodecode/templates/admin/users/user_add.html:77
+#: rhodecode/templates/admin/users/user_edit.html:104
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71
+#: rhodecode/templates/summary/summary.html:124
 msgid "Email"
 msgstr ""
 
@@ -1078,19 +1476,58 @@
 msgid "Your account must wait for activation by administrator"
 msgstr ""
 
-#: rhodecode/templates/repo_switcher_list.html:14
+#: rhodecode/templates/repo_switcher_list.html:11
+#: rhodecode/templates/admin/repos/repo_add_base.html:65
+#: rhodecode/templates/admin/repos/repo_edit.html:85
+#: rhodecode/templates/settings/repo_settings.html:76
 msgid "Private repository"
 msgstr ""
 
-#: rhodecode/templates/repo_switcher_list.html:19
+#: rhodecode/templates/repo_switcher_list.html:16
 msgid "Public repository"
 msgstr ""
 
+#: rhodecode/templates/switch_to_list.html:3
+#: rhodecode/templates/branches/branches.html:14
+msgid "branches"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:10
+#: rhodecode/templates/branches/branches_data.html:57
+msgid "There are no branches yet"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:15
+#: rhodecode/templates/shortlog/shortlog_data.html:10
+#: rhodecode/templates/tags/tags.html:15
+msgid "tags"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:22
+#: rhodecode/templates/tags/tags_data.html:33
+msgid "There are no tags yet"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:28
+#: rhodecode/templates/bookmarks/bookmarks.html:15
+msgid "bookmarks"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:35
+#: rhodecode/templates/bookmarks/bookmarks_data.html:32
+msgid "There are no bookmarks yet"
+msgstr ""
+
 #: rhodecode/templates/admin/admin.html:5 rhodecode/templates/admin/admin.html:9
 msgid "Admin journal"
 msgstr ""
 
 #: rhodecode/templates/admin/admin_log.html:6
+#: rhodecode/templates/admin/repos/repos.html:74
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:8
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:9
+#: rhodecode/templates/journal/journal.html:61
+#: rhodecode/templates/journal/journal.html:62
 msgid "Action"
 msgstr ""
 
@@ -1099,6 +1536,10 @@
 msgstr ""
 
 #: rhodecode/templates/admin/admin_log.html:8
+#: rhodecode/templates/bookmarks/bookmarks.html:37
+#: rhodecode/templates/bookmarks/bookmarks_data.html:7
+#: rhodecode/templates/branches/branches.html:52
+#: rhodecode/templates/tags/tags.html:37 rhodecode/templates/tags/tags_data.html:7
 msgid "Date"
 msgstr ""
 
@@ -1106,7 +1547,7 @@
 msgid "From IP"
 msgstr ""
 
-#: rhodecode/templates/admin/admin_log.html:52
+#: rhodecode/templates/admin/admin_log.html:53
 msgid "No actions yet"
 msgstr ""
 
@@ -1183,23 +1624,62 @@
 msgstr ""
 
 #: rhodecode/templates/admin/ldap/ldap.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:141
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:74
 #: rhodecode/templates/admin/settings/hooks.html:73
-#: rhodecode/templates/admin/users/user_edit.html:117
-#: rhodecode/templates/admin/users/user_edit.html:142
-#: rhodecode/templates/admin/users/user_edit_my_account.html:89
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:263
+#: rhodecode/templates/admin/users/user_edit.html:129
+#: rhodecode/templates/admin/users/user_edit.html:174
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:79
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:135
+#: rhodecode/templates/settings/repo_settings.html:93
 msgid "Save"
 msgstr ""
 
+#: rhodecode/templates/admin/notifications/notifications.html:5
+#: rhodecode/templates/admin/notifications/notifications.html:9
+msgid "My Notifications"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:29
+msgid "All"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:30
+msgid "Comments"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:31
+#: rhodecode/templates/base/base.html:254 rhodecode/templates/base/base.html:256
+msgid "Pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:35
+msgid "Mark all read"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications_data.html:39
+msgid "No notifications here yet"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/show_notification.html:5
+#: rhodecode/templates/admin/notifications/show_notification.html:11
+msgid "Show notification"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/show_notification.html:9
+msgid "Notifications"
+msgstr ""
+
 #: rhodecode/templates/admin/permissions/permissions.html:5
 msgid "Permissions administration"
 msgstr ""
 
 #: rhodecode/templates/admin/permissions/permissions.html:11
-#: rhodecode/templates/admin/repos/repo_edit.html:109
-#: rhodecode/templates/admin/users/user_edit.html:127
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:248
-#: rhodecode/templates/settings/repo_settings.html:58
+#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
+#: rhodecode/templates/admin/users/user_edit.html:139
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:100
+#: rhodecode/templates/settings/repo_settings.html:86
 msgid "Permissions"
 msgstr ""
 
@@ -1235,6 +1715,11 @@
 msgstr ""
 
 #: rhodecode/templates/admin/permissions/permissions.html:71
+msgid "Repository forking"
+msgstr ""
+
+#: rhodecode/templates/admin/permissions/permissions.html:78
+#: rhodecode/templates/admin/repos/repo_edit.html:241
 msgid "set"
 msgstr ""
 
@@ -1245,7 +1730,6 @@
 
 #: rhodecode/templates/admin/repos/repo_add.html:11
 #: rhodecode/templates/admin/repos/repo_edit.html:11
-#: rhodecode/templates/admin/repos/repos.html:10
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
 msgid "Repositories"
 msgstr ""
@@ -1255,30 +1739,70 @@
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_add_base.html:20
-#: rhodecode/templates/summary/summary.html:80
-#: rhodecode/templates/summary/summary.html:82
+#: rhodecode/templates/summary/summary.html:95
+#: rhodecode/templates/summary/summary.html:96
 msgid "Clone from"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:28
-#: rhodecode/templates/admin/repos/repo_edit.html:48
+#: rhodecode/templates/admin/repos/repo_add_base.html:24
+#: rhodecode/templates/admin/repos/repo_edit.html:44
+#: rhodecode/templates/settings/repo_settings.html:43
+msgid "Optional http[s] url from which repository should be cloned."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:29
+#: rhodecode/templates/admin/repos/repo_edit.html:49
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:4
+#: rhodecode/templates/forks/fork.html:50
+#: rhodecode/templates/settings/repo_settings.html:48
 msgid "Repository group"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:36
-#: rhodecode/templates/admin/repos/repo_edit.html:56
+#: rhodecode/templates/admin/repos/repo_add_base.html:33
+#: rhodecode/templates/forks/fork.html:54
+msgid "Optionaly select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:38
+#: rhodecode/templates/admin/repos/repo_edit.html:58
 msgid "Type"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:52
-#: rhodecode/templates/admin/repos/repo_edit.html:73
-#: rhodecode/templates/settings/repo_fork.html:48
-#: rhodecode/templates/settings/repo_settings.html:49
-msgid "Private"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_add_base.html:59
+#: rhodecode/templates/admin/repos/repo_add_base.html:42
+msgid "Type of repository to create."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:47
+#: rhodecode/templates/admin/repos/repo_edit.html:66
+#: rhodecode/templates/forks/fork.html:41
+#: rhodecode/templates/settings/repo_settings.html:57
+msgid "Landing revision"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:51
+#: rhodecode/templates/admin/repos/repo_edit.html:70
+#: rhodecode/templates/forks/fork.html:45
+#: rhodecode/templates/settings/repo_settings.html:61
+msgid "Default revision for files page, downloads, whoosh and readme"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:60
+#: rhodecode/templates/admin/repos/repo_edit.html:79
+#: rhodecode/templates/forks/fork.html:63
+#: rhodecode/templates/settings/repo_settings.html:70
+msgid "Keep it short and to the point. Use a README file for longer descriptions."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:69
+#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/forks/fork.html:72
+#: rhodecode/templates/settings/repo_settings.html:80
+msgid ""
+"Private repositories are only visible to people explicitly added as "
+"collaborators."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:73
 msgid "add"
 msgstr ""
 
@@ -1292,183 +1816,268 @@
 
 #: rhodecode/templates/admin/repos/repo_edit.html:13
 #: rhodecode/templates/admin/users/user_edit.html:13
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
+#: rhodecode/templates/admin/users/user_edit.html:224
+#: rhodecode/templates/admin/users/user_edit.html:226
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:13
-#: rhodecode/templates/files/files_annotate.html:49
-#: rhodecode/templates/files/files_source.html:20
+#: rhodecode/templates/files/files_source.html:44
+#: rhodecode/templates/journal/journal.html:81
 msgid "edit"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit.html:40
+#: rhodecode/templates/settings/repo_settings.html:39
 msgid "Clone uri"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:81
+#: rhodecode/templates/admin/repos/repo_edit.html:53
+#: rhodecode/templates/settings/repo_settings.html:52
+msgid "Optional select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:94
 msgid "Enable statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:98
+msgid "Enable statistics window on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:103
 msgid "Enable downloads"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:127
+#: rhodecode/templates/admin/repos/repo_edit.html:107
+msgid "Enable download menu on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:112
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:66
+msgid "Enable locking"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:116
+msgid "Enable lock-by-pulling on repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:126
+msgid "Change owner of this repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:142
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:75
+#: rhodecode/templates/admin/settings/settings.html:113
+#: rhodecode/templates/admin/settings/settings.html:168
+#: rhodecode/templates/admin/settings/settings.html:258
+#: rhodecode/templates/admin/users/user_edit.html:130
+#: rhodecode/templates/admin/users/user_edit.html:175
+#: rhodecode/templates/admin/users/user_edit.html:278
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:136
+#: rhodecode/templates/files/files_add.html:82
+#: rhodecode/templates/files/files_edit.html:68
+#: rhodecode/templates/pullrequests/pullrequest.html:124
+#: rhodecode/templates/settings/repo_settings.html:94
+msgid "Reset"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:152
 msgid "Administration"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:130
+#: rhodecode/templates/admin/repos/repo_edit.html:155
 msgid "Statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Reset current statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Confirm to remove current statistics"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:137
-msgid "Fetched to rev"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:138
-msgid "Percentage of stats gathered"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:147
-msgid "Remote"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:151
-msgid "Pull changes from remote location"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:151
-msgid "Confirm to pull changes from remote side"
-msgstr ""
-
 #: rhodecode/templates/admin/repos/repo_edit.html:162
+msgid "Fetched to rev"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:163
+msgid "Stats gathered"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:171
+msgid "Remote"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Pull changes from remote location"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Confirm to pull changes from remote side"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:186
 msgid "Cache"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Invalidate repository cache"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Confirm to invalidate repository cache"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:177
+#: rhodecode/templates/admin/repos/repo_edit.html:195
+#: rhodecode/templates/base/base.html:318 rhodecode/templates/base/base.html:320
+#: rhodecode/templates/base/base.html:322
+msgid "Public journal"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:201
 msgid "Remove from public journal"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:179
+#: rhodecode/templates/admin/repos/repo_edit.html:203
 msgid "Add to public journal"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:185
+#: rhodecode/templates/admin/repos/repo_edit.html:208
+msgid ""
+"All actions made on this repository will be accessible to everyone in public "
+"journal"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:215
+msgid "Locking"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Unlock locked repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Confirm to unlock repository"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "lock repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "Confirm to lock repository"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:224
+msgid "Repository is not locked"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:229
+msgid "Force locking on repository. Works only when anonymous access is disabled"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:236
+msgid "Set as fork of"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:245
+msgid "Manually set this repository as a fork of another from the list"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:251
+#: rhodecode/templates/changeset/changeset_file_comment.html:26
 msgid "Delete"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
+#: rhodecode/templates/admin/repos/repo_edit.html:255
 msgid "Remove this repository"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
-#: rhodecode/templates/admin/repos/repos.html:79
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+#: rhodecode/templates/journal/journal.html:84
 msgid "Confirm to delete this repository"
 msgstr ""
 
+#: rhodecode/templates/admin/repos/repo_edit.html:259
+msgid ""
+"This repository will be renamed in a special way in order to be unaccesible "
+"for RhodeCode and VCS systems.\n"
+"                         If you need fully delete it from filesystem please "
+"do it manually"
+msgstr ""
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:3
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3
 msgid "none"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:4
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4
 msgid "read"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:5
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5
 msgid "write"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:6
-#: rhodecode/templates/admin/users/users.html:38
-#: rhodecode/templates/base/base.html:296
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6
+#: rhodecode/templates/admin/users/users.html:85
+#: rhodecode/templates/base/base.html:217
 msgid "admin"
 msgstr ""
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:7
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7
 msgid "member"
 msgstr ""
 
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
+#: rhodecode/templates/data_table/_dt_elements.html:67
+#: rhodecode/templates/journal/journal.html:132
+#: rhodecode/templates/summary/summary.html:76
+msgid "private repository"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:19
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:28
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:18
+msgid "default"
+msgstr ""
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:33
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:53
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:58
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:23
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:42
 msgid "revoke"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:75
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:83
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:67
 msgid "Add another member"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:89
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:97
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81
 msgid "Failed to remove user"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:104
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:112
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:96
 msgid "Failed to remove users group"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:205
-msgid "Group"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:206
-#: rhodecode/templates/admin/users_groups/users_groups.html:33
-msgid "members"
-msgstr ""
-
 #: rhodecode/templates/admin/repos/repos.html:5
 msgid "Repositories administration"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repos.html:34
-#: rhodecode/templates/summary/summary.html:100
-msgid "Contact"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:35
-#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
-#: rhodecode/templates/admin/users/user_edit_my_account.html:119
-#: rhodecode/templates/admin/users/users.html:40
-#: rhodecode/templates/admin/users_groups/users_groups.html:35
-msgid "action"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:51
-#: rhodecode/templates/admin/users/user_edit_my_account.html:134
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
-msgid "private"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:53
-#: rhodecode/templates/admin/repos/repos.html:59
-#: rhodecode/templates/admin/users/user_edit_my_account.html:136
-#: rhodecode/templates/admin/users/user_edit_my_account.html:142
-#: rhodecode/templates/summary/summary.html:68
-msgid "public"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repos.html:79
-#: rhodecode/templates/admin/users/users.html:55
-msgid "delete"
-msgstr ""
-
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:8
 msgid "Groups"
 msgstr ""
 
-#: rhodecode/templates/admin/repos_groups/repos_groups.html:13
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:12
 msgid "with"
 msgstr ""
 
@@ -1491,10 +2100,10 @@
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:58
-#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
-#: rhodecode/templates/admin/users/user_add.html:85
+#: rhodecode/templates/admin/users/user_add.html:94
 #: rhodecode/templates/admin/users_groups/users_group_add.html:49
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:90
+#: rhodecode/templates/pullrequests/pullrequest_show.html:113
 msgid "save"
 msgstr ""
 
@@ -1506,6 +2115,12 @@
 msgid "edit repos group"
 msgstr ""
 
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:70
+msgid ""
+"Enable lock-by-pulling on group. This option will be applied to all other "
+"groups and repositories inside"
+msgstr ""
+
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5
 msgid "Repositories groups administration"
 msgstr ""
@@ -1515,11 +2130,26 @@
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:35
-msgid "Number of repositories"
+msgid "Number of toplevel repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
+#: rhodecode/templates/admin/users/users.html:87
+#: rhodecode/templates/admin/users_groups/users_groups.html:35
+msgid "action"
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
-msgid "Confirm to delete this group"
+#: rhodecode/templates/admin/users/user_edit.html:255
+#: rhodecode/templates/admin/users_groups/users_groups.html:44
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#: rhodecode/templates/data_table/_dt_elements.html:103
+msgid "delete"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#, python-format
+msgid "Confirm to delete this group: %s"
 msgstr ""
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:62
@@ -1533,7 +2163,6 @@
 
 #: rhodecode/templates/admin/settings/hooks.html:9
 #: rhodecode/templates/admin/settings/settings.html:9
-#: rhodecode/templates/settings/repo_settings.html:5
 #: rhodecode/templates/settings/repo_settings.html:13
 msgid "Settings"
 msgstr ""
@@ -1573,115 +2202,185 @@
 msgid "destroy old data"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:45
+#: rhodecode/templates/admin/settings/settings.html:41
+msgid ""
+"Rescan repositories location for new repositories. Also deletes obsolete if "
+"`destroy` flag is checked "
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:46
 msgid "Rescan repositories"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:51
+#: rhodecode/templates/admin/settings/settings.html:52
 msgid "Whoosh indexing"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:59
+#: rhodecode/templates/admin/settings/settings.html:60
 msgid "index build option"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:64
+#: rhodecode/templates/admin/settings/settings.html:65
 msgid "build from scratch"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:70
+#: rhodecode/templates/admin/settings/settings.html:71
 msgid "Reindex"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:76
+#: rhodecode/templates/admin/settings/settings.html:77
 msgid "Global application settings"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:85
+#: rhodecode/templates/admin/settings/settings.html:86
 msgid "Application name"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:94
+#: rhodecode/templates/admin/settings/settings.html:95
 msgid "Realm text"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:103
+#: rhodecode/templates/admin/settings/settings.html:104
 msgid "GA code"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:111
-#: rhodecode/templates/admin/settings/settings.html:177
-msgid "Save settings"
-msgstr ""
-
 #: rhodecode/templates/admin/settings/settings.html:112
-#: rhodecode/templates/admin/settings/settings.html:178
-#: rhodecode/templates/admin/users/user_edit.html:118
-#: rhodecode/templates/admin/users/user_edit.html:143
-#: rhodecode/templates/admin/users/user_edit_my_account.html:90
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:264
-#: rhodecode/templates/files/files_edit.html:50
-msgid "Reset"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:118
-msgid "Mercurial settings"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:127
+#: rhodecode/templates/admin/settings/settings.html:167
+#: rhodecode/templates/admin/settings/settings.html:257
+msgid "Save settings"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:119
+msgid "Visualisation settings"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:128
+msgid "Icons"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:133
+msgid "Show public repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:137
+msgid "Show private repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:144
+msgid "Meta-Tagging"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:149
+msgid "Stylify recognised metatags:"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:176
+msgid "VCS settings"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:185
 msgid "Web"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:132
-msgid "require ssl for pushing"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:139
+#: rhodecode/templates/admin/settings/settings.html:190
+msgid "require ssl for vcs operations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:192
+msgid ""
+"RhodeCode will require SSL for pushing or pulling. If SSL is missing it will "
+"return HTTP Error 406: Not Acceptable"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:198
 msgid "Hooks"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:142
-msgid "advanced setup"
-msgstr ""
-
-#: rhodecode/templates/admin/settings/settings.html:147
+#: rhodecode/templates/admin/settings/settings.html:203
 msgid "Update repository after push (hg update)"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:151
+#: rhodecode/templates/admin/settings/settings.html:207
 msgid "Show repository size after push"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:155
+#: rhodecode/templates/admin/settings/settings.html:211
 msgid "Log user push commands"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:159
+#: rhodecode/templates/admin/settings/settings.html:215
 msgid "Log user pull commands"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:166
+#: rhodecode/templates/admin/settings/settings.html:219
+msgid "advanced setup"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:224
+msgid "Mercurial Extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:229
+msgid "largefiles extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:233
+msgid "hgsubversion extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:235
+msgid ""
+"Requires hgsubversion library installed. Allows clonning from svn remote "
+"locations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:245
 msgid "Repositories location"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:171
+#: rhodecode/templates/admin/settings/settings.html:250
 msgid ""
 "This a crucial application setting. If you are really sure you need to change"
 " this, you must restart application in order to make this setting take "
 "effect. Click this label to unlock."
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:172
+#: rhodecode/templates/admin/settings/settings.html:251
 msgid "unlock"
 msgstr ""
 
+#: rhodecode/templates/admin/settings/settings.html:252
+msgid ""
+"Location where repositories are stored. After changing this value a restart, "
+"and rescan is required"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:272
+msgid "Test Email"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:280
+msgid "Email to"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:288
+msgid "Send"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:294
+msgid "System Info and Packages"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:297
+msgid "show"
+msgstr ""
+
 #: rhodecode/templates/admin/users/user_add.html:5
 msgid "Add user"
 msgstr ""
 
 #: rhodecode/templates/admin/users/user_add.html:10
 #: rhodecode/templates/admin/users/user_edit.html:11
-#: rhodecode/templates/admin/users/users.html:9
 msgid "Users"
 msgstr ""
 
@@ -1689,8 +2388,12 @@
 msgid "add new user"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_add.html:77
-#: rhodecode/templates/admin/users/user_edit.html:101
+#: rhodecode/templates/admin/users/user_add.html:50
+msgid "Password confirmation"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_add.html:86
+#: rhodecode/templates/admin/users/user_edit.html:113
 #: rhodecode/templates/admin/users_groups/users_group_add.html:41
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:42
 msgid "Active"
@@ -1700,36 +2403,93 @@
 msgid "Edit user"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:33
-#: rhodecode/templates/admin/users/user_edit_my_account.html:32
+#: rhodecode/templates/admin/users/user_edit.html:34
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10
 msgid "Change your avatar at"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:34
-#: rhodecode/templates/admin/users/user_edit_my_account.html:33
+#: rhodecode/templates/admin/users/user_edit.html:35
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11
 msgid "Using"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:40
-#: rhodecode/templates/admin/users/user_edit_my_account.html:39
+#: rhodecode/templates/admin/users/user_edit.html:43
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20
 msgid "API key"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:56
+#: rhodecode/templates/admin/users/user_edit.html:59
 msgid "LDAP DN"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:65
-#: rhodecode/templates/admin/users/user_edit_my_account.html:54
+#: rhodecode/templates/admin/users/user_edit.html:68
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:35
 msgid "New password"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:135
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:256
+#: rhodecode/templates/admin/users/user_edit.html:77
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44
+msgid "New password confirmation"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:147
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:108
+msgid "Inherit default permissions"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:152
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:113
+#, python-format
+msgid ""
+"Select to inherit permissions from %s settings. With this selected below "
+"options does not have any action"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:158
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:119
 msgid "Create repositories"
 msgstr ""
 
+#: rhodecode/templates/admin/users/user_edit.html:166
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:127
+msgid "Fork repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:186
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:22
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:39
+msgid "Nothing here yet"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account.html:60
+#: rhodecode/templates/admin/users/user_edit_my_account.html:194
+msgid "Permission"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:194
+msgid "Edit Permission"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:243
+msgid "Email addresses"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:256
+#, python-format
+msgid "Confirm to delete this email: %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:270
+msgid "New email address"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:277
+msgid "Add"
+msgstr ""
+
 #: rhodecode/templates/admin/users/user_edit_my_account.html:5
+#: rhodecode/templates/base/base.html:124
 msgid "My account"
 msgstr ""
 
@@ -1737,26 +2497,73 @@
 msgid "My Account"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:101
-msgid "My repositories"
-msgstr ""
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:107
-msgid "ADD REPOSITORY"
-msgstr ""
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:118
-#: rhodecode/templates/branches/branches_data.html:7
-#: rhodecode/templates/shortlog/shortlog_data.html:8
-#: rhodecode/templates/tags/tags_data.html:7
-msgid "revision"
-msgstr ""
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:35
+msgid "My permissions"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:38
+#: rhodecode/templates/journal/journal.html:41
+msgid "My repos"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:41
+msgid "My pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:45
+msgid "Add repo"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2
+msgid "Opened by me"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:10
+#, python-format
+msgid "Pull request #%s opened on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15
+msgid "Confirm to delete this pull request"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:26
+msgid "I participate in"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:33
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:30
+#, python-format
+msgid "Pull request #%s opened by %s on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:7
+#: rhodecode/templates/bookmarks/bookmarks.html:40
+#: rhodecode/templates/bookmarks/bookmarks_data.html:9
+#: rhodecode/templates/branches/branches.html:55
+#: rhodecode/templates/journal/journal.html:60
+#: rhodecode/templates/tags/tags.html:40 rhodecode/templates/tags/tags_data.html:9
+msgid "Revision"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/journal/journal.html:81
+msgid "private"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#, python-format
+msgid "Confirm to delete this repository: %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:38
+#: rhodecode/templates/journal/journal.html:94
 msgid "No repositories yet"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:40
+#: rhodecode/templates/journal/journal.html:96
 msgid "create one now"
 msgstr ""
 
@@ -1764,42 +2571,41 @@
 msgid "Users administration"
 msgstr ""
 
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/base/base.html:223
+msgid "users"
+msgstr ""
+
 #: rhodecode/templates/admin/users/users.html:23
 msgid "ADD NEW USER"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:33
+#: rhodecode/templates/admin/users/users.html:77
 msgid "username"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:34
-#: rhodecode/templates/branches/branches_data.html:5
-#: rhodecode/templates/tags/tags_data.html:5
-msgid "name"
-msgstr ""
-
-#: rhodecode/templates/admin/users/users.html:35
+#: rhodecode/templates/admin/users/users.html:80
+msgid "firstname"
+msgstr ""
+
+#: rhodecode/templates/admin/users/users.html:81
 msgid "lastname"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:36
+#: rhodecode/templates/admin/users/users.html:82
 msgid "last login"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:37
+#: rhodecode/templates/admin/users/users.html:84
 #: rhodecode/templates/admin/users_groups/users_groups.html:34
 msgid "active"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:39
-#: rhodecode/templates/base/base.html:305
+#: rhodecode/templates/admin/users/users.html:86
+#: rhodecode/templates/base/base.html:226
 msgid "ldap"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:56
-msgid "Confirm to delete this user"
-msgstr ""
-
 #: rhodecode/templates/admin/users_groups/users_group_add.html:5
 msgid "Add users group"
 msgstr ""
@@ -1841,6 +2647,10 @@
 msgid "Add all elements"
 msgstr ""
 
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:146
+msgid "Group members"
+msgstr ""
+
 #: rhodecode/templates/admin/users_groups/users_groups.html:5
 msgid "Users groups administration"
 msgstr ""
@@ -1853,387 +2663,598 @@
 msgid "group name"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:32
+#: rhodecode/templates/admin/users_groups/users_groups.html:33
+#: rhodecode/templates/base/root.html:46
+msgid "members"
+msgstr ""
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:45
+#, python-format
+msgid "Confirm to delete this users group: %s"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:41
+msgid "Submit a bug"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:77
+msgid "Login to your account"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:100
 msgid "Forgot password ?"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:57 rhodecode/templates/base/base.html:338
-#: rhodecode/templates/base/base.html:340 rhodecode/templates/base/base.html:342
-msgid "Home"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:61 rhodecode/templates/base/base.html:347
-#: rhodecode/templates/base/base.html:349 rhodecode/templates/base/base.html:351
-#: rhodecode/templates/journal/journal.html:4
-#: rhodecode/templates/journal/journal.html:17
-#: rhodecode/templates/journal/public_journal.html:4
-msgid "Journal"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:66
-msgid "Login"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:68
-msgid "Log Out"
-msgstr ""
-
 #: rhodecode/templates/base/base.html:107
-msgid "Submit a bug"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:141
+msgid "Log In"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:118
+msgid "Inbox"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:122 rhodecode/templates/base/base.html:300
+#: rhodecode/templates/base/base.html:302 rhodecode/templates/base/base.html:304
+#: rhodecode/templates/bookmarks/bookmarks.html:11
+#: rhodecode/templates/branches/branches.html:10
+#: rhodecode/templates/changelog/changelog.html:10
+#: rhodecode/templates/changeset/changeset.html:10
+#: rhodecode/templates/changeset/changeset_range.html:9
+#: rhodecode/templates/compare/compare_diff.html:9
+#: rhodecode/templates/files/file_diff.html:8
+#: rhodecode/templates/files/files.html:8
+#: rhodecode/templates/files/files_add.html:15
+#: rhodecode/templates/files/files_edit.html:15
+#: rhodecode/templates/followers/followers.html:9
+#: rhodecode/templates/forks/fork.html:9 rhodecode/templates/forks/forks.html:9
+#: rhodecode/templates/pullrequests/pullrequest.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8
+#: rhodecode/templates/settings/repo_settings.html:9
+#: rhodecode/templates/shortlog/shortlog.html:10
+#: rhodecode/templates/summary/summary.html:8 rhodecode/templates/tags/tags.html:11
+msgid "Home"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:123 rhodecode/templates/base/base.html:309
+#: rhodecode/templates/base/base.html:311 rhodecode/templates/base/base.html:313
+#: rhodecode/templates/journal/journal.html:4
+#: rhodecode/templates/journal/journal.html:21
+#: rhodecode/templates/journal/public_journal.html:4
+msgid "Journal"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:125
+msgid "Log Out"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:144
 msgid "Switch repository"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:143
+#: rhodecode/templates/base/base.html:146
 msgid "Products"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:149
+#: rhodecode/templates/base/base.html:152 rhodecode/templates/base/base.html:182
 msgid "loading..."
 msgstr ""
 
-#: rhodecode/templates/base/base.html:234 rhodecode/templates/base/base.html:236
-#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:158 rhodecode/templates/base/base.html:160
+#: rhodecode/templates/base/base.html:162
+#: rhodecode/templates/data_table/_dt_elements.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:17
+#: rhodecode/templates/data_table/_dt_elements.html:19
+msgid "Summary"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:166 rhodecode/templates/base/base.html:168
+#: rhodecode/templates/base/base.html:170
+#: rhodecode/templates/changelog/changelog.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:23
+#: rhodecode/templates/data_table/_dt_elements.html:25
+#: rhodecode/templates/data_table/_dt_elements.html:27
+msgid "Changelog"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:175 rhodecode/templates/base/base.html:177
+#: rhodecode/templates/base/base.html:179
 msgid "Switch to"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:242
-#: rhodecode/templates/branches/branches.html:13
-msgid "branches"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:249
-#: rhodecode/templates/branches/branches_data.html:52
-msgid "There are no branches yet"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:254
-#: rhodecode/templates/shortlog/shortlog_data.html:10
-#: rhodecode/templates/tags/tags.html:14
-msgid "tags"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:261
-#: rhodecode/templates/tags/tags_data.html:32
-msgid "There are no tags yet"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:277 rhodecode/templates/base/base.html:281
-#: rhodecode/templates/files/files_annotate.html:40
-#: rhodecode/templates/files/files_source.html:11
+#: rhodecode/templates/base/base.html:186 rhodecode/templates/base/base.html:188
+#: rhodecode/templates/base/base.html:190
+#: rhodecode/templates/data_table/_dt_elements.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:33
+#: rhodecode/templates/data_table/_dt_elements.html:35
+msgid "Files"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:195 rhodecode/templates/base/base.html:199
 msgid "Options"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:286 rhodecode/templates/base/base.html:288
-#: rhodecode/templates/base/base.html:306
+#: rhodecode/templates/base/base.html:204 rhodecode/templates/base/base.html:206
+#: rhodecode/templates/base/base.html:227
 msgid "settings"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:292
+#: rhodecode/templates/base/base.html:209
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/forks/fork.html:13
+msgid "fork"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:211
+#: rhodecode/templates/changelog/changelog.html:40
+msgid "Open new pull request"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:213
 msgid "search"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:299
-msgid "journal"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:301
+#: rhodecode/templates/base/base.html:222
 msgid "repositories groups"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:302
-msgid "users"
-msgstr ""
-
-#: rhodecode/templates/base/base.html:303
+#: rhodecode/templates/base/base.html:224
 msgid "users groups"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/base/base.html:225
 msgid "permissions"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:317 rhodecode/templates/base/base.html:319
-#: rhodecode/templates/followers/followers.html:5
+#: rhodecode/templates/base/base.html:238 rhodecode/templates/base/base.html:240
 msgid "Followers"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:325 rhodecode/templates/base/base.html:327
-#: rhodecode/templates/forks/forks.html:5
+#: rhodecode/templates/base/base.html:246 rhodecode/templates/base/base.html:248
 msgid "Forks"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:356 rhodecode/templates/base/base.html:358
-#: rhodecode/templates/base/base.html:360 rhodecode/templates/search/search.html:4
-#: rhodecode/templates/search/search.html:24
-#: rhodecode/templates/search/search.html:46
+#: rhodecode/templates/base/base.html:327 rhodecode/templates/base/base.html:329
+#: rhodecode/templates/base/base.html:331 rhodecode/templates/search/search.html:52
 msgid "Search"
 msgstr ""
 
-#: rhodecode/templates/base/root.html:57
-#: rhodecode/templates/journal/journal.html:48
-#: rhodecode/templates/summary/summary.html:36
+#: rhodecode/templates/base/root.html:42
+msgid "add another comment"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:43
+#: rhodecode/templates/journal/journal.html:120
+#: rhodecode/templates/summary/summary.html:57
 msgid "Stop following this repository"
 msgstr ""
 
-#: rhodecode/templates/base/root.html:66
-#: rhodecode/templates/summary/summary.html:40
+#: rhodecode/templates/base/root.html:44
+#: rhodecode/templates/summary/summary.html:61
 msgid "Start following this repository"
 msgstr ""
 
-#: rhodecode/templates/branches/branches_data.html:4
-#: rhodecode/templates/tags/tags_data.html:4
-msgid "date"
+#: rhodecode/templates/base/root.html:45
+msgid "Group"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:47
+msgid "search truncated"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:48
+msgid "no matching files"
+msgstr ""
+
+#: rhodecode/templates/bookmarks/bookmarks.html:5
+#, python-format
+msgid "%s Bookmarks"
+msgstr ""
+
+#: rhodecode/templates/bookmarks/bookmarks.html:39
+#: rhodecode/templates/bookmarks/bookmarks_data.html:8
+#: rhodecode/templates/branches/branches.html:54
+#: rhodecode/templates/tags/tags.html:39 rhodecode/templates/tags/tags_data.html:8
+msgid "Author"
+msgstr ""
+
+#: rhodecode/templates/branches/branches.html:5
+#, python-format
+msgid "%s Branches"
+msgstr ""
+
+#: rhodecode/templates/branches/branches.html:29
+msgid "Compare branches"
+msgstr ""
+
+#: rhodecode/templates/branches/branches.html:57
+#: rhodecode/templates/compare/compare_diff.html:5
+#: rhodecode/templates/compare/compare_diff.html:13
+msgid "Compare"
 msgstr ""
 
 #: rhodecode/templates/branches/branches_data.html:6
-#: rhodecode/templates/shortlog/shortlog_data.html:7
-#: rhodecode/templates/tags/tags_data.html:6
-msgid "author"
+msgid "name"
+msgstr ""
+
+#: rhodecode/templates/branches/branches_data.html:7
+msgid "date"
 msgstr ""
 
 #: rhodecode/templates/branches/branches_data.html:8
-#: rhodecode/templates/shortlog/shortlog_data.html:11
-#: rhodecode/templates/tags/tags_data.html:8
-msgid "links"
-msgstr ""
-
-#: rhodecode/templates/branches/branches_data.html:23
-#: rhodecode/templates/branches/branches_data.html:43
-#: rhodecode/templates/shortlog/shortlog_data.html:39
-#: rhodecode/templates/tags/tags_data.html:24
-msgid "changeset"
-msgstr ""
-
-#: rhodecode/templates/branches/branches_data.html:25
-#: rhodecode/templates/branches/branches_data.html:45
-#: rhodecode/templates/files/files.html:12
-#: rhodecode/templates/shortlog/shortlog_data.html:41
-#: rhodecode/templates/summary/summary.html:233
-#: rhodecode/templates/tags/tags_data.html:26
-msgid "files"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "showing "
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "out of"
+#: rhodecode/templates/shortlog/shortlog_data.html:8
+msgid "author"
+msgstr ""
+
+#: rhodecode/templates/branches/branches_data.html:9
+#: rhodecode/templates/shortlog/shortlog_data.html:5
+msgid "revision"
+msgstr ""
+
+#: rhodecode/templates/branches/branches_data.html:10
+msgid "compare"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:6
+#, python-format
+msgid "%s Changelog"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:15
+#, python-format
+msgid "showing %d out of %d revision"
+msgid_plural "showing %d out of %d revisions"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:19
+#, python-format
+msgid "compare fork with %s"
 msgstr ""
 
 #: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:21
+msgid "Compare fork"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:46
 msgid "Show"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:50
-#: rhodecode/templates/changeset/changeset.html:42
-#: rhodecode/templates/summary/summary.html:609
-msgid "commit"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:63
-msgid "Affected number of files, click to show more details"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:67
-#: rhodecode/templates/changeset/changeset.html:66
-msgid "merge"
-msgstr ""
-
 #: rhodecode/templates/changelog/changelog.html:72
-#: rhodecode/templates/changeset/changeset.html:72
+#: rhodecode/templates/summary/summary.html:364
+msgid "show more"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:76
+msgid "Affected number of files, click to show more details"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:89
+#: rhodecode/templates/changeset/changeset.html:38
+#: rhodecode/templates/changeset/changeset_file_comment.html:20
+#: rhodecode/templates/changeset/changeset_range.html:46
+msgid "Changeset status"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:92
+msgid "Click to open associated pull request"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:102
+#: rhodecode/templates/changeset/changeset.html:78
 msgid "Parent"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:77
-#: rhodecode/templates/changeset/changeset.html:77
+#: rhodecode/templates/changelog/changelog.html:108
+#: rhodecode/templates/changeset/changeset.html:84
 msgid "No parents"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:82
-#: rhodecode/templates/changeset/changeset.html:80
+#: rhodecode/templates/changelog/changelog.html:113
+#: rhodecode/templates/changeset/changeset.html:88
+msgid "merge"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:116
+#: rhodecode/templates/changeset/changeset.html:91
 #: rhodecode/templates/files/files.html:29
-#: rhodecode/templates/files/files_annotate.html:25
+#: rhodecode/templates/files/files_add.html:33
 #: rhodecode/templates/files/files_edit.html:33
 #: rhodecode/templates/shortlog/shortlog_data.html:9
 msgid "branch"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:86
-#: rhodecode/templates/changeset/changeset.html:83
+#: rhodecode/templates/changelog/changelog.html:122
+msgid "bookmark"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:128
+#: rhodecode/templates/changeset/changeset.html:96
 msgid "tag"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:122
+#: rhodecode/templates/changelog/changelog.html:164
 msgid "Show selected changes __S -> __E"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:172
-#: rhodecode/templates/shortlog/shortlog_data.html:61
+#: rhodecode/templates/changelog/changelog.html:255
 msgid "There are no changes yet"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog_details.html:2
-#: rhodecode/templates/changeset/changeset.html:55
-msgid "removed"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog_details.html:3
-#: rhodecode/templates/changeset/changeset.html:56
-msgid "changed"
-msgstr ""
-
 #: rhodecode/templates/changelog/changelog_details.html:4
-#: rhodecode/templates/changeset/changeset.html:57
-msgid "added"
+#: rhodecode/templates/changeset/changeset.html:66
+msgid "removed"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog_details.html:5
+#: rhodecode/templates/changeset/changeset.html:67
+msgid "changed"
 msgstr ""
 
 #: rhodecode/templates/changelog/changelog_details.html:6
-#: rhodecode/templates/changelog/changelog_details.html:7
+#: rhodecode/templates/changeset/changeset.html:68
+msgid "added"
+msgstr ""
+
 #: rhodecode/templates/changelog/changelog_details.html:8
-#: rhodecode/templates/changeset/changeset.html:59
-#: rhodecode/templates/changeset/changeset.html:60
-#: rhodecode/templates/changeset/changeset.html:61
+#: rhodecode/templates/changelog/changelog_details.html:9
+#: rhodecode/templates/changelog/changelog_details.html:10
+#: rhodecode/templates/changeset/changeset.html:70
+#: rhodecode/templates/changeset/changeset.html:71
+#: rhodecode/templates/changeset/changeset.html:72
 #, python-format
 msgid "affected %s files"
 msgstr ""
 
 #: rhodecode/templates/changeset/changeset.html:6
+#, python-format
+msgid "%s Changeset"
+msgstr ""
+
 #: rhodecode/templates/changeset/changeset.html:14
-#: rhodecode/templates/changeset/changeset.html:31
 msgid "Changeset"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:32
-#: rhodecode/templates/changeset/changeset.html:121
-#: rhodecode/templates/changeset/changeset_range.html:78
-#: rhodecode/templates/files/file_diff.html:32
-#: rhodecode/templates/files/file_diff.html:42
+#: rhodecode/templates/changeset/changeset.html:43
+#: rhodecode/templates/changeset/diff_block.html:20
 msgid "raw diff"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:34
-#: rhodecode/templates/changeset/changeset.html:123
-#: rhodecode/templates/changeset/changeset_range.html:80
-#: rhodecode/templates/files/file_diff.html:34
+#: rhodecode/templates/changeset/changeset.html:44
+#: rhodecode/templates/changeset/diff_block.html:21
 msgid "download diff"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:90
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
 #, python-format
-msgid "%s files affected with %s additions and %s deletions."
-msgstr ""
-
-#: rhodecode/templates/changeset/changeset.html:101
-msgid "Changeset was too big and was cut off..."
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "(%d inline)"
+msgid_plural "(%d inline)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/changeset/changeset.html:103
+#, python-format
+msgid "%s files affected with %s insertions and %s deletions:"
 msgstr ""
 
 #: rhodecode/templates/changeset/changeset.html:119
-#: rhodecode/templates/changeset/changeset_range.html:76
-#: rhodecode/templates/files/file_diff.html:30
+msgid "Changeset was too big and was cut off..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:42
+msgid "Submitting..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:45
+msgid "Commenting on line {1}."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:46
+#: rhodecode/templates/changeset/changeset_file_comment.html:121
+#, python-format
+msgid "Comments parsed using %s syntax with %s support."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:123
+msgid "Use @username inside this text to send notification to this RhodeCode user"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:59
+#: rhodecode/templates/changeset/changeset_file_comment.html:138
+msgid "Comment"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:60
+#: rhodecode/templates/changeset/changeset_file_comment.html:71
+msgid "Hide"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "You need to be logged in to comment."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "Login now"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:118
+msgid "Leave a comment"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "Check this to change current status of code-review for this changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "change status"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:140
+msgid "Comment and close"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:5
+#, python-format
+msgid "%s Changesets"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/templates/compare/compare_diff.html:29
+msgid "Compare View"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:54
+#: rhodecode/templates/compare/compare_diff.html:41
+#: rhodecode/templates/pullrequests/pullrequest_show.html:69
+msgid "Files affected"
+msgstr ""
+
+#: rhodecode/templates/changeset/diff_block.html:19
 msgid "diff"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:132
-#: rhodecode/templates/changeset/changeset_range.html:89
-msgid "No changes in this file"
-msgstr ""
-
-#: rhodecode/templates/changeset/changeset_range.html:30
-msgid "Compare View"
-msgstr ""
-
-#: rhodecode/templates/changeset/changeset_range.html:52
-msgid "Files affected"
-msgstr ""
-
-#: rhodecode/templates/errors/error_document.html:44
+#: rhodecode/templates/changeset/diff_block.html:27
+msgid "show inline comments"
+msgstr ""
+
+#: rhodecode/templates/compare/compare_cs.html:5
+msgid "No changesets"
+msgstr ""
+
+#: rhodecode/templates/compare/compare_diff.html:37
+msgid "Outgoing changesets"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:39
+#: rhodecode/templates/data_table/_dt_elements.html:41
+#: rhodecode/templates/data_table/_dt_elements.html:43
+msgid "Fork"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:60
+#: rhodecode/templates/journal/journal.html:126
+#: rhodecode/templates/summary/summary.html:68
+msgid "Mercurial repository"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:62
+#: rhodecode/templates/journal/journal.html:128
+#: rhodecode/templates/summary/summary.html:71
+msgid "Git repository"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:69
+#: rhodecode/templates/journal/journal.html:134
+#: rhodecode/templates/summary/summary.html:78
+msgid "public repository"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/summary/summary.html:87
+#: rhodecode/templates/summary/summary.html:88
+msgid "Fork of"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:92
+msgid "No changesets yet"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:104
+#, python-format
+msgid "Confirm to delete this user: %s"
+msgstr ""
+
+#: rhodecode/templates/email_templates/main.html:8
+msgid "This is an notification from RhodeCode."
+msgstr ""
+
+#: rhodecode/templates/errors/error_document.html:46
 #, python-format
 msgid "You will be redirected to %s in %s seconds"
 msgstr ""
 
 #: rhodecode/templates/files/file_diff.html:4
+#, python-format
+msgid "%s File diff"
+msgstr ""
+
 #: rhodecode/templates/files/file_diff.html:12
 msgid "File diff"
 msgstr ""
 
-#: rhodecode/templates/files/file_diff.html:42
-msgid "Diff is to big to display"
-msgstr ""
-
-#: rhodecode/templates/files/files.html:37
-#: rhodecode/templates/files/files_annotate.html:31
+#: rhodecode/templates/files/files.html:4 rhodecode/templates/files/files.html:72
+#, python-format
+msgid "%s files"
+msgstr ""
+
+#: rhodecode/templates/files/files.html:12
+#: rhodecode/templates/summary/summary.html:340
+msgid "files"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:4
+#: rhodecode/templates/files/files_edit.html:4
+#, python-format
+msgid "%s Edit file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:19
+msgid "add file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:40
+msgid "Add new file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:45
+msgid "File Name"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:58
+msgid "or"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:54
+msgid "Upload file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:58
+msgid "Create new file"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:63
 #: rhodecode/templates/files/files_edit.html:39
+#: rhodecode/templates/files/files_ypjax.html:3
 msgid "Location"
 msgstr ""
 
-#: rhodecode/templates/files/files.html:46
-msgid "Go back"
-msgstr ""
-
-#: rhodecode/templates/files/files.html:47
-msgid "No files at given path"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:4
-msgid "File annotate"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:12
-msgid "annotate"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:33
-#: rhodecode/templates/files/files_browser.html:160
-#: rhodecode/templates/files/files_source.html:2
-msgid "Revision"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:36
-#: rhodecode/templates/files/files_browser.html:158
-#: rhodecode/templates/files/files_source.html:7
-msgid "Size"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:38
-#: rhodecode/templates/files/files_browser.html:159
-#: rhodecode/templates/files/files_source.html:9
-msgid "Mimetype"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:41
-msgid "show source"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:43
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:14
-#: rhodecode/templates/files/files_source.html:51
-msgid "show as raw"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:45
-#: rhodecode/templates/files/files_source.html:16
-msgid "download as raw"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:54
-#: rhodecode/templates/files/files_source.html:25
-msgid "History"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:73
-#: rhodecode/templates/files/files_source.html:46
-#, python-format
-msgid "Binary file (%s)"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:51
-msgid "File is too big to display"
+#: rhodecode/templates/files/files_add.html:67
+msgid "use / to separate directories"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:77
+#: rhodecode/templates/files/files_edit.html:63
+#: rhodecode/templates/shortlog/shortlog_data.html:6
+msgid "commit message"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:81
+#: rhodecode/templates/files/files_edit.html:67
+msgid "Commit changes"
 msgstr ""
 
 #: rhodecode/templates/files/files_browser.html:13
@@ -2256,57 +3277,160 @@
 msgid "search file list"
 msgstr ""
 
-#: rhodecode/templates/files/files_browser.html:32
+#: rhodecode/templates/files/files_browser.html:31
+#: rhodecode/templates/shortlog/shortlog_data.html:65
+msgid "add new file"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:35
 msgid "Loading file list..."
 msgstr ""
 
-#: rhodecode/templates/files/files_browser.html:111
-msgid "search truncated"
-msgstr ""
-
-#: rhodecode/templates/files/files_browser.html:122
-msgid "no matching files"
-msgstr ""
-
-#: rhodecode/templates/files/files_browser.html:161
+#: rhodecode/templates/files/files_browser.html:48
+msgid "Size"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:49
+msgid "Mimetype"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:50
+msgid "Last Revision"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:51
 msgid "Last modified"
 msgstr ""
 
-#: rhodecode/templates/files/files_browser.html:162
+#: rhodecode/templates/files/files_browser.html:52
 msgid "Last commiter"
 msgstr ""
 
-#: rhodecode/templates/files/files_edit.html:4
-msgid "Edit file"
-msgstr ""
-
 #: rhodecode/templates/files/files_edit.html:19
 msgid "edit file"
 msgstr ""
 
-#: rhodecode/templates/files/files_edit.html:45
-#: rhodecode/templates/shortlog/shortlog_data.html:5
-msgid "commit message"
+#: rhodecode/templates/files/files_edit.html:49
+#: rhodecode/templates/files/files_source.html:38
+msgid "show annotation"
+msgstr ""
+
+#: rhodecode/templates/files/files_edit.html:50
+#: rhodecode/templates/files/files_source.html:40
+#: rhodecode/templates/files/files_source.html:68
+msgid "show as raw"
 msgstr ""
 
 #: rhodecode/templates/files/files_edit.html:51
-msgid "Commit changes"
-msgstr ""
-
-#: rhodecode/templates/files/files_source.html:12
-msgid "show annotation"
-msgstr ""
-
-#: rhodecode/templates/files/files_source.html:153
+#: rhodecode/templates/files/files_source.html:41
+msgid "download as raw"
+msgstr ""
+
+#: rhodecode/templates/files/files_edit.html:54
+msgid "source"
+msgstr ""
+
+#: rhodecode/templates/files/files_edit.html:59
+msgid "Editing file"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:2
+msgid "History"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:9
+msgid "diff to revision"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:10
+msgid "show at revision"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:14
+#, python-format
+msgid "%s author"
+msgid_plural "%s authors"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/files/files_source.html:36
+msgid "show source"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:59
+#, python-format
+msgid "Binary file (%s)"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:68
+msgid "File is too big to display"
+msgstr ""
+
+#: rhodecode/templates/files/files_source.html:124
 msgid "Selection link"
 msgstr ""
 
+#: rhodecode/templates/files/files_ypjax.html:5
+msgid "annotation"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:15
+msgid "Go back"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:16
+msgid "No files at given path"
+msgstr ""
+
+#: rhodecode/templates/followers/followers.html:5
+#, python-format
+msgid "%s Followers"
+msgstr ""
+
 #: rhodecode/templates/followers/followers.html:13
 msgid "followers"
 msgstr ""
 
 #: rhodecode/templates/followers/followers_data.html:12
-msgid "Started following"
+msgid "Started following -"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:5
+#, python-format
+msgid "%s Fork"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:31
+msgid "Fork name"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:68
+msgid "Private"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:77
+msgid "Copy permissions"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:81
+msgid "Copy permissions from forked repository"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:86
+msgid "Update after clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:90
+msgid "Checkout source after making a clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:94
+msgid "fork this repository"
+msgstr ""
+
+#: rhodecode/templates/forks/forks.html:5
+#, python-format
+msgid "%s Forks"
 msgstr ""
 
 #: rhodecode/templates/forks/forks.html:13
@@ -2317,184 +3441,395 @@
 msgid "forked"
 msgstr ""
 
-#: rhodecode/templates/forks/forks_data.html:34
+#: rhodecode/templates/forks/forks_data.html:38
 msgid "There are no forks yet"
 msgstr ""
 
-#: rhodecode/templates/journal/journal.html:34
-msgid "Following"
-msgstr ""
-
-#: rhodecode/templates/journal/journal.html:41
-msgid "following user"
+#: rhodecode/templates/journal/journal.html:13
+msgid "ATOM journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:14
+msgid "RSS journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:24
+#: rhodecode/templates/pullrequests/pullrequest.html:27
+msgid "Refresh"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:27
+#: rhodecode/templates/journal/public_journal.html:24
+msgid "RSS feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:30
+#: rhodecode/templates/journal/public_journal.html:27
+msgid "ATOM feed"
 msgstr ""
 
 #: rhodecode/templates/journal/journal.html:41
+msgid "Watched"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:46
+msgid "ADD"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "following user"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:114
 msgid "user"
 msgstr ""
 
-#: rhodecode/templates/journal/journal.html:65
+#: rhodecode/templates/journal/journal.html:147
 msgid "You are not following any users or repositories"
 msgstr ""
 
-#: rhodecode/templates/journal/journal_data.html:46
+#: rhodecode/templates/journal/journal_data.html:47
 msgid "No entries yet"
 msgstr ""
 
-#: rhodecode/templates/journal/public_journal.html:17
+#: rhodecode/templates/journal/public_journal.html:13
+msgid "ATOM public journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/public_journal.html:14
+msgid "RSS public journal feed"
+msgstr ""
+
+#: rhodecode/templates/journal/public_journal.html:21
 msgid "Public Journal"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:7
-#: rhodecode/templates/search/search.html:26
-msgid "in repository: "
-msgstr ""
-
-#: rhodecode/templates/search/search.html:9
-#: rhodecode/templates/search/search.html:28
-msgid "in all repositories"
-msgstr ""
-
-#: rhodecode/templates/search/search.html:42
+#: rhodecode/templates/pullrequests/pullrequest.html:4
+#: rhodecode/templates/pullrequests/pullrequest.html:12
+msgid "New pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:28
+msgid "refresh overview"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:66
+msgid "Detailed compare view"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:70
+#: rhodecode/templates/pullrequests/pullrequest_show.html:82
+msgid "Pull request reviewers"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:79
+#: rhodecode/templates/pullrequests/pullrequest_show.html:94
+msgid "owner"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:91
+#: rhodecode/templates/pullrequests/pullrequest_show.html:109
+msgid "Add reviewer to this pull request."
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:97
+msgid "Create new pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:106
+#: rhodecode/templates/pullrequests/pullrequest_show.html:25
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:33
+msgid "Title"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:115
+msgid "description"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:123
+msgid "Send pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:23
+#, python-format
+msgid "Closed %s"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:31
+msgid "Status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:36
+msgid "Pull request status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:44
+msgid "Still not reviewed by"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:47
+#, python-format
+msgid "%d reviewer"
+msgid_plural "%d reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:54
+msgid "Created on"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:61
+msgid "Compare view"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:65
+msgid "Incoming changesets"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4
+msgid "all pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:12
+msgid "All pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:27
+msgid "Closed"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:6
+#, python-format
+msgid "Search \"%s\" in repository: %s"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:8
+#, python-format
+msgid "Search \"%s\" in all repositories"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:12
+#: rhodecode/templates/search/search.html:32
+#, python-format
+msgid "Search in repository: %s"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:14
+#: rhodecode/templates/search/search.html:34
+msgid "Search in all repositories"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:48
 msgid "Search term"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:54
+#: rhodecode/templates/search/search.html:60
 msgid "Search in"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:57
+#: rhodecode/templates/search/search.html:63
 msgid "File contents"
 msgstr ""
 
-#: rhodecode/templates/search/search.html:59
+#: rhodecode/templates/search/search.html:64
+msgid "Commit messages"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:65
 msgid "File names"
 msgstr ""
 
-#: rhodecode/templates/search/search_content.html:20
+#: rhodecode/templates/search/search_commit.html:35
+#: rhodecode/templates/search/search_content.html:21
 #: rhodecode/templates/search/search_path.html:15
 msgid "Permission denied"
 msgstr ""
 
-#: rhodecode/templates/settings/repo_fork.html:5
-msgid "Fork"
-msgstr ""
-
-#: rhodecode/templates/settings/repo_fork.html:31
-msgid "Fork name"
-msgstr ""
-
-#: rhodecode/templates/settings/repo_fork.html:55
-msgid "fork this repository"
+#: rhodecode/templates/settings/repo_settings.html:5
+#, python-format
+msgid "%s Settings"
 msgstr ""
 
 #: rhodecode/templates/shortlog/shortlog.html:5
-#: rhodecode/templates/summary/summary.html:666
-msgid "Shortlog"
+#, python-format
+msgid "%s Shortlog"
 msgstr ""
 
 #: rhodecode/templates/shortlog/shortlog.html:14
 msgid "shortlog"
 msgstr ""
 
-#: rhodecode/templates/shortlog/shortlog_data.html:6
+#: rhodecode/templates/shortlog/shortlog_data.html:7
 msgid "age"
 msgstr ""
 
+#: rhodecode/templates/shortlog/shortlog_data.html:18
+msgid "No commit message"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:62
+msgid "Add or upload files directly via RhodeCode"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:71
+msgid "Push new repo"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:79
+msgid "Existing repository?"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:4
+#, python-format
+msgid "%s Summary"
+msgstr ""
+
 #: rhodecode/templates/summary/summary.html:12
 msgid "summary"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:79
+#: rhodecode/templates/summary/summary.html:20
+#, python-format
+msgid "repo %s ATOM feed"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:21
+#, python-format
+msgid "repo %s RSS feed"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:49
+#: rhodecode/templates/summary/summary.html:52
+msgid "ATOM"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:82
+#, python-format
+msgid "Non changable ID %s"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:87
+msgid "public"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:95
 msgid "remote clone"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:121
-msgid "by"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:128
+#: rhodecode/templates/summary/summary.html:116
+msgid "Contact"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:130
 msgid "Clone url"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:137
-msgid "Trending source files"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:146
-msgid "Download"
+#: rhodecode/templates/summary/summary.html:133
+msgid "Show by Name"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:134
+msgid "Show by ID"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:142
+msgid "Trending files"
 msgstr ""
 
 #: rhodecode/templates/summary/summary.html:150
-msgid "There are no downloads yet"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:152
-msgid "Downloads are disabled for this repository"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:154
-#: rhodecode/templates/summary/summary.html:320
+#: rhodecode/templates/summary/summary.html:166
+#: rhodecode/templates/summary/summary.html:194
 msgid "enable"
 msgstr ""
 
+#: rhodecode/templates/summary/summary.html:158
+msgid "Download"
+msgstr ""
+
 #: rhodecode/templates/summary/summary.html:162
-#: rhodecode/templates/summary/summary.html:297
+msgid "There are no downloads yet"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:164
+msgid "Downloads are disabled for this repository"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:170
+msgid "Download as zip"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "Check this to download archive with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:186
+msgid "Commit activity by day / author"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:197
+msgid "Stats gathered: "
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:218
+msgid "Shortlog"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:220
+msgid "Quick start"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:233
+#, python-format
+msgid "Readme file at revision '%s'"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:236
+msgid "Permalink to this readme"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:293
 #, python-format
 msgid "Download %s as %s"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:168
-msgid "Check this to download archive with subrepos"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:168
-msgid "with subrepos"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:176
-msgid "Feeds"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:257
-#: rhodecode/templates/summary/summary.html:684
-#: rhodecode/templates/summary/summary.html:695
-msgid "show more"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:312
-msgid "Commit activity by day / author"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:324
-msgid "Loaded in"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:603
+#: rhodecode/templates/summary/summary.html:650
 msgid "commits"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:604
+#: rhodecode/templates/summary/summary.html:651
 msgid "files added"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:605
+#: rhodecode/templates/summary/summary.html:652
 msgid "files changed"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:606
+#: rhodecode/templates/summary/summary.html:653
 msgid "files removed"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:610
+#: rhodecode/templates/summary/summary.html:656
+msgid "commit"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:657
 msgid "file added"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:611
+#: rhodecode/templates/summary/summary.html:658
 msgid "file changed"
 msgstr ""
 
-#: rhodecode/templates/summary/summary.html:612
+#: rhodecode/templates/summary/summary.html:659
 msgid "file removed"
 msgstr ""
 
+#: rhodecode/templates/tags/tags.html:5
+#, python-format
+msgid "%s Tags"
+msgstr ""
+
Binary file rhodecode/i18n/zh_CN/LC_MESSAGES/rhodecode.mo has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/i18n/zh_CN/LC_MESSAGES/rhodecode.po	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,4022 @@
+# Chinese (China) translations for RhodeCode.
+# Copyright (C) 2011 ORGANIZATION
+# This file is distributed under the same license as the RhodeCode project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
+# mikespook <mikespook@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: RhodeCode 1.2.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-02 20:30+0200\n"
+"PO-Revision-Date: 2012-04-05 17:37+0800\n"
+"Last-Translator: mikespook <mikespook@gmail.com>\n"
+"Language-Team: mikespook\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: rhodecode/controllers/changelog.py:94
+#, fuzzy
+msgid "All Branches"
+msgstr "分支"
+
+#: rhodecode/controllers/changeset.py:83
+msgid "show white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:90 rhodecode/controllers/changeset.py:97
+msgid "ignore white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:157
+#, fuzzy, python-format
+msgid "%s line context"
+msgstr "文件内容"
+
+#: rhodecode/controllers/changeset.py:333
+#: rhodecode/controllers/changeset.py:348 rhodecode/lib/diffs.py:70
+msgid "binary file"
+msgstr "二进制文件"
+
+#: rhodecode/controllers/changeset.py:408
+msgid ""
+"Changing status on a changeset associated witha closed pull request is "
+"not allowed"
+msgstr ""
+
+#: rhodecode/controllers/compare.py:69
+#, fuzzy
+msgid "There are no changesets yet"
+msgstr "没有任何变更"
+
+#: rhodecode/controllers/error.py:69
+msgid "Home page"
+msgstr "主页"
+
+#: rhodecode/controllers/error.py:98
+msgid "The request could not be understood by the server due to malformed syntax."
+msgstr "由于错误的语法,服务器无法对请求进行响应。"
+
+#: rhodecode/controllers/error.py:101
+msgid "Unauthorized access to resource"
+msgstr "未授权的资源访问"
+
+#: rhodecode/controllers/error.py:103
+msgid "You don't have permission to view this page"
+msgstr "无权访问该页面"
+
+#: rhodecode/controllers/error.py:105
+msgid "The resource could not be found"
+msgstr "资源未找到"
+
+#: rhodecode/controllers/error.py:107
+msgid ""
+"The server encountered an unexpected condition which prevented it from "
+"fulfilling the request."
+msgstr "服务进入非预期的混乱状态,这会阻止它对请求进行响应。"
+
+#: rhodecode/controllers/feed.py:49
+#, python-format
+msgid "Changes on %s repository"
+msgstr "%s 库的修改"
+
+#: rhodecode/controllers/feed.py:50
+#, python-format
+msgid "%s %s feed"
+msgstr "%s %s 订阅"
+
+#: rhodecode/controllers/feed.py:75
+#, fuzzy
+msgid "commited on"
+msgstr "提交"
+
+#: rhodecode/controllers/files.py:84
+#, fuzzy
+msgid "click here to add new file"
+msgstr "添加新用户"
+
+#: rhodecode/controllers/files.py:85
+#, fuzzy, python-format
+msgid "There are no files yet %s"
+msgstr "尚无文件"
+
+#: rhodecode/controllers/files.py:239 rhodecode/controllers/files.py:299
+#, python-format
+msgid "This repository is has been locked by %s on %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:266
+#, python-format
+msgid "Edited %s via RhodeCode"
+msgstr "通过 RhodeCode 修改了 %s"
+
+#: rhodecode/controllers/files.py:271
+msgid "No changes"
+msgstr "无变更"
+
+#: rhodecode/controllers/files.py:282 rhodecode/controllers/files.py:346
+#, python-format
+msgid "Successfully committed to %s"
+msgstr "成功提交到 %s"
+
+#: rhodecode/controllers/files.py:287 rhodecode/controllers/files.py:352
+msgid "Error occurred during commit"
+msgstr "提交时发生错误"
+
+#: rhodecode/controllers/files.py:318
+#, fuzzy, python-format
+msgid "Added %s via RhodeCode"
+msgstr "通过 RhodeCode 修改了 %s"
+
+#: rhodecode/controllers/files.py:332
+#, fuzzy
+msgid "No content"
+msgstr "文件内容"
+
+#: rhodecode/controllers/files.py:336
+#, fuzzy
+msgid "No filename"
+msgstr "文件名"
+
+#: rhodecode/controllers/files.py:378
+msgid "downloads disabled"
+msgstr "禁止下载"
+
+#: rhodecode/controllers/files.py:389
+#, python-format
+msgid "Unknown revision %s"
+msgstr "未知版本 %s"
+
+#: rhodecode/controllers/files.py:391
+msgid "Empty repository"
+msgstr "空版本库"
+
+#: rhodecode/controllers/files.py:393
+msgid "Unknown archive type"
+msgstr "未知包类型"
+
+#: rhodecode/controllers/files.py:494
+#: rhodecode/templates/changeset/changeset_range.html:13
+#: rhodecode/templates/changeset/changeset_range.html:31
+msgid "Changesets"
+msgstr "变更集"
+
+#: rhodecode/controllers/files.py:495 rhodecode/controllers/pullrequests.py:72
+#: rhodecode/controllers/summary.py:232 rhodecode/model/scm.py:543
+msgid "Branches"
+msgstr "分支"
+
+#: rhodecode/controllers/files.py:496 rhodecode/controllers/pullrequests.py:76
+#: rhodecode/controllers/summary.py:233 rhodecode/model/scm.py:554
+msgid "Tags"
+msgstr "标签"
+
+#: rhodecode/controllers/forks.py:73 rhodecode/controllers/admin/repos.py:90
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:133 rhodecode/controllers/settings.py:72
+#, python-format
+msgid ""
+"%s repository is not mapped to db perhaps it was created or renamed from "
+"the file system please run the application again in order to rescan "
+"repositories"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:167
+#, python-format
+msgid "forked %s repository as %s"
+msgstr "版本库 %s 被分支到 %s"
+
+#: rhodecode/controllers/forks.py:181
+#, python-format
+msgid "An error occurred during repository forking %s"
+msgstr ""
+
+#: rhodecode/controllers/journal.py:202 rhodecode/controllers/journal.py:239
+#, fuzzy
+msgid "public journal"
+msgstr "公共日志"
+
+#: rhodecode/controllers/journal.py:206 rhodecode/controllers/journal.py:243
+#: rhodecode/templates/base/base.html:220
+msgid "journal"
+msgstr "日志"
+
+#: rhodecode/controllers/login.py:143
+msgid "You have successfully registered into rhodecode"
+msgstr "成功注册到 rhodecode"
+
+#: rhodecode/controllers/login.py:164
+msgid "Your password reset link was sent"
+msgstr "密码重置链接已经发送"
+
+#: rhodecode/controllers/login.py:184
+msgid ""
+"Your password reset was successful, new password has been sent to your "
+"email"
+msgstr "密码已经成功重置,新密码已经发送到你的邮箱"
+
+#: rhodecode/controllers/pullrequests.py:74 rhodecode/model/scm.py:549
+msgid "Bookmarks"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:158
+msgid "Pull request requires a title with min. 3 chars"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:160
+#, fuzzy
+msgid "error during creation of pull request"
+msgstr "提交时发生错误"
+
+#: rhodecode/controllers/pullrequests.py:181
+#, fuzzy
+msgid "Successfully opened new pull request"
+msgstr "用户删除成功"
+
+#: rhodecode/controllers/pullrequests.py:184
+#, fuzzy
+msgid "Error occurred during sending pull request"
+msgstr "提交时发生错误"
+
+#: rhodecode/controllers/pullrequests.py:217
+#, fuzzy
+msgid "Successfully deleted pull request"
+msgstr "用户删除成功"
+
+#: rhodecode/controllers/search.py:131
+msgid "Invalid search query. Try quoting it."
+msgstr "错误的搜索。请尝试用引号包含它。"
+
+#: rhodecode/controllers/search.py:136
+msgid "There is no index to search in. Please run whoosh indexer"
+msgstr "没有索引用于搜索。请运行 whoosh 索引器"
+
+#: rhodecode/controllers/search.py:140
+msgid "An error occurred during this search operation"
+msgstr "在搜索操作中发生异常"
+
+#: rhodecode/controllers/settings.py:107
+#: rhodecode/controllers/admin/repos.py:266
+#, python-format
+msgid "Repository %s updated successfully"
+msgstr "版本库 %s 成功更新"
+
+#: rhodecode/controllers/settings.py:125
+#: rhodecode/controllers/admin/repos.py:284
+#, python-format
+msgid "error occurred during update of repository %s"
+msgstr ""
+
+#: rhodecode/controllers/settings.py:143
+#: rhodecode/controllers/admin/repos.py:302
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+
+#: rhodecode/controllers/settings.py:155
+#: rhodecode/controllers/admin/repos.py:314
+#, python-format
+msgid "deleted repository %s"
+msgstr "已经删除版本库 %s"
+
+#: rhodecode/controllers/settings.py:159
+#: rhodecode/controllers/admin/repos.py:324
+#: rhodecode/controllers/admin/repos.py:330
+#, python-format
+msgid "An error occurred during deletion of %s"
+msgstr ""
+
+#: rhodecode/controllers/summary.py:138
+msgid "No data loaded yet"
+msgstr ""
+
+#: rhodecode/controllers/summary.py:142
+#: rhodecode/templates/summary/summary.html:148
+msgid "Statistics are disabled for this repository"
+msgstr "该版本库统计功能已经禁用"
+
+#: rhodecode/controllers/admin/ldap_settings.py:50
+msgid "BASE"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:51
+msgid "ONELEVEL"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:52
+msgid "SUBTREE"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:56
+msgid "NEVER"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:57
+msgid "ALLOW"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:58
+msgid "TRY"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:59
+msgid "DEMAND"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:60
+msgid "HARD"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:64
+msgid "No encryption"
+msgstr "未加密"
+
+#: rhodecode/controllers/admin/ldap_settings.py:65
+msgid "LDAPS connection"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:66
+msgid "START_TLS on LDAP connection"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:126
+msgid "Ldap settings updated successfully"
+msgstr "LDAP 设置已经成功更新"
+
+#: rhodecode/controllers/admin/ldap_settings.py:130
+msgid "Unable to activate ldap. The \"python-ldap\" library is missing."
+msgstr "无法启用 LDAP。库“python-ldap”缺失。"
+
+#: rhodecode/controllers/admin/ldap_settings.py:147
+msgid "error occurred during update of ldap settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/permissions.py:59
+msgid "None"
+msgstr "无"
+
+#: rhodecode/controllers/admin/permissions.py:60
+msgid "Read"
+msgstr "读"
+
+#: rhodecode/controllers/admin/permissions.py:61
+msgid "Write"
+msgstr "写"
+
+#: rhodecode/controllers/admin/permissions.py:62
+#: rhodecode/templates/admin/ldap/ldap.html:9
+#: rhodecode/templates/admin/permissions/permissions.html:9
+#: rhodecode/templates/admin/repos/repo_add.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:9
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:8
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:8
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
+#: rhodecode/templates/admin/settings/hooks.html:9
+#: rhodecode/templates/admin/settings/settings.html:9
+#: rhodecode/templates/admin/users/user_add.html:8
+#: rhodecode/templates/admin/users/user_edit.html:9
+#: rhodecode/templates/admin/users/user_edit.html:122
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/admin/users_groups/users_group_add.html:8
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:9
+#: rhodecode/templates/admin/users_groups/users_groups.html:9
+#: rhodecode/templates/base/base.html:197
+#: rhodecode/templates/base/base.html:337
+#: rhodecode/templates/base/base.html:339
+#: rhodecode/templates/base/base.html:341
+msgid "Admin"
+msgstr "管理"
+
+#: rhodecode/controllers/admin/permissions.py:65
+msgid "disabled"
+msgstr "禁用"
+
+#: rhodecode/controllers/admin/permissions.py:67
+msgid "allowed with manual account activation"
+msgstr "允许手工启用帐号"
+
+#: rhodecode/controllers/admin/permissions.py:69
+msgid "allowed with automatic account activation"
+msgstr "允许自动启用帐号"
+
+#: rhodecode/controllers/admin/permissions.py:71
+#: rhodecode/controllers/admin/permissions.py:74
+msgid "Disabled"
+msgstr "停用"
+
+#: rhodecode/controllers/admin/permissions.py:72
+#: rhodecode/controllers/admin/permissions.py:75
+msgid "Enabled"
+msgstr "启用"
+
+#: rhodecode/controllers/admin/permissions.py:116
+msgid "Default permissions updated successfully"
+msgstr "成功更新默认权限"
+
+#: rhodecode/controllers/admin/permissions.py:130
+msgid "error occurred during update of permissions"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:123
+msgid "--REMOVE FORK--"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:192
+#, python-format
+msgid "created repository %s from %s"
+msgstr "新版本库 %s 基于 %s 建立。"
+
+#: rhodecode/controllers/admin/repos.py:196
+#, python-format
+msgid "created repository %s"
+msgstr "建立版本库 %s"
+
+#: rhodecode/controllers/admin/repos.py:227
+#, python-format
+msgid "error occurred during creation of repository %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:319
+#, python-format
+msgid "Cannot delete %s it still contains attached forks"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:348
+msgid "An error occurred during deletion of repository user"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:367
+msgid "An error occurred during deletion of repository users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:385
+msgid "An error occurred during deletion of repository stats"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:402
+msgid "An error occurred during cache invalidation"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:422
+#, fuzzy
+msgid "An error occurred during unlocking"
+msgstr "在搜索操作中发生异常"
+
+#: rhodecode/controllers/admin/repos.py:442
+msgid "Updated repository visibility in public journal"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:446
+msgid "An error occurred during setting this repository in public journal"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:451 rhodecode/model/validators.py:299
+msgid "Token mismatch"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:464
+msgid "Pulled from remote location"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:466
+msgid "An error occurred during pull from remote location"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:482
+msgid "Nothing"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:484
+#, fuzzy, python-format
+msgid "Marked repo %s as fork of %s"
+msgstr "新版本库 %s 基于 %s 建立。"
+
+#: rhodecode/controllers/admin/repos.py:488
+#, fuzzy
+msgid "An error occurred during this operation"
+msgstr "在搜索操作中发生异常"
+
+#: rhodecode/controllers/admin/repos_groups.py:116
+#, python-format
+msgid "created repos group %s"
+msgstr "建立版本库组 %s"
+
+#: rhodecode/controllers/admin/repos_groups.py:129
+#, python-format
+msgid "error occurred during creation of repos group %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:163
+#, python-format
+msgid "updated repos group %s"
+msgstr "更新版本库组 %s"
+
+#: rhodecode/controllers/admin/repos_groups.py:176
+#, python-format
+msgid "error occurred during update of repos group %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:194
+#, python-format
+msgid "This group contains %s repositores and cannot be deleted"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:202
+#, python-format
+msgid "removed repos group %s"
+msgstr "移除版本库组 %s"
+
+#: rhodecode/controllers/admin/repos_groups.py:208
+msgid "Cannot delete this group it still contains subgroups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:213
+#: rhodecode/controllers/admin/repos_groups.py:218
+#, python-format
+msgid "error occurred during deletion of repos group %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:238
+#, fuzzy
+msgid "An error occurred during deletion of group user"
+msgstr "在搜索操作中发生异常"
+
+#: rhodecode/controllers/admin/repos_groups.py:258
+msgid "An error occurred during deletion of group users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:121
+#, python-format
+msgid "Repositories successfully rescanned added: %s,removed: %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:129
+msgid "Whoosh reindex task scheduled"
+msgstr "Whoosh 重新索引任务调度"
+
+#: rhodecode/controllers/admin/settings.py:160
+msgid "Updated application settings"
+msgstr "更新应用设置"
+
+#: rhodecode/controllers/admin/settings.py:164
+#: rhodecode/controllers/admin/settings.py:275
+msgid "error occurred during updating application settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:200
+#, fuzzy
+msgid "Updated visualisation settings"
+msgstr "更新应用设置"
+
+#: rhodecode/controllers/admin/settings.py:205
+#, fuzzy
+msgid "error occurred during updating visualisation settings"
+msgstr "提交时发生错误"
+
+#: rhodecode/controllers/admin/settings.py:271
+#, fuzzy
+msgid "Updated VCS settings"
+msgstr "更新 mercurial 设置"
+
+#: rhodecode/controllers/admin/settings.py:285
+msgid "Added new hook"
+msgstr "新增钩子"
+
+#: rhodecode/controllers/admin/settings.py:297
+msgid "Updated hooks"
+msgstr "更新钩子"
+
+#: rhodecode/controllers/admin/settings.py:301
+msgid "error occurred during hook creation"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:320
+msgid "Email task created"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:375
+msgid "You can't edit this user since it's crucial for entire application"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:406
+msgid "Your account was updated successfully"
+msgstr "你的帐号已经更新完成"
+
+#: rhodecode/controllers/admin/settings.py:421
+#: rhodecode/controllers/admin/users.py:191
+#, python-format
+msgid "error occurred during update of user %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:130
+#, python-format
+msgid "created user %s"
+msgstr "创建用户 %s"
+
+#: rhodecode/controllers/admin/users.py:142
+#, python-format
+msgid "error occurred during creation of user %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:171
+msgid "User updated successfully"
+msgstr "用户更新成功"
+
+#: rhodecode/controllers/admin/users.py:207
+msgid "successfully deleted user"
+msgstr "用户删除成功"
+
+#: rhodecode/controllers/admin/users.py:212
+msgid "An error occurred during deletion of user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:226
+msgid "You can't edit this user"
+msgstr "无法编辑该用户"
+
+#: rhodecode/controllers/admin/users.py:266
+msgid "Granted 'repository create' permission to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:271
+msgid "Revoked 'repository create' permission to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:277
+#, fuzzy
+msgid "Granted 'repository fork' permission to user"
+msgstr "版本库权限"
+
+#: rhodecode/controllers/admin/users.py:282
+#, fuzzy
+msgid "Revoked 'repository fork' permission to user"
+msgstr "版本库权限"
+
+#: rhodecode/controllers/admin/users.py:288
+#: rhodecode/controllers/admin/users_groups.py:255
+#, fuzzy
+msgid "An error occurred during permissions saving"
+msgstr "在搜索操作中发生异常"
+
+#: rhodecode/controllers/admin/users.py:303
+#, python-format
+msgid "Added email %s to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:309
+#, fuzzy
+msgid "An error occurred during email saving"
+msgstr "在搜索操作中发生异常"
+
+#: rhodecode/controllers/admin/users.py:319
+#, fuzzy
+msgid "Removed email from user"
+msgstr "移除版本库组 %s"
+
+#: rhodecode/controllers/admin/users_groups.py:84
+#, python-format
+msgid "created users group %s"
+msgstr "建立用户组 %s"
+
+#: rhodecode/controllers/admin/users_groups.py:95
+#, python-format
+msgid "error occurred during creation of users group %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:135
+#, python-format
+msgid "updated users group %s"
+msgstr "更新用户组 %s"
+
+#: rhodecode/controllers/admin/users_groups.py:157
+#, python-format
+msgid "error occurred during update of users group %s"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:174
+msgid "successfully deleted users group"
+msgstr "删除用户组成功"
+
+#: rhodecode/controllers/admin/users_groups.py:179
+msgid "An error occurred during deletion of users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:233
+msgid "Granted 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:238
+msgid "Revoked 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:244
+msgid "Granted 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:249
+msgid "Revoked 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/lib/auth.py:499
+msgid "You need to be a registered user to perform this action"
+msgstr "必须是注册用户才能进行此操作"
+
+#: rhodecode/lib/auth.py:540
+msgid "You need to be a signed in to view this page"
+msgstr "必须登录才能访问该页面"
+
+#: rhodecode/lib/diffs.py:86
+msgid "Changeset was too big and was cut off, use diff menu to display this diff"
+msgstr "变更集因过大而被截断,可查看原始变更集作为替代"
+
+#: rhodecode/lib/diffs.py:96
+#, fuzzy
+msgid "No changes detected"
+msgstr "尚无修订"
+
+#: rhodecode/lib/helpers.py:372
+#, python-format
+msgid "%a, %d %b %Y %H:%M:%S"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:484
+msgid "True"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:488
+msgid "False"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:532
+#, fuzzy
+msgid "Changeset not found"
+msgstr "修改"
+
+#: rhodecode/lib/helpers.py:555
+#, python-format
+msgid "Show all combined changesets %s->%s"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:561
+msgid "compare view"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:581
+msgid "and"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:582
+#, python-format
+msgid "%s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:583 rhodecode/templates/changelog/changelog.html:48
+msgid "revisions"
+msgstr "修订"
+
+#: rhodecode/lib/helpers.py:606
+msgid "fork name "
+msgstr "分支名称"
+
+#: rhodecode/lib/helpers.py:620
+#: rhodecode/templates/pullrequests/pullrequest_show.html:4
+#: rhodecode/templates/pullrequests/pullrequest_show.html:12
+#, python-format
+msgid "Pull request #%s"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:626
+msgid "[deleted] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:628 rhodecode/lib/helpers.py:638
+msgid "[created] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:630
+#, fuzzy
+msgid "[created] repository as fork"
+msgstr "建立版本库 %s"
+
+#: rhodecode/lib/helpers.py:632 rhodecode/lib/helpers.py:640
+msgid "[forked] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:634 rhodecode/lib/helpers.py:642
+msgid "[updated] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:636
+msgid "[delete] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:644
+#, fuzzy
+msgid "[created] user"
+msgstr "创建用户 %s"
+
+#: rhodecode/lib/helpers.py:646
+#, fuzzy
+msgid "[updated] user"
+msgstr "更新用户组 %s"
+
+#: rhodecode/lib/helpers.py:648
+#, fuzzy
+msgid "[created] users group"
+msgstr "建立用户组 %s"
+
+#: rhodecode/lib/helpers.py:650
+#, fuzzy
+msgid "[updated] users group"
+msgstr "更新用户组 %s"
+
+#: rhodecode/lib/helpers.py:652
+msgid "[commented] on revision in repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:654
+#, fuzzy
+msgid "[commented] on pull request for"
+msgstr "创建用户 %s"
+
+#: rhodecode/lib/helpers.py:656
+msgid "[closed] pull request for"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:658
+msgid "[pushed] into"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:660
+msgid "[committed via RhodeCode] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:662
+msgid "[pulled from remote] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:664
+msgid "[pulled] from"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:666
+msgid "[started following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:668
+msgid "[stopped following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:840
+#, python-format
+msgid " and %s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:844
+msgid "No Files"
+msgstr "没有文件"
+
+#: rhodecode/lib/utils2.py:335
+#, fuzzy, python-format
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] "年"
+
+#: rhodecode/lib/utils2.py:336
+#, fuzzy, python-format
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] "月"
+
+#: rhodecode/lib/utils2.py:337
+#, fuzzy, python-format
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] "日"
+
+#: rhodecode/lib/utils2.py:338
+#, fuzzy, python-format
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] "时"
+
+#: rhodecode/lib/utils2.py:339
+#, fuzzy, python-format
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] "分"
+
+#: rhodecode/lib/utils2.py:340
+#, fuzzy, python-format
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] "秒"
+
+#: rhodecode/lib/utils2.py:355
+#, fuzzy, python-format
+msgid "%s ago"
+msgstr "之前"
+
+#: rhodecode/lib/utils2.py:357
+#, python-format
+msgid "%s and %s ago"
+msgstr ""
+
+#: rhodecode/lib/utils2.py:360
+msgid "just now"
+msgstr "现在"
+
+#: rhodecode/lib/celerylib/tasks.py:269
+#, fuzzy
+msgid "password reset link"
+msgstr "密码重置链接已经发送"
+
+#: rhodecode/model/comment.py:110
+#, python-format
+msgid "on line %s"
+msgstr ""
+
+#: rhodecode/model/comment.py:157
+msgid "[Mention]"
+msgstr ""
+
+#: rhodecode/model/db.py:1140
+#, fuzzy
+msgid "Repository no access"
+msgstr "个版本库"
+
+#: rhodecode/model/db.py:1141
+#, fuzzy
+msgid "Repository read access"
+msgstr "这个版本库已经存在"
+
+#: rhodecode/model/db.py:1142
+#, fuzzy
+msgid "Repository write access"
+msgstr "个版本库"
+
+#: rhodecode/model/db.py:1143
+#, fuzzy
+msgid "Repository admin access"
+msgstr "个版本库"
+
+#: rhodecode/model/db.py:1145
+#, fuzzy
+msgid "Repositories Group no access"
+msgstr "版本库组"
+
+#: rhodecode/model/db.py:1146
+#, fuzzy
+msgid "Repositories Group read access"
+msgstr "版本库组"
+
+#: rhodecode/model/db.py:1147
+#, fuzzy
+msgid "Repositories Group write access"
+msgstr "版本库组"
+
+#: rhodecode/model/db.py:1148
+#, fuzzy
+msgid "Repositories Group admin access"
+msgstr "版本库组"
+
+#: rhodecode/model/db.py:1150
+#, fuzzy
+msgid "RhodeCode Administrator"
+msgstr "用户管理员"
+
+#: rhodecode/model/db.py:1151
+#, fuzzy
+msgid "Repository creation disabled"
+msgstr "建立版本库"
+
+#: rhodecode/model/db.py:1152
+#, fuzzy
+msgid "Repository creation enabled"
+msgstr "建立版本库"
+
+#: rhodecode/model/db.py:1153
+#, fuzzy
+msgid "Repository forking disabled"
+msgstr "建立版本库"
+
+#: rhodecode/model/db.py:1154
+#, fuzzy
+msgid "Repository forking enabled"
+msgstr "建立版本库"
+
+#: rhodecode/model/db.py:1155
+#, fuzzy
+msgid "Register disabled"
+msgstr "禁用"
+
+#: rhodecode/model/db.py:1156
+msgid "Register new user with RhodeCode with manual activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1159
+msgid "Register new user with RhodeCode with auto activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1579
+msgid "Not Reviewed"
+msgstr ""
+
+#: rhodecode/model/db.py:1580
+#, fuzzy
+msgid "Approved"
+msgstr "移除"
+
+#: rhodecode/model/db.py:1581
+msgid "Rejected"
+msgstr ""
+
+#: rhodecode/model/db.py:1582
+msgid "Under Review"
+msgstr ""
+
+#: rhodecode/model/forms.py:43
+msgid "Please enter a login"
+msgstr "请登录"
+
+#: rhodecode/model/forms.py:44
+#, python-format
+msgid "Enter a value %(min)i characters long or more"
+msgstr ""
+
+#: rhodecode/model/forms.py:52
+msgid "Please enter a password"
+msgstr "请输入密码"
+
+#: rhodecode/model/forms.py:53
+#, python-format
+msgid "Enter %(min)i characters or more"
+msgstr ""
+
+#: rhodecode/model/notification.py:220
+msgid "commented on commit"
+msgstr ""
+
+#: rhodecode/model/notification.py:221
+#, fuzzy
+msgid "sent message"
+msgstr "提交信息"
+
+#: rhodecode/model/notification.py:222
+msgid "mentioned you"
+msgstr ""
+
+#: rhodecode/model/notification.py:223
+#, fuzzy
+msgid "registered in RhodeCode"
+msgstr "成功注册到 rhodecode"
+
+#: rhodecode/model/notification.py:224
+msgid "opened new pull request"
+msgstr ""
+
+#: rhodecode/model/notification.py:225
+msgid "commented on pull request"
+msgstr ""
+
+#: rhodecode/model/pull_request.py:84
+#, python-format
+msgid "%(user)s wants you to review pull request #%(pr_id)s"
+msgstr ""
+
+#: rhodecode/model/scm.py:535
+#, fuzzy
+msgid "latest tip"
+msgstr "最后登录"
+
+#: rhodecode/model/user.py:230
+#, fuzzy
+msgid "new user registration"
+msgstr "[RhodeCode] 新用户注册"
+
+#: rhodecode/model/user.py:255 rhodecode/model/user.py:277
+#: rhodecode/model/user.py:299
+msgid "You can't Edit this user since it's crucial for entire application"
+msgstr "由于是系统帐号,无法编辑该用户"
+
+#: rhodecode/model/user.py:323
+msgid "You can't remove this user since it's crucial for entire application"
+msgstr "由于是系统帐号,无法删除该用户"
+
+#: rhodecode/model/user.py:329
+#, fuzzy, python-format
+msgid ""
+"user \"%s\" still owns %s repositories and cannot be removed. Switch "
+"owners or remove those repositories. %s"
+msgstr "由于该用户拥有版本库 %s 因而无法删除,请变更版本库所有者或删除版本库"
+
+#: rhodecode/model/validators.py:35 rhodecode/model/validators.py:36
+msgid "Value cannot be an empty list"
+msgstr ""
+
+#: rhodecode/model/validators.py:82
+#, fuzzy, python-format
+msgid "Username \"%(username)s\" already exists"
+msgstr "该用户名已经存在"
+
+#: rhodecode/model/validators.py:84
+#, python-format
+msgid "Username \"%(username)s\" is forbidden"
+msgstr ""
+
+#: rhodecode/model/validators.py:86
+msgid ""
+"Username may only contain alphanumeric characters underscores, periods or"
+" dashes and must begin with alphanumeric character"
+msgstr "只能使用字母、数字、下划线、小数点或减号作为用户名,且必须由数字或字母开头"
+
+#: rhodecode/model/validators.py:114
+#, fuzzy, python-format
+msgid "Username %(username)s is not valid"
+msgstr "用户或用户组名称无效"
+
+#: rhodecode/model/validators.py:133
+#, fuzzy
+msgid "Invalid users group name"
+msgstr "无效用户名"
+
+#: rhodecode/model/validators.py:134
+#, fuzzy, python-format
+msgid "Users group \"%(usersgroup)s\" already exists"
+msgstr "该用户组名称已经存在"
+
+#: rhodecode/model/validators.py:136
+msgid ""
+"users group name may only contain  alphanumeric characters underscores, "
+"periods or dashes and must begin with alphanumeric character"
+msgstr "只能使用字母、数字、下划线、小数点或减号作为用户组名,且必须由数字或字母开头"
+
+#: rhodecode/model/validators.py:174
+msgid "Cannot assign this group as parent"
+msgstr ""
+
+#: rhodecode/model/validators.py:175
+#, fuzzy, python-format
+msgid "Group \"%(group_name)s\" already exists"
+msgstr "该用户名已经存在"
+
+#: rhodecode/model/validators.py:177
+#, fuzzy, python-format
+msgid "Repository with name \"%(group_name)s\" already exists"
+msgstr "这个版本库已经存在"
+
+#: rhodecode/model/validators.py:235
+#, fuzzy
+msgid "Invalid characters (non-ascii) in password"
+msgstr "密码含有无效字符"
+
+#: rhodecode/model/validators.py:250
+msgid "Passwords do not match"
+msgstr "密码不符"
+
+#: rhodecode/model/validators.py:267
+msgid "invalid password"
+msgstr "无效密码"
+
+#: rhodecode/model/validators.py:268
+msgid "invalid user name"
+msgstr "无效用户名"
+
+#: rhodecode/model/validators.py:269
+msgid "Your account is disabled"
+msgstr "该帐号已被禁用"
+
+#: rhodecode/model/validators.py:313
+#, fuzzy, python-format
+msgid "Repository name %(repo)s is disallowed"
+msgstr "该版本库名称被禁用"
+
+#: rhodecode/model/validators.py:315
+#, fuzzy, python-format
+msgid "Repository named %(repo)s already exists"
+msgstr "这个版本库已经存在"
+
+#: rhodecode/model/validators.py:316
+#, fuzzy, python-format
+msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
+msgstr "组中已经存在该版本库"
+
+#: rhodecode/model/validators.py:318
+#, fuzzy, python-format
+msgid "Repositories group with name \"%(repo)s\" already exists"
+msgstr "这个版本库已经存在"
+
+#: rhodecode/model/validators.py:431
+msgid "invalid clone url"
+msgstr "无效的 clone 地址"
+
+#: rhodecode/model/validators.py:432
+msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url"
+msgstr ""
+
+#: rhodecode/model/validators.py:457
+#, fuzzy
+msgid "Fork have to be the same type as parent"
+msgstr "分支必须使用相同的版本库类型"
+
+#: rhodecode/model/validators.py:478
+msgid "This username or users group name is not valid"
+msgstr "用户或用户组名称无效"
+
+#: rhodecode/model/validators.py:562
+msgid "This is not a valid path"
+msgstr "不是一个合法的路径"
+
+#: rhodecode/model/validators.py:577
+msgid "This e-mail address is already taken"
+msgstr "该邮件地址已被使用"
+
+#: rhodecode/model/validators.py:597
+#, fuzzy, python-format
+msgid "e-mail \"%(email)s\" does not exist."
+msgstr "该邮件地址不存在"
+
+#: rhodecode/model/validators.py:634
+msgid ""
+"The LDAP Login attribute of the CN must be specified - this is the name "
+"of the attribute that is equivalent to \"username\""
+msgstr ""
+
+#: rhodecode/model/validators.py:653
+#, python-format
+msgid "Revisions %(revs)s are already part of pull request or have set status"
+msgstr ""
+
+#: rhodecode/templates/index.html:3
+msgid "Dashboard"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/repo_switcher_list.html:4
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/users/user_edit_my_account.html:31
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/bookmarks/bookmarks.html:10
+#: rhodecode/templates/branches/branches.html:9
+#: rhodecode/templates/journal/journal.html:40
+#: rhodecode/templates/tags/tags.html:10
+msgid "quick filter..."
+msgstr "快速过滤..."
+
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/base/base.html:221
+msgid "repositories"
+msgstr "个版本库"
+
+#: rhodecode/templates/index_base.html:13
+#: rhodecode/templates/index_base.html:15
+#: rhodecode/templates/admin/repos/repos.html:21
+msgid "ADD REPOSITORY"
+msgstr "新增版本库"
+
+#: rhodecode/templates/index_base.html:29
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:32
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:32
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:33
+#: rhodecode/templates/admin/users_groups/users_group_add.html:32
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:33
+msgid "Group name"
+msgstr "组名"
+
+#: rhodecode/templates/index_base.html:30
+#: rhodecode/templates/index_base.html:71
+#: rhodecode/templates/index_base.html:142
+#: rhodecode/templates/index_base.html:168
+#: rhodecode/templates/admin/repos/repo_add_base.html:56
+#: rhodecode/templates/admin/repos/repo_edit.html:75
+#: rhodecode/templates/admin/repos/repos.html:72
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:41
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:41
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:34
+#: rhodecode/templates/forks/fork.html:59
+#: rhodecode/templates/settings/repo_settings.html:66
+#: rhodecode/templates/summary/summary.html:105
+msgid "Description"
+msgstr "描述"
+
+#: rhodecode/templates/index_base.html:40
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46
+msgid "Repositories group"
+msgstr "版本库组"
+
+#: rhodecode/templates/index_base.html:70
+#: rhodecode/templates/index_base.html:166
+#: rhodecode/templates/admin/repos/repo_add_base.html:9
+#: rhodecode/templates/admin/repos/repo_edit.html:32
+#: rhodecode/templates/admin/repos/repos.html:70
+#: rhodecode/templates/admin/users/user_edit.html:192
+#: rhodecode/templates/admin/users/user_edit_my_account.html:59
+#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:6
+#: rhodecode/templates/bookmarks/bookmarks.html:36
+#: rhodecode/templates/bookmarks/bookmarks_data.html:6
+#: rhodecode/templates/branches/branches.html:51
+#: rhodecode/templates/files/files_browser.html:47
+#: rhodecode/templates/journal/journal.html:59
+#: rhodecode/templates/journal/journal.html:107
+#: rhodecode/templates/journal/journal.html:186
+#: rhodecode/templates/settings/repo_settings.html:31
+#: rhodecode/templates/summary/summary.html:43
+#: rhodecode/templates/summary/summary.html:123
+#: rhodecode/templates/tags/tags.html:36
+#: rhodecode/templates/tags/tags_data.html:6
+msgid "Name"
+msgstr "名称"
+
+#: rhodecode/templates/index_base.html:72
+msgid "Last change"
+msgstr "最后修改"
+
+#: rhodecode/templates/index_base.html:73
+#: rhodecode/templates/index_base.html:171
+#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/journal/journal.html:188
+msgid "Tip"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:74
+#: rhodecode/templates/index_base.html:173
+#: rhodecode/templates/admin/repos/repo_edit.html:121
+#: rhodecode/templates/admin/repos/repos.html:73
+msgid "Owner"
+msgstr "所有者"
+
+#: rhodecode/templates/index_base.html:75
+#: rhodecode/templates/summary/summary.html:48
+#: rhodecode/templates/summary/summary.html:51
+msgid "RSS"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:76
+msgid "Atom"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:110
+#: rhodecode/templates/index_base.html:112
+#, python-format
+msgid "Subscribe to %s rss feed"
+msgstr "订阅 rss %s"
+
+#: rhodecode/templates/index_base.html:117
+#: rhodecode/templates/index_base.html:119
+#, python-format
+msgid "Subscribe to %s atom feed"
+msgstr "订阅 atom %s"
+
+#: rhodecode/templates/index_base.html:140
+#, fuzzy
+msgid "Group Name"
+msgstr "组名"
+
+#: rhodecode/templates/index_base.html:158
+#: rhodecode/templates/index_base.html:198
+#: rhodecode/templates/admin/repos/repos.html:94
+#: rhodecode/templates/admin/users/user_edit_my_account.html:179
+#: rhodecode/templates/admin/users/users.html:107
+#: rhodecode/templates/bookmarks/bookmarks.html:60
+#: rhodecode/templates/branches/branches.html:77
+#: rhodecode/templates/journal/journal.html:211
+#: rhodecode/templates/tags/tags.html:60
+msgid "Click to sort ascending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:159
+#: rhodecode/templates/index_base.html:199
+#: rhodecode/templates/admin/repos/repos.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account.html:180
+#: rhodecode/templates/admin/users/users.html:108
+#: rhodecode/templates/bookmarks/bookmarks.html:61
+#: rhodecode/templates/branches/branches.html:78
+#: rhodecode/templates/journal/journal.html:212
+#: rhodecode/templates/tags/tags.html:61
+msgid "Click to sort descending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:169
+#, fuzzy
+msgid "Last Change"
+msgstr "最后修改"
+
+#: rhodecode/templates/index_base.html:200
+#: rhodecode/templates/admin/repos/repos.html:96
+#: rhodecode/templates/admin/users/user_edit_my_account.html:181
+#: rhodecode/templates/admin/users/users.html:109
+#: rhodecode/templates/bookmarks/bookmarks.html:62
+#: rhodecode/templates/branches/branches.html:79
+#: rhodecode/templates/journal/journal.html:213
+#: rhodecode/templates/tags/tags.html:62
+msgid "No records found."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:201
+#: rhodecode/templates/admin/repos/repos.html:97
+#: rhodecode/templates/admin/users/user_edit_my_account.html:182
+#: rhodecode/templates/admin/users/users.html:110
+#: rhodecode/templates/bookmarks/bookmarks.html:63
+#: rhodecode/templates/branches/branches.html:80
+#: rhodecode/templates/journal/journal.html:214
+#: rhodecode/templates/tags/tags.html:63
+msgid "Data error."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:202
+#: rhodecode/templates/admin/repos/repos.html:98
+#: rhodecode/templates/admin/users/user_edit_my_account.html:183
+#: rhodecode/templates/admin/users/users.html:111
+#: rhodecode/templates/bookmarks/bookmarks.html:64
+#: rhodecode/templates/branches/branches.html:81
+#: rhodecode/templates/journal/journal.html:215
+#: rhodecode/templates/tags/tags.html:64
+#, fuzzy
+msgid "Loading..."
+msgstr "加载文件列表..."
+
+#: rhodecode/templates/login.html:5 rhodecode/templates/login.html:54
+msgid "Sign In"
+msgstr "登录"
+
+#: rhodecode/templates/login.html:21
+msgid "Sign In to"
+msgstr "登录到"
+
+#: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20
+#: rhodecode/templates/admin/admin_log.html:5
+#: rhodecode/templates/admin/users/user_add.html:32
+#: rhodecode/templates/admin/users/user_edit.html:50
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:26
+#: rhodecode/templates/base/base.html:83
+#: rhodecode/templates/summary/summary.html:122
+msgid "Username"
+msgstr "帐号"
+
+#: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29
+#: rhodecode/templates/admin/ldap/ldap.html:46
+#: rhodecode/templates/admin/users/user_add.html:41
+#: rhodecode/templates/base/base.html:92
+msgid "Password"
+msgstr "密码"
+
+#: rhodecode/templates/login.html:50
+#, fuzzy
+msgid "Remember me"
+msgstr "成员"
+
+#: rhodecode/templates/login.html:60
+msgid "Forgot your password ?"
+msgstr "忘记了密码?"
+
+#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:103
+msgid "Don't have an account ?"
+msgstr "还没有帐号?"
+
+#: rhodecode/templates/password_reset.html:5
+msgid "Reset your password"
+msgstr "重置密码"
+
+#: rhodecode/templates/password_reset.html:11
+msgid "Reset your password to"
+msgstr "重置密码"
+
+#: rhodecode/templates/password_reset.html:21
+msgid "Email address"
+msgstr "邮件地址"
+
+#: rhodecode/templates/password_reset.html:30
+msgid "Reset my password"
+msgstr "重置密码"
+
+#: rhodecode/templates/password_reset.html:31
+msgid "Password reset link will be send to matching email address"
+msgstr "密码重置地址已经发送到邮件"
+
+#: rhodecode/templates/register.html:5 rhodecode/templates/register.html:74
+msgid "Sign Up"
+msgstr "注册"
+
+#: rhodecode/templates/register.html:11
+msgid "Sign Up to"
+msgstr "注册"
+
+#: rhodecode/templates/register.html:38
+msgid "Re-enter password"
+msgstr "确认密码"
+
+#: rhodecode/templates/register.html:47
+#: rhodecode/templates/admin/users/user_add.html:59
+#: rhodecode/templates/admin/users/user_edit.html:86
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53
+msgid "First Name"
+msgstr "名"
+
+#: rhodecode/templates/register.html:56
+#: rhodecode/templates/admin/users/user_add.html:68
+#: rhodecode/templates/admin/users/user_edit.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62
+msgid "Last Name"
+msgstr "姓"
+
+#: rhodecode/templates/register.html:65
+#: rhodecode/templates/admin/users/user_add.html:77
+#: rhodecode/templates/admin/users/user_edit.html:104
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71
+#: rhodecode/templates/summary/summary.html:124
+msgid "Email"
+msgstr "电子邮件"
+
+#: rhodecode/templates/register.html:76
+msgid "Your account will be activated right after registration"
+msgstr "注册后,帐号将启用"
+
+#: rhodecode/templates/register.html:78
+msgid "Your account must wait for activation by administrator"
+msgstr "管理员审核后,你注册的帐号将被启用"
+
+#: rhodecode/templates/repo_switcher_list.html:11
+#: rhodecode/templates/admin/repos/repo_add_base.html:65
+#: rhodecode/templates/admin/repos/repo_edit.html:85
+#: rhodecode/templates/settings/repo_settings.html:76
+msgid "Private repository"
+msgstr "私有版本库"
+
+#: rhodecode/templates/repo_switcher_list.html:16
+msgid "Public repository"
+msgstr "公共版本库"
+
+#: rhodecode/templates/switch_to_list.html:3
+#: rhodecode/templates/branches/branches.html:14
+msgid "branches"
+msgstr "分支"
+
+#: rhodecode/templates/switch_to_list.html:10
+#: rhodecode/templates/branches/branches_data.html:57
+msgid "There are no branches yet"
+msgstr "没有任何分支"
+
+#: rhodecode/templates/switch_to_list.html:15
+#: rhodecode/templates/shortlog/shortlog_data.html:10
+#: rhodecode/templates/tags/tags.html:15
+msgid "tags"
+msgstr "标签"
+
+#: rhodecode/templates/switch_to_list.html:22
+#: rhodecode/templates/tags/tags_data.html:33
+msgid "There are no tags yet"
+msgstr "没有任何标签"
+
+#: rhodecode/templates/switch_to_list.html:28
+#: rhodecode/templates/bookmarks/bookmarks.html:15
+msgid "bookmarks"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:35
+#: rhodecode/templates/bookmarks/bookmarks_data.html:32
+#, fuzzy
+msgid "There are no bookmarks yet"
+msgstr "尚未有任何分支"
+
+#: rhodecode/templates/admin/admin.html:5
+#: rhodecode/templates/admin/admin.html:9
+msgid "Admin journal"
+msgstr "管理员日志"
+
+#: rhodecode/templates/admin/admin_log.html:6
+#: rhodecode/templates/admin/repos/repos.html:74
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:8
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:9
+#: rhodecode/templates/journal/journal.html:61
+#: rhodecode/templates/journal/journal.html:62
+msgid "Action"
+msgstr "操作"
+
+#: rhodecode/templates/admin/admin_log.html:7
+msgid "Repository"
+msgstr "版本库"
+
+#: rhodecode/templates/admin/admin_log.html:8
+#: rhodecode/templates/bookmarks/bookmarks.html:37
+#: rhodecode/templates/bookmarks/bookmarks_data.html:7
+#: rhodecode/templates/branches/branches.html:52
+#: rhodecode/templates/tags/tags.html:37
+#: rhodecode/templates/tags/tags_data.html:7
+msgid "Date"
+msgstr "日期"
+
+#: rhodecode/templates/admin/admin_log.html:9
+msgid "From IP"
+msgstr "来源 IP"
+
+#: rhodecode/templates/admin/admin_log.html:53
+msgid "No actions yet"
+msgstr "尚无操作"
+
+#: rhodecode/templates/admin/ldap/ldap.html:5
+msgid "LDAP administration"
+msgstr "LDAP 管理员"
+
+#: rhodecode/templates/admin/ldap/ldap.html:11
+msgid "Ldap"
+msgstr ""
+
+#: rhodecode/templates/admin/ldap/ldap.html:28
+msgid "Connection settings"
+msgstr "连接设置"
+
+#: rhodecode/templates/admin/ldap/ldap.html:30
+msgid "Enable LDAP"
+msgstr "启用 LDAP"
+
+#: rhodecode/templates/admin/ldap/ldap.html:34
+msgid "Host"
+msgstr "主机"
+
+#: rhodecode/templates/admin/ldap/ldap.html:38
+msgid "Port"
+msgstr "端口"
+
+#: rhodecode/templates/admin/ldap/ldap.html:42
+msgid "Account"
+msgstr "帐号"
+
+#: rhodecode/templates/admin/ldap/ldap.html:50
+msgid "Connection security"
+msgstr "连接安全"
+
+#: rhodecode/templates/admin/ldap/ldap.html:54
+msgid "Certificate Checks"
+msgstr "凭证确认"
+
+#: rhodecode/templates/admin/ldap/ldap.html:57
+msgid "Search settings"
+msgstr "搜索设置"
+
+#: rhodecode/templates/admin/ldap/ldap.html:59
+msgid "Base DN"
+msgstr ""
+
+#: rhodecode/templates/admin/ldap/ldap.html:63
+msgid "LDAP Filter"
+msgstr ""
+
+#: rhodecode/templates/admin/ldap/ldap.html:67
+msgid "LDAP Search Scope"
+msgstr ""
+
+#: rhodecode/templates/admin/ldap/ldap.html:70
+msgid "Attribute mappings"
+msgstr "属性映射"
+
+#: rhodecode/templates/admin/ldap/ldap.html:72
+msgid "Login Attribute"
+msgstr "登录属性"
+
+#: rhodecode/templates/admin/ldap/ldap.html:76
+msgid "First Name Attribute"
+msgstr "名"
+
+#: rhodecode/templates/admin/ldap/ldap.html:80
+msgid "Last Name Attribute"
+msgstr "姓"
+
+#: rhodecode/templates/admin/ldap/ldap.html:84
+msgid "E-mail Attribute"
+msgstr "电子邮件属性"
+
+#: rhodecode/templates/admin/ldap/ldap.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:141
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:74
+#: rhodecode/templates/admin/settings/hooks.html:73
+#: rhodecode/templates/admin/users/user_edit.html:129
+#: rhodecode/templates/admin/users/user_edit.html:174
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:79
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:135
+#: rhodecode/templates/settings/repo_settings.html:93
+msgid "Save"
+msgstr "保存"
+
+#: rhodecode/templates/admin/notifications/notifications.html:5
+#: rhodecode/templates/admin/notifications/notifications.html:9
+msgid "My Notifications"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:29
+msgid "All"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:30
+#, fuzzy
+msgid "Comments"
+msgstr "提交"
+
+#: rhodecode/templates/admin/notifications/notifications.html:31
+#: rhodecode/templates/base/base.html:254
+#: rhodecode/templates/base/base.html:256
+msgid "Pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:35
+msgid "Mark all read"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications_data.html:39
+#, fuzzy
+msgid "No notifications here yet"
+msgstr "尚无操作"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:5
+#: rhodecode/templates/admin/notifications/show_notification.html:11
+#, fuzzy
+msgid "Show notification"
+msgstr "显示注释"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:9
+#, fuzzy
+msgid "Notifications"
+msgstr "位置"
+
+#: rhodecode/templates/admin/permissions/permissions.html:5
+msgid "Permissions administration"
+msgstr "权限管理"
+
+#: rhodecode/templates/admin/permissions/permissions.html:11
+#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
+#: rhodecode/templates/admin/users/user_edit.html:139
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:100
+#: rhodecode/templates/settings/repo_settings.html:86
+msgid "Permissions"
+msgstr "权限"
+
+#: rhodecode/templates/admin/permissions/permissions.html:24
+msgid "Default permissions"
+msgstr "默认权限"
+
+#: rhodecode/templates/admin/permissions/permissions.html:31
+msgid "Anonymous access"
+msgstr "匿名访问"
+
+#: rhodecode/templates/admin/permissions/permissions.html:41
+msgid "Repository permission"
+msgstr "版本库权限"
+
+#: rhodecode/templates/admin/permissions/permissions.html:49
+msgid ""
+"All default permissions on each repository will be reset to choosen "
+"permission, note that all custom default permission on repositories will "
+"be lost"
+msgstr ""
+
+#: rhodecode/templates/admin/permissions/permissions.html:50
+msgid "overwrite existing settings"
+msgstr "覆盖已有设置"
+
+#: rhodecode/templates/admin/permissions/permissions.html:55
+msgid "Registration"
+msgstr "注册"
+
+#: rhodecode/templates/admin/permissions/permissions.html:63
+msgid "Repository creation"
+msgstr "建立版本库"
+
+#: rhodecode/templates/admin/permissions/permissions.html:71
+#, fuzzy
+msgid "Repository forking"
+msgstr "建立版本库"
+
+#: rhodecode/templates/admin/permissions/permissions.html:78
+#: rhodecode/templates/admin/repos/repo_edit.html:241
+msgid "set"
+msgstr "设置"
+
+#: rhodecode/templates/admin/repos/repo_add.html:5
+#: rhodecode/templates/admin/repos/repo_add_create_repository.html:5
+msgid "Add repository"
+msgstr "添加版本库"
+
+#: rhodecode/templates/admin/repos/repo_add.html:11
+#: rhodecode/templates/admin/repos/repo_edit.html:11
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
+msgid "Repositories"
+msgstr "版本库"
+
+#: rhodecode/templates/admin/repos/repo_add.html:13
+msgid "add new"
+msgstr "新增"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:20
+#: rhodecode/templates/summary/summary.html:95
+#: rhodecode/templates/summary/summary.html:96
+msgid "Clone from"
+msgstr "clone 自"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:24
+#: rhodecode/templates/admin/repos/repo_edit.html:44
+#: rhodecode/templates/settings/repo_settings.html:43
+msgid "Optional http[s] url from which repository should be cloned."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:29
+#: rhodecode/templates/admin/repos/repo_edit.html:49
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:4
+#: rhodecode/templates/forks/fork.html:50
+#: rhodecode/templates/settings/repo_settings.html:48
+msgid "Repository group"
+msgstr "版本库组"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:33
+#: rhodecode/templates/forks/fork.html:54
+msgid "Optionaly select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:38
+#: rhodecode/templates/admin/repos/repo_edit.html:58
+msgid "Type"
+msgstr "类型"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:42
+#, fuzzy
+msgid "Type of repository to create."
+msgstr "建立版本库"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:47
+#: rhodecode/templates/admin/repos/repo_edit.html:66
+#: rhodecode/templates/forks/fork.html:41
+#: rhodecode/templates/settings/repo_settings.html:57
+#, fuzzy
+msgid "Landing revision"
+msgstr "下一个修订"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:51
+#: rhodecode/templates/admin/repos/repo_edit.html:70
+#: rhodecode/templates/forks/fork.html:45
+#: rhodecode/templates/settings/repo_settings.html:61
+msgid "Default revision for files page, downloads, whoosh and readme"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:60
+#: rhodecode/templates/admin/repos/repo_edit.html:79
+#: rhodecode/templates/forks/fork.html:63
+#: rhodecode/templates/settings/repo_settings.html:70
+msgid "Keep it short and to the point. Use a README file for longer descriptions."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:69
+#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/forks/fork.html:72
+#: rhodecode/templates/settings/repo_settings.html:80
+msgid ""
+"Private repositories are only visible to people explicitly added as "
+"collaborators."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:73
+msgid "add"
+msgstr "新增"
+
+#: rhodecode/templates/admin/repos/repo_add_create_repository.html:9
+msgid "add new repository"
+msgstr "新增版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:5
+msgid "Edit repository"
+msgstr "编辑版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:13
+#: rhodecode/templates/admin/users/user_edit.html:13
+#: rhodecode/templates/admin/users/user_edit.html:224
+#: rhodecode/templates/admin/users/user_edit.html:226
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:13
+#: rhodecode/templates/files/files_source.html:44
+#: rhodecode/templates/journal/journal.html:81
+msgid "edit"
+msgstr "编辑"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:40
+#: rhodecode/templates/settings/repo_settings.html:39
+msgid "Clone uri"
+msgstr "clone 地址"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:53
+#: rhodecode/templates/settings/repo_settings.html:52
+msgid "Optional select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:94
+msgid "Enable statistics"
+msgstr "启用统计"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:98
+msgid "Enable statistics window on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:103
+msgid "Enable downloads"
+msgstr "启用下载"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:107
+msgid "Enable download menu on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:112
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:66
+#, fuzzy
+msgid "Enable locking"
+msgstr "启用"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:116
+msgid "Enable lock-by-pulling on repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:126
+#, fuzzy
+msgid "Change owner of this repository."
+msgstr "%s 库的修改"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:142
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:75
+#: rhodecode/templates/admin/settings/settings.html:113
+#: rhodecode/templates/admin/settings/settings.html:168
+#: rhodecode/templates/admin/settings/settings.html:258
+#: rhodecode/templates/admin/users/user_edit.html:130
+#: rhodecode/templates/admin/users/user_edit.html:175
+#: rhodecode/templates/admin/users/user_edit.html:278
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:136
+#: rhodecode/templates/files/files_add.html:82
+#: rhodecode/templates/files/files_edit.html:68
+#: rhodecode/templates/pullrequests/pullrequest.html:124
+#: rhodecode/templates/settings/repo_settings.html:94
+msgid "Reset"
+msgstr "重置"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:152
+msgid "Administration"
+msgstr "管理"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:155
+msgid "Statistics"
+msgstr "统计"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:159
+msgid "Reset current statistics"
+msgstr "重置统计"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:159
+msgid "Confirm to remove current statistics"
+msgstr "确认移除当前统计"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:162
+msgid "Fetched to rev"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:163
+msgid "Stats gathered"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:171
+msgid "Remote"
+msgstr "远程"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Pull changes from remote location"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:175
+msgid "Confirm to pull changes from remote side"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:186
+msgid "Cache"
+msgstr "缓存"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:190
+msgid "Invalidate repository cache"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:190
+msgid "Confirm to invalidate repository cache"
+msgstr "确认清除版本库缓存"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:195
+#: rhodecode/templates/base/base.html:318
+#: rhodecode/templates/base/base.html:320
+#: rhodecode/templates/base/base.html:322
+msgid "Public journal"
+msgstr "公共日志"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:201
+msgid "Remove from public journal"
+msgstr "从公共日志删除"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:203
+msgid "Add to public journal"
+msgstr "添加到公共日志"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:208
+msgid ""
+"All actions made on this repository will be accessible to everyone in "
+"public journal"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:215
+#, fuzzy
+msgid "Locking"
+msgstr "解锁"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Unlock locked repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+#, fuzzy
+msgid "Confirm to unlock repository"
+msgstr "确认删除版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "lock repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+#, fuzzy
+msgid "Confirm to lock repository"
+msgstr "确认删除版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:224
+#, fuzzy
+msgid "Repository is not locked"
+msgstr "个版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:229
+msgid "Force locking on repository. Works only when anonymous access is disabled"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:236
+msgid "Set as fork of"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:245
+msgid "Manually set this repository as a fork of another from the list"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:251
+#: rhodecode/templates/changeset/changeset_file_comment.html:26
+msgid "Delete"
+msgstr "删除"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+msgid "Remove this repository"
+msgstr "删除版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+#: rhodecode/templates/journal/journal.html:84
+msgid "Confirm to delete this repository"
+msgstr "确认删除版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:259
+msgid ""
+"This repository will be renamed in a special way in order to be "
+"unaccesible for RhodeCode and VCS systems.\n"
+"                         If you need fully delete it from filesystem "
+"please do it manually"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:3
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3
+msgid "none"
+msgstr "无"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:4
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4
+msgid "read"
+msgstr "读"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:5
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5
+msgid "write"
+msgstr "写"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:6
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6
+#: rhodecode/templates/admin/users/users.html:85
+#: rhodecode/templates/base/base.html:217
+msgid "admin"
+msgstr "管理员"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:7
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7
+msgid "member"
+msgstr "成员"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
+#: rhodecode/templates/data_table/_dt_elements.html:67
+#: rhodecode/templates/journal/journal.html:132
+#: rhodecode/templates/summary/summary.html:76
+msgid "private repository"
+msgstr "私有版本库"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:19
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:28
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:18
+#, fuzzy
+msgid "default"
+msgstr "删除"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:33
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:58
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:23
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:42
+msgid "revoke"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:83
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:67
+msgid "Add another member"
+msgstr "添加成员"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:97
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81
+msgid "Failed to remove user"
+msgstr "删除用户失败"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:112
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:96
+msgid "Failed to remove users group"
+msgstr "删除用户组失败"
+
+#: rhodecode/templates/admin/repos/repos.html:5
+msgid "Repositories administration"
+msgstr "版本库管理员"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:8
+msgid "Groups"
+msgstr "组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:12
+msgid "with"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:5
+msgid "Add repos group"
+msgstr "添加版本库组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:10
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:10
+msgid "Repos groups"
+msgstr "版本库组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:12
+msgid "add new repos group"
+msgstr "添加新版本库组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:50
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:50
+msgid "Group parent"
+msgstr "上级组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_add.html:58
+#: rhodecode/templates/admin/users/user_add.html:94
+#: rhodecode/templates/admin/users_groups/users_group_add.html:49
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:90
+#: rhodecode/templates/pullrequests/pullrequest_show.html:113
+msgid "save"
+msgstr "保存"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:5
+msgid "Edit repos group"
+msgstr "编辑版本库组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:12
+msgid "edit repos group"
+msgstr "编辑版本库组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:70
+msgid ""
+"Enable lock-by-pulling on group. This option will be applied to all other"
+" groups and repositories inside"
+msgstr ""
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5
+msgid "Repositories groups administration"
+msgstr "版本库管理员"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:22
+msgid "ADD NEW GROUP"
+msgstr "添加组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:35
+#, fuzzy
+msgid "Number of toplevel repositories"
+msgstr "版本库数量"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
+#: rhodecode/templates/admin/users/users.html:87
+#: rhodecode/templates/admin/users_groups/users_groups.html:35
+msgid "action"
+msgstr "操作"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#: rhodecode/templates/admin/users/user_edit.html:255
+#: rhodecode/templates/admin/users_groups/users_groups.html:44
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#: rhodecode/templates/data_table/_dt_elements.html:103
+msgid "delete"
+msgstr "删除"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#, fuzzy, python-format
+msgid "Confirm to delete this group: %s"
+msgstr "确认删除该组"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:62
+msgid "There are no repositories groups yet"
+msgstr "没有版本库组"
+
+#: rhodecode/templates/admin/settings/hooks.html:5
+#: rhodecode/templates/admin/settings/settings.html:5
+msgid "Settings administration"
+msgstr "设置管理员"
+
+#: rhodecode/templates/admin/settings/hooks.html:9
+#: rhodecode/templates/admin/settings/settings.html:9
+#: rhodecode/templates/settings/repo_settings.html:13
+msgid "Settings"
+msgstr "设置"
+
+#: rhodecode/templates/admin/settings/hooks.html:24
+msgid "Built in hooks - read only"
+msgstr "内建钩子 - 只读"
+
+#: rhodecode/templates/admin/settings/hooks.html:40
+msgid "Custom hooks"
+msgstr "自定义钩子"
+
+#: rhodecode/templates/admin/settings/hooks.html:56
+msgid "remove"
+msgstr "删除"
+
+#: rhodecode/templates/admin/settings/hooks.html:88
+msgid "Failed to remove hook"
+msgstr "移除钩子失败"
+
+#: rhodecode/templates/admin/settings/settings.html:24
+msgid "Remap and rescan repositories"
+msgstr "重新扫描并映射版本库"
+
+#: rhodecode/templates/admin/settings/settings.html:32
+msgid "rescan option"
+msgstr "重新扫描选项"
+
+#: rhodecode/templates/admin/settings/settings.html:38
+msgid ""
+"In case a repository was deleted from filesystem and there are leftovers "
+"in the database check this option to scan obsolete data in database and "
+"remove it."
+msgstr "如果版本库已经从文件系统删除,但数据库仍然有遗留信息,请勾选该项进行清理"
+
+#: rhodecode/templates/admin/settings/settings.html:39
+msgid "destroy old data"
+msgstr "清理旧数据"
+
+#: rhodecode/templates/admin/settings/settings.html:41
+msgid ""
+"Rescan repositories location for new repositories. Also deletes obsolete "
+"if `destroy` flag is checked "
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:46
+msgid "Rescan repositories"
+msgstr "重新扫描版本库"
+
+#: rhodecode/templates/admin/settings/settings.html:52
+msgid "Whoosh indexing"
+msgstr "Whoosh 索引"
+
+#: rhodecode/templates/admin/settings/settings.html:60
+msgid "index build option"
+msgstr "构建索引选项"
+
+#: rhodecode/templates/admin/settings/settings.html:65
+msgid "build from scratch"
+msgstr "重新建立"
+
+#: rhodecode/templates/admin/settings/settings.html:71
+msgid "Reindex"
+msgstr "重新索引"
+
+#: rhodecode/templates/admin/settings/settings.html:77
+msgid "Global application settings"
+msgstr "全局设置"
+
+#: rhodecode/templates/admin/settings/settings.html:86
+msgid "Application name"
+msgstr "应用名称"
+
+#: rhodecode/templates/admin/settings/settings.html:95
+msgid "Realm text"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:104
+msgid "GA code"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:112
+#: rhodecode/templates/admin/settings/settings.html:167
+#: rhodecode/templates/admin/settings/settings.html:257
+msgid "Save settings"
+msgstr "保存设置"
+
+#: rhodecode/templates/admin/settings/settings.html:119
+#, fuzzy
+msgid "Visualisation settings"
+msgstr "全局设置"
+
+#: rhodecode/templates/admin/settings/settings.html:128
+#, fuzzy
+msgid "Icons"
+msgstr "选项"
+
+#: rhodecode/templates/admin/settings/settings.html:133
+msgid "Show public repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:137
+#, fuzzy
+msgid "Show private repo icon on repositories"
+msgstr "私有版本库"
+
+#: rhodecode/templates/admin/settings/settings.html:144
+#, fuzzy
+msgid "Meta-Tagging"
+msgstr "设置"
+
+#: rhodecode/templates/admin/settings/settings.html:149
+msgid "Stylify recognised metatags:"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:176
+#, fuzzy
+msgid "VCS settings"
+msgstr "设置"
+
+#: rhodecode/templates/admin/settings/settings.html:185
+msgid "Web"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:190
+#, fuzzy
+msgid "require ssl for vcs operations"
+msgstr "使用 SSL 推送"
+
+#: rhodecode/templates/admin/settings/settings.html:192
+msgid ""
+"RhodeCode will require SSL for pushing or pulling. If SSL is missing it "
+"will return HTTP Error 406: Not Acceptable"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:198
+msgid "Hooks"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:203
+msgid "Update repository after push (hg update)"
+msgstr "推送后更新版本库(hg update)"
+
+#: rhodecode/templates/admin/settings/settings.html:207
+msgid "Show repository size after push"
+msgstr "推送后显示版本库大小"
+
+#: rhodecode/templates/admin/settings/settings.html:211
+msgid "Log user push commands"
+msgstr "记录用户推送命令"
+
+#: rhodecode/templates/admin/settings/settings.html:215
+msgid "Log user pull commands"
+msgstr "记录用户拉取命令"
+
+#: rhodecode/templates/admin/settings/settings.html:219
+msgid "advanced setup"
+msgstr "高级设置"
+
+#: rhodecode/templates/admin/settings/settings.html:224
+#, fuzzy
+msgid "Mercurial Extensions"
+msgstr "Mercurial 版本库"
+
+#: rhodecode/templates/admin/settings/settings.html:229
+msgid "largefiles extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:233
+msgid "hgsubversion extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:235
+msgid ""
+"Requires hgsubversion library installed. Allows clonning from svn remote "
+"locations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:245
+msgid "Repositories location"
+msgstr "版本库路径"
+
+#: rhodecode/templates/admin/settings/settings.html:250
+msgid ""
+"This a crucial application setting. If you are really sure you need to "
+"change this, you must restart application in order to make this setting "
+"take effect. Click this label to unlock."
+msgstr "这是一个关键设置。如果确认修改该项设置,请重启服务以便设置生效。"
+
+#: rhodecode/templates/admin/settings/settings.html:251
+msgid "unlock"
+msgstr "解锁"
+
+#: rhodecode/templates/admin/settings/settings.html:252
+msgid ""
+"Location where repositories are stored. After changing this value a "
+"restart, and rescan is required"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:272
+msgid "Test Email"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:280
+#, fuzzy
+msgid "Email to"
+msgstr "电子邮件"
+
+#: rhodecode/templates/admin/settings/settings.html:288
+#, fuzzy
+msgid "Send"
+msgstr "秒"
+
+#: rhodecode/templates/admin/settings/settings.html:294
+msgid "System Info and Packages"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:297
+#, fuzzy
+msgid "show"
+msgstr "显示"
+
+#: rhodecode/templates/admin/users/user_add.html:5
+msgid "Add user"
+msgstr "添加用户"
+
+#: rhodecode/templates/admin/users/user_add.html:10
+#: rhodecode/templates/admin/users/user_edit.html:11
+msgid "Users"
+msgstr "用户"
+
+#: rhodecode/templates/admin/users/user_add.html:12
+msgid "add new user"
+msgstr "添加新用户"
+
+#: rhodecode/templates/admin/users/user_add.html:50
+#, fuzzy
+msgid "Password confirmation"
+msgstr "密码不符"
+
+#: rhodecode/templates/admin/users/user_add.html:86
+#: rhodecode/templates/admin/users/user_edit.html:113
+#: rhodecode/templates/admin/users_groups/users_group_add.html:41
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:42
+msgid "Active"
+msgstr "启用"
+
+#: rhodecode/templates/admin/users/user_edit.html:5
+msgid "Edit user"
+msgstr "编辑用户"
+
+#: rhodecode/templates/admin/users/user_edit.html:34
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10
+msgid "Change your avatar at"
+msgstr "修改你的头像"
+
+#: rhodecode/templates/admin/users/user_edit.html:35
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11
+msgid "Using"
+msgstr "使用中"
+
+#: rhodecode/templates/admin/users/user_edit.html:43
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20
+msgid "API key"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:59
+msgid "LDAP DN"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:68
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:35
+msgid "New password"
+msgstr "新密码"
+
+#: rhodecode/templates/admin/users/user_edit.html:77
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44
+msgid "New password confirmation"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:147
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:108
+#, fuzzy
+msgid "Inherit default permissions"
+msgstr "默认权限"
+
+#: rhodecode/templates/admin/users/user_edit.html:152
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:113
+#, python-format
+msgid ""
+"Select to inherit permissions from %s settings. With this selected below "
+"options does not have any action"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:158
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:119
+msgid "Create repositories"
+msgstr "创建版本库"
+
+#: rhodecode/templates/admin/users/user_edit.html:166
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:127
+#, fuzzy
+msgid "Fork repositories"
+msgstr "个版本库"
+
+#: rhodecode/templates/admin/users/user_edit.html:186
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:22
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:39
+#, fuzzy
+msgid "Nothing here yet"
+msgstr "尚无操作"
+
+#: rhodecode/templates/admin/users/user_edit.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account.html:60
+#: rhodecode/templates/admin/users/user_edit_my_account.html:194
+#, fuzzy
+msgid "Permission"
+msgstr "权限"
+
+#: rhodecode/templates/admin/users/user_edit.html:194
+#, fuzzy
+msgid "Edit Permission"
+msgstr "版本库权限"
+
+#: rhodecode/templates/admin/users/user_edit.html:243
+#, fuzzy
+msgid "Email addresses"
+msgstr "邮件地址"
+
+#: rhodecode/templates/admin/users/user_edit.html:256
+#, fuzzy, python-format
+msgid "Confirm to delete this email: %s"
+msgstr "确认删除该用户"
+
+#: rhodecode/templates/admin/users/user_edit.html:270
+#, fuzzy
+msgid "New email address"
+msgstr "邮件地址"
+
+#: rhodecode/templates/admin/users/user_edit.html:277
+#, fuzzy
+msgid "Add"
+msgstr "新增"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:5
+#: rhodecode/templates/base/base.html:124
+msgid "My account"
+msgstr "我的账户"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:9
+msgid "My Account"
+msgstr "我的账户"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:35
+#, fuzzy
+msgid "My permissions"
+msgstr "权限"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:38
+#: rhodecode/templates/journal/journal.html:41
+#, fuzzy
+msgid "My repos"
+msgstr "空版本库"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:41
+#, fuzzy
+msgid "My pull requests"
+msgstr "创建用户 %s"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:45
+#, fuzzy
+msgid "Add repo"
+msgstr "新增"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2
+msgid "Opened by me"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:10
+#, python-format
+msgid "Pull request #%s opened on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15
+#, fuzzy
+msgid "Confirm to delete this pull request"
+msgstr "确认删除版本库"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:26
+msgid "I participate in"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:33
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:30
+#, python-format
+msgid "Pull request #%s opened by %s on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:7
+#: rhodecode/templates/bookmarks/bookmarks.html:40
+#: rhodecode/templates/bookmarks/bookmarks_data.html:9
+#: rhodecode/templates/branches/branches.html:55
+#: rhodecode/templates/journal/journal.html:60
+#: rhodecode/templates/tags/tags.html:40
+#: rhodecode/templates/tags/tags_data.html:9
+msgid "Revision"
+msgstr "修订"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/journal/journal.html:81
+msgid "private"
+msgstr "私有"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#, fuzzy, python-format
+msgid "Confirm to delete this repository: %s"
+msgstr "确认删除版本库"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:38
+#: rhodecode/templates/journal/journal.html:94
+msgid "No repositories yet"
+msgstr "没有任何版本库"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:40
+#: rhodecode/templates/journal/journal.html:96
+msgid "create one now"
+msgstr ""
+
+#: rhodecode/templates/admin/users/users.html:5
+msgid "Users administration"
+msgstr "用户管理员"
+
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/base/base.html:223
+msgid "users"
+msgstr "用户"
+
+#: rhodecode/templates/admin/users/users.html:23
+msgid "ADD NEW USER"
+msgstr "添加用户"
+
+#: rhodecode/templates/admin/users/users.html:77
+msgid "username"
+msgstr "用户名"
+
+#: rhodecode/templates/admin/users/users.html:80
+#, fuzzy
+msgid "firstname"
+msgstr "名"
+
+#: rhodecode/templates/admin/users/users.html:81
+msgid "lastname"
+msgstr "姓"
+
+#: rhodecode/templates/admin/users/users.html:82
+msgid "last login"
+msgstr "最后登录"
+
+#: rhodecode/templates/admin/users/users.html:84
+#: rhodecode/templates/admin/users_groups/users_groups.html:34
+msgid "active"
+msgstr "启用"
+
+#: rhodecode/templates/admin/users/users.html:86
+#: rhodecode/templates/base/base.html:226
+msgid "ldap"
+msgstr ""
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:5
+msgid "Add users group"
+msgstr "添加用户组"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:10
+#: rhodecode/templates/admin/users_groups/users_groups.html:9
+msgid "Users groups"
+msgstr "用户组"
+
+#: rhodecode/templates/admin/users_groups/users_group_add.html:12
+msgid "add new users group"
+msgstr "添加新用户组"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:5
+msgid "Edit users group"
+msgstr "编辑用户组"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:11
+msgid "UsersGroups"
+msgstr "用户组"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:50
+msgid "Members"
+msgstr "成员"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:58
+msgid "Choosen group members"
+msgstr "选择组成员"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:61
+msgid "Remove all elements"
+msgstr "移除全部项目"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:75
+msgid "Available members"
+msgstr "启用成员"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:79
+msgid "Add all elements"
+msgstr "添加全部项目"
+
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:146
+#, fuzzy
+msgid "Group members"
+msgstr "选择组成员"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:5
+msgid "Users groups administration"
+msgstr "用户组管理"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:23
+msgid "ADD NEW USER GROUP"
+msgstr "添加新用户组"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:32
+msgid "group name"
+msgstr "组名"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:33
+#: rhodecode/templates/base/root.html:46
+msgid "members"
+msgstr "成员"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:45
+#, fuzzy, python-format
+msgid "Confirm to delete this users group: %s"
+msgstr "确认删除该组"
+
+#: rhodecode/templates/base/base.html:41
+msgid "Submit a bug"
+msgstr "提交 bug"
+
+#: rhodecode/templates/base/base.html:77
+msgid "Login to your account"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:100
+msgid "Forgot password ?"
+msgstr "忘记密码?"
+
+#: rhodecode/templates/base/base.html:107
+#, fuzzy
+msgid "Log In"
+msgstr "登录"
+
+#: rhodecode/templates/base/base.html:118
+msgid "Inbox"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:122
+#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/base/base.html:302
+#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/bookmarks/bookmarks.html:11
+#: rhodecode/templates/branches/branches.html:10
+#: rhodecode/templates/changelog/changelog.html:10
+#: rhodecode/templates/changeset/changeset.html:10
+#: rhodecode/templates/changeset/changeset_range.html:9
+#: rhodecode/templates/compare/compare_diff.html:9
+#: rhodecode/templates/files/file_diff.html:8
+#: rhodecode/templates/files/files.html:8
+#: rhodecode/templates/files/files_add.html:15
+#: rhodecode/templates/files/files_edit.html:15
+#: rhodecode/templates/followers/followers.html:9
+#: rhodecode/templates/forks/fork.html:9 rhodecode/templates/forks/forks.html:9
+#: rhodecode/templates/pullrequests/pullrequest.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8
+#: rhodecode/templates/settings/repo_settings.html:9
+#: rhodecode/templates/shortlog/shortlog.html:10
+#: rhodecode/templates/summary/summary.html:8
+#: rhodecode/templates/tags/tags.html:11
+msgid "Home"
+msgstr "首页"
+
+#: rhodecode/templates/base/base.html:123
+#: rhodecode/templates/base/base.html:309
+#: rhodecode/templates/base/base.html:311
+#: rhodecode/templates/base/base.html:313
+#: rhodecode/templates/journal/journal.html:4
+#: rhodecode/templates/journal/journal.html:21
+#: rhodecode/templates/journal/public_journal.html:4
+msgid "Journal"
+msgstr "日志"
+
+#: rhodecode/templates/base/base.html:125
+msgid "Log Out"
+msgstr "退出"
+
+#: rhodecode/templates/base/base.html:144
+msgid "Switch repository"
+msgstr "切换版本库"
+
+#: rhodecode/templates/base/base.html:146
+msgid "Products"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:152
+#: rhodecode/templates/base/base.html:182
+msgid "loading..."
+msgstr ""
+
+#: rhodecode/templates/base/base.html:158
+#: rhodecode/templates/base/base.html:160
+#: rhodecode/templates/base/base.html:162
+#: rhodecode/templates/data_table/_dt_elements.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:17
+#: rhodecode/templates/data_table/_dt_elements.html:19
+msgid "Summary"
+msgstr "概况"
+
+#: rhodecode/templates/base/base.html:166
+#: rhodecode/templates/base/base.html:168
+#: rhodecode/templates/base/base.html:170
+#: rhodecode/templates/changelog/changelog.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:23
+#: rhodecode/templates/data_table/_dt_elements.html:25
+#: rhodecode/templates/data_table/_dt_elements.html:27
+msgid "Changelog"
+msgstr "修改记录"
+
+#: rhodecode/templates/base/base.html:175
+#: rhodecode/templates/base/base.html:177
+#: rhodecode/templates/base/base.html:179
+msgid "Switch to"
+msgstr "切换到"
+
+#: rhodecode/templates/base/base.html:186
+#: rhodecode/templates/base/base.html:188
+#: rhodecode/templates/base/base.html:190
+#: rhodecode/templates/data_table/_dt_elements.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:33
+#: rhodecode/templates/data_table/_dt_elements.html:35
+msgid "Files"
+msgstr "档案"
+
+#: rhodecode/templates/base/base.html:195
+#: rhodecode/templates/base/base.html:199
+msgid "Options"
+msgstr "选项"
+
+#: rhodecode/templates/base/base.html:204
+#: rhodecode/templates/base/base.html:206
+#: rhodecode/templates/base/base.html:227
+msgid "settings"
+msgstr "设置"
+
+#: rhodecode/templates/base/base.html:209
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/forks/fork.html:13
+msgid "fork"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:211
+#: rhodecode/templates/changelog/changelog.html:40
+msgid "Open new pull request"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:213
+msgid "search"
+msgstr "搜索"
+
+#: rhodecode/templates/base/base.html:222
+msgid "repositories groups"
+msgstr "版本库组"
+
+#: rhodecode/templates/base/base.html:224
+msgid "users groups"
+msgstr "用户组"
+
+#: rhodecode/templates/base/base.html:225
+msgid "permissions"
+msgstr "权限"
+
+#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:240
+msgid "Followers"
+msgstr "跟随者"
+
+#: rhodecode/templates/base/base.html:246
+#: rhodecode/templates/base/base.html:248
+msgid "Forks"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:327
+#: rhodecode/templates/base/base.html:329
+#: rhodecode/templates/base/base.html:331
+#: rhodecode/templates/search/search.html:52
+msgid "Search"
+msgstr "搜索"
+
+#: rhodecode/templates/base/root.html:42
+#, fuzzy
+msgid "add another comment"
+msgstr "添加成员"
+
+#: rhodecode/templates/base/root.html:43
+#: rhodecode/templates/journal/journal.html:120
+#: rhodecode/templates/summary/summary.html:57
+msgid "Stop following this repository"
+msgstr "停止跟随该版本库"
+
+#: rhodecode/templates/base/root.html:44
+#: rhodecode/templates/summary/summary.html:61
+msgid "Start following this repository"
+msgstr "开始跟随该版本库"
+
+#: rhodecode/templates/base/root.html:45
+msgid "Group"
+msgstr "组"
+
+#: rhodecode/templates/base/root.html:47
+msgid "search truncated"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:48
+msgid "no matching files"
+msgstr "没有符合的文件"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:5
+#, python-format
+msgid "%s Bookmarks"
+msgstr ""
+
+#: rhodecode/templates/bookmarks/bookmarks.html:39
+#: rhodecode/templates/bookmarks/bookmarks_data.html:8
+#: rhodecode/templates/branches/branches.html:54
+#: rhodecode/templates/tags/tags.html:39
+#: rhodecode/templates/tags/tags_data.html:8
+#, fuzzy
+msgid "Author"
+msgstr "作者"
+
+#: rhodecode/templates/branches/branches.html:5
+#, fuzzy, python-format
+msgid "%s Branches"
+msgstr "分支"
+
+#: rhodecode/templates/branches/branches.html:29
+#, fuzzy
+msgid "Compare branches"
+msgstr "分支"
+
+#: rhodecode/templates/branches/branches.html:57
+#: rhodecode/templates/compare/compare_diff.html:5
+#: rhodecode/templates/compare/compare_diff.html:13
+#, fuzzy
+msgid "Compare"
+msgstr "比较显示"
+
+#: rhodecode/templates/branches/branches_data.html:6
+msgid "name"
+msgstr "名称"
+
+#: rhodecode/templates/branches/branches_data.html:7
+msgid "date"
+msgstr "日期"
+
+#: rhodecode/templates/branches/branches_data.html:8
+#: rhodecode/templates/shortlog/shortlog_data.html:8
+msgid "author"
+msgstr "作者"
+
+#: rhodecode/templates/branches/branches_data.html:9
+#: rhodecode/templates/shortlog/shortlog_data.html:5
+msgid "revision"
+msgstr "修订"
+
+#: rhodecode/templates/branches/branches_data.html:10
+#, fuzzy
+msgid "compare"
+msgstr "比较显示"
+
+#: rhodecode/templates/changelog/changelog.html:6
+#, fuzzy, python-format
+msgid "%s Changelog"
+msgstr "修改记录"
+
+#: rhodecode/templates/changelog/changelog.html:15
+#, python-format
+msgid "showing %d out of %d revision"
+msgid_plural "showing %d out of %d revisions"
+msgstr[0] ""
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:19
+#, python-format
+msgid "compare fork with %s"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:21
+msgid "Compare fork"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:46
+msgid "Show"
+msgstr "显示"
+
+#: rhodecode/templates/changelog/changelog.html:72
+#: rhodecode/templates/summary/summary.html:364
+msgid "show more"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:76
+msgid "Affected number of files, click to show more details"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:89
+#: rhodecode/templates/changeset/changeset.html:38
+#: rhodecode/templates/changeset/changeset_file_comment.html:20
+#: rhodecode/templates/changeset/changeset_range.html:46
+#, fuzzy
+msgid "Changeset status"
+msgstr "变更集"
+
+#: rhodecode/templates/changelog/changelog.html:92
+msgid "Click to open associated pull request"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:102
+#: rhodecode/templates/changeset/changeset.html:78
+msgid "Parent"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:108
+#: rhodecode/templates/changeset/changeset.html:84
+msgid "No parents"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:113
+#: rhodecode/templates/changeset/changeset.html:88
+msgid "merge"
+msgstr "合并"
+
+#: rhodecode/templates/changelog/changelog.html:116
+#: rhodecode/templates/changeset/changeset.html:91
+#: rhodecode/templates/files/files.html:29
+#: rhodecode/templates/files/files_add.html:33
+#: rhodecode/templates/files/files_edit.html:33
+#: rhodecode/templates/shortlog/shortlog_data.html:9
+msgid "branch"
+msgstr "分支"
+
+#: rhodecode/templates/changelog/changelog.html:122
+msgid "bookmark"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:128
+#: rhodecode/templates/changeset/changeset.html:96
+msgid "tag"
+msgstr "标签"
+
+#: rhodecode/templates/changelog/changelog.html:164
+msgid "Show selected changes __S -> __E"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:255
+msgid "There are no changes yet"
+msgstr "没有任何变更"
+
+#: rhodecode/templates/changelog/changelog_details.html:4
+#: rhodecode/templates/changeset/changeset.html:66
+msgid "removed"
+msgstr "移除"
+
+#: rhodecode/templates/changelog/changelog_details.html:5
+#: rhodecode/templates/changeset/changeset.html:67
+msgid "changed"
+msgstr "修改"
+
+#: rhodecode/templates/changelog/changelog_details.html:6
+#: rhodecode/templates/changeset/changeset.html:68
+msgid "added"
+msgstr "添加"
+
+#: rhodecode/templates/changelog/changelog_details.html:8
+#: rhodecode/templates/changelog/changelog_details.html:9
+#: rhodecode/templates/changelog/changelog_details.html:10
+#: rhodecode/templates/changeset/changeset.html:70
+#: rhodecode/templates/changeset/changeset.html:71
+#: rhodecode/templates/changeset/changeset.html:72
+#, python-format
+msgid "affected %s files"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset.html:6
+#, fuzzy, python-format
+msgid "%s Changeset"
+msgstr "无变更"
+
+#: rhodecode/templates/changeset/changeset.html:14
+msgid "Changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset.html:43
+#: rhodecode/templates/changeset/diff_block.html:20
+msgid "raw diff"
+msgstr "原始 diff"
+
+#: rhodecode/templates/changeset/changeset.html:44
+#: rhodecode/templates/changeset/diff_block.html:21
+msgid "download diff"
+msgstr "下载 diff"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, fuzzy, python-format
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] "提交"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, python-format
+msgid "(%d inline)"
+msgid_plural "(%d inline)"
+msgstr[0] ""
+
+#: rhodecode/templates/changeset/changeset.html:103
+#, python-format
+msgid "%s files affected with %s insertions and %s deletions:"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset.html:119
+msgid "Changeset was too big and was cut off..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:42
+msgid "Submitting..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:45
+msgid "Commenting on line {1}."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:46
+#: rhodecode/templates/changeset/changeset_file_comment.html:121
+#, python-format
+msgid "Comments parsed using %s syntax with %s support."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:123
+msgid "Use @username inside this text to send notification to this RhodeCode user"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:59
+#: rhodecode/templates/changeset/changeset_file_comment.html:138
+#, fuzzy
+msgid "Comment"
+msgstr "提交"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:60
+#: rhodecode/templates/changeset/changeset_file_comment.html:71
+msgid "Hide"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+#, fuzzy
+msgid "You need to be logged in to comment."
+msgstr "必须登录才能访问该页面"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "Login now"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:118
+msgid "Leave a comment"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "Check this to change current status of code-review for this changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+#, fuzzy
+msgid "change status"
+msgstr "变更集"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:140
+msgid "Comment and close"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:5
+#, fuzzy, python-format
+msgid "%s Changesets"
+msgstr "变更集"
+
+#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/templates/compare/compare_diff.html:29
+msgid "Compare View"
+msgstr "比较显示"
+
+#: rhodecode/templates/changeset/changeset_range.html:54
+#: rhodecode/templates/compare/compare_diff.html:41
+#: rhodecode/templates/pullrequests/pullrequest_show.html:69
+msgid "Files affected"
+msgstr ""
+
+#: rhodecode/templates/changeset/diff_block.html:19
+msgid "diff"
+msgstr ""
+
+#: rhodecode/templates/changeset/diff_block.html:27
+#, fuzzy
+msgid "show inline comments"
+msgstr "文件内容"
+
+#: rhodecode/templates/compare/compare_cs.html:5
+#, fuzzy
+msgid "No changesets"
+msgstr "尚无修订"
+
+#: rhodecode/templates/compare/compare_diff.html:37
+#, fuzzy
+msgid "Outgoing changesets"
+msgstr "尚无修订"
+
+#: rhodecode/templates/data_table/_dt_elements.html:39
+#: rhodecode/templates/data_table/_dt_elements.html:41
+#: rhodecode/templates/data_table/_dt_elements.html:43
+msgid "Fork"
+msgstr "分支"
+
+#: rhodecode/templates/data_table/_dt_elements.html:60
+#: rhodecode/templates/journal/journal.html:126
+#: rhodecode/templates/summary/summary.html:68
+msgid "Mercurial repository"
+msgstr "Mercurial 版本库"
+
+#: rhodecode/templates/data_table/_dt_elements.html:62
+#: rhodecode/templates/journal/journal.html:128
+#: rhodecode/templates/summary/summary.html:71
+msgid "Git repository"
+msgstr "Git 版本库"
+
+#: rhodecode/templates/data_table/_dt_elements.html:69
+#: rhodecode/templates/journal/journal.html:134
+#: rhodecode/templates/summary/summary.html:78
+msgid "public repository"
+msgstr "公共版本库"
+
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/summary/summary.html:87
+#: rhodecode/templates/summary/summary.html:88
+msgid "Fork of"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:92
+msgid "No changesets yet"
+msgstr "尚无修订"
+
+#: rhodecode/templates/data_table/_dt_elements.html:104
+#, fuzzy, python-format
+msgid "Confirm to delete this user: %s"
+msgstr "确认删除该用户"
+
+#: rhodecode/templates/email_templates/main.html:8
+msgid "This is an notification from RhodeCode."
+msgstr ""
+
+#: rhodecode/templates/errors/error_document.html:46
+#, python-format
+msgid "You will be redirected to %s in %s seconds"
+msgstr ""
+
+#: rhodecode/templates/files/file_diff.html:4
+#, fuzzy, python-format
+msgid "%s File diff"
+msgstr "文件 diff"
+
+#: rhodecode/templates/files/file_diff.html:12
+msgid "File diff"
+msgstr "文件 diff"
+
+#: rhodecode/templates/files/files.html:4
+#: rhodecode/templates/files/files.html:72
+#, fuzzy, python-format
+msgid "%s files"
+msgstr "文件"
+
+#: rhodecode/templates/files/files.html:12
+#: rhodecode/templates/summary/summary.html:340
+msgid "files"
+msgstr "文件"
+
+#: rhodecode/templates/files/files_add.html:4
+#: rhodecode/templates/files/files_edit.html:4
+#, fuzzy, python-format
+msgid "%s Edit file"
+msgstr "编辑文件"
+
+#: rhodecode/templates/files/files_add.html:19
+#, fuzzy
+msgid "add file"
+msgstr "编辑文件"
+
+#: rhodecode/templates/files/files_add.html:40
+#, fuzzy
+msgid "Add new file"
+msgstr "添加新用户"
+
+#: rhodecode/templates/files/files_add.html:45
+#, fuzzy
+msgid "File Name"
+msgstr "文件名"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:58
+#, fuzzy
+msgid "or"
+msgstr "时"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:54
+#, fuzzy
+msgid "Upload file"
+msgstr "编辑文件"
+
+#: rhodecode/templates/files/files_add.html:58
+#, fuzzy
+msgid "Create new file"
+msgstr "创建用户 %s"
+
+#: rhodecode/templates/files/files_add.html:63
+#: rhodecode/templates/files/files_edit.html:39
+#: rhodecode/templates/files/files_ypjax.html:3
+msgid "Location"
+msgstr "位置"
+
+#: rhodecode/templates/files/files_add.html:67
+msgid "use / to separate directories"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:77
+#: rhodecode/templates/files/files_edit.html:63
+#: rhodecode/templates/shortlog/shortlog_data.html:6
+msgid "commit message"
+msgstr "提交信息"
+
+#: rhodecode/templates/files/files_add.html:81
+#: rhodecode/templates/files/files_edit.html:67
+msgid "Commit changes"
+msgstr "提交修改"
+
+#: rhodecode/templates/files/files_browser.html:13
+msgid "view"
+msgstr "显示"
+
+#: rhodecode/templates/files/files_browser.html:14
+msgid "previous revision"
+msgstr "上一个修订"
+
+#: rhodecode/templates/files/files_browser.html:16
+msgid "next revision"
+msgstr "下一个修订"
+
+#: rhodecode/templates/files/files_browser.html:23
+msgid "follow current branch"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:27
+msgid "search file list"
+msgstr "搜索文件列表"
+
+#: rhodecode/templates/files/files_browser.html:31
+#: rhodecode/templates/shortlog/shortlog_data.html:65
+#, fuzzy
+msgid "add new file"
+msgstr "添加新用户"
+
+#: rhodecode/templates/files/files_browser.html:35
+msgid "Loading file list..."
+msgstr "加载文件列表..."
+
+#: rhodecode/templates/files/files_browser.html:48
+msgid "Size"
+msgstr "大小"
+
+#: rhodecode/templates/files/files_browser.html:49
+msgid "Mimetype"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:50
+#, fuzzy
+msgid "Last Revision"
+msgstr "下一个修订"
+
+#: rhodecode/templates/files/files_browser.html:51
+msgid "Last modified"
+msgstr "最后修改"
+
+#: rhodecode/templates/files/files_browser.html:52
+msgid "Last commiter"
+msgstr "最后提交"
+
+#: rhodecode/templates/files/files_edit.html:19
+msgid "edit file"
+msgstr "编辑文件"
+
+#: rhodecode/templates/files/files_edit.html:49
+#: rhodecode/templates/files/files_source.html:38
+msgid "show annotation"
+msgstr "显示注释"
+
+#: rhodecode/templates/files/files_edit.html:50
+#: rhodecode/templates/files/files_source.html:40
+#: rhodecode/templates/files/files_source.html:68
+msgid "show as raw"
+msgstr "显示原始文件"
+
+#: rhodecode/templates/files/files_edit.html:51
+#: rhodecode/templates/files/files_source.html:41
+msgid "download as raw"
+msgstr "下载原始文件"
+
+#: rhodecode/templates/files/files_edit.html:54
+#, fuzzy
+msgid "source"
+msgstr "显示代码"
+
+#: rhodecode/templates/files/files_edit.html:59
+#, fuzzy
+msgid "Editing file"
+msgstr "编辑文件"
+
+#: rhodecode/templates/files/files_source.html:2
+msgid "History"
+msgstr "历史"
+
+#: rhodecode/templates/files/files_source.html:9
+#, fuzzy
+msgid "diff to revision"
+msgstr "下一个修订"
+
+#: rhodecode/templates/files/files_source.html:10
+#, fuzzy
+msgid "show at revision"
+msgstr "下一个修订"
+
+#: rhodecode/templates/files/files_source.html:14
+#, fuzzy, python-format
+msgid "%s author"
+msgid_plural "%s authors"
+msgstr[0] "作者"
+
+#: rhodecode/templates/files/files_source.html:36
+msgid "show source"
+msgstr "显示代码"
+
+#: rhodecode/templates/files/files_source.html:59
+#, python-format
+msgid "Binary file (%s)"
+msgstr "二进制文件(%s)"
+
+#: rhodecode/templates/files/files_source.html:68
+msgid "File is too big to display"
+msgstr "文件过大,不能显示"
+
+#: rhodecode/templates/files/files_source.html:124
+msgid "Selection link"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:5
+#, fuzzy
+msgid "annotation"
+msgstr "显示注释"
+
+#: rhodecode/templates/files/files_ypjax.html:15
+msgid "Go back"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:16
+msgid "No files at given path"
+msgstr ""
+
+#: rhodecode/templates/followers/followers.html:5
+#, fuzzy, python-format
+msgid "%s Followers"
+msgstr "跟随者"
+
+#: rhodecode/templates/followers/followers.html:13
+msgid "followers"
+msgstr "跟随者"
+
+#: rhodecode/templates/followers/followers_data.html:12
+#, fuzzy
+msgid "Started following -"
+msgstr "开始跟随"
+
+#: rhodecode/templates/forks/fork.html:5
+#, fuzzy, python-format
+msgid "%s Fork"
+msgstr "分支"
+
+#: rhodecode/templates/forks/fork.html:31
+msgid "Fork name"
+msgstr "分支名"
+
+#: rhodecode/templates/forks/fork.html:68
+msgid "Private"
+msgstr "私有"
+
+#: rhodecode/templates/forks/fork.html:77
+#, fuzzy
+msgid "Copy permissions"
+msgstr "权限"
+
+#: rhodecode/templates/forks/fork.html:81
+msgid "Copy permissions from forked repository"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:86
+msgid "Update after clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:90
+msgid "Checkout source after making a clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:94
+msgid "fork this repository"
+msgstr "对该版本库建立分支"
+
+#: rhodecode/templates/forks/forks.html:5
+#, fuzzy, python-format
+msgid "%s Forks"
+msgstr "分支"
+
+#: rhodecode/templates/forks/forks.html:13
+msgid "forks"
+msgstr "分支"
+
+#: rhodecode/templates/forks/forks_data.html:17
+msgid "forked"
+msgstr "已有分支"
+
+#: rhodecode/templates/forks/forks_data.html:38
+msgid "There are no forks yet"
+msgstr "尚未有任何分支"
+
+#: rhodecode/templates/journal/journal.html:13
+#, fuzzy
+msgid "ATOM journal feed"
+msgstr "公共日志 %s %s 订阅"
+
+#: rhodecode/templates/journal/journal.html:14
+#, fuzzy
+msgid "RSS journal feed"
+msgstr "公共日志 %s %s 订阅"
+
+#: rhodecode/templates/journal/journal.html:24
+#: rhodecode/templates/pullrequests/pullrequest.html:27
+msgid "Refresh"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:27
+#: rhodecode/templates/journal/public_journal.html:24
+#, fuzzy
+msgid "RSS feed"
+msgstr "%s %s 订阅"
+
+#: rhodecode/templates/journal/journal.html:30
+#: rhodecode/templates/journal/public_journal.html:27
+msgid "ATOM feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:41
+#, fuzzy
+msgid "Watched"
+msgstr "缓存"
+
+#: rhodecode/templates/journal/journal.html:46
+#, fuzzy
+msgid "ADD"
+msgstr "新增"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "following user"
+msgstr "跟随中用户"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "user"
+msgstr "用户"
+
+#: rhodecode/templates/journal/journal.html:147
+msgid "You are not following any users or repositories"
+msgstr "尚未跟随任何用户或版本库"
+
+#: rhodecode/templates/journal/journal_data.html:47
+msgid "No entries yet"
+msgstr ""
+
+#: rhodecode/templates/journal/public_journal.html:13
+#, fuzzy
+msgid "ATOM public journal feed"
+msgstr "公共日志 %s %s 订阅"
+
+#: rhodecode/templates/journal/public_journal.html:14
+#, fuzzy
+msgid "RSS public journal feed"
+msgstr "公共日志 %s %s 订阅"
+
+#: rhodecode/templates/journal/public_journal.html:21
+msgid "Public Journal"
+msgstr "公共日志"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:4
+#: rhodecode/templates/pullrequests/pullrequest.html:12
+msgid "New pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:28
+msgid "refresh overview"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:66
+#, fuzzy
+msgid "Detailed compare view"
+msgstr "比较显示"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:70
+#: rhodecode/templates/pullrequests/pullrequest_show.html:82
+msgid "Pull request reviewers"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:79
+#: rhodecode/templates/pullrequests/pullrequest_show.html:94
+#, fuzzy
+msgid "owner"
+msgstr "所有者"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:91
+#: rhodecode/templates/pullrequests/pullrequest_show.html:109
+msgid "Add reviewer to this pull request."
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:97
+#, fuzzy
+msgid "Create new pull request"
+msgstr "创建用户 %s"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:106
+#: rhodecode/templates/pullrequests/pullrequest_show.html:25
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:33
+#, fuzzy
+msgid "Title"
+msgstr "写"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:115
+#, fuzzy
+msgid "description"
+msgstr "描述"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:123
+msgid "Send pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:23
+#, python-format
+msgid "Closed %s"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:31
+#, fuzzy
+msgid "Status"
+msgstr "变更集"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:36
+msgid "Pull request status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:44
+msgid "Still not reviewed by"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:47
+#, python-format
+msgid "%d reviewer"
+msgid_plural "%d reviewers"
+msgstr[0] ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:54
+#, fuzzy
+msgid "Created on"
+msgstr "创建用户 %s"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:61
+#, fuzzy
+msgid "Compare view"
+msgstr "比较显示"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:65
+#, fuzzy
+msgid "Incoming changesets"
+msgstr "尚无修订"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4
+#, fuzzy
+msgid "all pull requests"
+msgstr "创建用户 %s"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:12
+msgid "All pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:27
+msgid "Closed"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:6
+#, fuzzy, python-format
+msgid "Search \"%s\" in repository: %s"
+msgstr "在版本库:"
+
+#: rhodecode/templates/search/search.html:8
+#, fuzzy, python-format
+msgid "Search \"%s\" in all repositories"
+msgstr "在所有的版本库"
+
+#: rhodecode/templates/search/search.html:12
+#: rhodecode/templates/search/search.html:32
+#, fuzzy, python-format
+msgid "Search in repository: %s"
+msgstr "在版本库:"
+
+#: rhodecode/templates/search/search.html:14
+#: rhodecode/templates/search/search.html:34
+#, fuzzy
+msgid "Search in all repositories"
+msgstr "在所有的版本库"
+
+#: rhodecode/templates/search/search.html:48
+msgid "Search term"
+msgstr "搜索短语"
+
+#: rhodecode/templates/search/search.html:60
+msgid "Search in"
+msgstr "搜索范围"
+
+#: rhodecode/templates/search/search.html:63
+msgid "File contents"
+msgstr "文件内容"
+
+#: rhodecode/templates/search/search.html:64
+#, fuzzy
+msgid "Commit messages"
+msgstr "提交信息"
+
+#: rhodecode/templates/search/search.html:65
+msgid "File names"
+msgstr "文件名"
+
+#: rhodecode/templates/search/search_commit.html:35
+#: rhodecode/templates/search/search_content.html:21
+#: rhodecode/templates/search/search_path.html:15
+msgid "Permission denied"
+msgstr "权限不足"
+
+#: rhodecode/templates/settings/repo_settings.html:5
+#, fuzzy, python-format
+msgid "%s Settings"
+msgstr "设置"
+
+#: rhodecode/templates/shortlog/shortlog.html:5
+#, fuzzy, python-format
+msgid "%s Shortlog"
+msgstr "简短日志"
+
+#: rhodecode/templates/shortlog/shortlog.html:14
+msgid "shortlog"
+msgstr "简短日志"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:7
+msgid "age"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:18
+#, fuzzy
+msgid "No commit message"
+msgstr "提交信息"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:62
+msgid "Add or upload files directly via RhodeCode"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:71
+msgid "Push new repo"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:79
+#, fuzzy
+msgid "Existing repository?"
+msgstr "Git 版本库"
+
+#: rhodecode/templates/summary/summary.html:4
+#, fuzzy, python-format
+msgid "%s Summary"
+msgstr "概要"
+
+#: rhodecode/templates/summary/summary.html:12
+msgid "summary"
+msgstr "概要"
+
+#: rhodecode/templates/summary/summary.html:20
+#, fuzzy, python-format
+msgid "repo %s ATOM feed"
+msgstr "订阅 atom %s"
+
+#: rhodecode/templates/summary/summary.html:21
+#, fuzzy, python-format
+msgid "repo %s RSS feed"
+msgstr "订阅 rss %s"
+
+#: rhodecode/templates/summary/summary.html:49
+#: rhodecode/templates/summary/summary.html:52
+#, fuzzy
+msgid "ATOM"
+msgstr "作者"
+
+#: rhodecode/templates/summary/summary.html:82
+#, fuzzy, python-format
+msgid "Non changable ID %s"
+msgstr "无变更"
+
+#: rhodecode/templates/summary/summary.html:87
+msgid "public"
+msgstr "公共"
+
+#: rhodecode/templates/summary/summary.html:95
+msgid "remote clone"
+msgstr "远程 clone"
+
+#: rhodecode/templates/summary/summary.html:116
+msgid "Contact"
+msgstr "联系方式"
+
+#: rhodecode/templates/summary/summary.html:130
+msgid "Clone url"
+msgstr "clone 地址"
+
+#: rhodecode/templates/summary/summary.html:133
+msgid "Show by Name"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:134
+msgid "Show by ID"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:142
+#, fuzzy
+msgid "Trending files"
+msgstr "编辑文件"
+
+#: rhodecode/templates/summary/summary.html:150
+#: rhodecode/templates/summary/summary.html:166
+#: rhodecode/templates/summary/summary.html:194
+msgid "enable"
+msgstr "启用"
+
+#: rhodecode/templates/summary/summary.html:158
+msgid "Download"
+msgstr "下载"
+
+#: rhodecode/templates/summary/summary.html:162
+msgid "There are no downloads yet"
+msgstr "尚无任何下载"
+
+#: rhodecode/templates/summary/summary.html:164
+msgid "Downloads are disabled for this repository"
+msgstr "这个版本库的下载已经禁用"
+
+#: rhodecode/templates/summary/summary.html:170
+#, fuzzy
+msgid "Download as zip"
+msgstr "下载原始文件"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "Check this to download archive with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:186
+msgid "Commit activity by day / author"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:197
+msgid "Stats gathered: "
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:218
+msgid "Shortlog"
+msgstr "简短日志"
+
+#: rhodecode/templates/summary/summary.html:220
+#, fuzzy
+msgid "Quick start"
+msgstr "快速过滤..."
+
+#: rhodecode/templates/summary/summary.html:233
+#, python-format
+msgid "Readme file at revision '%s'"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:236
+msgid "Permalink to this readme"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:293
+#, python-format
+msgid "Download %s as %s"
+msgstr "下载 %s 作为 %s"
+
+#: rhodecode/templates/summary/summary.html:650
+msgid "commits"
+msgstr "提交"
+
+#: rhodecode/templates/summary/summary.html:651
+msgid "files added"
+msgstr "文件已添加"
+
+#: rhodecode/templates/summary/summary.html:652
+msgid "files changed"
+msgstr "文件已更改"
+
+#: rhodecode/templates/summary/summary.html:653
+msgid "files removed"
+msgstr "文件已删除"
+
+#: rhodecode/templates/summary/summary.html:656
+msgid "commit"
+msgstr "提交"
+
+#: rhodecode/templates/summary/summary.html:657
+msgid "file added"
+msgstr "文件已添加"
+
+#: rhodecode/templates/summary/summary.html:658
+msgid "file changed"
+msgstr "文件已更改"
+
+#: rhodecode/templates/summary/summary.html:659
+msgid "file removed"
+msgstr "文件已删除"
+
+#: rhodecode/templates/tags/tags.html:5
+#, fuzzy, python-format
+msgid "%s Tags"
+msgstr "之前"
+
--- a/rhodecode/i18n/zh_TW/LC_MESSAGES/rhodecode.po	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/i18n/zh_TW/LC_MESSAGES/rhodecode.po	Sun Sep 02 21:19:54 2012 +0200
@@ -1,4 +1,4 @@
-# Translations template for RhodeCode.
+# Chinese (Taiwan) translations for RhodeCode.
 # Copyright (C) 2011 ORGANIZATION
 # This file is distributed under the same license as the RhodeCode project.
 # FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
@@ -7,33 +7,49 @@
 msgstr ""
 "Project-Id-Version: RhodeCode 1.2.0\n"
 "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2011-09-14 15:50-0300\n"
+"POT-Creation-Date: 2012-09-02 20:30+0200\n"
 "PO-Revision-Date: 2012-05-09 22:23+0800\n"
 "Last-Translator: Nansen <nansenat16@gmail.com>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: zh_TW <LL@li.org>\n"
+"Plural-Forms: nplurals=1; plural=0\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: Babel 0.9.6\n"
-"X-Poedit-Language: Chinese\n"
-"X-Poedit-Country: TAIWAN\n"
-"X-Poedit-SourceCharset: utf-8\n"
-
-#: rhodecode/controllers/changeset.py:108
-#: rhodecode/controllers/changeset.py:149
-#: rhodecode/controllers/changeset.py:216
-#: rhodecode/controllers/changeset.py:229
+
+#: rhodecode/controllers/changelog.py:94
+#, fuzzy
+msgid "All Branches"
+msgstr "分支"
+
+#: rhodecode/controllers/changeset.py:83
+msgid "show white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:90 rhodecode/controllers/changeset.py:97
+msgid "ignore white space"
+msgstr ""
+
+#: rhodecode/controllers/changeset.py:157
+#, fuzzy, python-format
+msgid "%s line context"
+msgstr "文件內容"
+
+#: rhodecode/controllers/changeset.py:333
+#: rhodecode/controllers/changeset.py:348 rhodecode/lib/diffs.py:70
 msgid "binary file"
 msgstr "二進位檔"
 
-#: rhodecode/controllers/changeset.py:123
-#: rhodecode/controllers/changeset.py:168
-msgid "Changeset is to big and was cut off, see raw changeset instead"
-msgstr ""
-
-#: rhodecode/controllers/changeset.py:159
-msgid "Diff is to big and was cut off, see raw diff instead"
-msgstr ""
+#: rhodecode/controllers/changeset.py:408
+msgid ""
+"Changing status on a changeset associated witha closed pull request is "
+"not allowed"
+msgstr ""
+
+#: rhodecode/controllers/compare.py:69
+#, fuzzy
+msgid "There are no changesets yet"
+msgstr "尚未有任何變更"
 
 #: rhodecode/controllers/error.py:69
 msgid "Home page"
@@ -56,250 +72,313 @@
 msgstr "找不到這個資源"
 
 #: rhodecode/controllers/error.py:107
-msgid "The server encountered an unexpected condition which prevented it from fulfilling the request."
-msgstr ""
-
-#: rhodecode/controllers/feed.py:48
+msgid ""
+"The server encountered an unexpected condition which prevented it from "
+"fulfilling the request."
+msgstr ""
+
+#: rhodecode/controllers/feed.py:49
 #, python-format
 msgid "Changes on %s repository"
 msgstr "修改於版本庫 %s"
 
-#: rhodecode/controllers/feed.py:49
+#: rhodecode/controllers/feed.py:50
 #, python-format
 msgid "%s %s feed"
 msgstr ""
 
-#: rhodecode/controllers/files.py:72
-msgid "There are no files yet"
+#: rhodecode/controllers/feed.py:75
+#, fuzzy
+msgid "commited on"
+msgstr "遞交"
+
+#: rhodecode/controllers/files.py:84
+#, fuzzy
+msgid "click here to add new file"
+msgstr "新增使用者"
+
+#: rhodecode/controllers/files.py:85
+#, fuzzy, python-format
+msgid "There are no files yet %s"
 msgstr "尚未有任何檔案"
 
-#: rhodecode/controllers/files.py:262
+#: rhodecode/controllers/files.py:239 rhodecode/controllers/files.py:299
+#, python-format
+msgid "This repository is has been locked by %s on %s"
+msgstr ""
+
+#: rhodecode/controllers/files.py:266
 #, python-format
 msgid "Edited %s via RhodeCode"
 msgstr "使用 RhodeCode 編輯 %s"
 
-#: rhodecode/controllers/files.py:267
-#: rhodecode/templates/files/file_diff.html:40
+#: rhodecode/controllers/files.py:271
 msgid "No changes"
 msgstr "沒有修改"
 
-#: rhodecode/controllers/files.py:278
+#: rhodecode/controllers/files.py:282 rhodecode/controllers/files.py:346
 #, python-format
 msgid "Successfully committed to %s"
 msgstr "成功遞交至 %s"
 
-#: rhodecode/controllers/files.py:283
+#: rhodecode/controllers/files.py:287 rhodecode/controllers/files.py:352
 msgid "Error occurred during commit"
 msgstr ""
 
-#: rhodecode/controllers/files.py:308
+#: rhodecode/controllers/files.py:318
+#, fuzzy, python-format
+msgid "Added %s via RhodeCode"
+msgstr "使用 RhodeCode 編輯 %s"
+
+#: rhodecode/controllers/files.py:332
+#, fuzzy
+msgid "No content"
+msgstr "文件內容"
+
+#: rhodecode/controllers/files.py:336
+#, fuzzy
+msgid "No filename"
+msgstr "檔案名稱"
+
+#: rhodecode/controllers/files.py:378
 msgid "downloads disabled"
 msgstr "下載已關閉"
 
-#: rhodecode/controllers/files.py:313
+#: rhodecode/controllers/files.py:389
 #, python-format
 msgid "Unknown revision %s"
 msgstr "未知修訂 %s"
 
-#: rhodecode/controllers/files.py:315
+#: rhodecode/controllers/files.py:391
 msgid "Empty repository"
 msgstr "空的版本庫"
 
-#: rhodecode/controllers/files.py:317
+#: rhodecode/controllers/files.py:393
 msgid "Unknown archive type"
 msgstr "未知的存檔類型"
 
-#: rhodecode/controllers/files.py:385
-#: rhodecode/controllers/files.py:398
-msgid "Binary file"
-msgstr "二進位檔"
-
-#: rhodecode/controllers/files.py:417
-#: rhodecode/templates/changeset/changeset_range.html:4
-#: rhodecode/templates/changeset/changeset_range.html:12
-#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/controllers/files.py:494
+#: rhodecode/templates/changeset/changeset_range.html:13
+#: rhodecode/templates/changeset/changeset_range.html:31
 msgid "Changesets"
 msgstr "變更"
 
-#: rhodecode/controllers/files.py:418
-#: rhodecode/controllers/summary.py:175
-#: rhodecode/templates/branches/branches.html:5
-#: rhodecode/templates/summary/summary.html:690
+#: rhodecode/controllers/files.py:495 rhodecode/controllers/pullrequests.py:72
+#: rhodecode/controllers/summary.py:232 rhodecode/model/scm.py:543
 msgid "Branches"
 msgstr "分支"
 
-#: rhodecode/controllers/files.py:419
-#: rhodecode/controllers/summary.py:176
-#: rhodecode/templates/summary/summary.html:679
-#: rhodecode/templates/tags/tags.html:5
+#: rhodecode/controllers/files.py:496 rhodecode/controllers/pullrequests.py:76
+#: rhodecode/controllers/summary.py:233 rhodecode/model/scm.py:554
 msgid "Tags"
 msgstr "標籤"
 
-#: rhodecode/controllers/journal.py:50
+#: rhodecode/controllers/forks.py:73 rhodecode/controllers/admin/repos.py:90
+#, python-format
+msgid ""
+"%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"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:133 rhodecode/controllers/settings.py:72
+#, python-format
+msgid ""
+"%s repository is not mapped to db perhaps it was created or renamed from "
+"the file system please run the application again in order to rescan "
+"repositories"
+msgstr ""
+
+#: rhodecode/controllers/forks.py:167
 #, python-format
-msgid "%s public journal %s feed"
-msgstr "%s 公開日誌 %s feed"
-
-#: rhodecode/controllers/journal.py:178
-#: rhodecode/controllers/journal.py:212
-#: rhodecode/templates/admin/repos/repo_edit.html:171
-#: rhodecode/templates/base/base.html:50
-msgid "Public journal"
+msgid "forked %s repository as %s"
+msgstr "forked %s 版本庫為 %s"
+
+#: rhodecode/controllers/forks.py:181
+#, python-format
+msgid "An error occurred during repository forking %s"
+msgstr ""
+
+#: rhodecode/controllers/journal.py:202 rhodecode/controllers/journal.py:239
+#, fuzzy
+msgid "public journal"
 msgstr "公開日誌"
 
-#: rhodecode/controllers/login.py:111
+#: rhodecode/controllers/journal.py:206 rhodecode/controllers/journal.py:243
+#: rhodecode/templates/base/base.html:220
+msgid "journal"
+msgstr "日誌"
+
+#: rhodecode/controllers/login.py:143
 msgid "You have successfully registered into rhodecode"
 msgstr "您已經成功註冊rhodecode"
 
-#: rhodecode/controllers/login.py:133
+#: rhodecode/controllers/login.py:164
 msgid "Your password reset link was sent"
 msgstr "您的密碼重設連結已寄出"
 
-#: rhodecode/controllers/login.py:155
-msgid "Your password reset was successful, new password has been sent to your email"
+#: rhodecode/controllers/login.py:184
+msgid ""
+"Your password reset was successful, new password has been sent to your "
+"email"
 msgstr "您的密碼重設動作已完成,新的密碼已寄至您的信箱"
 
-#: rhodecode/controllers/search.py:109
+#: rhodecode/controllers/pullrequests.py:74 rhodecode/model/scm.py:549
+msgid "Bookmarks"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:158
+msgid "Pull request requires a title with min. 3 chars"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:160
+#, fuzzy
+msgid "error during creation of pull request"
+msgstr "建立使用者 %s"
+
+#: rhodecode/controllers/pullrequests.py:181
+#, fuzzy
+msgid "Successfully opened new pull request"
+msgstr "成功刪除使用者"
+
+#: rhodecode/controllers/pullrequests.py:184
+msgid "Error occurred during sending pull request"
+msgstr ""
+
+#: rhodecode/controllers/pullrequests.py:217
+#, fuzzy
+msgid "Successfully deleted pull request"
+msgstr "成功刪除使用者"
+
+#: rhodecode/controllers/search.py:131
 msgid "Invalid search query. Try quoting it."
 msgstr "無效的查詢。請使用跳脫字元"
 
-#: rhodecode/controllers/search.py:114
+#: rhodecode/controllers/search.py:136
 msgid "There is no index to search in. Please run whoosh indexer"
 msgstr "沒有任何索引可以搜尋。請執行 whoosh 建立索引"
 
-#: rhodecode/controllers/search.py:118
+#: rhodecode/controllers/search.py:140
 msgid "An error occurred during this search operation"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:61
-#: rhodecode/controllers/settings.py:171
-#, python-format
-msgid "%s repository is not mapped to db perhaps it was created or renamed from the file system please run the application again in order to rescan repositories"
-msgstr ""
-
-#: rhodecode/controllers/settings.py:109
-#: rhodecode/controllers/admin/repos.py:239
+#: rhodecode/controllers/settings.py:107
+#: rhodecode/controllers/admin/repos.py:266
 #, python-format
 msgid "Repository %s updated successfully"
 msgstr "版本庫 %s 更新完成"
 
-#: rhodecode/controllers/settings.py:126
-#: rhodecode/controllers/admin/repos.py:257
+#: rhodecode/controllers/settings.py:125
+#: rhodecode/controllers/admin/repos.py:284
 #, python-format
 msgid "error occurred during update of repository %s"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:144
-#: rhodecode/controllers/admin/repos.py:275
+#: rhodecode/controllers/settings.py:143
+#: rhodecode/controllers/admin/repos.py:302
 #, python-format
-msgid "%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"
-msgstr ""
-
-#: rhodecode/controllers/settings.py:156
-#: rhodecode/controllers/admin/repos.py:287
+msgid ""
+"%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"
+msgstr ""
+
+#: rhodecode/controllers/settings.py:155
+#: rhodecode/controllers/admin/repos.py:314
 #, python-format
 msgid "deleted repository %s"
 msgstr "刪除版本庫 %s"
 
 #: rhodecode/controllers/settings.py:159
-#: rhodecode/controllers/admin/repos.py:297
-#: rhodecode/controllers/admin/repos.py:303
+#: rhodecode/controllers/admin/repos.py:324
+#: rhodecode/controllers/admin/repos.py:330
 #, python-format
 msgid "An error occurred during deletion of %s"
 msgstr ""
 
-#: rhodecode/controllers/settings.py:193
-#, python-format
-msgid "forked %s repository as %s"
-msgstr "forked %s 版本庫為 %s"
-
-#: rhodecode/controllers/settings.py:211
-#, python-format
-msgid "An error occurred during repository forking %s"
-msgstr ""
-
-#: rhodecode/controllers/summary.py:123
+#: rhodecode/controllers/summary.py:138
 msgid "No data loaded yet"
 msgstr ""
 
-#: rhodecode/controllers/summary.py:126
+#: rhodecode/controllers/summary.py:142
+#: rhodecode/templates/summary/summary.html:148
 msgid "Statistics are disabled for this repository"
 msgstr "這個版本庫的統計功能已停用"
 
-#: rhodecode/controllers/admin/ldap_settings.py:49
+#: rhodecode/controllers/admin/ldap_settings.py:50
 msgid "BASE"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:50
-msgid "ONELEVEL"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:51
+msgid "ONELEVEL"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:52
 msgid "SUBTREE"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:55
-msgid "NEVER"
-msgstr ""
-
 #: rhodecode/controllers/admin/ldap_settings.py:56
-msgid "ALLOW"
+msgid "NEVER"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:57
-msgid "TRY"
+msgid "ALLOW"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:58
-msgid "DEMAND"
+msgid "TRY"
 msgstr ""
 
 #: rhodecode/controllers/admin/ldap_settings.py:59
+msgid "DEMAND"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:60
 msgid "HARD"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:63
-msgid "No encryption"
-msgstr "無加密"
-
 #: rhodecode/controllers/admin/ldap_settings.py:64
-msgid "LDAPS connection"
-msgstr ""
+msgid "No encryption"
+msgstr "無加密"
 
 #: rhodecode/controllers/admin/ldap_settings.py:65
+msgid "LDAPS connection"
+msgstr ""
+
+#: rhodecode/controllers/admin/ldap_settings.py:66
 msgid "START_TLS on LDAP connection"
 msgstr ""
 
-#: rhodecode/controllers/admin/ldap_settings.py:115
+#: rhodecode/controllers/admin/ldap_settings.py:126
 msgid "Ldap settings updated successfully"
 msgstr "LDAP設定更新完成"
 
-#: rhodecode/controllers/admin/ldap_settings.py:120
+#: rhodecode/controllers/admin/ldap_settings.py:130
 msgid "Unable to activate ldap. The \"python-ldap\" library is missing."
 msgstr "無法啟用LDAP。找不到python-ldap函式庫"
 
-#: rhodecode/controllers/admin/ldap_settings.py:134
+#: rhodecode/controllers/admin/ldap_settings.py:147
 msgid "error occurred during update of ldap settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/permissions.py:56
+#: rhodecode/controllers/admin/permissions.py:59
 msgid "None"
 msgstr "無"
 
-#: rhodecode/controllers/admin/permissions.py:57
+#: rhodecode/controllers/admin/permissions.py:60
 msgid "Read"
 msgstr "讀"
 
-#: rhodecode/controllers/admin/permissions.py:58
+#: rhodecode/controllers/admin/permissions.py:61
 msgid "Write"
 msgstr "寫"
 
-#: rhodecode/controllers/admin/permissions.py:59
+#: rhodecode/controllers/admin/permissions.py:62
 #: rhodecode/templates/admin/ldap/ldap.html:9
 #: rhodecode/templates/admin/permissions/permissions.html:9
 #: rhodecode/templates/admin/repos/repo_add.html:9
 #: rhodecode/templates/admin/repos/repo_edit.html:9
-#: rhodecode/templates/admin/repos/repos.html:10
+#: rhodecode/templates/admin/repos/repos.html:9
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:8
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
@@ -307,547 +386,900 @@
 #: rhodecode/templates/admin/settings/settings.html:9
 #: rhodecode/templates/admin/users/user_add.html:8
 #: rhodecode/templates/admin/users/user_edit.html:9
-#: rhodecode/templates/admin/users/user_edit.html:110
+#: rhodecode/templates/admin/users/user_edit.html:122
 #: rhodecode/templates/admin/users/users.html:9
 #: rhodecode/templates/admin/users_groups/users_group_add.html:8
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:9
 #: rhodecode/templates/admin/users_groups/users_groups.html:9
-#: rhodecode/templates/base/base.html:279
-#: rhodecode/templates/base/base.html:366
-#: rhodecode/templates/base/base.html:368
-#: rhodecode/templates/base/base.html:370
+#: rhodecode/templates/base/base.html:197
+#: rhodecode/templates/base/base.html:337
+#: rhodecode/templates/base/base.html:339
+#: rhodecode/templates/base/base.html:341
 msgid "Admin"
 msgstr "管理"
 
-#: rhodecode/controllers/admin/permissions.py:62
+#: rhodecode/controllers/admin/permissions.py:65
 msgid "disabled"
 msgstr "停用"
 
-#: rhodecode/controllers/admin/permissions.py:64
+#: rhodecode/controllers/admin/permissions.py:67
 msgid "allowed with manual account activation"
 msgstr "允許手動啟用帳號"
 
-#: rhodecode/controllers/admin/permissions.py:66
+#: rhodecode/controllers/admin/permissions.py:69
 msgid "allowed with automatic account activation"
 msgstr "允許自動啟用帳號"
 
-#: rhodecode/controllers/admin/permissions.py:68
+#: rhodecode/controllers/admin/permissions.py:71
+#: rhodecode/controllers/admin/permissions.py:74
 msgid "Disabled"
 msgstr "停用"
 
-#: rhodecode/controllers/admin/permissions.py:69
+#: rhodecode/controllers/admin/permissions.py:72
+#: rhodecode/controllers/admin/permissions.py:75
 msgid "Enabled"
 msgstr "啟用"
 
-#: rhodecode/controllers/admin/permissions.py:102
+#: rhodecode/controllers/admin/permissions.py:116
 msgid "Default permissions updated successfully"
 msgstr "預設權限更新完成"
 
-#: rhodecode/controllers/admin/permissions.py:119
+#: rhodecode/controllers/admin/permissions.py:130
 msgid "error occurred during update of permissions"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:96
-#, python-format
-msgid "%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"
-msgstr ""
-
-#: rhodecode/controllers/admin/repos.py:172
+#: rhodecode/controllers/admin/repos.py:123
+msgid "--REMOVE FORK--"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:192
 #, python-format
 msgid "created repository %s from %s"
 msgstr "建立版本庫 %s 到 %s"
 
-#: rhodecode/controllers/admin/repos.py:176
+#: rhodecode/controllers/admin/repos.py:196
 #, python-format
 msgid "created repository %s"
 msgstr "建立版本庫 %s"
 
-#: rhodecode/controllers/admin/repos.py:205
+#: rhodecode/controllers/admin/repos.py:227
 #, python-format
 msgid "error occurred during creation of repository %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:292
+#: rhodecode/controllers/admin/repos.py:319
 #, python-format
 msgid "Cannot delete %s it still contains attached forks"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:320
+#: rhodecode/controllers/admin/repos.py:348
 msgid "An error occurred during deletion of repository user"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:335
-msgid "An error occurred during deletion of repository users groups"
-msgstr ""
-
-#: rhodecode/controllers/admin/repos.py:352
-msgid "An error occurred during deletion of repository stats"
-msgstr ""
-
 #: rhodecode/controllers/admin/repos.py:367
+msgid "An error occurred during deletion of repository users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:385
+msgid "An error occurred during deletion of repository stats"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:402
 msgid "An error occurred during cache invalidation"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:387
+#: rhodecode/controllers/admin/repos.py:422
+msgid "An error occurred during unlocking"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:442
 msgid "Updated repository visibility in public journal"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:390
+#: rhodecode/controllers/admin/repos.py:446
 msgid "An error occurred during setting this repository in public journal"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:395
-#: rhodecode/model/forms.py:53
+#: rhodecode/controllers/admin/repos.py:451 rhodecode/model/validators.py:299
 msgid "Token mismatch"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:408
+#: rhodecode/controllers/admin/repos.py:464
 msgid "Pulled from remote location"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos.py:410
+#: rhodecode/controllers/admin/repos.py:466
 msgid "An error occurred during pull from remote location"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:83
+#: rhodecode/controllers/admin/repos.py:482
+msgid "Nothing"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos.py:484
+#, fuzzy, python-format
+msgid "Marked repo %s as fork of %s"
+msgstr "建立版本庫 %s 到 %s"
+
+#: rhodecode/controllers/admin/repos.py:488
+msgid "An error occurred during this operation"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:116
 #, python-format
 msgid "created repos group %s"
 msgstr "建立版本庫群組 %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:96
+#: rhodecode/controllers/admin/repos_groups.py:129
 #, python-format
 msgid "error occurred during creation of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:130
+#: rhodecode/controllers/admin/repos_groups.py:163
 #, python-format
 msgid "updated repos group %s"
 msgstr "更新版本庫群組 %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:143
+#: rhodecode/controllers/admin/repos_groups.py:176
 #, python-format
 msgid "error occurred during update of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:164
+#: rhodecode/controllers/admin/repos_groups.py:194
 #, python-format
 msgid "This group contains %s repositores and cannot be deleted"
 msgstr ""
 
-#: rhodecode/controllers/admin/repos_groups.py:171
+#: rhodecode/controllers/admin/repos_groups.py:202
 #, python-format
 msgid "removed repos group %s"
 msgstr "移除版本庫群組 %s"
 
-#: rhodecode/controllers/admin/repos_groups.py:175
+#: rhodecode/controllers/admin/repos_groups.py:208
+msgid "Cannot delete this group it still contains subgroups"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:213
+#: rhodecode/controllers/admin/repos_groups.py:218
 #, python-format
 msgid "error occurred during deletion of repos group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:109
+#: rhodecode/controllers/admin/repos_groups.py:238
+msgid "An error occurred during deletion of group user"
+msgstr ""
+
+#: rhodecode/controllers/admin/repos_groups.py:258
+msgid "An error occurred during deletion of group users groups"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:121
 #, python-format
 msgid "Repositories successfully rescanned added: %s,removed: %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:118
+#: rhodecode/controllers/admin/settings.py:129
 msgid "Whoosh reindex task scheduled"
 msgstr "Whoosh 重新索引工作排程"
 
-#: rhodecode/controllers/admin/settings.py:143
+#: rhodecode/controllers/admin/settings.py:160
 msgid "Updated application settings"
 msgstr "更新應用設定"
 
-#: rhodecode/controllers/admin/settings.py:148
-#: rhodecode/controllers/admin/settings.py:215
+#: rhodecode/controllers/admin/settings.py:164
+#: rhodecode/controllers/admin/settings.py:275
 msgid "error occurred during updating application settings"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:210
-msgid "Updated mercurial settings"
+#: rhodecode/controllers/admin/settings.py:200
+#, fuzzy
+msgid "Updated visualisation settings"
+msgstr "更新應用設定"
+
+#: rhodecode/controllers/admin/settings.py:205
+msgid "error occurred during updating visualisation settings"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:271
+#, fuzzy
+msgid "Updated VCS settings"
 msgstr "更新 mercurial 設定"
 
-#: rhodecode/controllers/admin/settings.py:236
+#: rhodecode/controllers/admin/settings.py:285
 msgid "Added new hook"
 msgstr "新增hook"
 
-#: rhodecode/controllers/admin/settings.py:247
+#: rhodecode/controllers/admin/settings.py:297
 msgid "Updated hooks"
 msgstr "更新hook"
 
-#: rhodecode/controllers/admin/settings.py:251
+#: rhodecode/controllers/admin/settings.py:301
 msgid "error occurred during hook creation"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:310
+#: rhodecode/controllers/admin/settings.py:320
+msgid "Email task created"
+msgstr ""
+
+#: rhodecode/controllers/admin/settings.py:375
 msgid "You can't edit this user since it's crucial for entire application"
 msgstr ""
 
-#: rhodecode/controllers/admin/settings.py:339
+#: rhodecode/controllers/admin/settings.py:406
 msgid "Your account was updated successfully"
 msgstr "您的帳號已更新完成"
 
-#: rhodecode/controllers/admin/settings.py:359
-#: rhodecode/controllers/admin/users.py:130
+#: rhodecode/controllers/admin/settings.py:421
+#: rhodecode/controllers/admin/users.py:191
 #, python-format
 msgid "error occurred during update of user %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:78
+#: rhodecode/controllers/admin/users.py:130
 #, python-format
 msgid "created user %s"
 msgstr "建立使用者 %s"
 
-#: rhodecode/controllers/admin/users.py:90
+#: rhodecode/controllers/admin/users.py:142
 #, python-format
 msgid "error occurred during creation of user %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:116
+#: rhodecode/controllers/admin/users.py:171
 msgid "User updated successfully"
 msgstr "使用者更新完成"
 
-#: rhodecode/controllers/admin/users.py:146
+#: rhodecode/controllers/admin/users.py:207
 msgid "successfully deleted user"
 msgstr "成功刪除使用者"
 
-#: rhodecode/controllers/admin/users.py:150
+#: rhodecode/controllers/admin/users.py:212
 msgid "An error occurred during deletion of user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:166
+#: rhodecode/controllers/admin/users.py:226
 msgid "You can't edit this user"
 msgstr "您無法編輯這位使用者"
 
-#: rhodecode/controllers/admin/users.py:195
-#: rhodecode/controllers/admin/users_groups.py:202
+#: rhodecode/controllers/admin/users.py:266
 msgid "Granted 'repository create' permission to user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users.py:204
-#: rhodecode/controllers/admin/users_groups.py:211
+#: rhodecode/controllers/admin/users.py:271
 msgid "Revoked 'repository create' permission to user"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:74
+#: rhodecode/controllers/admin/users.py:277
+#, fuzzy
+msgid "Granted 'repository fork' permission to user"
+msgstr "版本庫權限"
+
+#: rhodecode/controllers/admin/users.py:282
+#, fuzzy
+msgid "Revoked 'repository fork' permission to user"
+msgstr "版本庫權限"
+
+#: rhodecode/controllers/admin/users.py:288
+#: rhodecode/controllers/admin/users_groups.py:255
+msgid "An error occurred during permissions saving"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:303
+#, python-format
+msgid "Added email %s to user"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:309
+msgid "An error occurred during email saving"
+msgstr ""
+
+#: rhodecode/controllers/admin/users.py:319
+#, fuzzy
+msgid "Removed email from user"
+msgstr "移除版本庫群組 %s"
+
+#: rhodecode/controllers/admin/users_groups.py:84
 #, python-format
 msgid "created users group %s"
 msgstr "建立使用者群組 %s"
 
-#: rhodecode/controllers/admin/users_groups.py:86
+#: rhodecode/controllers/admin/users_groups.py:95
 #, python-format
 msgid "error occurred during creation of users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:119
+#: rhodecode/controllers/admin/users_groups.py:135
 #, python-format
 msgid "updated users group %s"
 msgstr "更新使用者群組 %s"
 
-#: rhodecode/controllers/admin/users_groups.py:138
+#: rhodecode/controllers/admin/users_groups.py:157
 #, python-format
 msgid "error occurred during update of users group %s"
 msgstr ""
 
-#: rhodecode/controllers/admin/users_groups.py:154
+#: rhodecode/controllers/admin/users_groups.py:174
 msgid "successfully deleted users group"
 msgstr "成功移除使用者群組"
 
-#: rhodecode/controllers/admin/users_groups.py:158
+#: rhodecode/controllers/admin/users_groups.py:179
 msgid "An error occurred during deletion of users group"
 msgstr ""
 
-#: rhodecode/lib/__init__.py:279
-msgid "year"
-msgstr "年"
-
-#: rhodecode/lib/__init__.py:280
-msgid "month"
-msgstr "月"
-
-#: rhodecode/lib/__init__.py:281
-msgid "day"
-msgstr "日"
-
-#: rhodecode/lib/__init__.py:282
-msgid "hour"
-msgstr "時"
-
-#: rhodecode/lib/__init__.py:283
-msgid "minute"
-msgstr "分"
-
-#: rhodecode/lib/__init__.py:284
-msgid "second"
-msgstr "秒"
-
-#: rhodecode/lib/__init__.py:293
-msgid "ago"
-msgstr "之前"
-
-#: rhodecode/lib/__init__.py:296
-msgid "just now"
-msgstr "現在"
-
-#: rhodecode/lib/auth.py:377
+#: rhodecode/controllers/admin/users_groups.py:233
+msgid "Granted 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:238
+msgid "Revoked 'repository create' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:244
+msgid "Granted 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/controllers/admin/users_groups.py:249
+msgid "Revoked 'repository fork' permission to users group"
+msgstr ""
+
+#: rhodecode/lib/auth.py:499
 msgid "You need to be a registered user to perform this action"
 msgstr "您必須是註冊使用者才能執行這個動作"
 
-#: rhodecode/lib/auth.py:421
+#: rhodecode/lib/auth.py:540
 msgid "You need to be a signed in to view this page"
 msgstr "您必須登入後才能瀏覽這個頁面"
 
-#: rhodecode/lib/helpers.py:307
+#: rhodecode/lib/diffs.py:86
+msgid "Changeset was too big and was cut off, use diff menu to display this diff"
+msgstr ""
+
+#: rhodecode/lib/diffs.py:96
+msgid "No changes detected"
+msgstr "尚未有任何變更"
+
+#: rhodecode/lib/helpers.py:372
+#, python-format
+msgid "%a, %d %b %Y %H:%M:%S"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:484
 msgid "True"
 msgstr "真"
 
-#: rhodecode/lib/helpers.py:311
+#: rhodecode/lib/helpers.py:488
 msgid "False"
 msgstr "假"
 
-#: rhodecode/lib/helpers.py:352
+#: rhodecode/lib/helpers.py:532
+#, fuzzy
+msgid "Changeset not found"
+msgstr "修改"
+
+#: rhodecode/lib/helpers.py:555
 #, python-format
 msgid "Show all combined changesets %s->%s"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:356
+#: rhodecode/lib/helpers.py:561
 msgid "compare view"
 msgstr ""
 
-#: rhodecode/lib/helpers.py:365
-msgid "and"
-msgstr "和"
-
-#: rhodecode/lib/helpers.py:365
-#, python-format
-msgid "%s more"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:367
-#: rhodecode/templates/changelog/changelog.html:14
-#: rhodecode/templates/changelog/changelog.html:39
-msgid "revisions"
-msgstr "修訂"
-
-#: rhodecode/lib/helpers.py:385
-msgid "fork name "
-msgstr "fork 名稱"
-
-#: rhodecode/lib/helpers.py:388
-msgid "[deleted] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:389
-#: rhodecode/lib/helpers.py:393
-msgid "[created] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:390
-#: rhodecode/lib/helpers.py:394
-msgid "[forked] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:391
-#: rhodecode/lib/helpers.py:395
-msgid "[updated] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:392
-msgid "[delete] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:396
-msgid "[pushed] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:397
-msgid "[committed via RhodeCode] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:398
-msgid "[pulled from remote] into"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:399
-msgid "[pulled] from"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:400
-msgid "[started following] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:401
-msgid "[stopped following] repository"
-msgstr ""
-
-#: rhodecode/lib/helpers.py:577
-#, python-format
-msgid " and %s more"
-msgstr ""
-
 #: rhodecode/lib/helpers.py:581
+msgid "and"
+msgstr "和"
+
+#: rhodecode/lib/helpers.py:582
+#, python-format
+msgid "%s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:583 rhodecode/templates/changelog/changelog.html:48
+msgid "revisions"
+msgstr "修訂"
+
+#: rhodecode/lib/helpers.py:606
+msgid "fork name "
+msgstr "fork 名稱"
+
+#: rhodecode/lib/helpers.py:620
+#: rhodecode/templates/pullrequests/pullrequest_show.html:4
+#: rhodecode/templates/pullrequests/pullrequest_show.html:12
+#, python-format
+msgid "Pull request #%s"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:626
+msgid "[deleted] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:628 rhodecode/lib/helpers.py:638
+msgid "[created] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:630
+#, fuzzy
+msgid "[created] repository as fork"
+msgstr "建立版本庫 %s"
+
+#: rhodecode/lib/helpers.py:632 rhodecode/lib/helpers.py:640
+msgid "[forked] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:634 rhodecode/lib/helpers.py:642
+msgid "[updated] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:636
+msgid "[delete] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:644
+#, fuzzy
+msgid "[created] user"
+msgstr "建立使用者 %s"
+
+#: rhodecode/lib/helpers.py:646
+#, fuzzy
+msgid "[updated] user"
+msgstr "更新使用者群組 %s"
+
+#: rhodecode/lib/helpers.py:648
+#, fuzzy
+msgid "[created] users group"
+msgstr "建立使用者群組 %s"
+
+#: rhodecode/lib/helpers.py:650
+#, fuzzy
+msgid "[updated] users group"
+msgstr "更新使用者群組 %s"
+
+#: rhodecode/lib/helpers.py:652
+msgid "[commented] on revision in repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:654
+#, fuzzy
+msgid "[commented] on pull request for"
+msgstr "建立使用者 %s"
+
+#: rhodecode/lib/helpers.py:656
+msgid "[closed] pull request for"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:658
+msgid "[pushed] into"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:660
+msgid "[committed via RhodeCode] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:662
+msgid "[pulled from remote] into repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:664
+msgid "[pulled] from"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:666
+msgid "[started following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:668
+msgid "[stopped following] repository"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:840
+#, python-format
+msgid " and %s more"
+msgstr ""
+
+#: rhodecode/lib/helpers.py:844
 msgid "No Files"
 msgstr "沒有檔案"
 
-#: rhodecode/model/forms.py:66
-msgid "Invalid username"
-msgstr "無效的使用者名稱"
-
-#: rhodecode/model/forms.py:75
-msgid "This username already exists"
+#: rhodecode/lib/utils2.py:335
+#, fuzzy, python-format
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] "年"
+
+#: rhodecode/lib/utils2.py:336
+#, fuzzy, python-format
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] "月"
+
+#: rhodecode/lib/utils2.py:337
+#, fuzzy, python-format
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] "日"
+
+#: rhodecode/lib/utils2.py:338
+#, fuzzy, python-format
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] "時"
+
+#: rhodecode/lib/utils2.py:339
+#, fuzzy, python-format
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] "分"
+
+#: rhodecode/lib/utils2.py:340
+#, fuzzy, python-format
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] "秒"
+
+#: rhodecode/lib/utils2.py:355
+#, fuzzy, python-format
+msgid "%s ago"
+msgstr "之前"
+
+#: rhodecode/lib/utils2.py:357
+#, python-format
+msgid "%s and %s ago"
+msgstr ""
+
+#: rhodecode/lib/utils2.py:360
+msgid "just now"
+msgstr "現在"
+
+#: rhodecode/lib/celerylib/tasks.py:269
+#, fuzzy
+msgid "password reset link"
+msgstr "您的密碼重設連結已寄出"
+
+#: rhodecode/model/comment.py:110
+#, python-format
+msgid "on line %s"
+msgstr ""
+
+#: rhodecode/model/comment.py:157
+msgid "[Mention]"
+msgstr ""
+
+#: rhodecode/model/db.py:1140
+#, fuzzy
+msgid "Repository no access"
+msgstr "個版本庫"
+
+#: rhodecode/model/db.py:1141
+#, fuzzy
+msgid "Repository read access"
+msgstr "這個版本庫已經存在"
+
+#: rhodecode/model/db.py:1142
+#, fuzzy
+msgid "Repository write access"
+msgstr "個版本庫"
+
+#: rhodecode/model/db.py:1143
+#, fuzzy
+msgid "Repository admin access"
+msgstr "個版本庫"
+
+#: rhodecode/model/db.py:1145
+#, fuzzy
+msgid "Repositories Group no access"
+msgstr "版本庫群組"
+
+#: rhodecode/model/db.py:1146
+#, fuzzy
+msgid "Repositories Group read access"
+msgstr "版本庫群組"
+
+#: rhodecode/model/db.py:1147
+#, fuzzy
+msgid "Repositories Group write access"
+msgstr "版本庫群組"
+
+#: rhodecode/model/db.py:1148
+#, fuzzy
+msgid "Repositories Group admin access"
+msgstr "版本庫群組"
+
+#: rhodecode/model/db.py:1150
+#, fuzzy
+msgid "RhodeCode Administrator"
+msgstr "使用者管理員"
+
+#: rhodecode/model/db.py:1151
+#, fuzzy
+msgid "Repository creation disabled"
+msgstr "版本庫建立"
+
+#: rhodecode/model/db.py:1152
+#, fuzzy
+msgid "Repository creation enabled"
+msgstr "版本庫建立"
+
+#: rhodecode/model/db.py:1153
+#, fuzzy
+msgid "Repository forking disabled"
+msgstr "版本庫建立"
+
+#: rhodecode/model/db.py:1154
+#, fuzzy
+msgid "Repository forking enabled"
+msgstr "版本庫建立"
+
+#: rhodecode/model/db.py:1155
+#, fuzzy
+msgid "Register disabled"
+msgstr "停用"
+
+#: rhodecode/model/db.py:1156
+msgid "Register new user with RhodeCode with manual activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1159
+msgid "Register new user with RhodeCode with auto activation"
+msgstr ""
+
+#: rhodecode/model/db.py:1579
+msgid "Not Reviewed"
+msgstr ""
+
+#: rhodecode/model/db.py:1580
+#, fuzzy
+msgid "Approved"
+msgstr "移除"
+
+#: rhodecode/model/db.py:1581
+msgid "Rejected"
+msgstr ""
+
+#: rhodecode/model/db.py:1582
+msgid "Under Review"
+msgstr ""
+
+#: rhodecode/model/forms.py:43
+msgid "Please enter a login"
+msgstr "請登入"
+
+#: rhodecode/model/forms.py:44
+#, python-format
+msgid "Enter a value %(min)i characters long or more"
+msgstr ""
+
+#: rhodecode/model/forms.py:52
+msgid "Please enter a password"
+msgstr "請輸入密碼"
+
+#: rhodecode/model/forms.py:53
+#, python-format
+msgid "Enter %(min)i characters or more"
+msgstr ""
+
+#: rhodecode/model/notification.py:220
+msgid "commented on commit"
+msgstr ""
+
+#: rhodecode/model/notification.py:221
+#, fuzzy
+msgid "sent message"
+msgstr "遞交資訊"
+
+#: rhodecode/model/notification.py:222
+msgid "mentioned you"
+msgstr ""
+
+#: rhodecode/model/notification.py:223
+#, fuzzy
+msgid "registered in RhodeCode"
+msgstr "您已經成功註冊rhodecode"
+
+#: rhodecode/model/notification.py:224
+msgid "opened new pull request"
+msgstr ""
+
+#: rhodecode/model/notification.py:225
+msgid "commented on pull request"
+msgstr ""
+
+#: rhodecode/model/pull_request.py:84
+#, python-format
+msgid "%(user)s wants you to review pull request #%(pr_id)s"
+msgstr ""
+
+#: rhodecode/model/scm.py:535
+#, fuzzy
+msgid "latest tip"
+msgstr "最後登入"
+
+#: rhodecode/model/user.py:230
+#, fuzzy
+msgid "new user registration"
+msgstr "[RhodeCode] 新使用者註冊"
+
+#: rhodecode/model/user.py:255 rhodecode/model/user.py:277
+#: rhodecode/model/user.py:299
+msgid "You can't Edit this user since it's crucial for entire application"
+msgstr "您無法編輯這個使用者,因為他是系統帳號"
+
+#: rhodecode/model/user.py:323
+msgid "You can't remove this user since it's crucial for entire application"
+msgstr "您無法移除這個使用者,因為他是系統帳號"
+
+#: rhodecode/model/user.py:329
+#, fuzzy, python-format
+msgid ""
+"user \"%s\" still owns %s repositories and cannot be removed. Switch "
+"owners or remove those repositories. %s"
+msgstr "這個使用者擁有 %s 個版本庫所以無法移除,請先變更版本庫擁有者或者刪除版本庫"
+
+#: rhodecode/model/validators.py:35 rhodecode/model/validators.py:36
+msgid "Value cannot be an empty list"
+msgstr ""
+
+#: rhodecode/model/validators.py:82
+#, fuzzy, python-format
+msgid "Username \"%(username)s\" already exists"
 msgstr "使用者名稱已存在"
 
-#: rhodecode/model/forms.py:79
-msgid "Username may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character"
+#: rhodecode/model/validators.py:84
+#, python-format
+msgid "Username \"%(username)s\" is forbidden"
+msgstr ""
+
+#: rhodecode/model/validators.py:86
+msgid ""
+"Username may only contain alphanumeric characters underscores, periods or"
+" dashes and must begin with alphanumeric character"
 msgstr "使用者名稱只能使用字母數字、底線、小數點或破折號,且必須使用數字或字母開頭"
 
-#: rhodecode/model/forms.py:94
-msgid "Invalid group name"
-msgstr "無效的群組名稱"
-
-#: rhodecode/model/forms.py:104
-msgid "This users group already exists"
+#: rhodecode/model/validators.py:114
+#, fuzzy, python-format
+msgid "Username %(username)s is not valid"
+msgstr "使用者名稱或群組名稱無效"
+
+#: rhodecode/model/validators.py:133
+#, fuzzy
+msgid "Invalid users group name"
+msgstr "無效的使用者名稱"
+
+#: rhodecode/model/validators.py:134
+#, fuzzy, python-format
+msgid "Users group \"%(usersgroup)s\" already exists"
 msgstr "這個使用者群組已存在"
 
-#: rhodecode/model/forms.py:110
-msgid "Group name may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character"
+#: rhodecode/model/validators.py:136
+msgid ""
+"users group name may only contain  alphanumeric characters underscores, "
+"periods or dashes and must begin with alphanumeric character"
 msgstr "群組名稱只能使用字母數字、底線、小數點或破折號,且必須使用數字或字母開頭"
 
-#: rhodecode/model/forms.py:132
+#: rhodecode/model/validators.py:174
 msgid "Cannot assign this group as parent"
 msgstr ""
 
-#: rhodecode/model/forms.py:148
-msgid "This group already exists"
-msgstr "這個群組已存在"
-
-#: rhodecode/model/forms.py:164
-#: rhodecode/model/forms.py:172
-#: rhodecode/model/forms.py:180
-msgid "Invalid characters in password"
+#: rhodecode/model/validators.py:175
+#, fuzzy, python-format
+msgid "Group \"%(group_name)s\" already exists"
+msgstr "使用者名稱已存在"
+
+#: rhodecode/model/validators.py:177
+#, fuzzy, python-format
+msgid "Repository with name \"%(group_name)s\" already exists"
+msgstr "這個版本庫已經存在"
+
+#: rhodecode/model/validators.py:235
+#, fuzzy
+msgid "Invalid characters (non-ascii) in password"
 msgstr "無效的字元在密碼中"
 
-#: rhodecode/model/forms.py:191
+#: rhodecode/model/validators.py:250
 msgid "Passwords do not match"
 msgstr "密碼不相符"
 
-#: rhodecode/model/forms.py:196
+#: rhodecode/model/validators.py:267
 msgid "invalid password"
 msgstr "無效的密碼"
 
-#: rhodecode/model/forms.py:197
+#: rhodecode/model/validators.py:268
 msgid "invalid user name"
 msgstr "無效的使用者名稱"
 
-#: rhodecode/model/forms.py:198
+#: rhodecode/model/validators.py:269
 msgid "Your account is disabled"
 msgstr "您的帳號已被停用"
 
-#: rhodecode/model/forms.py:233
-msgid "This username is not valid"
-msgstr "無效的使用者名稱"
-
-#: rhodecode/model/forms.py:245
-msgid "This repository name is disallowed"
+#: rhodecode/model/validators.py:313
+#, fuzzy, python-format
+msgid "Repository name %(repo)s is disallowed"
 msgstr "不允許的版本庫名稱"
 
-#: rhodecode/model/forms.py:266
-#, python-format
-msgid "This repository already exists in group \"%s\""
+#: rhodecode/model/validators.py:315
+#, fuzzy, python-format
+msgid "Repository named %(repo)s already exists"
+msgstr "這個版本庫已經存在"
+
+#: rhodecode/model/validators.py:316
+#, fuzzy, python-format
+msgid "Repository \"%(repo)s\" already exists in group \"%(group)s\""
 msgstr "這個版本庫已存在於群組 \"%s\""
 
-#: rhodecode/model/forms.py:274
-msgid "This repository already exists"
+#: rhodecode/model/validators.py:318
+#, fuzzy, python-format
+msgid "Repositories group with name \"%(repo)s\" already exists"
 msgstr "這個版本庫已經存在"
 
-#: rhodecode/model/forms.py:312
-#: rhodecode/model/forms.py:319
+#: rhodecode/model/validators.py:431
 msgid "invalid clone url"
 msgstr "無效的複製URL"
 
-#: rhodecode/model/forms.py:322
-msgid "Invalid clone url, provide a valid clone http\\s url"
-msgstr ""
-
-#: rhodecode/model/forms.py:334
-msgid "Fork have to be the same type as original"
+#: rhodecode/model/validators.py:432
+msgid "Invalid clone url, provide a valid clone http(s)/svn+http(s) url"
+msgstr ""
+
+#: rhodecode/model/validators.py:457
+#, fuzzy
+msgid "Fork have to be the same type as parent"
 msgstr "Fork 必須使用相同的版本庫類型"
 
-#: rhodecode/model/forms.py:341
+#: rhodecode/model/validators.py:478
 msgid "This username or users group name is not valid"
 msgstr "使用者名稱或群組名稱無效"
 
-#: rhodecode/model/forms.py:403
+#: rhodecode/model/validators.py:562
 msgid "This is not a valid path"
 msgstr "不是一個有效的路徑"
 
-#: rhodecode/model/forms.py:416
+#: rhodecode/model/validators.py:577
 msgid "This e-mail address is already taken"
 msgstr "這個郵件位址已經使用了"
 
-#: rhodecode/model/forms.py:427
-msgid "This e-mail address doesn't exist."
+#: rhodecode/model/validators.py:597
+#, fuzzy, python-format
+msgid "e-mail \"%(email)s\" does not exist."
 msgstr "這個郵件位址不存在"
 
-#: rhodecode/model/forms.py:447
-msgid "The LDAP Login attribute of the CN must be specified - this is the name of the attribute that is equivalent to 'username'"
-msgstr ""
-
-#: rhodecode/model/forms.py:466
-msgid "Please enter a login"
-msgstr "請登入"
-
-#: rhodecode/model/forms.py:467
-#, python-format
-msgid "Enter a value %(min)i characters long or more"
-msgstr ""
-
-#: rhodecode/model/forms.py:475
-msgid "Please enter a password"
-msgstr "請輸入密碼"
-
-#: rhodecode/model/forms.py:476
+#: rhodecode/model/validators.py:634
+msgid ""
+"The LDAP Login attribute of the CN must be specified - this is the name "
+"of the attribute that is equivalent to \"username\""
+msgstr ""
+
+#: rhodecode/model/validators.py:653
 #, python-format
-msgid "Enter %(min)i characters or more"
-msgstr ""
-
-#: rhodecode/model/user.py:145
-msgid "[RhodeCode] New User registration"
-msgstr "[RhodeCode] 新使用者註冊"
-
-#: rhodecode/model/user.py:157
-#: rhodecode/model/user.py:179
-msgid "You can't Edit this user since it's crucial for entire application"
-msgstr "您無法編輯這個使用者,因為他是系統帳號"
-
-#: rhodecode/model/user.py:201
-msgid "You can't remove this user since it's crucial for entire application"
-msgstr "您無法移除這個使用者,因為他是系統帳號"
-
-#: rhodecode/model/user.py:204
-#, python-format
-msgid "This user still owns %s repositories and cannot be removed. Switch owners or remove those repositories"
-msgstr "這個使用者擁有 %s 個版本庫所以無法移除,請先變更版本庫擁有者或者刪除版本庫"
-
-#: rhodecode/templates/index.html:4
+msgid "Revisions %(revs)s are already part of pull request or have set status"
+msgstr ""
+
+#: rhodecode/templates/index.html:3
 msgid "Dashboard"
 msgstr "儀表板"
 
-#: rhodecode/templates/index_base.html:22
-#: rhodecode/templates/admin/users/user_edit_my_account.html:102
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/repo_switcher_list.html:4
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/admin/users/user_edit_my_account.html:31
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/bookmarks/bookmarks.html:10
+#: rhodecode/templates/branches/branches.html:9
+#: rhodecode/templates/journal/journal.html:40
+#: rhodecode/templates/tags/tags.html:10
 msgid "quick filter..."
 msgstr "快速過濾..."
 
-#: rhodecode/templates/index_base.html:23
-#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/index_base.html:6
+#: rhodecode/templates/admin/repos/repos.html:9
+#: rhodecode/templates/base/base.html:221
 msgid "repositories"
 msgstr "個版本庫"
 
+#: rhodecode/templates/index_base.html:13
+#: rhodecode/templates/index_base.html:15
+#: rhodecode/templates/admin/repos/repos.html:21
+msgid "ADD REPOSITORY"
+msgstr "新增版本庫"
+
 #: rhodecode/templates/index_base.html:29
-#: rhodecode/templates/admin/repos/repos.html:22
-msgid "ADD NEW REPOSITORY"
-msgstr "新增版本庫"
-
-#: rhodecode/templates/index_base.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:32
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:33
@@ -856,159 +1288,161 @@
 msgid "Group name"
 msgstr "群組名稱"
 
-#: rhodecode/templates/index_base.html:42
-#: rhodecode/templates/index_base.html:73
-#: rhodecode/templates/admin/repos/repo_add_base.html:44
-#: rhodecode/templates/admin/repos/repo_edit.html:64
-#: rhodecode/templates/admin/repos/repos.html:31
+#: rhodecode/templates/index_base.html:30
+#: rhodecode/templates/index_base.html:71
+#: rhodecode/templates/index_base.html:142
+#: rhodecode/templates/index_base.html:168
+#: rhodecode/templates/admin/repos/repo_add_base.html:56
+#: rhodecode/templates/admin/repos/repo_edit.html:75
+#: rhodecode/templates/admin/repos/repos.html:72
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:41
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:34
-#: rhodecode/templates/settings/repo_fork.html:40
-#: rhodecode/templates/settings/repo_settings.html:40
-#: rhodecode/templates/summary/summary.html:92
+#: rhodecode/templates/forks/fork.html:59
+#: rhodecode/templates/settings/repo_settings.html:66
+#: rhodecode/templates/summary/summary.html:105
 msgid "Description"
 msgstr "描述"
 
-#: rhodecode/templates/index_base.html:53
+#: rhodecode/templates/index_base.html:40
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:46
 msgid "Repositories group"
 msgstr "版本庫群組"
 
-#: rhodecode/templates/index_base.html:72
+#: rhodecode/templates/index_base.html:70
+#: rhodecode/templates/index_base.html:166
 #: rhodecode/templates/admin/repos/repo_add_base.html:9
 #: rhodecode/templates/admin/repos/repo_edit.html:32
-#: rhodecode/templates/admin/repos/repos.html:30
-#: rhodecode/templates/admin/users/user_edit_my_account.html:117
-#: rhodecode/templates/files/files_browser.html:157
+#: rhodecode/templates/admin/repos/repos.html:70
+#: rhodecode/templates/admin/users/user_edit.html:192
+#: rhodecode/templates/admin/users/user_edit_my_account.html:59
+#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:6
+#: rhodecode/templates/bookmarks/bookmarks.html:36
+#: rhodecode/templates/bookmarks/bookmarks_data.html:6
+#: rhodecode/templates/branches/branches.html:51
+#: rhodecode/templates/files/files_browser.html:47
+#: rhodecode/templates/journal/journal.html:59
+#: rhodecode/templates/journal/journal.html:107
+#: rhodecode/templates/journal/journal.html:186
 #: rhodecode/templates/settings/repo_settings.html:31
-#: rhodecode/templates/summary/summary.html:31
-#: rhodecode/templates/summary/summary.html:107
+#: rhodecode/templates/summary/summary.html:43
+#: rhodecode/templates/summary/summary.html:123
+#: rhodecode/templates/tags/tags.html:36
+#: rhodecode/templates/tags/tags_data.html:6
 msgid "Name"
 msgstr "名稱"
 
-#: rhodecode/templates/index_base.html:74
-#: rhodecode/templates/admin/repos/repos.html:32
-#: rhodecode/templates/summary/summary.html:114
+#: rhodecode/templates/index_base.html:72
 msgid "Last change"
 msgstr "最後修改"
 
+#: rhodecode/templates/index_base.html:73
+#: rhodecode/templates/index_base.html:171
+#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/journal/journal.html:188
+msgid "Tip"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:74
+#: rhodecode/templates/index_base.html:173
+#: rhodecode/templates/admin/repos/repo_edit.html:121
+#: rhodecode/templates/admin/repos/repos.html:73
+msgid "Owner"
+msgstr "擁有者"
+
 #: rhodecode/templates/index_base.html:75
-#: rhodecode/templates/admin/repos/repos.html:33
-msgid "Tip"
+#: rhodecode/templates/summary/summary.html:48
+#: rhodecode/templates/summary/summary.html:51
+msgid "RSS"
 msgstr ""
 
 #: rhodecode/templates/index_base.html:76
-#: rhodecode/templates/admin/repos/repo_edit.html:97
-msgid "Owner"
-msgstr "擁有者"
-
-#: rhodecode/templates/index_base.html:77
-#: rhodecode/templates/journal/public_journal.html:20
-#: rhodecode/templates/summary/summary.html:180
-#: rhodecode/templates/summary/summary.html:183
-msgid "RSS"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:78
-#: rhodecode/templates/journal/public_journal.html:23
-#: rhodecode/templates/summary/summary.html:181
-#: rhodecode/templates/summary/summary.html:184
 msgid "Atom"
 msgstr ""
 
-#: rhodecode/templates/index_base.html:87
-#: rhodecode/templates/index_base.html:89
-#: rhodecode/templates/index_base.html:91
-#: rhodecode/templates/base/base.html:209
-#: rhodecode/templates/base/base.html:211
-#: rhodecode/templates/base/base.html:213
-#: rhodecode/templates/summary/summary.html:4
-msgid "Summary"
-msgstr "概況"
-
-#: rhodecode/templates/index_base.html:95
-#: rhodecode/templates/index_base.html:97
-#: rhodecode/templates/index_base.html:99
-#: rhodecode/templates/base/base.html:225
-#: rhodecode/templates/base/base.html:227
-#: rhodecode/templates/base/base.html:229
-#: rhodecode/templates/changelog/changelog.html:6
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "Changelog"
-msgstr "修改紀錄"
-
-#: rhodecode/templates/index_base.html:103
-#: rhodecode/templates/index_base.html:105
-#: rhodecode/templates/index_base.html:107
-#: rhodecode/templates/base/base.html:268
-#: rhodecode/templates/base/base.html:270
-#: rhodecode/templates/base/base.html:272
-#: rhodecode/templates/files/files.html:4
-msgid "Files"
-msgstr "檔案"
-
-#: rhodecode/templates/index_base.html:116
-#: rhodecode/templates/admin/repos/repos.html:42
-#: rhodecode/templates/admin/users/user_edit_my_account.html:127
-#: rhodecode/templates/summary/summary.html:48
-msgid "Mercurial repository"
-msgstr "Mercurial 版本庫"
-
-#: rhodecode/templates/index_base.html:118
-#: rhodecode/templates/admin/repos/repos.html:44
-#: rhodecode/templates/admin/users/user_edit_my_account.html:129
-#: rhodecode/templates/summary/summary.html:51
-msgid "Git repository"
-msgstr "Git 版本庫"
-
-#: rhodecode/templates/index_base.html:123
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
-#: rhodecode/templates/journal/journal.html:53
-#: rhodecode/templates/summary/summary.html:56
-msgid "private repository"
-msgstr "私有版本庫"
-
-#: rhodecode/templates/index_base.html:125
-#: rhodecode/templates/journal/journal.html:55
-#: rhodecode/templates/summary/summary.html:58
-msgid "public repository"
-msgstr "公開版本庫"
-
-#: rhodecode/templates/index_base.html:133
-#: rhodecode/templates/base/base.html:291
-#: rhodecode/templates/settings/repo_fork.html:13
-msgid "fork"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:134
-#: rhodecode/templates/admin/repos/repos.html:60
-#: rhodecode/templates/admin/users/user_edit_my_account.html:143
-#: rhodecode/templates/summary/summary.html:69
-#: rhodecode/templates/summary/summary.html:71
-msgid "Fork of"
-msgstr ""
-
-#: rhodecode/templates/index_base.html:155
-#: rhodecode/templates/admin/repos/repos.html:73
-msgid "No changesets yet"
-msgstr "尚未有任何變更"
-
-#: rhodecode/templates/index_base.html:161
-#: rhodecode/templates/index_base.html:163
+#: rhodecode/templates/index_base.html:110
+#: rhodecode/templates/index_base.html:112
 #, python-format
 msgid "Subscribe to %s rss feed"
 msgstr "訂閱 %s rss"
 
-#: rhodecode/templates/index_base.html:168
-#: rhodecode/templates/index_base.html:170
+#: rhodecode/templates/index_base.html:117
+#: rhodecode/templates/index_base.html:119
 #, python-format
 msgid "Subscribe to %s atom feed"
 msgstr "訂閱 %s atom"
 
-#: rhodecode/templates/login.html:5
-#: rhodecode/templates/login.html:54
-#: rhodecode/templates/base/base.html:38
+#: rhodecode/templates/index_base.html:140
+#, fuzzy
+msgid "Group Name"
+msgstr "群組名稱"
+
+#: rhodecode/templates/index_base.html:158
+#: rhodecode/templates/index_base.html:198
+#: rhodecode/templates/admin/repos/repos.html:94
+#: rhodecode/templates/admin/users/user_edit_my_account.html:179
+#: rhodecode/templates/admin/users/users.html:107
+#: rhodecode/templates/bookmarks/bookmarks.html:60
+#: rhodecode/templates/branches/branches.html:77
+#: rhodecode/templates/journal/journal.html:211
+#: rhodecode/templates/tags/tags.html:60
+msgid "Click to sort ascending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:159
+#: rhodecode/templates/index_base.html:199
+#: rhodecode/templates/admin/repos/repos.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account.html:180
+#: rhodecode/templates/admin/users/users.html:108
+#: rhodecode/templates/bookmarks/bookmarks.html:61
+#: rhodecode/templates/branches/branches.html:78
+#: rhodecode/templates/journal/journal.html:212
+#: rhodecode/templates/tags/tags.html:61
+msgid "Click to sort descending"
+msgstr ""
+
+#: rhodecode/templates/index_base.html:169
+#, fuzzy
+msgid "Last Change"
+msgstr "最後修改"
+
+#: rhodecode/templates/index_base.html:200
+#: rhodecode/templates/admin/repos/repos.html:96
+#: rhodecode/templates/admin/users/user_edit_my_account.html:181
+#: rhodecode/templates/admin/users/users.html:109
+#: rhodecode/templates/bookmarks/bookmarks.html:62
+#: rhodecode/templates/branches/branches.html:79
+#: rhodecode/templates/journal/journal.html:213
+#: rhodecode/templates/tags/tags.html:62
+msgid "No records found."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:201
+#: rhodecode/templates/admin/repos/repos.html:97
+#: rhodecode/templates/admin/users/user_edit_my_account.html:182
+#: rhodecode/templates/admin/users/users.html:110
+#: rhodecode/templates/bookmarks/bookmarks.html:63
+#: rhodecode/templates/branches/branches.html:80
+#: rhodecode/templates/journal/journal.html:214
+#: rhodecode/templates/tags/tags.html:63
+msgid "Data error."
+msgstr ""
+
+#: rhodecode/templates/index_base.html:202
+#: rhodecode/templates/admin/repos/repos.html:98
+#: rhodecode/templates/admin/users/user_edit_my_account.html:183
+#: rhodecode/templates/admin/users/users.html:111
+#: rhodecode/templates/bookmarks/bookmarks.html:64
+#: rhodecode/templates/branches/branches.html:81
+#: rhodecode/templates/journal/journal.html:215
+#: rhodecode/templates/tags/tags.html:64
+#, fuzzy
+msgid "Loading..."
+msgstr "載入中..."
+
+#: rhodecode/templates/login.html:5 rhodecode/templates/login.html:54
 msgid "Sign In"
 msgstr "登入"
 
@@ -1016,31 +1450,33 @@
 msgid "Sign In to"
 msgstr "登入"
 
-#: rhodecode/templates/login.html:31
-#: rhodecode/templates/register.html:20
+#: rhodecode/templates/login.html:31 rhodecode/templates/register.html:20
 #: rhodecode/templates/admin/admin_log.html:5
 #: rhodecode/templates/admin/users/user_add.html:32
-#: rhodecode/templates/admin/users/user_edit.html:47
-#: rhodecode/templates/admin/users/user_edit_my_account.html:45
-#: rhodecode/templates/base/base.html:15
-#: rhodecode/templates/summary/summary.html:106
+#: rhodecode/templates/admin/users/user_edit.html:50
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:26
+#: rhodecode/templates/base/base.html:83
+#: rhodecode/templates/summary/summary.html:122
 msgid "Username"
 msgstr "帳號"
 
-#: rhodecode/templates/login.html:40
-#: rhodecode/templates/register.html:29
+#: rhodecode/templates/login.html:40 rhodecode/templates/register.html:29
 #: rhodecode/templates/admin/ldap/ldap.html:46
 #: rhodecode/templates/admin/users/user_add.html:41
-#: rhodecode/templates/base/base.html:24
+#: rhodecode/templates/base/base.html:92
 msgid "Password"
 msgstr "密碼"
 
+#: rhodecode/templates/login.html:50
+#, fuzzy
+msgid "Remember me"
+msgstr "成員"
+
 #: rhodecode/templates/login.html:60
 msgid "Forgot your password ?"
 msgstr "忘記您的密碼?"
 
-#: rhodecode/templates/login.html:63
-#: rhodecode/templates/base/base.html:35
+#: rhodecode/templates/login.html:63 rhodecode/templates/base/base.html:103
 msgid "Don't have an account ?"
 msgstr "沒有帳號?"
 
@@ -1064,8 +1500,7 @@
 msgid "Password reset link will be send to matching email address"
 msgstr "密碼重設連結已郵寄至您的信箱"
 
-#: rhodecode/templates/register.html:5
-#: rhodecode/templates/register.html:74
+#: rhodecode/templates/register.html:5 rhodecode/templates/register.html:74
 msgid "Sign Up"
 msgstr "登入"
 
@@ -1078,24 +1513,24 @@
 msgstr "確認密碼"
 
 #: rhodecode/templates/register.html:47
-#: rhodecode/templates/admin/users/user_add.html:50
-#: rhodecode/templates/admin/users/user_edit.html:74
-#: rhodecode/templates/admin/users/user_edit_my_account.html:63
+#: rhodecode/templates/admin/users/user_add.html:59
+#: rhodecode/templates/admin/users/user_edit.html:86
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:53
 msgid "First Name"
 msgstr "名"
 
 #: rhodecode/templates/register.html:56
-#: rhodecode/templates/admin/users/user_add.html:59
-#: rhodecode/templates/admin/users/user_edit.html:83
-#: rhodecode/templates/admin/users/user_edit_my_account.html:72
+#: rhodecode/templates/admin/users/user_add.html:68
+#: rhodecode/templates/admin/users/user_edit.html:95
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:62
 msgid "Last Name"
 msgstr "姓"
 
 #: rhodecode/templates/register.html:65
-#: rhodecode/templates/admin/users/user_add.html:68
-#: rhodecode/templates/admin/users/user_edit.html:92
-#: rhodecode/templates/admin/users/user_edit_my_account.html:81
-#: rhodecode/templates/summary/summary.html:108
+#: rhodecode/templates/admin/users/user_add.html:77
+#: rhodecode/templates/admin/users/user_edit.html:104
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:71
+#: rhodecode/templates/summary/summary.html:124
 msgid "Email"
 msgstr "電子郵件"
 
@@ -1107,20 +1542,60 @@
 msgid "Your account must wait for activation by administrator"
 msgstr "您的帳號註冊後將等待管理員啟用"
 
-#: rhodecode/templates/repo_switcher_list.html:14
+#: rhodecode/templates/repo_switcher_list.html:11
+#: rhodecode/templates/admin/repos/repo_add_base.html:65
+#: rhodecode/templates/admin/repos/repo_edit.html:85
+#: rhodecode/templates/settings/repo_settings.html:76
 msgid "Private repository"
 msgstr "私有的版本庫"
 
-#: rhodecode/templates/repo_switcher_list.html:19
+#: rhodecode/templates/repo_switcher_list.html:16
 msgid "Public repository"
 msgstr "公開的版本庫"
 
+#: rhodecode/templates/switch_to_list.html:3
+#: rhodecode/templates/branches/branches.html:14
+msgid "branches"
+msgstr "分支"
+
+#: rhodecode/templates/switch_to_list.html:10
+#: rhodecode/templates/branches/branches_data.html:57
+msgid "There are no branches yet"
+msgstr "沒有任何分支"
+
+#: rhodecode/templates/switch_to_list.html:15
+#: rhodecode/templates/shortlog/shortlog_data.html:10
+#: rhodecode/templates/tags/tags.html:15
+msgid "tags"
+msgstr "標籤"
+
+#: rhodecode/templates/switch_to_list.html:22
+#: rhodecode/templates/tags/tags_data.html:33
+msgid "There are no tags yet"
+msgstr "沒有任何標籤"
+
+#: rhodecode/templates/switch_to_list.html:28
+#: rhodecode/templates/bookmarks/bookmarks.html:15
+msgid "bookmarks"
+msgstr ""
+
+#: rhodecode/templates/switch_to_list.html:35
+#: rhodecode/templates/bookmarks/bookmarks_data.html:32
+#, fuzzy
+msgid "There are no bookmarks yet"
+msgstr "尚未有任何 fork"
+
 #: rhodecode/templates/admin/admin.html:5
 #: rhodecode/templates/admin/admin.html:9
 msgid "Admin journal"
 msgstr "管理員日誌"
 
 #: rhodecode/templates/admin/admin_log.html:6
+#: rhodecode/templates/admin/repos/repos.html:74
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:8
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:9
+#: rhodecode/templates/journal/journal.html:61
+#: rhodecode/templates/journal/journal.html:62
 msgid "Action"
 msgstr "動作"
 
@@ -1129,6 +1604,11 @@
 msgstr "版本庫"
 
 #: rhodecode/templates/admin/admin_log.html:8
+#: rhodecode/templates/bookmarks/bookmarks.html:37
+#: rhodecode/templates/bookmarks/bookmarks_data.html:7
+#: rhodecode/templates/branches/branches.html:52
+#: rhodecode/templates/tags/tags.html:37
+#: rhodecode/templates/tags/tags_data.html:7
 msgid "Date"
 msgstr "時間"
 
@@ -1136,7 +1616,7 @@
 msgid "From IP"
 msgstr "來源IP"
 
-#: rhodecode/templates/admin/admin_log.html:52
+#: rhodecode/templates/admin/admin_log.html:53
 msgid "No actions yet"
 msgstr ""
 
@@ -1213,23 +1693,66 @@
 msgstr "電子郵件屬性"
 
 #: rhodecode/templates/admin/ldap/ldap.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:141
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:74
 #: rhodecode/templates/admin/settings/hooks.html:73
-#: rhodecode/templates/admin/users/user_edit.html:117
-#: rhodecode/templates/admin/users/user_edit.html:142
-#: rhodecode/templates/admin/users/user_edit_my_account.html:89
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:263
+#: rhodecode/templates/admin/users/user_edit.html:129
+#: rhodecode/templates/admin/users/user_edit.html:174
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:79
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:135
+#: rhodecode/templates/settings/repo_settings.html:93
 msgid "Save"
 msgstr "儲存"
 
+#: rhodecode/templates/admin/notifications/notifications.html:5
+#: rhodecode/templates/admin/notifications/notifications.html:9
+msgid "My Notifications"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:29
+msgid "All"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:30
+#, fuzzy
+msgid "Comments"
+msgstr "遞交"
+
+#: rhodecode/templates/admin/notifications/notifications.html:31
+#: rhodecode/templates/base/base.html:254
+#: rhodecode/templates/base/base.html:256
+msgid "Pull requests"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications.html:35
+msgid "Mark all read"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/notifications_data.html:39
+msgid "No notifications here yet"
+msgstr ""
+
+#: rhodecode/templates/admin/notifications/show_notification.html:5
+#: rhodecode/templates/admin/notifications/show_notification.html:11
+#, fuzzy
+msgid "Show notification"
+msgstr "險是註釋"
+
+#: rhodecode/templates/admin/notifications/show_notification.html:9
+#, fuzzy
+msgid "Notifications"
+msgstr "位置"
+
 #: rhodecode/templates/admin/permissions/permissions.html:5
 msgid "Permissions administration"
 msgstr "權限管理員"
 
 #: rhodecode/templates/admin/permissions/permissions.html:11
-#: rhodecode/templates/admin/repos/repo_edit.html:109
-#: rhodecode/templates/admin/users/user_edit.html:127
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:248
-#: rhodecode/templates/settings/repo_settings.html:58
+#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
+#: rhodecode/templates/admin/users/user_edit.html:139
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:100
+#: rhodecode/templates/settings/repo_settings.html:86
 msgid "Permissions"
 msgstr "權限"
 
@@ -1246,7 +1769,10 @@
 msgstr "版本庫權限"
 
 #: rhodecode/templates/admin/permissions/permissions.html:49
-msgid "All default permissions on each repository will be reset to choosen permission, note that all custom default permission on repositories will be lost"
+msgid ""
+"All default permissions on each repository will be reset to choosen "
+"permission, note that all custom default permission on repositories will "
+"be lost"
 msgstr ""
 
 #: rhodecode/templates/admin/permissions/permissions.html:50
@@ -1262,6 +1788,12 @@
 msgstr "版本庫建立"
 
 #: rhodecode/templates/admin/permissions/permissions.html:71
+#, fuzzy
+msgid "Repository forking"
+msgstr "版本庫建立"
+
+#: rhodecode/templates/admin/permissions/permissions.html:78
+#: rhodecode/templates/admin/repos/repo_edit.html:241
 msgid "set"
 msgstr "設定"
 
@@ -1272,7 +1804,6 @@
 
 #: rhodecode/templates/admin/repos/repo_add.html:11
 #: rhodecode/templates/admin/repos/repo_edit.html:11
-#: rhodecode/templates/admin/repos/repos.html:10
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:10
 msgid "Repositories"
 msgstr "版本庫"
@@ -1282,30 +1813,72 @@
 msgstr "新增"
 
 #: rhodecode/templates/admin/repos/repo_add_base.html:20
-#: rhodecode/templates/summary/summary.html:80
-#: rhodecode/templates/summary/summary.html:82
+#: rhodecode/templates/summary/summary.html:95
+#: rhodecode/templates/summary/summary.html:96
 msgid "Clone from"
 msgstr "複製由"
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:28
-#: rhodecode/templates/admin/repos/repo_edit.html:48
+#: rhodecode/templates/admin/repos/repo_add_base.html:24
+#: rhodecode/templates/admin/repos/repo_edit.html:44
+#: rhodecode/templates/settings/repo_settings.html:43
+msgid "Optional http[s] url from which repository should be cloned."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:29
+#: rhodecode/templates/admin/repos/repo_edit.html:49
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:4
+#: rhodecode/templates/forks/fork.html:50
+#: rhodecode/templates/settings/repo_settings.html:48
 msgid "Repository group"
 msgstr "版本庫群組"
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:36
-#: rhodecode/templates/admin/repos/repo_edit.html:56
+#: rhodecode/templates/admin/repos/repo_add_base.html:33
+#: rhodecode/templates/forks/fork.html:54
+msgid "Optionaly select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:38
+#: rhodecode/templates/admin/repos/repo_edit.html:58
 msgid "Type"
 msgstr "類型"
 
-#: rhodecode/templates/admin/repos/repo_add_base.html:52
-#: rhodecode/templates/admin/repos/repo_edit.html:73
-#: rhodecode/templates/settings/repo_fork.html:48
-#: rhodecode/templates/settings/repo_settings.html:49
-msgid "Private"
-msgstr "私有"
-
-#: rhodecode/templates/admin/repos/repo_add_base.html:59
+#: rhodecode/templates/admin/repos/repo_add_base.html:42
+#, fuzzy
+msgid "Type of repository to create."
+msgstr "版本庫建立"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:47
+#: rhodecode/templates/admin/repos/repo_edit.html:66
+#: rhodecode/templates/forks/fork.html:41
+#: rhodecode/templates/settings/repo_settings.html:57
+#, fuzzy
+msgid "Landing revision"
+msgstr "下一個修訂"
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:51
+#: rhodecode/templates/admin/repos/repo_edit.html:70
+#: rhodecode/templates/forks/fork.html:45
+#: rhodecode/templates/settings/repo_settings.html:61
+msgid "Default revision for files page, downloads, whoosh and readme"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:60
+#: rhodecode/templates/admin/repos/repo_edit.html:79
+#: rhodecode/templates/forks/fork.html:63
+#: rhodecode/templates/settings/repo_settings.html:70
+msgid "Keep it short and to the point. Use a README file for longer descriptions."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:69
+#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/forks/fork.html:72
+#: rhodecode/templates/settings/repo_settings.html:80
+msgid ""
+"Private repositories are only visible to people explicitly added as "
+"collaborators."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_add_base.html:73
 msgid "add"
 msgstr "新增"
 
@@ -1319,183 +1892,276 @@
 
 #: rhodecode/templates/admin/repos/repo_edit.html:13
 #: rhodecode/templates/admin/users/user_edit.html:13
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
+#: rhodecode/templates/admin/users/user_edit.html:224
+#: rhodecode/templates/admin/users/user_edit.html:226
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:13
-#: rhodecode/templates/files/files_annotate.html:49
-#: rhodecode/templates/files/files_source.html:20
+#: rhodecode/templates/files/files_source.html:44
+#: rhodecode/templates/journal/journal.html:81
 msgid "edit"
 msgstr "編輯"
 
 #: rhodecode/templates/admin/repos/repo_edit.html:40
+#: rhodecode/templates/settings/repo_settings.html:39
 msgid "Clone uri"
 msgstr "複製URL"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:81
+#: rhodecode/templates/admin/repos/repo_edit.html:53
+#: rhodecode/templates/settings/repo_settings.html:52
+msgid "Optional select a group to put this repository into."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:94
 msgid "Enable statistics"
 msgstr "啟用統計"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:89
+#: rhodecode/templates/admin/repos/repo_edit.html:98
+msgid "Enable statistics window on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:103
 msgid "Enable downloads"
 msgstr "啟用下載"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:127
+#: rhodecode/templates/admin/repos/repo_edit.html:107
+msgid "Enable download menu on summary page."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:112
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:66
+#, fuzzy
+msgid "Enable locking"
+msgstr "啟用"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:116
+msgid "Enable lock-by-pulling on repository."
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:126
+#, fuzzy
+msgid "Change owner of this repository."
+msgstr "修改於版本庫 %s"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:142
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:75
+#: rhodecode/templates/admin/settings/settings.html:113
+#: rhodecode/templates/admin/settings/settings.html:168
+#: rhodecode/templates/admin/settings/settings.html:258
+#: rhodecode/templates/admin/users/user_edit.html:130
+#: rhodecode/templates/admin/users/user_edit.html:175
+#: rhodecode/templates/admin/users/user_edit.html:278
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:80
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:136
+#: rhodecode/templates/files/files_add.html:82
+#: rhodecode/templates/files/files_edit.html:68
+#: rhodecode/templates/pullrequests/pullrequest.html:124
+#: rhodecode/templates/settings/repo_settings.html:94
+msgid "Reset"
+msgstr "重設"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:152
 msgid "Administration"
 msgstr "管理者"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:130
+#: rhodecode/templates/admin/repos/repo_edit.html:155
 msgid "Statistics"
 msgstr "統計"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Reset current statistics"
 msgstr "重設目前的統計"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:134
+#: rhodecode/templates/admin/repos/repo_edit.html:159
 msgid "Confirm to remove current statistics"
 msgstr "確認移除目前的統計"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:137
+#: rhodecode/templates/admin/repos/repo_edit.html:162
 msgid "Fetched to rev"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:138
-msgid "Percentage of stats gathered"
-msgstr ""
-
-#: rhodecode/templates/admin/repos/repo_edit.html:147
+#: rhodecode/templates/admin/repos/repo_edit.html:163
+msgid "Stats gathered"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:171
 msgid "Remote"
 msgstr "遠端"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:151
+#: rhodecode/templates/admin/repos/repo_edit.html:175
 msgid "Pull changes from remote location"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:151
+#: rhodecode/templates/admin/repos/repo_edit.html:175
 msgid "Confirm to pull changes from remote side"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:162
+#: rhodecode/templates/admin/repos/repo_edit.html:186
 msgid "Cache"
 msgstr "快取"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Invalidate repository cache"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit.html:166
+#: rhodecode/templates/admin/repos/repo_edit.html:190
 msgid "Confirm to invalidate repository cache"
 msgstr "確認廢止版本庫快取"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:177
+#: rhodecode/templates/admin/repos/repo_edit.html:195
+#: rhodecode/templates/base/base.html:318
+#: rhodecode/templates/base/base.html:320
+#: rhodecode/templates/base/base.html:322
+msgid "Public journal"
+msgstr "公開日誌"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:201
 msgid "Remove from public journal"
 msgstr "從公開日誌移除"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:179
+#: rhodecode/templates/admin/repos/repo_edit.html:203
 msgid "Add to public journal"
 msgstr "新增至公開日誌"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:185
+#: rhodecode/templates/admin/repos/repo_edit.html:208
+msgid ""
+"All actions made on this repository will be accessible to everyone in "
+"public journal"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:215
+#, fuzzy
+msgid "Locking"
+msgstr "解鎖"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+msgid "Unlock locked repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:220
+#, fuzzy
+msgid "Confirm to unlock repository"
+msgstr "確認移除這個版本庫"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+msgid "lock repo"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:223
+#, fuzzy
+msgid "Confirm to lock repository"
+msgstr "確認移除這個版本庫"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:224
+#, fuzzy
+msgid "Repository is not locked"
+msgstr "個版本庫"
+
+#: rhodecode/templates/admin/repos/repo_edit.html:229
+msgid "Force locking on repository. Works only when anonymous access is disabled"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:236
+msgid "Set as fork of"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:245
+msgid "Manually set this repository as a fork of another from the list"
+msgstr ""
+
+#: rhodecode/templates/admin/repos/repo_edit.html:251
+#: rhodecode/templates/changeset/changeset_file_comment.html:26
 msgid "Delete"
 msgstr "移除"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
+#: rhodecode/templates/admin/repos/repo_edit.html:255
 msgid "Remove this repository"
 msgstr "移除版本庫"
 
-#: rhodecode/templates/admin/repos/repo_edit.html:189
-#: rhodecode/templates/admin/repos/repos.html:79
+#: rhodecode/templates/admin/repos/repo_edit.html:255
+#: rhodecode/templates/journal/journal.html:84
 msgid "Confirm to delete this repository"
 msgstr "確認移除這個版本庫"
 
+#: rhodecode/templates/admin/repos/repo_edit.html:259
+msgid ""
+"This repository will be renamed in a special way in order to be "
+"unaccesible for RhodeCode and VCS systems.\n"
+"                         If you need fully delete it from filesystem "
+"please do it manually"
+msgstr ""
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:3
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:3
 msgid "none"
 msgstr "無"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:4
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:4
 msgid "read"
 msgstr "讀"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:5
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:5
 msgid "write"
 msgstr "寫"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:6
-#: rhodecode/templates/admin/users/users.html:38
-#: rhodecode/templates/base/base.html:296
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:6
+#: rhodecode/templates/admin/users/users.html:85
+#: rhodecode/templates/base/base.html:217
 msgid "admin"
 msgstr "管理員"
 
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:7
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:7
 msgid "member"
 msgstr "成員"
 
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:16
+#: rhodecode/templates/data_table/_dt_elements.html:67
+#: rhodecode/templates/journal/journal.html:132
+#: rhodecode/templates/summary/summary.html:76
+msgid "private repository"
+msgstr "私有版本庫"
+
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:19
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:28
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:18
+#, fuzzy
+msgid "default"
+msgstr "刪除"
+
 #: rhodecode/templates/admin/repos/repo_edit_perms.html:33
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:53
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:58
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:23
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:42
 msgid "revoke"
 msgstr ""
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:75
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:83
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:67
 msgid "Add another member"
 msgstr "新增另ㄧ位成員"
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:89
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:97
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:81
 msgid "Failed to remove user"
 msgstr "移除使用者失敗"
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:104
+#: rhodecode/templates/admin/repos/repo_edit_perms.html:112
+#: rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html:96
 msgid "Failed to remove users group"
 msgstr "移除使用者群組失敗"
 
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:205
-msgid "Group"
-msgstr "群組"
-
-#: rhodecode/templates/admin/repos/repo_edit_perms.html:206
-#: rhodecode/templates/admin/users_groups/users_groups.html:33
-msgid "members"
-msgstr "成員"
-
 #: rhodecode/templates/admin/repos/repos.html:5
 msgid "Repositories administration"
 msgstr "版本庫管理員"
 
-#: rhodecode/templates/admin/repos/repos.html:34
-#: rhodecode/templates/summary/summary.html:100
-msgid "Contact"
-msgstr "聯絡方式"
-
-#: rhodecode/templates/admin/repos/repos.html:35
-#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
-#: rhodecode/templates/admin/users/user_edit_my_account.html:119
-#: rhodecode/templates/admin/users/users.html:40
-#: rhodecode/templates/admin/users_groups/users_groups.html:35
-msgid "action"
-msgstr "動作"
-
-#: rhodecode/templates/admin/repos/repos.html:51
-#: rhodecode/templates/admin/users/user_edit_my_account.html:134
-#: rhodecode/templates/admin/users/user_edit_my_account.html:148
-msgid "private"
-msgstr "私有"
-
-#: rhodecode/templates/admin/repos/repos.html:53
-#: rhodecode/templates/admin/repos/repos.html:59
-#: rhodecode/templates/admin/users/user_edit_my_account.html:136
-#: rhodecode/templates/admin/users/user_edit_my_account.html:142
-#: rhodecode/templates/summary/summary.html:68
-msgid "public"
-msgstr "公開"
-
-#: rhodecode/templates/admin/repos/repos.html:79
-#: rhodecode/templates/admin/users/users.html:55
-msgid "delete"
-msgstr "刪除"
-
 #: rhodecode/templates/admin/repos_groups/repos_groups.html:8
 msgid "Groups"
 msgstr "群組"
 
-#: rhodecode/templates/admin/repos_groups/repos_groups.html:13
+#: rhodecode/templates/admin/repos_groups/repos_groups.html:12
 msgid "with"
 msgstr ""
 
@@ -1518,10 +2184,10 @@
 msgstr "父群組"
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_add.html:58
-#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:58
-#: rhodecode/templates/admin/users/user_add.html:85
+#: rhodecode/templates/admin/users/user_add.html:94
 #: rhodecode/templates/admin/users_groups/users_group_add.html:49
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:90
+#: rhodecode/templates/pullrequests/pullrequest_show.html:113
 msgid "save"
 msgstr "儲存"
 
@@ -1533,6 +2199,12 @@
 msgid "edit repos group"
 msgstr "編輯版本庫群組"
 
+#: rhodecode/templates/admin/repos_groups/repos_groups_edit.html:70
+msgid ""
+"Enable lock-by-pulling on group. This option will be applied to all other"
+" groups and repositories inside"
+msgstr ""
+
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:5
 msgid "Repositories groups administration"
 msgstr "版本庫群組管理員"
@@ -1542,11 +2214,27 @@
 msgstr "新增群組"
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:35
-msgid "Number of repositories"
+#, fuzzy
+msgid "Number of toplevel repositories"
 msgstr "版本庫數量"
 
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:36
+#: rhodecode/templates/admin/users/users.html:87
+#: rhodecode/templates/admin/users_groups/users_groups.html:35
+msgid "action"
+msgstr "動作"
+
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
-msgid "Confirm to delete this group"
+#: rhodecode/templates/admin/users/user_edit.html:255
+#: rhodecode/templates/admin/users_groups/users_groups.html:44
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#: rhodecode/templates/data_table/_dt_elements.html:103
+msgid "delete"
+msgstr "刪除"
+
+#: rhodecode/templates/admin/repos_groups/repos_groups_show.html:54
+#, fuzzy, python-format
+msgid "Confirm to delete this group: %s"
 msgstr "確認刪除這個群組"
 
 #: rhodecode/templates/admin/repos_groups/repos_groups_show.html:62
@@ -1560,7 +2248,6 @@
 
 #: rhodecode/templates/admin/settings/hooks.html:9
 #: rhodecode/templates/admin/settings/settings.html:9
-#: rhodecode/templates/settings/repo_settings.html:5
 #: rhodecode/templates/settings/repo_settings.html:13
 msgid "Settings"
 msgstr "設定"
@@ -1590,119 +2277,205 @@
 msgstr "重新掃描選項"
 
 #: rhodecode/templates/admin/settings/settings.html:38
-msgid "In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it."
+msgid ""
+"In case a repository was deleted from filesystem and there are leftovers "
+"in the database check this option to scan obsolete data in database and "
+"remove it."
 msgstr "如果版本庫已從檔案系統中刪除,但是資料還留在資料庫,請勾選這個項目清理資料庫中舊的資料"
 
 #: rhodecode/templates/admin/settings/settings.html:39
 msgid "destroy old data"
 msgstr "移除舊資料"
 
-#: rhodecode/templates/admin/settings/settings.html:45
+#: rhodecode/templates/admin/settings/settings.html:41
+msgid ""
+"Rescan repositories location for new repositories. Also deletes obsolete "
+"if `destroy` flag is checked "
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:46
 msgid "Rescan repositories"
 msgstr "重新掃描版本庫"
 
-#: rhodecode/templates/admin/settings/settings.html:51
+#: rhodecode/templates/admin/settings/settings.html:52
 msgid "Whoosh indexing"
 msgstr "Whoosh 索引"
 
-#: rhodecode/templates/admin/settings/settings.html:59
+#: rhodecode/templates/admin/settings/settings.html:60
 msgid "index build option"
 msgstr "索引選項"
 
-#: rhodecode/templates/admin/settings/settings.html:64
+#: rhodecode/templates/admin/settings/settings.html:65
 msgid "build from scratch"
 msgstr "重頭建立索引"
 
-#: rhodecode/templates/admin/settings/settings.html:70
+#: rhodecode/templates/admin/settings/settings.html:71
 msgid "Reindex"
 msgstr "重新索引"
 
-#: rhodecode/templates/admin/settings/settings.html:76
+#: rhodecode/templates/admin/settings/settings.html:77
 msgid "Global application settings"
 msgstr "全域設定"
 
-#: rhodecode/templates/admin/settings/settings.html:85
+#: rhodecode/templates/admin/settings/settings.html:86
 msgid "Application name"
 msgstr "應用名稱"
 
-#: rhodecode/templates/admin/settings/settings.html:94
+#: rhodecode/templates/admin/settings/settings.html:95
 msgid "Realm text"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:103
+#: rhodecode/templates/admin/settings/settings.html:104
 msgid "GA code"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:111
-#: rhodecode/templates/admin/settings/settings.html:177
-msgid "Save settings"
-msgstr "儲存設定"
-
 #: rhodecode/templates/admin/settings/settings.html:112
-#: rhodecode/templates/admin/settings/settings.html:178
-#: rhodecode/templates/admin/users/user_edit.html:118
-#: rhodecode/templates/admin/users/user_edit.html:143
-#: rhodecode/templates/admin/users/user_edit_my_account.html:90
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:264
-#: rhodecode/templates/files/files_edit.html:50
-msgid "Reset"
-msgstr "重設"
-
-#: rhodecode/templates/admin/settings/settings.html:118
-msgid "Mercurial settings"
-msgstr "Mercurial 設定"
-
-#: rhodecode/templates/admin/settings/settings.html:127
+#: rhodecode/templates/admin/settings/settings.html:167
+#: rhodecode/templates/admin/settings/settings.html:257
+msgid "Save settings"
+msgstr "儲存設定"
+
+#: rhodecode/templates/admin/settings/settings.html:119
+#, fuzzy
+msgid "Visualisation settings"
+msgstr "全域設定"
+
+#: rhodecode/templates/admin/settings/settings.html:128
+#, fuzzy
+msgid "Icons"
+msgstr "選項"
+
+#: rhodecode/templates/admin/settings/settings.html:133
+msgid "Show public repo icon on repositories"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:137
+#, fuzzy
+msgid "Show private repo icon on repositories"
+msgstr "私有版本庫"
+
+#: rhodecode/templates/admin/settings/settings.html:144
+#, fuzzy
+msgid "Meta-Tagging"
+msgstr "設定"
+
+#: rhodecode/templates/admin/settings/settings.html:149
+msgid "Stylify recognised metatags:"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:176
+#, fuzzy
+msgid "VCS settings"
+msgstr "設定"
+
+#: rhodecode/templates/admin/settings/settings.html:185
 msgid "Web"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:132
-msgid "require ssl for pushing"
+#: rhodecode/templates/admin/settings/settings.html:190
+#, fuzzy
+msgid "require ssl for vcs operations"
 msgstr "推送時要求使用SSL"
 
-#: rhodecode/templates/admin/settings/settings.html:139
+#: rhodecode/templates/admin/settings/settings.html:192
+msgid ""
+"RhodeCode will require SSL for pushing or pulling. If SSL is missing it "
+"will return HTTP Error 406: Not Acceptable"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:198
 msgid "Hooks"
 msgstr ""
 
-#: rhodecode/templates/admin/settings/settings.html:142
+#: rhodecode/templates/admin/settings/settings.html:203
+msgid "Update repository after push (hg update)"
+msgstr "push後更新版本庫 (hg update)"
+
+#: rhodecode/templates/admin/settings/settings.html:207
+msgid "Show repository size after push"
+msgstr "push 後顯示版本庫大小"
+
+#: rhodecode/templates/admin/settings/settings.html:211
+msgid "Log user push commands"
+msgstr "紀錄使用者推送命令"
+
+#: rhodecode/templates/admin/settings/settings.html:215
+msgid "Log user pull commands"
+msgstr "紀錄使用者抓取命令"
+
+#: rhodecode/templates/admin/settings/settings.html:219
 msgid "advanced setup"
 msgstr "進階設定"
 
-#: rhodecode/templates/admin/settings/settings.html:147
-msgid "Update repository after push (hg update)"
-msgstr "push後更新版本庫 (hg update)"
-
-#: rhodecode/templates/admin/settings/settings.html:151
-msgid "Show repository size after push"
-msgstr "push 後顯示版本庫大小"
-
-#: rhodecode/templates/admin/settings/settings.html:155
-msgid "Log user push commands"
-msgstr "紀錄使用者推送命令"
-
-#: rhodecode/templates/admin/settings/settings.html:159
-msgid "Log user pull commands"
-msgstr "紀錄使用者抓取命令"
-
-#: rhodecode/templates/admin/settings/settings.html:166
+#: rhodecode/templates/admin/settings/settings.html:224
+#, fuzzy
+msgid "Mercurial Extensions"
+msgstr "Mercurial 版本庫"
+
+#: rhodecode/templates/admin/settings/settings.html:229
+msgid "largefiles extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:233
+msgid "hgsubversion extensions"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:235
+msgid ""
+"Requires hgsubversion library installed. Allows clonning from svn remote "
+"locations"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:245
 msgid "Repositories location"
 msgstr "版本庫路徑"
 
-#: rhodecode/templates/admin/settings/settings.html:171
-msgid "This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock."
+#: rhodecode/templates/admin/settings/settings.html:250
+msgid ""
+"This a crucial application setting. If you are really sure you need to "
+"change this, you must restart application in order to make this setting "
+"take effect. Click this label to unlock."
 msgstr "這是一個關鍵的設定,如果您確定要修改這個設定,請重新啟動應用程式以套用設定"
 
-#: rhodecode/templates/admin/settings/settings.html:172
+#: rhodecode/templates/admin/settings/settings.html:251
 msgid "unlock"
 msgstr "解鎖"
 
+#: rhodecode/templates/admin/settings/settings.html:252
+msgid ""
+"Location where repositories are stored. After changing this value a "
+"restart, and rescan is required"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:272
+msgid "Test Email"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:280
+#, fuzzy
+msgid "Email to"
+msgstr "電子郵件"
+
+#: rhodecode/templates/admin/settings/settings.html:288
+#, fuzzy
+msgid "Send"
+msgstr "秒"
+
+#: rhodecode/templates/admin/settings/settings.html:294
+msgid "System Info and Packages"
+msgstr ""
+
+#: rhodecode/templates/admin/settings/settings.html:297
+#, fuzzy
+msgid "show"
+msgstr "顯示"
+
 #: rhodecode/templates/admin/users/user_add.html:5
 msgid "Add user"
 msgstr "新增使用者"
 
 #: rhodecode/templates/admin/users/user_add.html:10
 #: rhodecode/templates/admin/users/user_edit.html:11
-#: rhodecode/templates/admin/users/users.html:9
 msgid "Users"
 msgstr "使用者"
 
@@ -1710,8 +2483,13 @@
 msgid "add new user"
 msgstr "新增使用者"
 
-#: rhodecode/templates/admin/users/user_add.html:77
-#: rhodecode/templates/admin/users/user_edit.html:101
+#: rhodecode/templates/admin/users/user_add.html:50
+#, fuzzy
+msgid "Password confirmation"
+msgstr "密碼不相符"
+
+#: rhodecode/templates/admin/users/user_add.html:86
+#: rhodecode/templates/admin/users/user_edit.html:113
 #: rhodecode/templates/admin/users_groups/users_group_add.html:41
 #: rhodecode/templates/admin/users_groups/users_group_edit.html:42
 msgid "Active"
@@ -1721,36 +2499,101 @@
 msgid "Edit user"
 msgstr "編輯使用者"
 
-#: rhodecode/templates/admin/users/user_edit.html:33
-#: rhodecode/templates/admin/users/user_edit_my_account.html:32
+#: rhodecode/templates/admin/users/user_edit.html:34
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:10
 msgid "Change your avatar at"
 msgstr "修改您的頭像於"
 
-#: rhodecode/templates/admin/users/user_edit.html:34
-#: rhodecode/templates/admin/users/user_edit_my_account.html:33
+#: rhodecode/templates/admin/users/user_edit.html:35
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:11
 msgid "Using"
 msgstr "使用中"
 
-#: rhodecode/templates/admin/users/user_edit.html:40
-#: rhodecode/templates/admin/users/user_edit_my_account.html:39
+#: rhodecode/templates/admin/users/user_edit.html:43
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:20
 msgid "API key"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:56
+#: rhodecode/templates/admin/users/user_edit.html:59
 msgid "LDAP DN"
 msgstr ""
 
-#: rhodecode/templates/admin/users/user_edit.html:65
-#: rhodecode/templates/admin/users/user_edit_my_account.html:54
+#: rhodecode/templates/admin/users/user_edit.html:68
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:35
 msgid "New password"
 msgstr "新密碼"
 
-#: rhodecode/templates/admin/users/user_edit.html:135
-#: rhodecode/templates/admin/users_groups/users_group_edit.html:256
+#: rhodecode/templates/admin/users/user_edit.html:77
+#: rhodecode/templates/admin/users/user_edit_my_account_form.html:44
+msgid "New password confirmation"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:147
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:108
+#, fuzzy
+msgid "Inherit default permissions"
+msgstr "預設權限"
+
+#: rhodecode/templates/admin/users/user_edit.html:152
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:113
+#, python-format
+msgid ""
+"Select to inherit permissions from %s settings. With this selected below "
+"options does not have any action"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit.html:158
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:119
 msgid "Create repositories"
 msgstr "建立版本庫"
 
+#: rhodecode/templates/admin/users/user_edit.html:166
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:127
+#, fuzzy
+msgid "Fork repositories"
+msgstr "個版本庫"
+
+#: rhodecode/templates/admin/users/user_edit.html:186
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:22
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:39
+#, fuzzy
+msgid "Nothing here yet"
+msgstr "尚未有任何變更"
+
+#: rhodecode/templates/admin/users/user_edit.html:193
+#: rhodecode/templates/admin/users/user_edit_my_account.html:60
+#: rhodecode/templates/admin/users/user_edit_my_account.html:194
+#, fuzzy
+msgid "Permission"
+msgstr "權限"
+
+#: rhodecode/templates/admin/users/user_edit.html:194
+#, fuzzy
+msgid "Edit Permission"
+msgstr "版本庫權限"
+
+#: rhodecode/templates/admin/users/user_edit.html:243
+#, fuzzy
+msgid "Email addresses"
+msgstr "郵件位址"
+
+#: rhodecode/templates/admin/users/user_edit.html:256
+#, fuzzy, python-format
+msgid "Confirm to delete this email: %s"
+msgstr "確認刪除這個使用者"
+
+#: rhodecode/templates/admin/users/user_edit.html:270
+#, fuzzy
+msgid "New email address"
+msgstr "郵件位址"
+
+#: rhodecode/templates/admin/users/user_edit.html:277
+#, fuzzy
+msgid "Add"
+msgstr "新增"
+
 #: rhodecode/templates/admin/users/user_edit_my_account.html:5
+#: rhodecode/templates/base/base.html:124
 msgid "My account"
 msgstr "我的帳號"
 
@@ -1758,26 +2601,79 @@
 msgid "My Account"
 msgstr "我的帳號"
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:101
-msgid "My repositories"
-msgstr "我的版本庫"
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:107
-msgid "ADD REPOSITORY"
-msgstr "新增版本庫"
-
-#: rhodecode/templates/admin/users/user_edit_my_account.html:118
-#: rhodecode/templates/branches/branches_data.html:7
-#: rhodecode/templates/shortlog/shortlog_data.html:8
-#: rhodecode/templates/tags/tags_data.html:7
-msgid "revision"
+#: rhodecode/templates/admin/users/user_edit_my_account.html:35
+#, fuzzy
+msgid "My permissions"
+msgstr "權限"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:38
+#: rhodecode/templates/journal/journal.html:41
+#, fuzzy
+msgid "My repos"
+msgstr "空的版本庫"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:41
+#, fuzzy
+msgid "My pull requests"
+msgstr "建立使用者 %s"
+
+#: rhodecode/templates/admin/users/user_edit_my_account.html:45
+#, fuzzy
+msgid "Add repo"
+msgstr "新增"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:2
+msgid "Opened by me"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:10
+#, python-format
+msgid "Pull request #%s opened on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:15
+#, fuzzy
+msgid "Confirm to delete this pull request"
+msgstr "確認移除這個版本庫"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:26
+msgid "I participate in"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html:33
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:30
+#, python-format
+msgid "Pull request #%s opened by %s on %s"
+msgstr ""
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:7
+#: rhodecode/templates/bookmarks/bookmarks.html:40
+#: rhodecode/templates/bookmarks/bookmarks_data.html:9
+#: rhodecode/templates/branches/branches.html:55
+#: rhodecode/templates/journal/journal.html:60
+#: rhodecode/templates/tags/tags.html:40
+#: rhodecode/templates/tags/tags_data.html:9
+msgid "Revision"
 msgstr "修訂"
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:157
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:28
+#: rhodecode/templates/journal/journal.html:81
+msgid "private"
+msgstr "私有"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:7
+#, fuzzy, python-format
+msgid "Confirm to delete this repository: %s"
+msgstr "確認移除這個版本庫"
+
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:38
+#: rhodecode/templates/journal/journal.html:94
 msgid "No repositories yet"
 msgstr "沒有任何版本庫"
 
-#: rhodecode/templates/admin/users/user_edit_my_account.html:159
+#: rhodecode/templates/admin/users/user_edit_my_account_repos.html:40
+#: rhodecode/templates/journal/journal.html:96
 msgid "create one now"
 msgstr ""
 
@@ -1785,42 +2681,42 @@
 msgid "Users administration"
 msgstr "使用者管理員"
 
+#: rhodecode/templates/admin/users/users.html:9
+#: rhodecode/templates/base/base.html:223
+msgid "users"
+msgstr "使用者"
+
 #: rhodecode/templates/admin/users/users.html:23
 msgid "ADD NEW USER"
 msgstr "新增使用者"
 
-#: rhodecode/templates/admin/users/users.html:33
+#: rhodecode/templates/admin/users/users.html:77
 msgid "username"
 msgstr "使用者名稱"
 
-#: rhodecode/templates/admin/users/users.html:34
-#: rhodecode/templates/branches/branches_data.html:5
-#: rhodecode/templates/tags/tags_data.html:5
-msgid "name"
-msgstr "名字"
-
-#: rhodecode/templates/admin/users/users.html:35
+#: rhodecode/templates/admin/users/users.html:80
+#, fuzzy
+msgid "firstname"
+msgstr "名"
+
+#: rhodecode/templates/admin/users/users.html:81
 msgid "lastname"
 msgstr "姓"
 
-#: rhodecode/templates/admin/users/users.html:36
+#: rhodecode/templates/admin/users/users.html:82
 msgid "last login"
 msgstr "最後登入"
 
-#: rhodecode/templates/admin/users/users.html:37
+#: rhodecode/templates/admin/users/users.html:84
 #: rhodecode/templates/admin/users_groups/users_groups.html:34
 msgid "active"
 msgstr "啟用"
 
-#: rhodecode/templates/admin/users/users.html:39
-#: rhodecode/templates/base/base.html:305
+#: rhodecode/templates/admin/users/users.html:86
+#: rhodecode/templates/base/base.html:226
 msgid "ldap"
 msgstr ""
 
-#: rhodecode/templates/admin/users/users.html:56
-msgid "Confirm to delete this user"
-msgstr "確認刪除這個使用者"
-
 #: rhodecode/templates/admin/users_groups/users_group_add.html:5
 msgid "Add users group"
 msgstr "新增使用者群組"
@@ -1862,6 +2758,11 @@
 msgid "Add all elements"
 msgstr "新增索有元素"
 
+#: rhodecode/templates/admin/users_groups/users_group_edit.html:146
+#, fuzzy
+msgid "Group members"
+msgstr "選擇群組成員"
+
 #: rhodecode/templates/admin/users_groups/users_groups.html:5
 msgid "Users groups administration"
 msgstr "使用者群組管理員"
@@ -1874,399 +2775,633 @@
 msgid "group name"
 msgstr "群組名稱"
 
-#: rhodecode/templates/base/base.html:32
+#: rhodecode/templates/admin/users_groups/users_groups.html:33
+#: rhodecode/templates/base/root.html:46
+msgid "members"
+msgstr "成員"
+
+#: rhodecode/templates/admin/users_groups/users_groups.html:45
+#, fuzzy, python-format
+msgid "Confirm to delete this users group: %s"
+msgstr "確認刪除這個群組"
+
+#: rhodecode/templates/base/base.html:41
+msgid "Submit a bug"
+msgstr "回報錯誤"
+
+#: rhodecode/templates/base/base.html:77
+msgid "Login to your account"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:100
 msgid "Forgot password ?"
 msgstr "忘記密碼?"
 
-#: rhodecode/templates/base/base.html:57
-#: rhodecode/templates/base/base.html:338
-#: rhodecode/templates/base/base.html:340
-#: rhodecode/templates/base/base.html:342
+#: rhodecode/templates/base/base.html:107
+#, fuzzy
+msgid "Log In"
+msgstr "登入"
+
+#: rhodecode/templates/base/base.html:118
+msgid "Inbox"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:122
+#: rhodecode/templates/base/base.html:300
+#: rhodecode/templates/base/base.html:302
+#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/bookmarks/bookmarks.html:11
+#: rhodecode/templates/branches/branches.html:10
+#: rhodecode/templates/changelog/changelog.html:10
+#: rhodecode/templates/changeset/changeset.html:10
+#: rhodecode/templates/changeset/changeset_range.html:9
+#: rhodecode/templates/compare/compare_diff.html:9
+#: rhodecode/templates/files/file_diff.html:8
+#: rhodecode/templates/files/files.html:8
+#: rhodecode/templates/files/files_add.html:15
+#: rhodecode/templates/files/files_edit.html:15
+#: rhodecode/templates/followers/followers.html:9
+#: rhodecode/templates/forks/fork.html:9 rhodecode/templates/forks/forks.html:9
+#: rhodecode/templates/pullrequests/pullrequest.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show.html:8
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:8
+#: rhodecode/templates/settings/repo_settings.html:9
+#: rhodecode/templates/shortlog/shortlog.html:10
+#: rhodecode/templates/summary/summary.html:8
+#: rhodecode/templates/tags/tags.html:11
 msgid "Home"
 msgstr "首頁"
 
-#: rhodecode/templates/base/base.html:61
-#: rhodecode/templates/base/base.html:347
-#: rhodecode/templates/base/base.html:349
-#: rhodecode/templates/base/base.html:351
+#: rhodecode/templates/base/base.html:123
+#: rhodecode/templates/base/base.html:309
+#: rhodecode/templates/base/base.html:311
+#: rhodecode/templates/base/base.html:313
 #: rhodecode/templates/journal/journal.html:4
-#: rhodecode/templates/journal/journal.html:17
+#: rhodecode/templates/journal/journal.html:21
 #: rhodecode/templates/journal/public_journal.html:4
 msgid "Journal"
 msgstr "日誌"
 
-#: rhodecode/templates/base/base.html:66
-msgid "Login"
-msgstr "登入"
-
-#: rhodecode/templates/base/base.html:68
+#: rhodecode/templates/base/base.html:125
 msgid "Log Out"
 msgstr "登出"
 
-#: rhodecode/templates/base/base.html:107
-msgid "Submit a bug"
-msgstr "回報錯誤"
-
-#: rhodecode/templates/base/base.html:141
+#: rhodecode/templates/base/base.html:144
 msgid "Switch repository"
 msgstr "切換版本庫"
 
-#: rhodecode/templates/base/base.html:143
+#: rhodecode/templates/base/base.html:146
 msgid "Products"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:149
+#: rhodecode/templates/base/base.html:152
+#: rhodecode/templates/base/base.html:182
 msgid "loading..."
 msgstr "載入中..."
 
-#: rhodecode/templates/base/base.html:234
-#: rhodecode/templates/base/base.html:236
-#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:158
+#: rhodecode/templates/base/base.html:160
+#: rhodecode/templates/base/base.html:162
+#: rhodecode/templates/data_table/_dt_elements.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:17
+#: rhodecode/templates/data_table/_dt_elements.html:19
+msgid "Summary"
+msgstr "概況"
+
+#: rhodecode/templates/base/base.html:166
+#: rhodecode/templates/base/base.html:168
+#: rhodecode/templates/base/base.html:170
+#: rhodecode/templates/changelog/changelog.html:15
+#: rhodecode/templates/data_table/_dt_elements.html:23
+#: rhodecode/templates/data_table/_dt_elements.html:25
+#: rhodecode/templates/data_table/_dt_elements.html:27
+msgid "Changelog"
+msgstr "修改紀錄"
+
+#: rhodecode/templates/base/base.html:175
+#: rhodecode/templates/base/base.html:177
+#: rhodecode/templates/base/base.html:179
 msgid "Switch to"
 msgstr "切換至"
 
-#: rhodecode/templates/base/base.html:242
-#: rhodecode/templates/branches/branches.html:13
-msgid "branches"
-msgstr "分支"
-
-#: rhodecode/templates/base/base.html:249
-#: rhodecode/templates/branches/branches_data.html:52
-msgid "There are no branches yet"
-msgstr "沒有任何分支"
-
-#: rhodecode/templates/base/base.html:254
-#: rhodecode/templates/shortlog/shortlog_data.html:10
-#: rhodecode/templates/tags/tags.html:14
-msgid "tags"
-msgstr "標籤"
-
-#: rhodecode/templates/base/base.html:261
-#: rhodecode/templates/tags/tags_data.html:32
-msgid "There are no tags yet"
-msgstr "沒有任何標籤"
-
-#: rhodecode/templates/base/base.html:277
-#: rhodecode/templates/base/base.html:281
-#: rhodecode/templates/files/files_annotate.html:40
-#: rhodecode/templates/files/files_source.html:11
+#: rhodecode/templates/base/base.html:186
+#: rhodecode/templates/base/base.html:188
+#: rhodecode/templates/base/base.html:190
+#: rhodecode/templates/data_table/_dt_elements.html:31
+#: rhodecode/templates/data_table/_dt_elements.html:33
+#: rhodecode/templates/data_table/_dt_elements.html:35
+msgid "Files"
+msgstr "檔案"
+
+#: rhodecode/templates/base/base.html:195
+#: rhodecode/templates/base/base.html:199
 msgid "Options"
 msgstr "選項"
 
-#: rhodecode/templates/base/base.html:286
-#: rhodecode/templates/base/base.html:288
-#: rhodecode/templates/base/base.html:306
+#: rhodecode/templates/base/base.html:204
+#: rhodecode/templates/base/base.html:206
+#: rhodecode/templates/base/base.html:227
 msgid "settings"
 msgstr "設定"
 
-#: rhodecode/templates/base/base.html:292
+#: rhodecode/templates/base/base.html:209
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/forks/fork.html:13
+msgid "fork"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:211
+#: rhodecode/templates/changelog/changelog.html:40
+msgid "Open new pull request"
+msgstr ""
+
+#: rhodecode/templates/base/base.html:213
 msgid "search"
 msgstr "搜尋"
 
-#: rhodecode/templates/base/base.html:299
-msgid "journal"
-msgstr "日誌"
-
-#: rhodecode/templates/base/base.html:301
+#: rhodecode/templates/base/base.html:222
 msgid "repositories groups"
 msgstr "版本庫群組"
 
-#: rhodecode/templates/base/base.html:302
-msgid "users"
-msgstr "使用者"
-
-#: rhodecode/templates/base/base.html:303
+#: rhodecode/templates/base/base.html:224
 msgid "users groups"
 msgstr "使用者群組"
 
-#: rhodecode/templates/base/base.html:304
+#: rhodecode/templates/base/base.html:225
 msgid "permissions"
 msgstr "權限"
 
-#: rhodecode/templates/base/base.html:317
-#: rhodecode/templates/base/base.html:319
-#: rhodecode/templates/followers/followers.html:5
+#: rhodecode/templates/base/base.html:238
+#: rhodecode/templates/base/base.html:240
 msgid "Followers"
 msgstr "追蹤者"
 
-#: rhodecode/templates/base/base.html:325
-#: rhodecode/templates/base/base.html:327
-#: rhodecode/templates/forks/forks.html:5
+#: rhodecode/templates/base/base.html:246
+#: rhodecode/templates/base/base.html:248
 msgid "Forks"
 msgstr ""
 
-#: rhodecode/templates/base/base.html:356
-#: rhodecode/templates/base/base.html:358
-#: rhodecode/templates/base/base.html:360
-#: rhodecode/templates/search/search.html:4
-#: rhodecode/templates/search/search.html:24
-#: rhodecode/templates/search/search.html:46
+#: rhodecode/templates/base/base.html:327
+#: rhodecode/templates/base/base.html:329
+#: rhodecode/templates/base/base.html:331
+#: rhodecode/templates/search/search.html:52
 msgid "Search"
 msgstr "搜尋"
 
-#: rhodecode/templates/base/root.html:57
-#: rhodecode/templates/journal/journal.html:48
-#: rhodecode/templates/summary/summary.html:36
+#: rhodecode/templates/base/root.html:42
+#, fuzzy
+msgid "add another comment"
+msgstr "新增另ㄧ位成員"
+
+#: rhodecode/templates/base/root.html:43
+#: rhodecode/templates/journal/journal.html:120
+#: rhodecode/templates/summary/summary.html:57
 msgid "Stop following this repository"
 msgstr "停止追蹤這個版本庫"
 
-#: rhodecode/templates/base/root.html:66
-#: rhodecode/templates/summary/summary.html:40
+#: rhodecode/templates/base/root.html:44
+#: rhodecode/templates/summary/summary.html:61
 msgid "Start following this repository"
 msgstr "開始追蹤這個版本庫"
 
-#: rhodecode/templates/branches/branches_data.html:4
-#: rhodecode/templates/tags/tags_data.html:4
+#: rhodecode/templates/base/root.html:45
+msgid "Group"
+msgstr "群組"
+
+#: rhodecode/templates/base/root.html:47
+msgid "search truncated"
+msgstr ""
+
+#: rhodecode/templates/base/root.html:48
+msgid "no matching files"
+msgstr "無符合的檔案"
+
+#: rhodecode/templates/bookmarks/bookmarks.html:5
+#, python-format
+msgid "%s Bookmarks"
+msgstr ""
+
+#: rhodecode/templates/bookmarks/bookmarks.html:39
+#: rhodecode/templates/bookmarks/bookmarks_data.html:8
+#: rhodecode/templates/branches/branches.html:54
+#: rhodecode/templates/tags/tags.html:39
+#: rhodecode/templates/tags/tags_data.html:8
+#, fuzzy
+msgid "Author"
+msgstr "作者"
+
+#: rhodecode/templates/branches/branches.html:5
+#, fuzzy, python-format
+msgid "%s Branches"
+msgstr "分支"
+
+#: rhodecode/templates/branches/branches.html:29
+#, fuzzy
+msgid "Compare branches"
+msgstr "分支"
+
+#: rhodecode/templates/branches/branches.html:57
+#: rhodecode/templates/compare/compare_diff.html:5
+#: rhodecode/templates/compare/compare_diff.html:13
+#, fuzzy
+msgid "Compare"
+msgstr "比較顯示"
+
+#: rhodecode/templates/branches/branches_data.html:6
+msgid "name"
+msgstr "名字"
+
+#: rhodecode/templates/branches/branches_data.html:7
 msgid "date"
 msgstr "日期"
 
-#: rhodecode/templates/branches/branches_data.html:6
-#: rhodecode/templates/shortlog/shortlog_data.html:7
-#: rhodecode/templates/tags/tags_data.html:6
-msgid "author"
-msgstr "作者"
-
 #: rhodecode/templates/branches/branches_data.html:8
-#: rhodecode/templates/shortlog/shortlog_data.html:11
-#: rhodecode/templates/tags/tags_data.html:8
-msgid "links"
-msgstr "連結"
-
-#: rhodecode/templates/branches/branches_data.html:23
-#: rhodecode/templates/branches/branches_data.html:43
-#: rhodecode/templates/shortlog/shortlog_data.html:39
-#: rhodecode/templates/tags/tags_data.html:24
-msgid "changeset"
-msgstr "修改"
-
-#: rhodecode/templates/branches/branches_data.html:25
-#: rhodecode/templates/branches/branches_data.html:45
-#: rhodecode/templates/files/files.html:12
-#: rhodecode/templates/shortlog/shortlog_data.html:41
-#: rhodecode/templates/summary/summary.html:233
-#: rhodecode/templates/tags/tags_data.html:26
-msgid "files"
-msgstr "檔案"
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "showing "
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:14
-msgid "out of"
+#: rhodecode/templates/shortlog/shortlog_data.html:8
+msgid "author"
+msgstr "作者"
+
+#: rhodecode/templates/branches/branches_data.html:9
+#: rhodecode/templates/shortlog/shortlog_data.html:5
+msgid "revision"
+msgstr "修訂"
+
+#: rhodecode/templates/branches/branches_data.html:10
+#, fuzzy
+msgid "compare"
+msgstr "比較顯示"
+
+#: rhodecode/templates/changelog/changelog.html:6
+#, fuzzy, python-format
+msgid "%s Changelog"
+msgstr "修改紀錄"
+
+#: rhodecode/templates/changelog/changelog.html:15
+#, python-format
+msgid "showing %d out of %d revision"
+msgid_plural "showing %d out of %d revisions"
+msgstr[0] ""
+
+#: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:19
+#, python-format
+msgid "compare fork with %s"
 msgstr ""
 
 #: rhodecode/templates/changelog/changelog.html:37
+#: rhodecode/templates/forks/forks_data.html:21
+msgid "Compare fork"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:46
 msgid "Show"
 msgstr "顯示"
 
-#: rhodecode/templates/changelog/changelog.html:50
-#: rhodecode/templates/changeset/changeset.html:42
-#: rhodecode/templates/summary/summary.html:609
-msgid "commit"
-msgstr "遞交"
-
-#: rhodecode/templates/changelog/changelog.html:63
+#: rhodecode/templates/changelog/changelog.html:72
+#: rhodecode/templates/summary/summary.html:364
+msgid "show more"
+msgstr "顯示更多"
+
+#: rhodecode/templates/changelog/changelog.html:76
 msgid "Affected number of files, click to show more details"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:67
-#: rhodecode/templates/changeset/changeset.html:66
+#: rhodecode/templates/changelog/changelog.html:89
+#: rhodecode/templates/changeset/changeset.html:38
+#: rhodecode/templates/changeset/changeset_file_comment.html:20
+#: rhodecode/templates/changeset/changeset_range.html:46
+#, fuzzy
+msgid "Changeset status"
+msgstr "變更"
+
+#: rhodecode/templates/changelog/changelog.html:92
+msgid "Click to open associated pull request"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:102
+#: rhodecode/templates/changeset/changeset.html:78
+msgid "Parent"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:108
+#: rhodecode/templates/changeset/changeset.html:84
+msgid "No parents"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:113
+#: rhodecode/templates/changeset/changeset.html:88
 msgid "merge"
 msgstr "合併"
 
-#: rhodecode/templates/changelog/changelog.html:72
-#: rhodecode/templates/changeset/changeset.html:72
-msgid "Parent"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:77
-#: rhodecode/templates/changeset/changeset.html:77
-msgid "No parents"
-msgstr ""
-
-#: rhodecode/templates/changelog/changelog.html:82
-#: rhodecode/templates/changeset/changeset.html:80
+#: rhodecode/templates/changelog/changelog.html:116
+#: rhodecode/templates/changeset/changeset.html:91
 #: rhodecode/templates/files/files.html:29
-#: rhodecode/templates/files/files_annotate.html:25
+#: rhodecode/templates/files/files_add.html:33
 #: rhodecode/templates/files/files_edit.html:33
 #: rhodecode/templates/shortlog/shortlog_data.html:9
 msgid "branch"
 msgstr "分支"
 
-#: rhodecode/templates/changelog/changelog.html:86
-#: rhodecode/templates/changeset/changeset.html:83
+#: rhodecode/templates/changelog/changelog.html:122
+msgid "bookmark"
+msgstr ""
+
+#: rhodecode/templates/changelog/changelog.html:128
+#: rhodecode/templates/changeset/changeset.html:96
 msgid "tag"
 msgstr "標籤"
 
-#: rhodecode/templates/changelog/changelog.html:122
+#: rhodecode/templates/changelog/changelog.html:164
 msgid "Show selected changes __S -> __E"
 msgstr ""
 
-#: rhodecode/templates/changelog/changelog.html:172
-#: rhodecode/templates/shortlog/shortlog_data.html:61
+#: rhodecode/templates/changelog/changelog.html:255
 msgid "There are no changes yet"
 msgstr "尚未有任何變更"
 
-#: rhodecode/templates/changelog/changelog_details.html:2
-#: rhodecode/templates/changeset/changeset.html:55
+#: rhodecode/templates/changelog/changelog_details.html:4
+#: rhodecode/templates/changeset/changeset.html:66
 msgid "removed"
 msgstr "移除"
 
-#: rhodecode/templates/changelog/changelog_details.html:3
-#: rhodecode/templates/changeset/changeset.html:56
+#: rhodecode/templates/changelog/changelog_details.html:5
+#: rhodecode/templates/changeset/changeset.html:67
 msgid "changed"
 msgstr "修改"
 
-#: rhodecode/templates/changelog/changelog_details.html:4
-#: rhodecode/templates/changeset/changeset.html:57
+#: rhodecode/templates/changelog/changelog_details.html:6
+#: rhodecode/templates/changeset/changeset.html:68
 msgid "added"
 msgstr "新增"
 
-#: rhodecode/templates/changelog/changelog_details.html:6
-#: rhodecode/templates/changelog/changelog_details.html:7
 #: rhodecode/templates/changelog/changelog_details.html:8
-#: rhodecode/templates/changeset/changeset.html:59
-#: rhodecode/templates/changeset/changeset.html:60
-#: rhodecode/templates/changeset/changeset.html:61
+#: rhodecode/templates/changelog/changelog_details.html:9
+#: rhodecode/templates/changelog/changelog_details.html:10
+#: rhodecode/templates/changeset/changeset.html:70
+#: rhodecode/templates/changeset/changeset.html:71
+#: rhodecode/templates/changeset/changeset.html:72
 #, python-format
 msgid "affected %s files"
 msgstr ""
 
 #: rhodecode/templates/changeset/changeset.html:6
+#, fuzzy, python-format
+msgid "%s Changeset"
+msgstr "沒有修改"
+
 #: rhodecode/templates/changeset/changeset.html:14
-#: rhodecode/templates/changeset/changeset.html:31
 msgid "Changeset"
 msgstr ""
 
-#: rhodecode/templates/changeset/changeset.html:32
-#: rhodecode/templates/changeset/changeset.html:121
-#: rhodecode/templates/changeset/changeset_range.html:78
-#: rhodecode/templates/files/file_diff.html:32
-#: rhodecode/templates/files/file_diff.html:42
+#: rhodecode/templates/changeset/changeset.html:43
+#: rhodecode/templates/changeset/diff_block.html:20
 msgid "raw diff"
 msgstr "原始差異"
 
-#: rhodecode/templates/changeset/changeset.html:34
-#: rhodecode/templates/changeset/changeset.html:123
-#: rhodecode/templates/changeset/changeset_range.html:80
-#: rhodecode/templates/files/file_diff.html:34
+#: rhodecode/templates/changeset/changeset.html:44
+#: rhodecode/templates/changeset/diff_block.html:21
 msgid "download diff"
 msgstr "下載差異"
 
-#: rhodecode/templates/changeset/changeset.html:90
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
+#, fuzzy, python-format
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] "遞交"
+
+#: rhodecode/templates/changeset/changeset.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:82
 #, python-format
-msgid "%s files affected with %s additions and %s deletions."
-msgstr ""
-
-#: rhodecode/templates/changeset/changeset.html:101
-msgid "Changeset was too big and was cut off..."
+msgid "(%d inline)"
+msgid_plural "(%d inline)"
+msgstr[0] ""
+
+#: rhodecode/templates/changeset/changeset.html:103
+#, python-format
+msgid "%s files affected with %s insertions and %s deletions:"
 msgstr ""
 
 #: rhodecode/templates/changeset/changeset.html:119
-#: rhodecode/templates/changeset/changeset_range.html:76
-#: rhodecode/templates/files/file_diff.html:30
+msgid "Changeset was too big and was cut off..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:42
+msgid "Submitting..."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:45
+msgid "Commenting on line {1}."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:46
+#: rhodecode/templates/changeset/changeset_file_comment.html:121
+#, python-format
+msgid "Comments parsed using %s syntax with %s support."
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:48
+#: rhodecode/templates/changeset/changeset_file_comment.html:123
+msgid "Use @username inside this text to send notification to this RhodeCode user"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:59
+#: rhodecode/templates/changeset/changeset_file_comment.html:138
+#, fuzzy
+msgid "Comment"
+msgstr "遞交"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:60
+#: rhodecode/templates/changeset/changeset_file_comment.html:71
+msgid "Hide"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+#, fuzzy
+msgid "You need to be logged in to comment."
+msgstr "您必須登入後才能瀏覽這個頁面"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:67
+msgid "Login now"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:118
+msgid "Leave a comment"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+msgid "Check this to change current status of code-review for this changeset"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:124
+#, fuzzy
+msgid "change status"
+msgstr "變更"
+
+#: rhodecode/templates/changeset/changeset_file_comment.html:140
+msgid "Comment and close"
+msgstr ""
+
+#: rhodecode/templates/changeset/changeset_range.html:5
+#, fuzzy, python-format
+msgid "%s Changesets"
+msgstr "變更"
+
+#: rhodecode/templates/changeset/changeset_range.html:29
+#: rhodecode/templates/compare/compare_diff.html:29
+msgid "Compare View"
+msgstr "比較顯示"
+
+#: rhodecode/templates/changeset/changeset_range.html:54
+#: rhodecode/templates/compare/compare_diff.html:41
+#: rhodecode/templates/pullrequests/pullrequest_show.html:69
+msgid "Files affected"
+msgstr ""
+
+#: rhodecode/templates/changeset/diff_block.html:19
 msgid "diff"
 msgstr "差異"
 
-#: rhodecode/templates/changeset/changeset.html:132
-#: rhodecode/templates/changeset/changeset_range.html:89
-msgid "No changes in this file"
-msgstr "這個檔案沒有任何變更"
-
-#: rhodecode/templates/changeset/changeset_range.html:30
-msgid "Compare View"
-msgstr "比較顯示"
-
-#: rhodecode/templates/changeset/changeset_range.html:52
-msgid "Files affected"
-msgstr ""
-
-#: rhodecode/templates/errors/error_document.html:44
+#: rhodecode/templates/changeset/diff_block.html:27
+#, fuzzy
+msgid "show inline comments"
+msgstr "文件內容"
+
+#: rhodecode/templates/compare/compare_cs.html:5
+#, fuzzy
+msgid "No changesets"
+msgstr "尚未有任何變更"
+
+#: rhodecode/templates/compare/compare_diff.html:37
+#, fuzzy
+msgid "Outgoing changesets"
+msgstr "尚未有任何變更"
+
+#: rhodecode/templates/data_table/_dt_elements.html:39
+#: rhodecode/templates/data_table/_dt_elements.html:41
+#: rhodecode/templates/data_table/_dt_elements.html:43
+msgid "Fork"
+msgstr "分支"
+
+#: rhodecode/templates/data_table/_dt_elements.html:60
+#: rhodecode/templates/journal/journal.html:126
+#: rhodecode/templates/summary/summary.html:68
+msgid "Mercurial repository"
+msgstr "Mercurial 版本庫"
+
+#: rhodecode/templates/data_table/_dt_elements.html:62
+#: rhodecode/templates/journal/journal.html:128
+#: rhodecode/templates/summary/summary.html:71
+msgid "Git repository"
+msgstr "Git 版本庫"
+
+#: rhodecode/templates/data_table/_dt_elements.html:69
+#: rhodecode/templates/journal/journal.html:134
+#: rhodecode/templates/summary/summary.html:78
+msgid "public repository"
+msgstr "公開版本庫"
+
+#: rhodecode/templates/data_table/_dt_elements.html:80
+#: rhodecode/templates/summary/summary.html:87
+#: rhodecode/templates/summary/summary.html:88
+msgid "Fork of"
+msgstr ""
+
+#: rhodecode/templates/data_table/_dt_elements.html:92
+msgid "No changesets yet"
+msgstr "尚未有任何變更"
+
+#: rhodecode/templates/data_table/_dt_elements.html:104
+#, fuzzy, python-format
+msgid "Confirm to delete this user: %s"
+msgstr "確認刪除這個使用者"
+
+#: rhodecode/templates/email_templates/main.html:8
+msgid "This is an notification from RhodeCode."
+msgstr ""
+
+#: rhodecode/templates/errors/error_document.html:46
 #, python-format
 msgid "You will be redirected to %s in %s seconds"
 msgstr ""
 
 #: rhodecode/templates/files/file_diff.html:4
+#, fuzzy, python-format
+msgid "%s File diff"
+msgstr "檔案差異"
+
 #: rhodecode/templates/files/file_diff.html:12
 msgid "File diff"
 msgstr "檔案差異"
 
-#: rhodecode/templates/files/file_diff.html:42
-msgid "Diff is to big to display"
-msgstr ""
-
-#: rhodecode/templates/files/files.html:37
-#: rhodecode/templates/files/files_annotate.html:31
+#: rhodecode/templates/files/files.html:4
+#: rhodecode/templates/files/files.html:72
+#, fuzzy, python-format
+msgid "%s files"
+msgstr "檔案"
+
+#: rhodecode/templates/files/files.html:12
+#: rhodecode/templates/summary/summary.html:340
+msgid "files"
+msgstr "檔案"
+
+#: rhodecode/templates/files/files_add.html:4
+#: rhodecode/templates/files/files_edit.html:4
+#, fuzzy, python-format
+msgid "%s Edit file"
+msgstr "編輯檔案"
+
+#: rhodecode/templates/files/files_add.html:19
+#, fuzzy
+msgid "add file"
+msgstr "編輯檔案"
+
+#: rhodecode/templates/files/files_add.html:40
+#, fuzzy
+msgid "Add new file"
+msgstr "新增使用者"
+
+#: rhodecode/templates/files/files_add.html:45
+#, fuzzy
+msgid "File Name"
+msgstr "檔案名稱"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:58
+#, fuzzy
+msgid "or"
+msgstr "時"
+
+#: rhodecode/templates/files/files_add.html:49
+#: rhodecode/templates/files/files_add.html:54
+#, fuzzy
+msgid "Upload file"
+msgstr "編輯檔案"
+
+#: rhodecode/templates/files/files_add.html:58
+#, fuzzy
+msgid "Create new file"
+msgstr "建立使用者 %s"
+
+#: rhodecode/templates/files/files_add.html:63
 #: rhodecode/templates/files/files_edit.html:39
+#: rhodecode/templates/files/files_ypjax.html:3
 msgid "Location"
 msgstr "位置"
 
-#: rhodecode/templates/files/files.html:46
-msgid "Go back"
-msgstr ""
-
-#: rhodecode/templates/files/files.html:47
-msgid "No files at given path"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:4
-msgid "File annotate"
-msgstr "檔案註釋"
-
-#: rhodecode/templates/files/files_annotate.html:12
-msgid "annotate"
-msgstr "註釋"
-
-#: rhodecode/templates/files/files_annotate.html:33
-#: rhodecode/templates/files/files_browser.html:160
-#: rhodecode/templates/files/files_source.html:2
-msgid "Revision"
-msgstr "修訂"
-
-#: rhodecode/templates/files/files_annotate.html:36
-#: rhodecode/templates/files/files_browser.html:158
-#: rhodecode/templates/files/files_source.html:7
-msgid "Size"
-msgstr "大小"
-
-#: rhodecode/templates/files/files_annotate.html:38
-#: rhodecode/templates/files/files_browser.html:159
-#: rhodecode/templates/files/files_source.html:9
-msgid "Mimetype"
-msgstr ""
-
-#: rhodecode/templates/files/files_annotate.html:41
-msgid "show source"
-msgstr "顯示原始碼"
-
-#: rhodecode/templates/files/files_annotate.html:43
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:14
-#: rhodecode/templates/files/files_source.html:51
-msgid "show as raw"
-msgstr "顯示原始文件"
-
-#: rhodecode/templates/files/files_annotate.html:45
-#: rhodecode/templates/files/files_source.html:16
-msgid "download as raw"
-msgstr "下載原始文件"
-
-#: rhodecode/templates/files/files_annotate.html:54
-#: rhodecode/templates/files/files_source.html:25
-msgid "History"
-msgstr "歷史"
-
-#: rhodecode/templates/files/files_annotate.html:73
-#: rhodecode/templates/files/files_source.html:46
-#, python-format
-msgid "Binary file (%s)"
-msgstr "二進位檔 (%s)"
-
-#: rhodecode/templates/files/files_annotate.html:78
-#: rhodecode/templates/files/files_source.html:51
-msgid "File is too big to display"
-msgstr "顯示的檔案太大"
+#: rhodecode/templates/files/files_add.html:67
+msgid "use / to separate directories"
+msgstr ""
+
+#: rhodecode/templates/files/files_add.html:77
+#: rhodecode/templates/files/files_edit.html:63
+#: rhodecode/templates/shortlog/shortlog_data.html:6
+msgid "commit message"
+msgstr "遞交資訊"
+
+#: rhodecode/templates/files/files_add.html:81
+#: rhodecode/templates/files/files_edit.html:67
+msgid "Commit changes"
+msgstr "遞交修改"
 
 #: rhodecode/templates/files/files_browser.html:13
 msgid "view"
@@ -2288,59 +3423,170 @@
 msgid "search file list"
 msgstr "搜尋檔案列表"
 
-#: rhodecode/templates/files/files_browser.html:32
+#: rhodecode/templates/files/files_browser.html:31
+#: rhodecode/templates/shortlog/shortlog_data.html:65
+#, fuzzy
+msgid "add new file"
+msgstr "新增使用者"
+
+#: rhodecode/templates/files/files_browser.html:35
 msgid "Loading file list..."
 msgstr "載入檔案列表..."
 
-#: rhodecode/templates/files/files_browser.html:111
-msgid "search truncated"
-msgstr ""
-
-#: rhodecode/templates/files/files_browser.html:122
-msgid "no matching files"
-msgstr "無符合的檔案"
-
-#: rhodecode/templates/files/files_browser.html:161
+#: rhodecode/templates/files/files_browser.html:48
+msgid "Size"
+msgstr "大小"
+
+#: rhodecode/templates/files/files_browser.html:49
+msgid "Mimetype"
+msgstr ""
+
+#: rhodecode/templates/files/files_browser.html:50
+#, fuzzy
+msgid "Last Revision"
+msgstr "下一個修訂"
+
+#: rhodecode/templates/files/files_browser.html:51
 msgid "Last modified"
 msgstr "最後修改"
 
-#: rhodecode/templates/files/files_browser.html:162
+#: rhodecode/templates/files/files_browser.html:52
 msgid "Last commiter"
 msgstr "最後的遞交者"
 
-#: rhodecode/templates/files/files_edit.html:4
-msgid "Edit file"
-msgstr "編輯檔案"
-
 #: rhodecode/templates/files/files_edit.html:19
 msgid "edit file"
 msgstr "編輯檔案"
 
-#: rhodecode/templates/files/files_edit.html:45
-#: rhodecode/templates/shortlog/shortlog_data.html:5
-msgid "commit message"
-msgstr "遞交資訊"
+#: rhodecode/templates/files/files_edit.html:49
+#: rhodecode/templates/files/files_source.html:38
+msgid "show annotation"
+msgstr "險是註釋"
+
+#: rhodecode/templates/files/files_edit.html:50
+#: rhodecode/templates/files/files_source.html:40
+#: rhodecode/templates/files/files_source.html:68
+msgid "show as raw"
+msgstr "顯示原始文件"
 
 #: rhodecode/templates/files/files_edit.html:51
-msgid "Commit changes"
-msgstr "遞交修改"
-
-#: rhodecode/templates/files/files_source.html:12
-msgid "show annotation"
+#: rhodecode/templates/files/files_source.html:41
+msgid "download as raw"
+msgstr "下載原始文件"
+
+#: rhodecode/templates/files/files_edit.html:54
+#, fuzzy
+msgid "source"
+msgstr "顯示原始碼"
+
+#: rhodecode/templates/files/files_edit.html:59
+#, fuzzy
+msgid "Editing file"
+msgstr "編輯檔案"
+
+#: rhodecode/templates/files/files_source.html:2
+msgid "History"
+msgstr "歷史"
+
+#: rhodecode/templates/files/files_source.html:9
+#, fuzzy
+msgid "diff to revision"
+msgstr "下一個修訂"
+
+#: rhodecode/templates/files/files_source.html:10
+#, fuzzy
+msgid "show at revision"
+msgstr "下一個修訂"
+
+#: rhodecode/templates/files/files_source.html:14
+#, fuzzy, python-format
+msgid "%s author"
+msgid_plural "%s authors"
+msgstr[0] "作者"
+
+#: rhodecode/templates/files/files_source.html:36
+msgid "show source"
+msgstr "顯示原始碼"
+
+#: rhodecode/templates/files/files_source.html:59
+#, python-format
+msgid "Binary file (%s)"
+msgstr "二進位檔 (%s)"
+
+#: rhodecode/templates/files/files_source.html:68
+msgid "File is too big to display"
+msgstr "顯示的檔案太大"
+
+#: rhodecode/templates/files/files_source.html:124
+msgid "Selection link"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:5
+#, fuzzy
+msgid "annotation"
 msgstr "險是註釋"
 
-#: rhodecode/templates/files/files_source.html:153
-msgid "Selection link"
-msgstr ""
+#: rhodecode/templates/files/files_ypjax.html:15
+msgid "Go back"
+msgstr ""
+
+#: rhodecode/templates/files/files_ypjax.html:16
+msgid "No files at given path"
+msgstr ""
+
+#: rhodecode/templates/followers/followers.html:5
+#, fuzzy, python-format
+msgid "%s Followers"
+msgstr "追蹤者"
 
 #: rhodecode/templates/followers/followers.html:13
 msgid "followers"
 msgstr "追蹤者"
 
 #: rhodecode/templates/followers/followers_data.html:12
-msgid "Started following"
+#, fuzzy
+msgid "Started following -"
 msgstr "開始追蹤"
 
+#: rhodecode/templates/forks/fork.html:5
+#, fuzzy, python-format
+msgid "%s Fork"
+msgstr "分支"
+
+#: rhodecode/templates/forks/fork.html:31
+msgid "Fork name"
+msgstr "分支名稱"
+
+#: rhodecode/templates/forks/fork.html:68
+msgid "Private"
+msgstr "私有"
+
+#: rhodecode/templates/forks/fork.html:77
+#, fuzzy
+msgid "Copy permissions"
+msgstr "權限"
+
+#: rhodecode/templates/forks/fork.html:81
+msgid "Copy permissions from forked repository"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:86
+msgid "Update after clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:90
+msgid "Checkout source after making a clone"
+msgstr ""
+
+#: rhodecode/templates/forks/fork.html:94
+msgid "fork this repository"
+msgstr "fork 這個版本庫"
+
+#: rhodecode/templates/forks/forks.html:5
+#, fuzzy, python-format
+msgid "%s Forks"
+msgstr "分支"
+
 #: rhodecode/templates/forks/forks.html:13
 msgid "forks"
 msgstr "分支"
@@ -2349,184 +3595,419 @@
 msgid "forked"
 msgstr "已建立分支"
 
-#: rhodecode/templates/forks/forks_data.html:34
+#: rhodecode/templates/forks/forks_data.html:38
 msgid "There are no forks yet"
 msgstr "尚未有任何 fork"
 
-#: rhodecode/templates/journal/journal.html:34
-msgid "Following"
-msgstr "已追蹤"
-
-#: rhodecode/templates/journal/journal.html:41
-msgid "following user"
-msgstr "追蹤使用者"
+#: rhodecode/templates/journal/journal.html:13
+#, fuzzy
+msgid "ATOM journal feed"
+msgstr "%s 公開日誌 %s feed"
+
+#: rhodecode/templates/journal/journal.html:14
+#, fuzzy
+msgid "RSS journal feed"
+msgstr "%s 公開日誌 %s feed"
+
+#: rhodecode/templates/journal/journal.html:24
+#: rhodecode/templates/pullrequests/pullrequest.html:27
+msgid "Refresh"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:27
+#: rhodecode/templates/journal/public_journal.html:24
+msgid "RSS feed"
+msgstr ""
+
+#: rhodecode/templates/journal/journal.html:30
+#: rhodecode/templates/journal/public_journal.html:27
+msgid "ATOM feed"
+msgstr ""
 
 #: rhodecode/templates/journal/journal.html:41
+#, fuzzy
+msgid "Watched"
+msgstr "快取"
+
+#: rhodecode/templates/journal/journal.html:46
+#, fuzzy
+msgid "ADD"
+msgstr "新增"
+
+#: rhodecode/templates/journal/journal.html:114
+msgid "following user"
+msgstr "追蹤使用者"
+
+#: rhodecode/templates/journal/journal.html:114
 msgid "user"
 msgstr "使用者"
 
-#: rhodecode/templates/journal/journal.html:65
+#: rhodecode/templates/journal/journal.html:147
 msgid "You are not following any users or repositories"
 msgstr "您尚未追蹤任何使用者或版本庫"
 
-#: rhodecode/templates/journal/journal_data.html:46
+#: rhodecode/templates/journal/journal_data.html:47
 msgid "No entries yet"
 msgstr ""
 
-#: rhodecode/templates/journal/public_journal.html:17
+#: rhodecode/templates/journal/public_journal.html:13
+#, fuzzy
+msgid "ATOM public journal feed"
+msgstr "%s 公開日誌 %s feed"
+
+#: rhodecode/templates/journal/public_journal.html:14
+#, fuzzy
+msgid "RSS public journal feed"
+msgstr "%s 公開日誌 %s feed"
+
+#: rhodecode/templates/journal/public_journal.html:21
 msgid "Public Journal"
 msgstr "開放日誌"
 
-#: rhodecode/templates/search/search.html:7
-#: rhodecode/templates/search/search.html:26
-msgid "in repository: "
+#: rhodecode/templates/pullrequests/pullrequest.html:4
+#: rhodecode/templates/pullrequests/pullrequest.html:12
+msgid "New pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:28
+msgid "refresh overview"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:66
+#, fuzzy
+msgid "Detailed compare view"
+msgstr "比較顯示"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:70
+#: rhodecode/templates/pullrequests/pullrequest_show.html:82
+msgid "Pull request reviewers"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:79
+#: rhodecode/templates/pullrequests/pullrequest_show.html:94
+#, fuzzy
+msgid "owner"
+msgstr "擁有者"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:91
+#: rhodecode/templates/pullrequests/pullrequest_show.html:109
+msgid "Add reviewer to this pull request."
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest.html:97
+#, fuzzy
+msgid "Create new pull request"
+msgstr "建立使用者 %s"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:106
+#: rhodecode/templates/pullrequests/pullrequest_show.html:25
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:33
+#, fuzzy
+msgid "Title"
+msgstr "寫"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:115
+#, fuzzy
+msgid "description"
+msgstr "描述"
+
+#: rhodecode/templates/pullrequests/pullrequest.html:123
+msgid "Send pull request"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:23
+#, python-format
+msgid "Closed %s"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:31
+#, fuzzy
+msgid "Status"
+msgstr "變更"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:36
+msgid "Pull request status"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:44
+msgid "Still not reviewed by"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:47
+#, python-format
+msgid "%d reviewer"
+msgid_plural "%d reviewers"
+msgstr[0] ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:54
+#, fuzzy
+msgid "Created on"
+msgstr "建立使用者 %s"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:61
+#, fuzzy
+msgid "Compare view"
+msgstr "比較顯示"
+
+#: rhodecode/templates/pullrequests/pullrequest_show.html:65
+#, fuzzy
+msgid "Incoming changesets"
+msgstr "尚未有任何變更"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:4
+#, fuzzy
+msgid "all pull requests"
+msgstr "建立使用者 %s"
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:12
+msgid "All pull requests"
+msgstr ""
+
+#: rhodecode/templates/pullrequests/pullrequest_show_all.html:27
+msgid "Closed"
+msgstr ""
+
+#: rhodecode/templates/search/search.html:6
+#, fuzzy, python-format
+msgid "Search \"%s\" in repository: %s"
 msgstr "於版本庫:"
 
-#: rhodecode/templates/search/search.html:9
-#: rhodecode/templates/search/search.html:28
-msgid "in all repositories"
+#: rhodecode/templates/search/search.html:8
+#, fuzzy, python-format
+msgid "Search \"%s\" in all repositories"
 msgstr "於所有的版本庫"
 
-#: rhodecode/templates/search/search.html:42
+#: rhodecode/templates/search/search.html:12
+#: rhodecode/templates/search/search.html:32
+#, fuzzy, python-format
+msgid "Search in repository: %s"
+msgstr "於版本庫:"
+
+#: rhodecode/templates/search/search.html:14
+#: rhodecode/templates/search/search.html:34
+#, fuzzy
+msgid "Search in all repositories"
+msgstr "於所有的版本庫"
+
+#: rhodecode/templates/search/search.html:48
 msgid "Search term"
 msgstr "搜尋關鍵字"
 
-#: rhodecode/templates/search/search.html:54
+#: rhodecode/templates/search/search.html:60
 msgid "Search in"
 msgstr "搜尋範圍"
 
-#: rhodecode/templates/search/search.html:57
+#: rhodecode/templates/search/search.html:63
 msgid "File contents"
 msgstr "文件內容"
 
-#: rhodecode/templates/search/search.html:59
+#: rhodecode/templates/search/search.html:64
+#, fuzzy
+msgid "Commit messages"
+msgstr "遞交資訊"
+
+#: rhodecode/templates/search/search.html:65
 msgid "File names"
 msgstr "檔案名稱"
 
-#: rhodecode/templates/search/search_content.html:20
+#: rhodecode/templates/search/search_commit.html:35
+#: rhodecode/templates/search/search_content.html:21
 #: rhodecode/templates/search/search_path.html:15
 msgid "Permission denied"
 msgstr "權限不足"
 
-#: rhodecode/templates/settings/repo_fork.html:5
-msgid "Fork"
-msgstr "分支"
-
-#: rhodecode/templates/settings/repo_fork.html:31
-msgid "Fork name"
-msgstr "分支名稱"
-
-#: rhodecode/templates/settings/repo_fork.html:55
-msgid "fork this repository"
-msgstr "fork 這個版本庫"
+#: rhodecode/templates/settings/repo_settings.html:5
+#, fuzzy, python-format
+msgid "%s Settings"
+msgstr "設定"
 
 #: rhodecode/templates/shortlog/shortlog.html:5
-#: rhodecode/templates/summary/summary.html:666
-msgid "Shortlog"
+#, fuzzy, python-format
+msgid "%s Shortlog"
 msgstr "簡短紀錄"
 
 #: rhodecode/templates/shortlog/shortlog.html:14
 msgid "shortlog"
 msgstr "簡短紀錄"
 
-#: rhodecode/templates/shortlog/shortlog_data.html:6
+#: rhodecode/templates/shortlog/shortlog_data.html:7
 msgid "age"
 msgstr ""
 
+#: rhodecode/templates/shortlog/shortlog_data.html:18
+#, fuzzy
+msgid "No commit message"
+msgstr "遞交資訊"
+
+#: rhodecode/templates/shortlog/shortlog_data.html:62
+msgid "Add or upload files directly via RhodeCode"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:71
+msgid "Push new repo"
+msgstr ""
+
+#: rhodecode/templates/shortlog/shortlog_data.html:79
+#, fuzzy
+msgid "Existing repository?"
+msgstr "Git 版本庫"
+
+#: rhodecode/templates/summary/summary.html:4
+#, fuzzy, python-format
+msgid "%s Summary"
+msgstr "概況"
+
 #: rhodecode/templates/summary/summary.html:12
 msgid "summary"
 msgstr "概況"
 
-#: rhodecode/templates/summary/summary.html:79
+#: rhodecode/templates/summary/summary.html:20
+#, fuzzy, python-format
+msgid "repo %s ATOM feed"
+msgstr "訂閱 %s atom"
+
+#: rhodecode/templates/summary/summary.html:21
+#, fuzzy, python-format
+msgid "repo %s RSS feed"
+msgstr "訂閱 %s rss"
+
+#: rhodecode/templates/summary/summary.html:49
+#: rhodecode/templates/summary/summary.html:52
+#, fuzzy
+msgid "ATOM"
+msgstr "作者"
+
+#: rhodecode/templates/summary/summary.html:82
+#, fuzzy, python-format
+msgid "Non changable ID %s"
+msgstr "沒有修改"
+
+#: rhodecode/templates/summary/summary.html:87
+msgid "public"
+msgstr "公開"
+
+#: rhodecode/templates/summary/summary.html:95
 msgid "remote clone"
 msgstr "遠端複製"
 
-#: rhodecode/templates/summary/summary.html:121
-msgid "by"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:128
+#: rhodecode/templates/summary/summary.html:116
+msgid "Contact"
+msgstr "聯絡方式"
+
+#: rhodecode/templates/summary/summary.html:130
 msgid "Clone url"
 msgstr "複製連結"
 
-#: rhodecode/templates/summary/summary.html:137
-msgid "Trending source files"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:146
+#: rhodecode/templates/summary/summary.html:133
+#, fuzzy
+msgid "Show by Name"
+msgstr "顯示更多"
+
+#: rhodecode/templates/summary/summary.html:134
+msgid "Show by ID"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:142
+#, fuzzy
+msgid "Trending files"
+msgstr "編輯檔案"
+
+#: rhodecode/templates/summary/summary.html:150
+#: rhodecode/templates/summary/summary.html:166
+#: rhodecode/templates/summary/summary.html:194
+msgid "enable"
+msgstr "啟用"
+
+#: rhodecode/templates/summary/summary.html:158
 msgid "Download"
 msgstr "下載"
 
-#: rhodecode/templates/summary/summary.html:150
+#: rhodecode/templates/summary/summary.html:162
 msgid "There are no downloads yet"
 msgstr "沒有任何下載"
 
-#: rhodecode/templates/summary/summary.html:152
+#: rhodecode/templates/summary/summary.html:164
 msgid "Downloads are disabled for this repository"
 msgstr "這個版本庫的下載已停用"
 
-#: rhodecode/templates/summary/summary.html:154
-#: rhodecode/templates/summary/summary.html:320
-msgid "enable"
-msgstr "啟用"
-
-#: rhodecode/templates/summary/summary.html:162
-#: rhodecode/templates/summary/summary.html:297
+#: rhodecode/templates/summary/summary.html:170
+#, fuzzy
+msgid "Download as zip"
+msgstr "下載原始文件"
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "Check this to download archive with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:173
+msgid "with subrepos"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:186
+msgid "Commit activity by day / author"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:197
+msgid "Stats gathered: "
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:218
+msgid "Shortlog"
+msgstr "簡短紀錄"
+
+#: rhodecode/templates/summary/summary.html:220
+#, fuzzy
+msgid "Quick start"
+msgstr "快速過濾..."
+
+#: rhodecode/templates/summary/summary.html:233
+#, python-format
+msgid "Readme file at revision '%s'"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:236
+msgid "Permalink to this readme"
+msgstr ""
+
+#: rhodecode/templates/summary/summary.html:293
 #, python-format
 msgid "Download %s as %s"
 msgstr "下載 %s 為 %s"
 
-#: rhodecode/templates/summary/summary.html:168
-msgid "Check this to download archive with subrepos"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:168
-msgid "with subrepos"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:176
-msgid "Feeds"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:257
-#: rhodecode/templates/summary/summary.html:684
-#: rhodecode/templates/summary/summary.html:695
-msgid "show more"
-msgstr "顯示更多"
-
-#: rhodecode/templates/summary/summary.html:312
-msgid "Commit activity by day / author"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:324
-msgid "Loaded in"
-msgstr ""
-
-#: rhodecode/templates/summary/summary.html:603
+#: rhodecode/templates/summary/summary.html:650
 msgid "commits"
 msgstr "遞交"
 
-#: rhodecode/templates/summary/summary.html:604
+#: rhodecode/templates/summary/summary.html:651
 msgid "files added"
 msgstr "多個檔案新增"
 
-#: rhodecode/templates/summary/summary.html:605
+#: rhodecode/templates/summary/summary.html:652
 msgid "files changed"
 msgstr "多個檔案修改"
 
-#: rhodecode/templates/summary/summary.html:606
+#: rhodecode/templates/summary/summary.html:653
 msgid "files removed"
 msgstr "移除多個檔案"
 
-#: rhodecode/templates/summary/summary.html:610
+#: rhodecode/templates/summary/summary.html:656
+msgid "commit"
+msgstr "遞交"
+
+#: rhodecode/templates/summary/summary.html:657
 msgid "file added"
 msgstr "檔案新增"
 
-#: rhodecode/templates/summary/summary.html:611
+#: rhodecode/templates/summary/summary.html:658
 msgid "file changed"
 msgstr "檔案修改"
 
-#: rhodecode/templates/summary/summary.html:612
+#: rhodecode/templates/summary/summary.html:659
 msgid "file removed"
 msgstr "移除檔案"
 
+#: rhodecode/templates/tags/tags.html:5
+#, fuzzy, python-format
+msgid "%s Tags"
+msgstr "之前"
+
--- a/rhodecode/lib/auth.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/auth.py	Sun Sep 02 21:19:54 2012 +0200
@@ -35,14 +35,9 @@
 from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _
 
-from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
+from rhodecode import __platform__, is_windows, is_unix
 from rhodecode.model.meta import Session
 
-if __platform__ in PLATFORM_WIN:
-    from hashlib import sha256
-if __platform__ in PLATFORM_OTHERS:
-    import bcrypt
-
 from rhodecode.lib.utils2 import str2bool, safe_unicode
 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
@@ -97,9 +92,11 @@
 
         :param password: password to hash
         """
-        if __platform__ in PLATFORM_WIN:
+        if is_windows:
+            from hashlib import sha256
             return sha256(str_).hexdigest()
-        elif __platform__ in PLATFORM_OTHERS:
+        elif is_unix:
+            import bcrypt
             return bcrypt.hashpw(str_, bcrypt.gensalt(10))
         else:
             raise Exception('Unknown or unsupported platform %s' \
@@ -115,9 +112,11 @@
         :param hashed: password in hashed form
         """
 
-        if __platform__ in PLATFORM_WIN:
+        if is_windows:
+            from hashlib import sha256
             return sha256(password).hexdigest() == hashed
-        elif __platform__ in PLATFORM_OTHERS:
+        elif is_unix:
+            import bcrypt
             return bcrypt.hashpw(password, hashed) == hashed
         else:
             raise Exception('Unknown or unsupported platform %s' \
@@ -236,7 +235,7 @@
                                           user_attrs):
                     log.info('created new ldap user %s' % username)
 
-                Session.commit()
+                Session().commit()
                 return True
             except (LdapUsernameError, LdapPasswordError,):
                 pass
@@ -263,7 +262,7 @@
         return None
 
     user.update_lastlogin()
-    Session.commit()
+    Session().commit()
 
     log.debug('User %s is now logged in by container authentication',
               user.username)
@@ -325,6 +324,7 @@
         self.email = ''
         self.is_authenticated = False
         self.admin = False
+        self.inherit_default_permissions = False
         self.permissions = {}
         self._api_key = api_key
         self.propagate_data()
@@ -351,6 +351,7 @@
             log.debug('Auth User lookup by USER NAME %s' % self.username)
             dbuser = login_container_auth(self.username)
             if dbuser is not None:
+                log.debug('filling all attributes to object')
                 for k, v in dbuser.get_dict().items():
                     setattr(self, k, v)
                 self.set_authenticated()
@@ -460,8 +461,9 @@
         loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
         log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
         if user.is_authenticated or api_access_ok:
-            log.info('user %s is authenticated and granted access to %s' % (
-                       user.username, loc)
+            reason = 'RegularAuth' if user.is_authenticated else 'APIAuth'
+            log.info('user %s is authenticated and granted access to %s '
+                     'using %s' % (user.username, loc, reason)
             )
             return func(*fargs, **fkwargs)
         else:
@@ -768,7 +770,7 @@
 class HasReposGroupPermissionAll(PermsFunction):
     def __call__(self, group_name=None, check_Location=''):
         self.group_name = group_name
-        return super(HasReposGroupPermissionAny, self).__call__(check_Location)
+        return super(HasReposGroupPermissionAll, self).__call__(check_Location)
 
     def check_permissions(self):
         try:
@@ -805,7 +807,7 @@
         return self.check_permissions()
 
     def check_permissions(self):
-        log.debug('checking mercurial protocol '
+        log.debug('checking VCS protocol '
                   'permissions %s for user:%s repository:%s', self.user_perms,
                                                 self.username, self.repo_name)
         if self.required_perms.intersection(self.user_perms):
--- a/rhodecode/lib/auth_ldap.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/auth_ldap.py	Sun Sep 02 21:19:54 2012 +0200
@@ -27,6 +27,7 @@
 
 from rhodecode.lib.exceptions import LdapConnectionError, LdapUsernameError, \
     LdapPasswordError
+from rhodecode.lib.utils2 import safe_str
 
 log = logging.getLogger(__name__)
 
@@ -60,15 +61,15 @@
         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
+        self.LDAP_BIND_DN = safe_str(bind_dn)
+        self.LDAP_BIND_PASS = safe_str(bind_pass)
 
         self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
                                            self.LDAP_SERVER_ADDRESS,
                                            self.LDAP_SERVER_PORT)
 
-        self.BASE_DN = base_dn
-        self.LDAP_FILTER = ldap_filter
+        self.BASE_DN = safe_str(base_dn)
+        self.LDAP_FILTER = safe_str(ldap_filter)
         self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope)
         self.attr_login = attr_login
 
--- a/rhodecode/lib/backup_manager.py	Sat May 19 14:54:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    rhodecode.lib.backup_manager
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    Mercurial repositories backup manager, it allows to backups all
-    repositories and send it to backup server using RSA key via ssh.
-
-    :created_on: Feb 28, 2010
-    :author: marcink
-    :copyright: (C) 2010-2012 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, either version 3 of the License, or
-# (at your option) any later version.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-import os
-import sys
-
-import logging
-import tarfile
-import datetime
-import subprocess
-
-logging.basicConfig(level=logging.DEBUG,
-                    format="%(asctime)s %(levelname)-5.5s %(message)s")
-
-
-class BackupManager(object):
-    def __init__(self, repos_location, rsa_key, backup_server):
-        today = datetime.datetime.now().weekday() + 1
-        self.backup_file_name = "mercurial_repos.%s.tar.gz" % today
-
-        self.id_rsa_path = self.get_id_rsa(rsa_key)
-        self.repos_path = self.get_repos_path(repos_location)
-        self.backup_server = backup_server
-
-        self.backup_file_path = '/tmp'
-
-        logging.info('starting backup for %s', self.repos_path)
-        logging.info('backup target %s', self.backup_file_path)
-
-    def get_id_rsa(self, rsa_key):
-        if not os.path.isfile(rsa_key):
-            logging.error('Could not load id_rsa key file in %s', rsa_key)
-            sys.exit()
-        return rsa_key
-
-    def get_repos_path(self, path):
-        if not os.path.isdir(path):
-            logging.error('Wrong location for repositories in %s', path)
-            sys.exit()
-        return path
-
-    def backup_repos(self):
-        bckp_file = os.path.join(self.backup_file_path, self.backup_file_name)
-        tar = tarfile.open(bckp_file, "w:gz")
-
-        for dir_name in os.listdir(self.repos_path):
-            logging.info('backing up %s', dir_name)
-            tar.add(os.path.join(self.repos_path, dir_name), dir_name)
-        tar.close()
-        logging.info('finished backup of mercurial repositories')
-
-    def transfer_files(self):
-        params = {
-                  'id_rsa_key': self.id_rsa_path,
-                  'backup_file': os.path.join(self.backup_file_path,
-                                             self.backup_file_name),
-                  'backup_server': self.backup_server
-                  }
-        cmd = ['scp', '-l', '40000', '-i', '%(id_rsa_key)s' % params,
-               '%(backup_file)s' % params,
-               '%(backup_server)s' % params]
-
-        subprocess.call(cmd)
-        logging.info('Transfered file %s to %s', self.backup_file_name, cmd[4])
-
-    def rm_file(self):
-        logging.info('Removing file %s', self.backup_file_name)
-        os.remove(os.path.join(self.backup_file_path, self.backup_file_name))
-
-if __name__ == "__main__":
-
-    repo_location = '/home/repo_path'
-    backup_server = 'root@192.168.1.100:/backups/mercurial'
-    rsa_key = '/home/id_rsa'
-
-    B_MANAGER = BackupManager(repo_location, rsa_key, backup_server)
-    B_MANAGER.backup_repos()
-    B_MANAGER.transfer_files()
-    B_MANAGER.rm_file()
--- a/rhodecode/lib/base.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/base.py	Sun Sep 02 21:19:54 2012 +0200
@@ -8,6 +8,7 @@
 
 from paste.auth.basic import AuthBasicAuthenticator
 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden
+from webob.exc import HTTPClientError
 from paste.httpheaders import WWW_AUTHENTICATE
 
 from pylons import config, tmpl_context as c, request, session, url
@@ -17,19 +18,47 @@
 
 from rhodecode import __version__, BACKENDS
 
-from rhodecode.lib.utils2 import str2bool, safe_unicode
+from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
+    safe_str
 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
     HasPermissionAnyMiddleware, CookieStoreWrapper
 from rhodecode.lib.utils import get_repo_slug, invalidate_cache
 from rhodecode.model import meta
 
-from rhodecode.model.db import Repository
+from rhodecode.model.db import Repository, RhodeCodeUi, User
 from rhodecode.model.notification import NotificationModel
 from rhodecode.model.scm import ScmModel
+from rhodecode.model.meta import Session
 
 log = logging.getLogger(__name__)
 
 
+def _get_ip_addr(environ):
+    proxy_key = 'HTTP_X_REAL_IP'
+    proxy_key2 = 'HTTP_X_FORWARDED_FOR'
+    def_key = 'REMOTE_ADDR'
+
+    ip = environ.get(proxy_key2)
+    if ip:
+        return ip
+
+    ip = environ.get(proxy_key)
+
+    if ip:
+        return ip
+
+    ip = environ.get(def_key, '0.0.0.0')
+    return ip
+
+
+def _get_access_path(environ):
+    path = environ.get('PATH_INFO')
+    org_req = environ.get('pylons.original_request')
+    if org_req:
+        path = org_req.environ.get('PATH_INFO')
+    return path
+
+
 class BasicAuth(AuthBasicAuthenticator):
 
     def __init__(self, realm, authfunc, auth_http_code=None):
@@ -117,15 +146,65 @@
         return True
 
     def _get_ip_addr(self, environ):
-        proxy_key = 'HTTP_X_REAL_IP'
-        proxy_key2 = 'HTTP_X_FORWARDED_FOR'
-        def_key = 'REMOTE_ADDR'
+        return _get_ip_addr(environ)
+
+    def _check_ssl(self, environ, start_response):
+        """
+        Checks the SSL check flag and returns False if SSL is not present
+        and required True otherwise
+        """
+        org_proto = environ['wsgi._org_proto']
+        #check if we have SSL required  ! if not it's a bad request !
+        require_ssl = str2bool(RhodeCodeUi.get_by_key('push_ssl').ui_value)
+        if require_ssl and org_proto == 'http':
+            log.debug('proto is %s and SSL is required BAD REQUEST !'
+                      % org_proto)
+            return False
+        return True
+
+    def _check_locking_state(self, environ, action, repo, user_id):
+        """
+        Checks locking on this repository, if locking is enabled and lock is
+        present returns a tuple of make_lock, locked, locked_by.
+        make_lock can have 3 states None (do nothing) True, make lock
+        False release lock, This value is later propagated to hooks, which
+        do the locking. Think about this as signals passed to hooks what to do.
+
+        """
+        locked = False  # defines that locked error should be thrown to user
+        make_lock = None
+        repo = Repository.get_by_repo_name(repo)
+        user = User.get(user_id)
 
-        return environ.get(proxy_key2,
-                           environ.get(proxy_key,
-                                       environ.get(def_key, '0.0.0.0')
-                            )
-                        )
+        # this is kind of hacky, but due to how mercurial handles client-server
+        # server see all operation on changeset; bookmarks, phases and
+        # obsolescence marker in different transaction, we don't want to check
+        # locking on those
+        obsolete_call = environ['QUERY_STRING'] in ['cmd=listkeys',]
+        locked_by = repo.locked
+        if repo and repo.enable_locking and not obsolete_call:
+            if action == 'push':
+                #check if it's already locked !, if it is compare users
+                user_id, _date = repo.locked
+                if user.user_id == user_id:
+                    log.debug('Got push from user %s, now unlocking' % (user))
+                    # unlock if we have push from user who locked
+                    make_lock = False
+                else:
+                    # we're not the same user who locked, ban with 423 !
+                    locked = True
+            if action == 'pull':
+                if repo.locked[0] and repo.locked[1]:
+                    locked = True
+                else:
+                    log.debug('Setting lock on repo %s by %s' % (repo, user))
+                    make_lock = True
+
+        else:
+            log.debug('Repository %s do not have locking enabled' % (repo))
+        log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s'
+                  % (make_lock, locked, locked_by))
+        return make_lock, locked, locked_by
 
     def __call__(self, environ, start_response):
         start = time.time()
@@ -145,6 +224,12 @@
         c.rhodecode_name = config.get('rhodecode_title')
         c.use_gravatar = str2bool(config.get('use_gravatar'))
         c.ga_code = config.get('rhodecode_ga_code')
+        # Visual options
+        c.visual = AttributeDict({})
+        c.visual.show_public_icon = str2bool(config.get('rhodecode_show_public_icon'))
+        c.visual.show_private_icon = str2bool(config.get('rhodecode_show_private_icon'))
+        c.visual.stylify_metatags = str2bool(config.get('rhodecode_stylify_metatags'))
+
         c.repo_name = get_repo_slug(request)
         c.backends = BACKENDS.keys()
         c.unread_notifications = NotificationModel()\
@@ -153,6 +238,7 @@
 
         self.sa = meta.Session
         self.scm_model = ScmModel(self.sa)
+        self.ip_addr = ''
 
     def __call__(self, environ, start_response):
         """Invoke the Controller"""
@@ -161,6 +247,7 @@
         # available in environ['pylons.routes_dict']
         start = time.time()
         try:
+            self.ip_addr = _get_ip_addr(environ)
             # make sure that we update permissions each time we call controller
             api_key = request.GET.get('api_key')
             cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
@@ -174,13 +261,14 @@
                 self.rhodecode_user.set_authenticated(
                     cookie_store.get('is_authenticated')
                 )
-            log.info('User: %s accessed %s' % (
-                auth_user, safe_unicode(environ.get('PATH_INFO')))
+            log.info('IP: %s User: %s accessed %s' % (
+               self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
             )
             return WSGIController.__call__(self, environ, start_response)
         finally:
-            log.info('Request to %s time: %.3fs' % (
-                safe_unicode(environ.get('PATH_INFO')), time.time() - start)
+            log.info('IP: %s Request to %s time: %.3fs' % (
+                _get_ip_addr(environ),
+                safe_unicode(_get_access_path(environ)), time.time() - start)
             )
             meta.Session.remove()
 
@@ -200,7 +288,7 @@
         super(BaseRepoController, self).__before__()
         if c.repo_name:
 
-            c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
+            dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
             c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
 
             if c.rhodecode_repo is None:
@@ -209,5 +297,7 @@
 
                 redirect(url('home'))
 
-            c.repository_followers = self.scm_model.get_followers(c.repo_name)
-            c.repository_forks = self.scm_model.get_forks(c.repo_name)
+            # some globals counter for menu
+            c.repository_followers = self.scm_model.get_followers(dbr)
+            c.repository_forks = self.scm_model.get_forks(dbr)
+            c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
--- a/rhodecode/lib/celerylib/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/celerylib/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -112,7 +112,7 @@
     if CELERY_ON:
         engine = engine_from_config(config, 'sqlalchemy.db1.')
         init_model(engine)
-    sa = meta.Session
+    sa = meta.Session()
     return sa
 
 
--- a/rhodecode/lib/celerylib/tasks.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/celerylib/tasks.py	Sun Sep 02 21:19:54 2012 +0200
@@ -75,7 +75,7 @@
 @dbsession
 def whoosh_index(repo_location, full_index):
     from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
-    log = whoosh_index.get_logger(whoosh_index)
+    log = get_logger(whoosh_index)
     DBS = get_session()
 
     index_location = config['index_dir']
@@ -367,32 +367,46 @@
     :param cur_user:
     """
     from rhodecode.model.repo import RepoModel
+    from rhodecode.model.user import UserModel
 
     log = get_logger(create_repo_fork)
     DBS = get_session()
 
     base_path = Repository.base_path()
-
-    fork_repo = RepoModel(DBS).create(form_data, cur_user,
-                                      just_db=True, fork=True)
+    cur_user = UserModel(DBS)._get_user(cur_user)
 
-    alias = form_data['repo_type']
-    org_repo_name = form_data['org_path']
     fork_name = form_data['repo_name_full']
+    repo_type = form_data['repo_type']
+    description = form_data['description']
+    owner = cur_user
+    private = form_data['private']
+    clone_uri = form_data.get('clone_uri')
+    repos_group = form_data['repo_group']
+    landing_rev = form_data['landing_rev']
+    copy_fork_permissions = form_data.get('copy_permissions')
+    fork_of = RepoModel(DBS)._get_repo(form_data.get('fork_parent_id'))
+
+    fork_repo = RepoModel(DBS).create_repo(
+        fork_name, repo_type, description, owner, private, clone_uri,
+        repos_group, landing_rev, just_db=True, fork_of=fork_of,
+        copy_fork_permissions=copy_fork_permissions
+    )
+
     update_after_clone = form_data['update_after_clone']
-    source_repo_path = os.path.join(base_path, org_repo_name)
+
+    source_repo_path = os.path.join(base_path, fork_of.repo_name)
     destination_fork_path = os.path.join(base_path, fork_name)
 
     log.info('creating fork of %s as %s', source_repo_path,
              destination_fork_path)
-    backend = get_backend(alias)
+    backend = get_backend(repo_type)
     backend(safe_str(destination_fork_path), create=True,
             src_url=safe_str(source_repo_path),
             update_after_clone=update_after_clone)
     log_create_repository(fork_repo.get_dict(), created_by=cur_user.username)
 
     action_logger(cur_user, 'user_forked_repo:%s' % fork_name,
-                   org_repo_name, '', DBS)
+                   fork_of.repo_name, '', DBS)
 
     action_logger(cur_user, 'user_created_fork:%s' % fork_name,
                    fork_name, '', DBS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/cleanup.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,142 @@
+# -*- coding: utf-8 -*-
+"""
+    package.rhodecode.lib.cleanup
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    :created_on: Jul 14, 2012
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+from __future__ import with_statement
+
+import os
+import sys
+import re
+import shutil
+import logging
+import datetime
+
+from os.path import dirname as dn, join as jn
+from rhodecode.model import init_model
+from rhodecode.lib.utils2 import engine_from_config
+from rhodecode.model.db import RhodeCodeUi
+
+
+#to get the rhodecode import
+sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
+
+from rhodecode.lib.utils import BasePasterCommand, Command, ask_ok,\
+    REMOVED_REPO_PAT, add_cache
+
+log = logging.getLogger(__name__)
+
+
+class CleanupCommand(BasePasterCommand):
+
+    max_args = 1
+    min_args = 1
+
+    usage = "CONFIG_FILE"
+    summary = "Cleanup deleted repos"
+    group_name = "RhodeCode"
+    takes_config_file = -1
+    parser = Command.standard_parser(verbose=True)
+
+    def _parse_older_than(self, val):
+        regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
+        parts = regex.match(val)
+        if not parts:
+            return
+        parts = parts.groupdict()
+        time_params = {}
+        for (name, param) in parts.iteritems():
+            if param:
+                time_params[name] = int(param)
+        return datetime.timedelta(**time_params)
+
+    def _extract_date(self, name):
+        """
+        Extract the date part from rm__<date> pattern of removed repos,
+        and convert it to datetime object
+
+        :param name:
+        """
+        date_part = name[4:19]  # 4:19 since we don't parse milisecods
+        return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
+
+    def command(self):
+        logging.config.fileConfig(self.path_to_ini_file)
+        from pylons import config
+
+        #get to remove repos !!
+        add_cache(config)
+        engine = engine_from_config(config, 'sqlalchemy.db1.')
+        init_model(engine)
+
+        repos_location = RhodeCodeUi.get_repos_location()
+        to_remove = []
+        for loc in os.listdir(repos_location):
+            if REMOVED_REPO_PAT.match(loc):
+                to_remove.append([loc, self._extract_date(loc)])
+
+        #filter older than (if present)!
+        now = datetime.datetime.now()
+        older_than = self.options.older_than
+        if older_than:
+            to_remove_filtered = []
+            older_than_date = self._parse_older_than(older_than)
+            for name, date_ in to_remove:
+                repo_age = now - date_
+                if repo_age > older_than_date:
+                    to_remove_filtered.append([name, date_])
+
+            to_remove = to_remove_filtered
+            print >> sys.stdout, 'removing [%s] deleted repos older than %s[%s]' \
+                % (len(to_remove), older_than, older_than_date)
+        else:
+            print >> sys.stdout, 'removing all [%s] deleted repos' \
+                % len(to_remove)
+        if self.options.dont_ask or not to_remove:
+            # don't ask just remove !
+            remove = True
+        else:
+            remove = ask_ok('are you sure to remove listed repos \n%s [y/n]?'
+                            % ', \n'.join(['%s removed on %s' % (x[0], x[1])
+                                           for x in to_remove]))
+
+        if remove:
+            for name, date_ in to_remove:
+                print >> sys.stdout, 'removing repository %s' % name
+                shutil.rmtree(os.path.join(repos_location, name))
+        else:
+            print 'nothing done exiting...'
+            sys.exit(0)
+
+    def update_parser(self):
+        self.parser.add_option('--older-than',
+                          action='store',
+                          dest='older_than',
+                          help=(
+                            "only remove repos that have been removed "
+                            "at least given time ago "
+                            "ex. --older-than=30d deletes repositores "
+                            "removed more than 30days ago. Possible options "
+                            "d[ays]/h[ours]/m[inutes]/s[seconds]. OPTIONAL"),
+                          )
+        self.parser.add_option('--dont-ask',
+                               action='store_true',
+                               dest='dont_ask',
+                               help=("Don't ask to remove repos"))
--- a/rhodecode/lib/compat.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/compat.py	Sun Sep 02 21:19:54 2012 +0200
@@ -25,7 +25,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
-from rhodecode import __platform__, PLATFORM_WIN
+from rhodecode import __platform__, PLATFORM_WIN, __py_version__
 
 #==============================================================================
 # json
@@ -394,3 +394,192 @@
             result = [x + [y] for x in result for y in pool]
         for prod in result:
             yield tuple(prod)
+
+
+#==============================================================================
+# BytesIO
+#==============================================================================
+
+try:
+    from io import BytesIO
+except ImportError:
+    from cStringIO import StringIO as BytesIO
+
+
+#==============================================================================
+# deque
+#==============================================================================
+
+if __py_version__ >= (2, 6):
+    from collections import deque
+else:
+    #need to implement our own deque with maxlen
+    class deque(object):
+
+        def __init__(self, iterable=(), maxlen=-1):
+            if not hasattr(self, 'data'):
+                self.left = self.right = 0
+                self.data = {}
+            self.maxlen = maxlen
+            self.extend(iterable)
+
+        def append(self, x):
+            self.data[self.right] = x
+            self.right += 1
+            if self.maxlen != -1 and len(self) > self.maxlen:
+                self.popleft()
+
+        def appendleft(self, x):
+            self.left -= 1
+            self.data[self.left] = x
+            if self.maxlen != -1 and len(self) > self.maxlen:
+                self.pop()
+
+        def pop(self):
+            if self.left == self.right:
+                raise IndexError('cannot pop from empty deque')
+            self.right -= 1
+            elem = self.data[self.right]
+            del self.data[self.right]
+            return elem
+
+        def popleft(self):
+            if self.left == self.right:
+                raise IndexError('cannot pop from empty deque')
+            elem = self.data[self.left]
+            del self.data[self.left]
+            self.left += 1
+            return elem
+
+        def clear(self):
+            self.data.clear()
+            self.left = self.right = 0
+
+        def extend(self, iterable):
+            for elem in iterable:
+                self.append(elem)
+
+        def extendleft(self, iterable):
+            for elem in iterable:
+                self.appendleft(elem)
+
+        def rotate(self, n=1):
+            if self:
+                n %= len(self)
+                for i in xrange(n):
+                    self.appendleft(self.pop())
+
+        def __getitem__(self, i):
+            if i < 0:
+                i += len(self)
+            try:
+                return self.data[i + self.left]
+            except KeyError:
+                raise IndexError
+
+        def __setitem__(self, i, value):
+            if i < 0:
+                i += len(self)
+            try:
+                self.data[i + self.left] = value
+            except KeyError:
+                raise IndexError
+
+        def __delitem__(self, i):
+            size = len(self)
+            if not (-size <= i < size):
+                raise IndexError
+            data = self.data
+            if i < 0:
+                i += size
+            for j in xrange(self.left + i, self.right - 1):
+                data[j] = data[j + 1]
+            self.pop()
+
+        def __len__(self):
+            return self.right - self.left
+
+        def __cmp__(self, other):
+            if type(self) != type(other):
+                return cmp(type(self), type(other))
+            return cmp(list(self), list(other))
+
+        def __repr__(self, _track=[]):
+            if id(self) in _track:
+                return '...'
+            _track.append(id(self))
+            r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
+            _track.remove(id(self))
+            return r
+
+        def __getstate__(self):
+            return (tuple(self),)
+
+        def __setstate__(self, s):
+            self.__init__(s[0])
+
+        def __hash__(self):
+            raise TypeError
+
+        def __copy__(self):
+            return self.__class__(self)
+
+        def __deepcopy__(self, memo={}):
+            from copy import deepcopy
+            result = self.__class__()
+            memo[id(self)] = result
+            result.__init__(deepcopy(tuple(self), memo))
+            return result
+
+
+#==============================================================================
+# threading.Event
+#==============================================================================
+
+if __py_version__ >= (2, 6):
+    from threading import Event
+else:
+    from threading import _Verbose, Condition, Lock
+
+    def Event(*args, **kwargs):
+        return _Event(*args, **kwargs)
+
+    class _Event(_Verbose):
+
+        # After Tim Peters' event class (without is_posted())
+
+        def __init__(self, verbose=None):
+            _Verbose.__init__(self, verbose)
+            self.__cond = Condition(Lock())
+            self.__flag = False
+
+        def isSet(self):
+            return self.__flag
+
+        is_set = isSet
+
+        def set(self):
+            self.__cond.acquire()
+            try:
+                self.__flag = True
+                self.__cond.notify_all()
+            finally:
+                self.__cond.release()
+
+        def clear(self):
+            self.__cond.acquire()
+            try:
+                self.__flag = False
+            finally:
+                self.__cond.release()
+
+        def wait(self, timeout=None):
+            self.__cond.acquire()
+            try:
+                if not self.__flag:
+                    self.__cond.wait(timeout)
+            finally:
+                self.__cond.release()
+
+
+
--- a/rhodecode/lib/db_manage.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/db_manage.py	Sun Sep 02 21:19:54 2012 +0200
@@ -31,17 +31,20 @@
 from os.path import dirname as dn, join as jn
 
 from rhodecode import __dbversion__
-from rhodecode.model import meta
 
 from rhodecode.model.user import UserModel
 from rhodecode.lib.utils import ask_ok
 from rhodecode.model import init_model
 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
-    RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup,\
+    RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup, \
     UserRepoGroupToPerm
 
 from sqlalchemy.engine import create_engine
+from sqlalchemy.schema import MetaData
 from rhodecode.model.repos_group import ReposGroupModel
+#from rhodecode.model import meta
+from rhodecode.model.meta import Session, Base
+
 
 log = logging.getLogger(__name__)
 
@@ -59,25 +62,25 @@
     def init_db(self):
         engine = create_engine(self.dburi, echo=self.log_sql)
         init_model(engine)
-        self.sa = meta.Session
+        self.sa = Session()
 
-    def create_tables(self, override=False):
+    def create_tables(self, override=False, defaults={}):
         """
         Create a auth database
         """
-
+        quiet = defaults.get('quiet')
         log.info("Any existing database is going to be destroyed")
-        if self.tests:
+        if self.tests or quiet:
             destroy = True
         else:
             destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
         if not destroy:
             sys.exit()
         if destroy:
-            meta.Base.metadata.drop_all()
+            Base.metadata.drop_all()
 
         checkfirst = not override
-        meta.Base.metadata.create_all(checkfirst=checkfirst)
+        Base.metadata.create_all(checkfirst=checkfirst)
         log.info('Created tables for %s' % self.dbname)
 
     def set_db_version(self):
@@ -178,6 +181,44 @@
             def step_5(self):
                 pass
 
+            def step_6(self):
+                print ('re-checking permissions')
+                self.klass.create_permissions()
+
+                print ('installing new hooks')
+                hooks4 = RhodeCodeUi()
+                hooks4.ui_section = 'hooks'
+                hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
+                hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
+                Session().add(hooks4)
+
+                hooks6 = RhodeCodeUi()
+                hooks6.ui_section = 'hooks'
+                hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
+                hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
+                Session().add(hooks6)
+
+                print ('installing hgsubversion option')
+                # enable hgsubversion disabled by default
+                hgsubversion = RhodeCodeUi()
+                hgsubversion.ui_section = 'extensions'
+                hgsubversion.ui_key = 'hgsubversion'
+                hgsubversion.ui_value = ''
+                hgsubversion.ui_active = False
+                Session().add(hgsubversion)
+
+                print ('installing hg git option')
+                # enable hggit disabled by default
+                hggit = RhodeCodeUi()
+                hggit.ui_section = 'extensions'
+                hggit.ui_key = 'hggit'
+                hggit.ui_value = ''
+                hggit.ui_active = False
+                Session().add(hggit)
+
+                print ('re-check default permissions')
+                self.klass.populate_default_permissions()
+
         upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
 
         # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
@@ -274,9 +315,9 @@
             self.create_user(username, password, email, True)
         else:
             log.info('creating admin and regular test users')
-            from rhodecode.tests import TEST_USER_ADMIN_LOGIN,\
-            TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL,\
-            TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,\
+            from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
+            TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
+            TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
             TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
             TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
 
@@ -305,43 +346,63 @@
         hooks1.ui_key = hooks1_key
         hooks1.ui_value = 'hg update >&2'
         hooks1.ui_active = False
+        self.sa.add(hooks1)
 
         hooks2_key = RhodeCodeUi.HOOK_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'
+        self.sa.add(hooks2)
 
         hooks3 = RhodeCodeUi()
         hooks3.ui_section = 'hooks'
         hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
         hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
+        self.sa.add(hooks3)
 
         hooks4 = RhodeCodeUi()
         hooks4.ui_section = 'hooks'
-        hooks4.ui_key = RhodeCodeUi.HOOK_PULL
-        hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
+        hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
+        hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
+        self.sa.add(hooks4)
 
-        # 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'
+        hooks5 = RhodeCodeUi()
+        hooks5.ui_section = 'hooks'
+        hooks5.ui_key = RhodeCodeUi.HOOK_PULL
+        hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
+        self.sa.add(hooks5)
+
+        hooks6 = RhodeCodeUi()
+        hooks6.ui_section = 'hooks'
+        hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
+        hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
+        self.sa.add(hooks6)
 
         # enable largefiles
         largefiles = RhodeCodeUi()
         largefiles.ui_section = 'extensions'
         largefiles.ui_key = 'largefiles'
         largefiles.ui_value = ''
+        self.sa.add(largefiles)
 
-        self.sa.add(hooks1)
-        self.sa.add(hooks2)
-        self.sa.add(hooks3)
-        self.sa.add(hooks4)
-        self.sa.add(largefiles)
+        # enable hgsubversion disabled by default
+        hgsubversion = RhodeCodeUi()
+        hgsubversion.ui_section = 'extensions'
+        hgsubversion.ui_key = 'hgsubversion'
+        hgsubversion.ui_value = ''
+        hgsubversion.ui_active = False
+        self.sa.add(hgsubversion)
+
+        # enable hggit disabled by default
+        hggit = RhodeCodeUi()
+        hggit.ui_section = 'extensions'
+        hggit.ui_key = 'hggit'
+        hggit.ui_value = ''
+        hggit.ui_active = False
+        self.sa.add(hggit)
 
     def create_ldap_options(self, skip_existing=False):
         """Creates ldap settings"""
@@ -443,18 +504,30 @@
         paths.ui_key = '/'
         paths.ui_value = path
 
-        hgsettings1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
-        hgsettings2 = RhodeCodeSetting('title', 'RhodeCode')
-        hgsettings3 = RhodeCodeSetting('ga_code', '')
+        phases = RhodeCodeUi()
+        phases.ui_section = 'phases'
+        phases.ui_key = 'publish'
+        phases.ui_value = False
+
+        sett1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
+        sett2 = RhodeCodeSetting('title', 'RhodeCode')
+        sett3 = RhodeCodeSetting('ga_code', '')
+
+        sett4 = RhodeCodeSetting('show_public_icon', True)
+        sett5 = RhodeCodeSetting('show_private_icon', True)
+        sett6 = RhodeCodeSetting('stylify_metatags', False)
 
         self.sa.add(web1)
         self.sa.add(web2)
         self.sa.add(web3)
         self.sa.add(web4)
         self.sa.add(paths)
-        self.sa.add(hgsettings1)
-        self.sa.add(hgsettings2)
-        self.sa.add(hgsettings3)
+        self.sa.add(sett1)
+        self.sa.add(sett2)
+        self.sa.add(sett3)
+        self.sa.add(sett4)
+        self.sa.add(sett5)
+        self.sa.add(sett6)
 
         self.create_ldap_options()
 
@@ -463,7 +536,7 @@
     def create_user(self, username, password, email='', admin=False):
         log.info('creating user %s' % username)
         UserModel().create_or_update(username, password, email,
-                                     name='RhodeCode', lastname='Admin',
+                                     firstname='RhodeCode', lastname='Admin',
                                      active=True, admin=admin)
 
     def create_default_user(self):
@@ -472,64 +545,39 @@
         UserModel().create_or_update(username='default',
                               password=str(uuid.uuid1())[:8],
                               email='anonymous@rhodecode.org',
-                              name='Anonymous', lastname='User')
+                              firstname='Anonymous', lastname='User')
 
     def create_permissions(self):
         # module.(access|create|change|delete)_[name]
         # module.(none|read|write|admin)
-        perms = [
-         ('repository.none', 'Repository no access'),
-         ('repository.read', 'Repository read access'),
-         ('repository.write', 'Repository write access'),
-         ('repository.admin', 'Repository admin access'),
 
-         ('group.none', 'Repositories Group no access'),
-         ('group.read', 'Repositories Group read access'),
-         ('group.write', 'Repositories Group write access'),
-         ('group.admin', 'Repositories Group admin access'),
-
-         ('hg.admin', 'Hg Administrator'),
-         ('hg.create.repository', 'Repository create'),
-         ('hg.create.none', 'Repository creation disabled'),
-         ('hg.register.none', 'Register disabled'),
-         ('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:
+        for p in Permission.PERMS:
             if not Permission.get_by_key(p[0]):
                 new_perm = Permission()
                 new_perm.permission_name = p[0]
-                new_perm.permission_longname = p[1]
+                new_perm.permission_longname = p[0]
                 self.sa.add(new_perm)
 
     def populate_default_permissions(self):
         log.info('creating default user permissions')
 
-        default_user = self.sa.query(User)\
-        .filter(User.username == 'default').scalar()
+        default_user = User.get_by_username('default')
 
-        reg_perm = UserToPerm()
-        reg_perm.user = default_user
-        reg_perm.permission = self.sa.query(Permission)\
-        .filter(Permission.permission_name == 'hg.register.manual_activate')\
-        .scalar()
+        for def_perm in ['hg.register.manual_activate', 'hg.create.repository',
+                         'hg.fork.repository', 'repository.read']:
 
-        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()
-
-        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()
-
-        self.sa.add(reg_perm)
-        self.sa.add(create_repo_perm)
-        self.sa.add(default_repo_perm)
+            perm = self.sa.query(Permission)\
+             .filter(Permission.permission_name == def_perm)\
+             .scalar()
+            if not perm:
+                raise Exception(
+                  'CRITICAL: permission %s not found inside database !!'
+                  % def_perm
+                )
+            if not UserToPerm.query()\
+                .filter(UserToPerm.permission == perm)\
+                .filter(UserToPerm.user == default_user).scalar():
+                reg_perm = UserToPerm()
+                reg_perm.user = default_user
+                reg_perm.permission = perm
+                self.sa.add(reg_perm)
--- a/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py	Sun Sep 02 21:19:54 2012 +0200
@@ -94,6 +94,7 @@
 
         table = self.start_alter_table(column)
         self.append("ADD ")
+
         self.append(self.get_column_specification(column))
 
         for cons in column.constraints:
--- a/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py	Sun Sep 02 21:19:54 2012 +0200
@@ -49,6 +49,7 @@
         else:
             column = delta
             table = self._to_table(column.table)
+
         self.recreate_table(table,column,delta)
 
 class SQLiteColumnGenerator(SQLiteSchemaGenerator,
--- a/rhodecode/lib/dbmigrate/schema/db_1_2_0.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/dbmigrate/schema/db_1_2_0.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 """
-    rhodecode.model.db
-    ~~~~~~~~~~~~~~~~~~
+    rhodecode.model.db_1_2_0
+    ~~~~~~~~~~~~~~~~~~~~~~~~
 
-    Database Models for RhodeCode
+    Database Models for RhodeCode <=1.2.X
 
     :created_on: Apr 08, 2010
     :author: marcink
--- a/rhodecode/lib/dbmigrate/schema/db_1_3_0.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/dbmigrate/schema/db_1_3_0.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 """
-    rhodecode.model.db
-    ~~~~~~~~~~~~~~~~~~
+    rhodecode.model.db_1_3_0
+    ~~~~~~~~~~~~~~~~~~~~~~~~
 
-    Database Models for RhodeCode
+    Database Models for RhodeCode <=1.3.X
 
     :created_on: Apr 08, 2010
     :author: marcink
@@ -23,6 +23,1298 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-#TODO: when branch 1.3 is finished replacem with db.py content
+import os
+import logging
+import datetime
+import traceback
+from collections import defaultdict
+
+from sqlalchemy import *
+from sqlalchemy.ext.hybrid import hybrid_property
+from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
+from beaker.cache import cache_region, region_invalidate
+
+from rhodecode.lib.vcs import get_backend
+from rhodecode.lib.vcs.utils.helpers import get_scm
+from rhodecode.lib.vcs.exceptions import VCSError
+from rhodecode.lib.vcs.utils.lazy import LazyProperty
+
+from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
+    safe_unicode
+from rhodecode.lib.compat import json
+from rhodecode.lib.caching_query import FromCache
+
+from rhodecode.model.meta import Base, Session
+import hashlib
+
+
+log = logging.getLogger(__name__)
+
+#==============================================================================
+# BASE CLASSES
+#==============================================================================
+
+_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
+
+
+class ModelSerializer(json.JSONEncoder):
+    """
+    Simple Serializer for JSON,
+
+    usage::
+
+        to make object customized for serialization implement a __json__
+        method that will return a dict for serialization into json
+
+    example::
+
+        class Task(object):
+
+            def __init__(self, name, value):
+                self.name = name
+                self.value = value
+
+            def __json__(self):
+                return dict(name=self.name,
+                            value=self.value)
+
+    """
+
+    def default(self, obj):
+
+        if hasattr(obj, '__json__'):
+            return obj.__json__()
+        else:
+            return json.JSONEncoder.default(self, obj)
+
+
+class BaseModel(object):
+    """
+    Base Model for all classess
+    """
+
+    @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)
+
+        # also use __json__() if present to get additional fields
+        for k, val in getattr(self, '__json__', lambda: {})().iteritems():
+            d[k] = val
+        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])
+
+    @classmethod
+    def query(cls):
+        return Session.query(cls)
+
+    @classmethod
+    def get(cls, id_):
+        if id_:
+            return cls.query().get(id_)
+
+    @classmethod
+    def getAll(cls):
+        return cls.query().all()
+
+    @classmethod
+    def delete(cls, id_):
+        obj = cls.query().get(id_)
+        Session.delete(obj)
+
+    def __repr__(self):
+        if hasattr(self, '__unicode__'):
+            # python repr needs to return str
+            return safe_str(self.__unicode__())
+        return '<DB:%s>' % (self.__class__.__name__)
+
+class RhodeCodeSetting(Base, BaseModel):
+    __tablename__ = 'rhodecode_settings'
+    __table_args__ = (
+        UniqueConstraint('app_settings_name'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    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=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    _app_settings_value = Column("app_settings_value", String(length=255, 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
+
+    @validates('_app_settings_value')
+    def validate_settings_value(self, key, val):
+        assert type(val) == unicode
+        return val
+
+    @hybrid_property
+    def app_settings_value(self):
+        v = self._app_settings_value
+        if self.app_settings_name == 'ldap_active':
+            v = str2bool(v)
+        return v
+
+    @app_settings_value.setter
+    def app_settings_value(self, val):
+        """
+        Setter that will always make sure we use unicode in app_settings_value
+
+        :param val:
+        """
+        self._app_settings_value = safe_unicode(val)
+
+    def __unicode__(self):
+        return u"<%s('%s:%s')>" % (
+            self.__class__.__name__,
+            self.app_settings_name, self.app_settings_value
+        )
+
+    @classmethod
+    def get_by_name(cls, ldap_key):
+        return cls.query()\
+            .filter(cls.app_settings_name == ldap_key).scalar()
+
+    @classmethod
+    def get_app_settings(cls, cache=False):
+
+        ret = cls.query()
+
+        if cache:
+            ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
+
+        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
+
+    @classmethod
+    def get_ldap_settings(cls, cache=False):
+        ret = cls.query()\
+                .filter(cls.app_settings_name.startswith('ldap_')).all()
+        fd = {}
+        for row in ret:
+            fd.update({row.app_settings_name:row.app_settings_value})
+
+        return fd
+
+
+class RhodeCodeUi(Base, BaseModel):
+    __tablename__ = 'rhodecode_ui'
+    __table_args__ = (
+        UniqueConstraint('ui_key'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+
+    HOOK_UPDATE = 'changegroup.update'
+    HOOK_REPO_SIZE = 'changegroup.repo_size'
+    HOOK_PUSH = 'pretxnchangegroup.push_logger'
+    HOOK_PULL = 'preoutgoing.pull_logger'
+
+    ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
+
+    @classmethod
+    def get_by_key(cls, key):
+        return cls.query().filter(cls.ui_key == key)
+
+    @classmethod
+    def get_builtin_hooks(cls):
+        q = cls.query()
+        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
+                                    cls.HOOK_REPO_SIZE,
+                                    cls.HOOK_PUSH, cls.HOOK_PULL]))
+        return q.all()
+
+    @classmethod
+    def get_custom_hooks(cls):
+        q = cls.query()
+        q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
+                                    cls.HOOK_REPO_SIZE,
+                                    cls.HOOK_PUSH, cls.HOOK_PULL]))
+        q = q.filter(cls.ui_section == 'hooks')
+        return q.all()
+
+    @classmethod
+    def create_or_update_hook(cls, key, val):
+        new_ui = cls.get_by_key(key).scalar() or cls()
+        new_ui.ui_section = 'hooks'
+        new_ui.ui_active = True
+        new_ui.ui_key = key
+        new_ui.ui_value = val
+
+        Session.add(new_ui)
+
+
+class User(Base, BaseModel):
+    __tablename__ = 'users'
+    __table_args__ = (
+        UniqueConstraint('username'), UniqueConstraint('email'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    password = Column("password", String(length=255, 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=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    _email = Column("email", String(length=255, 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)
+    ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+
+    user_log = relationship('UserLog', cascade='all')
+    user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
+
+    repositories = relationship('Repository')
+    user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
+    repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
+    repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
+
+    group_member = relationship('UsersGroupMember', cascade='all')
+
+    notifications = relationship('UserNotification', cascade='all')
+    # notifications assigned to this user
+    user_created_notifications = relationship('Notification', cascade='all')
+    # comments created by this user
+    user_comments = relationship('ChangesetComment', cascade='all')
+
+    @hybrid_property
+    def email(self):
+        return self._email
+
+    @email.setter
+    def email(self, val):
+        self._email = val.lower() if val else None
+
+    @property
+    def full_name(self):
+        return '%s %s' % (self.name, self.lastname)
+
+    @property
+    def full_name_or_username(self):
+        return ('%s %s' % (self.name, self.lastname)
+                if (self.name and self.lastname) else self.username)
+
+    @property
+    def full_contact(self):
+        return '%s %s <%s>' % (self.name, self.lastname, self.email)
+
+    @property
+    def short_contact(self):
+        return '%s %s' % (self.name, self.lastname)
+
+    @property
+    def is_admin(self):
+        return self.admin
+
+    def __unicode__(self):
+        return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
+                                     self.user_id, self.username)
+
+    @classmethod
+    def get_by_username(cls, username, case_insensitive=False, cache=False):
+        if case_insensitive:
+            q = cls.query().filter(cls.username.ilike(username))
+        else:
+            q = cls.query().filter(cls.username == username)
+
+        if cache:
+            q = q.options(FromCache(
+                            "sql_cache_short",
+                            "get_user_%s" % _hash_key(username)
+                          )
+            )
+        return q.scalar()
+
+    @classmethod
+    def get_by_api_key(cls, api_key, cache=False):
+        q = cls.query().filter(cls.api_key == api_key)
+
+        if cache:
+            q = q.options(FromCache("sql_cache_short",
+                                    "get_api_key_%s" % api_key))
+        return q.scalar()
+
+    @classmethod
+    def get_by_email(cls, email, case_insensitive=False, cache=False):
+        if case_insensitive:
+            q = cls.query().filter(cls.email.ilike(email))
+        else:
+            q = cls.query().filter(cls.email == email)
+
+        if cache:
+            q = q.options(FromCache("sql_cache_short",
+                                    "get_api_key_%s" % email))
+        return q.scalar()
+
+    def update_lastlogin(self):
+        """Update user lastlogin"""
+        self.last_login = datetime.datetime.now()
+        Session.add(self)
+        log.debug('updated user %s lastlogin' % self.username)
+
+    def __json__(self):
+        return dict(
+            user_id=self.user_id,
+            first_name=self.name,
+            last_name=self.lastname,
+            email=self.email,
+            full_name=self.full_name,
+            full_name_or_username=self.full_name_or_username,
+            short_contact=self.short_contact,
+            full_contact=self.full_contact
+        )
+
+
+class UserLog(Base, BaseModel):
+    __tablename__ = 'user_logs'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
+    repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    action = Column("action", UnicodeText(length=1200000, 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)
+
+    @property
+    def action_as_day(self):
+        return datetime.date(*self.action_date.timetuple()[:3])
+
+    user = relationship('User')
+    repository = relationship('Repository', cascade='')
+
+
+class UsersGroup(Base, BaseModel):
+    __tablename__ = 'users_groups'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+
+    users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
+
+    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
+    users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
+    users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+
+    def __unicode__(self):
+        return u'<userGroup(%s)>' % (self.users_group_name)
+
+    @classmethod
+    def get_by_group_name(cls, group_name, cache=False,
+                          case_insensitive=False):
+        if case_insensitive:
+            q = cls.query().filter(cls.users_group_name.ilike(group_name))
+        else:
+            q = cls.query().filter(cls.users_group_name == group_name)
+        if cache:
+            q = q.options(FromCache(
+                            "sql_cache_short",
+                            "get_user_%s" % _hash_key(group_name)
+                          )
+            )
+        return q.scalar()
+
+    @classmethod
+    def get(cls, users_group_id, cache=False):
+        users_group = cls.query()
+        if cache:
+            users_group = users_group.options(FromCache("sql_cache_short",
+                                    "get_users_group_%s" % users_group_id))
+        return users_group.get(users_group_id)
+
+
+class UsersGroupMember(Base, BaseModel):
+    __tablename__ = 'users_groups_members'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+
+    users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+
+    user = relationship('User', lazy='joined')
+    users_group = relationship('UsersGroup')
+
+    def __init__(self, gr_id='', u_id=''):
+        self.users_group_id = gr_id
+        self.user_id = u_id
+
+
+class Repository(Base, BaseModel):
+    __tablename__ = 'repositories'
+    __table_args__ = (
+        UniqueConstraint('repo_name'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+
+    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
+    repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
+    user_id = Column("user_id", Integer(), ForeignKey('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)
+    enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
+    description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
+
+    fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
+    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
+
+    user = relationship('User')
+    fork = relationship('Repository', remote_side=repo_id)
+    group = relationship('RepoGroup')
+    repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
+    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
+    stats = relationship('Statistics', cascade='all', uselist=False)
+
+    followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
+
+    logs = relationship('UserLog')
+
+    def __unicode__(self):
+        return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
+                                   self.repo_name)
+
+    @classmethod
+    def url_sep(cls):
+        return '/'
+
+    @classmethod
+    def get_by_repo_name(cls, repo_name):
+        q = Session.query(cls).filter(cls.repo_name == repo_name)
+        q = q.options(joinedload(Repository.fork))\
+                .options(joinedload(Repository.user))\
+                .options(joinedload(Repository.group))
+        return q.scalar()
+
+    @classmethod
+    def get_repo_forks(cls, repo_id):
+        return cls.query().filter(Repository.fork_id == repo_id)
+
+    @classmethod
+    def base_path(cls):
+        """
+        Returns base path when all repos are stored
+
+        :param cls:
+        """
+        q = Session.query(RhodeCodeUi)\
+            .filter(RhodeCodeUi.ui_key == cls.url_sep())
+        q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
+        return q.one().ui_value
+
+    @property
+    def just_name(self):
+        return self.repo_name.split(Repository.url_sep())[-1]
+
+    @property
+    def groups_with_parents(self):
+        groups = []
+        if self.group is None:
+            return groups
+
+        cur_gr = self.group
+        groups.insert(0, cur_gr)
+        while 1:
+            gr = getattr(cur_gr, 'parent_group', None)
+            cur_gr = cur_gr.parent_group
+            if gr is None:
+                break
+            groups.insert(0, gr)
+
+        return groups
+
+    @property
+    def groups_and_repo(self):
+        return self.groups_with_parents, self.just_name
+
+    @LazyProperty
+    def repo_path(self):
+        """
+        Returns base full path for that repository means where it actually
+        exists on a filesystem
+        """
+        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
+                                              Repository.url_sep())
+        q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
+        return q.one().ui_value
+
+    @property
+    def repo_full_path(self):
+        p = [self.repo_path]
+        # we need to split the name by / since this is how we store the
+        # names in the database, but that eventually needs to be converted
+        # into a valid system path
+        p += self.repo_name.split(Repository.url_sep())
+        return os.path.join(*p)
+
+    def get_new_name(self, repo_name):
+        """
+        returns new full repository name based on assigned group and new new
+
+        :param group_name:
+        """
+        path_prefix = self.group.full_path_splitted if self.group else []
+        return Repository.url_sep().join(path_prefix + [repo_name])
+
+    @property
+    def _ui(self):
+        """
+        Creates an db based ui object for this repository
+        """
+        from mercurial import ui
+        from mercurial import config
+        baseui = ui.ui()
+
+        #clean the baseui object
+        baseui._ocfg = config.config()
+        baseui._ucfg = config.config()
+        baseui._tcfg = config.config()
+
+        ret = RhodeCodeUi.query()\
+            .options(FromCache("sql_cache_short", "repository_repo_ui")).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)
+                baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
+
+        return baseui
+
+    @classmethod
+    def is_valid(cls, repo_name):
+        """
+        returns True if given repo name is a valid filesystem repository
+
+        :param cls:
+        :param repo_name:
+        """
+        from rhodecode.lib.utils import is_valid_repo
+
+        return is_valid_repo(repo_name, cls.base_path())
+
+    #==========================================================================
+    # SCM PROPERTIES
+    #==========================================================================
+
+    def get_changeset(self, rev):
+        return get_changeset_safe(self.scm_instance, rev)
+
+    @property
+    def tip(self):
+        return self.get_changeset('tip')
+
+    @property
+    def author(self):
+        return self.tip.author
+
+    @property
+    def last_change(self):
+        return self.scm_instance.last_change
+
+    def comments(self, revisions=None):
+        """
+        Returns comments for this repository grouped by revisions
 
-from rhodecode.model.db import *
+        :param revisions: filter query by revisions only
+        """
+        cmts = ChangesetComment.query()\
+            .filter(ChangesetComment.repo == self)
+        if revisions:
+            cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
+        grouped = defaultdict(list)
+        for cmt in cmts.all():
+            grouped[cmt.revision].append(cmt)
+        return grouped
+
+    #==========================================================================
+    # SCM CACHE INSTANCE
+    #==========================================================================
+
+    @property
+    def invalidate(self):
+        return CacheInvalidation.invalidate(self.repo_name)
+
+    def set_invalidate(self):
+        """
+        set a cache for invalidation for this instance
+        """
+        CacheInvalidation.set_invalidate(self.repo_name)
+
+    @LazyProperty
+    def scm_instance(self):
+        return self.__get_instance()
+
+    @property
+    def scm_instance_cached(self):
+        @cache_region('long_term')
+        def _c(repo_name):
+            return self.__get_instance()
+        rn = self.repo_name
+        log.debug('Getting cached instance of repo')
+        inv = self.invalidate
+        if inv is not None:
+            region_invalidate(_c, None, rn)
+            # update our cache
+            CacheInvalidation.set_valid(inv.cache_key)
+        return _c(rn)
+
+    def __get_instance(self):
+        repo_full_path = self.repo_full_path
+        try:
+            alias = get_scm(repo_full_path)[0]
+            log.debug('Creating instance of %s repository' % alias)
+            backend = get_backend(alias)
+        except VCSError:
+            log.error(traceback.format_exc())
+            log.error('Perhaps this repository is in db and not in '
+                      'filesystem run rescan repositories with '
+                      '"destroy old data " option from admin panel')
+            return
+
+        if alias == 'hg':
+
+            repo = backend(safe_str(repo_full_path), create=False,
+                           baseui=self._ui)
+            # skip hidden web repository
+            if repo._get_hidden():
+                return
+        else:
+            repo = backend(repo_full_path, create=False)
+
+        return repo
+
+
+class RepoGroup(Base, BaseModel):
+    __tablename__ = 'groups'
+    __table_args__ = (
+        UniqueConstraint('group_name', 'group_parent_id'),
+        CheckConstraint('group_id != group_parent_id'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+    __mapper_args__ = {'order_by': 'group_name'}
+
+    group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
+    group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+
+    repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
+    users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
+
+    parent_group = relationship('RepoGroup', remote_side=group_id)
+
+    def __init__(self, group_name='', parent_group=None):
+        self.group_name = group_name
+        self.parent_group = parent_group
+
+    def __unicode__(self):
+        return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
+                                  self.group_name)
+
+    @classmethod
+    def groups_choices(cls):
+        from webhelpers.html import literal as _literal
+        repo_groups = [('', '')]
+        sep = ' &raquo; '
+        _name = lambda k: _literal(sep.join(k))
+
+        repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
+                              for x in cls.query().all()])
+
+        repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
+        return repo_groups
+
+    @classmethod
+    def url_sep(cls):
+        return '/'
+
+    @classmethod
+    def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
+        if case_insensitive:
+            gr = cls.query()\
+                .filter(cls.group_name.ilike(group_name))
+        else:
+            gr = cls.query()\
+                .filter(cls.group_name == group_name)
+        if cache:
+            gr = gr.options(FromCache(
+                            "sql_cache_short",
+                            "get_group_%s" % _hash_key(group_name)
+                            )
+            )
+        return gr.scalar()
+
+    @property
+    def parents(self):
+        parents_recursion_limit = 5
+        groups = []
+        if self.parent_group is None:
+            return groups
+        cur_gr = self.parent_group
+        groups.insert(0, cur_gr)
+        cnt = 0
+        while 1:
+            cnt += 1
+            gr = getattr(cur_gr, 'parent_group', None)
+            cur_gr = cur_gr.parent_group
+            if gr is None:
+                break
+            if cnt == parents_recursion_limit:
+                # this will prevent accidental infinit loops
+                log.error('group nested more than %s' %
+                          parents_recursion_limit)
+                break
+
+            groups.insert(0, gr)
+        return groups
+
+    @property
+    def children(self):
+        return RepoGroup.query().filter(RepoGroup.parent_group == self)
+
+    @property
+    def name(self):
+        return self.group_name.split(RepoGroup.url_sep())[-1]
+
+    @property
+    def full_path(self):
+        return self.group_name
+
+    @property
+    def full_path_splitted(self):
+        return self.group_name.split(RepoGroup.url_sep())
+
+    @property
+    def repositories(self):
+        return Repository.query()\
+                .filter(Repository.group == self)\
+                .order_by(Repository.repo_name)
+
+    @property
+    def repositories_recursive_count(self):
+        cnt = self.repositories.count()
+
+        def children_count(group):
+            cnt = 0
+            for child in group.children:
+                cnt += child.repositories.count()
+                cnt += children_count(child)
+            return cnt
+
+        return cnt + children_count(self)
+
+    def get_new_name(self, group_name):
+        """
+        returns new full group name based on parent and new name
+
+        :param group_name:
+        """
+        path_prefix = (self.parent_group.full_path_splitted if
+                       self.parent_group else [])
+        return RepoGroup.url_sep().join(path_prefix + [group_name])
+
+
+class Permission(Base, BaseModel):
+    __tablename__ = 'permissions'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+    permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+
+    def __unicode__(self):
+        return u"<%s('%s:%s')>" % (
+            self.__class__.__name__, self.permission_id, self.permission_name
+        )
+
+    @classmethod
+    def get_by_key(cls, key):
+        return cls.query().filter(cls.permission_name == key).scalar()
+
+    @classmethod
+    def get_default_perms(cls, default_user_id):
+        q = Session.query(UserRepoToPerm, Repository, cls)\
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+         .filter(UserRepoToPerm.user_id == default_user_id)
+
+        return q.all()
+
+    @classmethod
+    def get_default_group_perms(cls, default_user_id):
+        q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+         .filter(UserRepoGroupToPerm.user_id == default_user_id)
+
+        return q.all()
+
+
+class UserRepoToPerm(Base, BaseModel):
+    __tablename__ = 'repo_to_perm'
+    __table_args__ = (
+        UniqueConstraint('user_id', 'repository_id', 'permission_id'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    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('users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
+
+    user = relationship('User')
+    repository = relationship('Repository')
+    permission = relationship('Permission')
+
+    @classmethod
+    def create(cls, user, repository, permission):
+        n = cls()
+        n.user = user
+        n.repository = repository
+        n.permission = permission
+        Session.add(n)
+        return n
+
+    def __unicode__(self):
+        return u'<user:%s => %s >' % (self.user, self.repository)
+
+
+class UserToPerm(Base, BaseModel):
+    __tablename__ = 'user_to_perm'
+    __table_args__ = (
+        UniqueConstraint('user_id', 'permission_id'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    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('users.user_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+
+    user = relationship('User')
+    permission = relationship('Permission', lazy='joined')
+
+
+class UsersGroupRepoToPerm(Base, BaseModel):
+    __tablename__ = 'users_group_repo_to_perm'
+    __table_args__ = (
+        UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
+
+    users_group = relationship('UsersGroup')
+    permission = relationship('Permission')
+    repository = relationship('Repository')
+
+    @classmethod
+    def create(cls, users_group, repository, permission):
+        n = cls()
+        n.users_group = users_group
+        n.repository = repository
+        n.permission = permission
+        Session.add(n)
+        return n
+
+    def __unicode__(self):
+        return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
+
+
+class UsersGroupToPerm(Base, BaseModel):
+    __tablename__ = 'users_group_to_perm'
+    __table_args__ = (
+        UniqueConstraint('users_group_id', 'permission_id',),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+
+    users_group = relationship('UsersGroup')
+    permission = relationship('Permission')
+
+
+class UserRepoGroupToPerm(Base, BaseModel):
+    __tablename__ = 'user_repo_group_to_perm'
+    __table_args__ = (
+        UniqueConstraint('user_id', 'group_id', 'permission_id'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+
+    group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+
+    user = relationship('User')
+    group = relationship('RepoGroup')
+    permission = relationship('Permission')
+
+
+class UsersGroupRepoGroupToPerm(Base, BaseModel):
+    __tablename__ = 'users_group_repo_group_to_perm'
+    __table_args__ = (
+        UniqueConstraint('users_group_id', 'group_id'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+
+    users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
+    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+
+    users_group = relationship('UsersGroup')
+    permission = relationship('Permission')
+    group = relationship('RepoGroup')
+
+
+class Statistics(Base, BaseModel):
+    __tablename__ = 'statistics'
+    __table_args__ = (
+         UniqueConstraint('repository_id'),
+         {'extend_existing': True, 'mysql_engine':'InnoDB',
+          'mysql_charset': 'utf8'}
+    )
+    stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    repository_id = Column("repository_id", Integer(), ForeignKey('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(1000000), nullable=False)#JSON data
+    commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
+    languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
+
+    repository = relationship('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'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+
+    user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
+    follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
+    follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
+
+    user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
+
+    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
+    follows_repository = relationship('Repository', order_by='Repository.repo_name')
+
+    @classmethod
+    def get_repo_followers(cls, repo_id):
+        return cls.query().filter(cls.follows_repo_id == repo_id)
+
+
+class CacheInvalidation(Base, BaseModel):
+    __tablename__ = 'cache_invalidation'
+    __table_args__ = (
+        UniqueConstraint('cache_key'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+    cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    cache_args = Column("cache_args", String(length=255, 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 __unicode__(self):
+        return u"<%s('%s:%s')>" % (self.__class__.__name__,
+                                  self.cache_id, self.cache_key)
+    @classmethod
+    def clear_cache(cls):
+        cls.query().delete()
+
+    @classmethod
+    def _get_key(cls, key):
+        """
+        Wrapper for generating a key, together with a prefix
+
+        :param key:
+        """
+        import rhodecode
+        prefix = ''
+        iid = rhodecode.CONFIG.get('instance_id')
+        if iid:
+            prefix = iid
+        return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
+
+    @classmethod
+    def get_by_key(cls, key):
+        return cls.query().filter(cls.cache_key == key).scalar()
+
+    @classmethod
+    def _get_or_create_key(cls, key, prefix, org_key):
+        inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
+        if not inv_obj:
+            try:
+                inv_obj = CacheInvalidation(key, org_key)
+                Session.add(inv_obj)
+                Session.commit()
+            except Exception:
+                log.error(traceback.format_exc())
+                Session.rollback()
+        return inv_obj
+
+    @classmethod
+    def invalidate(cls, key):
+        """
+        Returns Invalidation object if this given key should be invalidated
+        None otherwise. `cache_active = False` means that this cache
+        state is not valid and needs to be invalidated
+
+        :param key:
+        """
+
+        key, _prefix, _org_key = cls._get_key(key)
+        inv = cls._get_or_create_key(key, _prefix, _org_key)
+
+        if inv and inv.cache_active is False:
+            return inv
+
+    @classmethod
+    def set_invalidate(cls, key):
+        """
+        Mark this Cache key for invalidation
+
+        :param key:
+        """
+
+        key, _prefix, _org_key = cls._get_key(key)
+        inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
+        log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
+                                                             _org_key))
+        try:
+            for inv_obj in inv_objs:
+                if inv_obj:
+                    inv_obj.cache_active = False
+
+                Session.add(inv_obj)
+            Session.commit()
+        except Exception:
+            log.error(traceback.format_exc())
+            Session.rollback()
+
+    @classmethod
+    def set_valid(cls, key):
+        """
+        Mark this cache key as active and currently cached
+
+        :param key:
+        """
+        inv_obj = cls.get_by_key(key)
+        inv_obj.cache_active = True
+        Session.add(inv_obj)
+        Session.commit()
+
+
+class ChangesetComment(Base, BaseModel):
+    __tablename__ = 'changeset_comments'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+    comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
+    repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
+    revision = Column('revision', String(40), nullable=False)
+    line_no = Column('line_no', Unicode(10), nullable=True)
+    f_path = Column('f_path', Unicode(1000), nullable=True)
+    user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
+    text = Column('text', Unicode(25000), nullable=False)
+    modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
+
+    author = relationship('User', lazy='joined')
+    repo = relationship('Repository')
+
+    @classmethod
+    def get_users(cls, revision):
+        """
+        Returns user associated with this changesetComment. ie those
+        who actually commented
+
+        :param cls:
+        :param revision:
+        """
+        return Session.query(User)\
+                .filter(cls.revision == revision)\
+                .join(ChangesetComment.author).all()
+
+
+class Notification(Base, BaseModel):
+    __tablename__ = 'notifications'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+
+    TYPE_CHANGESET_COMMENT = u'cs_comment'
+    TYPE_MESSAGE = u'message'
+    TYPE_MENTION = u'mention'
+    TYPE_REGISTRATION = u'registration'
+
+    notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
+    subject = Column('subject', Unicode(512), nullable=True)
+    body = Column('body', Unicode(50000), nullable=True)
+    created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
+    created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    type_ = Column('type', Unicode(256))
+
+    created_by_user = relationship('User')
+    notifications_to_users = relationship('UserNotification', lazy='joined',
+                                          cascade="all, delete, delete-orphan")
+
+    @property
+    def recipients(self):
+        return [x.user for x in UserNotification.query()\
+                .filter(UserNotification.notification == self).all()]
+
+    @classmethod
+    def create(cls, created_by, subject, body, recipients, type_=None):
+        if type_ is None:
+            type_ = Notification.TYPE_MESSAGE
+
+        notification = cls()
+        notification.created_by_user = created_by
+        notification.subject = subject
+        notification.body = body
+        notification.type_ = type_
+        notification.created_on = datetime.datetime.now()
+
+        for u in recipients:
+            assoc = UserNotification()
+            assoc.notification = notification
+            u.notifications.append(assoc)
+        Session.add(notification)
+        return notification
+
+    @property
+    def description(self):
+        from rhodecode.model.notification import NotificationModel
+        return NotificationModel().make_description(self)
+
+
+class UserNotification(Base, BaseModel):
+    __tablename__ = 'user_to_notification'
+    __table_args__ = (
+        UniqueConstraint('user_id', 'notification_id'),
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
+    notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
+    read = Column('read', Boolean, default=False)
+    sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
+
+    user = relationship('User', lazy="joined")
+    notification = relationship('Notification', lazy="joined",
+                                order_by=lambda: Notification.created_on.desc(),)
+
+    def mark_as_read(self):
+        self.read = True
+        Session.add(self)
+
+
+class DbMigrateVersion(Base, BaseModel):
+    __tablename__ = 'db_migrate_version'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine':'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+    repository_id = Column('repository_id', String(250), primary_key=True)
+    repository_path = Column('repository_path', Text)
+    version = Column('version', Integer)
+
+## this is migration from 1_4_0, but now it's here to overcome a problem of
+## attaching a FK to this from 1_3_0 !
+
+
+class PullRequest(Base, BaseModel):
+    __tablename__ = 'pull_requests'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+
+    STATUS_NEW = u'new'
+    STATUS_OPEN = u'open'
+    STATUS_CLOSED = u'closed'
+
+    pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
+    title = Column('title', Unicode(256), nullable=True)
+    description = Column('description', UnicodeText(10240), nullable=True)
+    status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
+    created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
+    _revisions = Column('revisions', UnicodeText(20500))  # 500 revisions max
+    org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
+    org_ref = Column('org_ref', Unicode(256), nullable=False)
+    other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
+    other_ref = Column('other_ref', Unicode(256), nullable=False)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/schema/db_1_4_0.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.db_1_4_0
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Database Models for RhodeCode <=1.4.X
+
+    :created_on: Apr 08, 2010
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+#TODO: replace that will db.py content after 1.5 Release
+
+from rhodecode.model.db import *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/dbmigrate/versions/006_version_1_4_0.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,186 @@
+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 sqlalchemy.ext.declarative import declarative_base
+
+from rhodecode.lib.dbmigrate.migrate import *
+from rhodecode.lib.dbmigrate.migrate.changeset import *
+
+from rhodecode.model.meta import Base
+from rhodecode.model import meta
+
+log = logging.getLogger(__name__)
+
+
+def upgrade(migrate_engine):
+    """
+    Upgrade operations go here.
+    Don't create your own engine; bind migrate_engine to your metadata
+    """
+
+    #==========================================================================
+    # USEREMAILMAP
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_4_0 import UserEmailMap
+    tbl = UserEmailMap.__table__
+    tbl.create()
+    #==========================================================================
+    # PULL REQUEST
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_4_0 import PullRequest
+    tbl = PullRequest.__table__
+    tbl.create()
+
+    #==========================================================================
+    # PULL REQUEST REVIEWERS
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_4_0 import PullRequestReviewers
+    tbl = PullRequestReviewers.__table__
+    tbl.create()
+
+    #==========================================================================
+    # CHANGESET STATUS
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_4_0 import ChangesetStatus
+    tbl = ChangesetStatus.__table__
+    tbl.create()
+
+    ## RESET COMPLETLY THE metadata for sqlalchemy to use the 1_3_0 Base 
+    Base = declarative_base()
+    Base.metadata.clear()
+    Base.metadata = MetaData()
+    Base.metadata.bind = migrate_engine
+    meta.Base = Base
+
+    #==========================================================================
+    # USERS TABLE
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import User
+    tbl = User.__table__
+
+    # change column name -> firstname
+    col = User.__table__.columns.name
+    col.alter(index=Index('u_username_idx', 'username'))
+    col.alter(index=Index('u_email_idx', 'email'))
+    col.alter(name="firstname", table=tbl)
+
+    # add inherit_default_permission column
+    inherit_default_permissions = Column("inherit_default_permissions",
+                                         Boolean(), nullable=True, unique=None,
+                                         default=True)
+    inherit_default_permissions.create(table=tbl)
+    inherit_default_permissions.alter(nullable=False, default=True, table=tbl)
+
+    #==========================================================================
+    # USERS GROUP TABLE
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import UsersGroup
+    tbl = UsersGroup.__table__
+    # add inherit_default_permission column
+    gr_inherit_default_permissions = Column(
+                                    "users_group_inherit_default_permissions",
+                                    Boolean(), nullable=True, unique=None,
+                                    default=True)
+    gr_inherit_default_permissions.create(table=tbl)
+    gr_inherit_default_permissions.alter(nullable=False, default=True, table=tbl)
+
+    #==========================================================================
+    # REPOSITORIES
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import Repository
+    tbl = Repository.__table__
+
+    # add enable locking column
+    enable_locking = Column("enable_locking", Boolean(), nullable=True,
+                            unique=None, default=False)
+    enable_locking.create(table=tbl)
+    enable_locking.alter(nullable=False, default=False, table=tbl)
+
+    # add locked column
+    _locked = Column("locked", String(255), nullable=True, unique=False,
+                     default=None)
+    _locked.create(table=tbl)
+
+    #add langing revision column
+    landing_rev = Column("landing_revision", String(255), nullable=True,
+                         unique=False, default='tip')
+    landing_rev.create(table=tbl)
+    landing_rev.alter(nullable=False, default='tip', table=tbl)
+
+    #==========================================================================
+    # GROUPS
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import RepoGroup
+    tbl = RepoGroup.__table__
+
+    # add enable locking column
+    enable_locking = Column("enable_locking", Boolean(), nullable=True,
+                            unique=None, default=False)
+    enable_locking.create(table=tbl)
+    enable_locking.alter(nullable=False, default=False)
+
+    #==========================================================================
+    # CACHE INVALIDATION
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import CacheInvalidation
+    tbl = CacheInvalidation.__table__
+
+    # add INDEX for cache keys
+    col = CacheInvalidation.__table__.columns.cache_key
+    col.alter(index=Index('key_idx', 'cache_key'))
+
+    #==========================================================================
+    # NOTIFICATION
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import Notification
+    tbl = Notification.__table__
+
+    # add index for notification type
+    col = Notification.__table__.columns.type
+    col.alter(index=Index('notification_type_idx', 'type'),)
+
+    #==========================================================================
+    # CHANGESET_COMMENTS
+    #==========================================================================
+    from rhodecode.lib.dbmigrate.schema.db_1_3_0 import ChangesetComment
+
+    tbl = ChangesetComment.__table__
+    col = ChangesetComment.__table__.columns.revision
+
+    # add index for revisions
+    col.alter(index=Index('cc_revision_idx', 'revision'),)
+
+    # add hl_lines column
+    hl_lines = Column('hl_lines', Unicode(512), nullable=True)
+    hl_lines.create(table=tbl)
+
+    # add created_on column
+    created_on = Column('created_on', DateTime(timezone=False), nullable=True,
+                        default=datetime.datetime.now)
+    created_on.create(table=tbl)
+    created_on.alter(nullable=False, default=datetime.datetime.now)
+
+    modified_at = Column('modified_at', DateTime(timezone=False), nullable=False,
+                         default=datetime.datetime.now)
+    modified_at.alter(type=DateTime(timezone=False), table=tbl)
+
+    # add FK to pull_request
+    pull_request_id = Column("pull_request_id", Integer(),
+                             ForeignKey('pull_requests.pull_request_id'),
+                             nullable=True)
+    pull_request_id.create(table=tbl)
+    ## RESET COMPLETLY THE metadata for sqlalchemy back after using 1_3_0
+    Base = declarative_base()
+    Base.metadata.clear()
+    Base.metadata = MetaData()
+    Base.metadata.bind = migrate_engine
+    meta.Base = Base
+
+
+def downgrade(migrate_engine):
+    meta = MetaData()
+    meta.bind = migrate_engine
--- a/rhodecode/lib/diffs.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/diffs.py	Sun Sep 02 21:19:54 2012 +0200
@@ -28,14 +28,22 @@
 import re
 import difflib
 import markupsafe
+
 from itertools import tee, imap
 
+from mercurial import patch
+from mercurial.mdiff import diffopts
+from mercurial.bundlerepo import bundlerepository
+
 from pylons.i18n.translation import _
 
+from rhodecode.lib.compat import BytesIO
+from rhodecode.lib.vcs.utils.hgcompat import localrepo
 from rhodecode.lib.vcs.exceptions import VCSError
 from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
 from rhodecode.lib.helpers import escape
-from rhodecode.lib.utils import EmptyChangeset
+from rhodecode.lib.utils import make_ui
 
 
 def wrap_to_table(str_):
@@ -75,7 +83,7 @@
         stats = diff_processor.stat()
         size = len(diff or '')
     else:
-        diff = wrap_to_table(_('Changeset was to big and was cut off, use '
+        diff = wrap_to_table(_('Changeset was too big and was cut off, use '
                                'diff menu to display this diff'))
         stats = (0, 0)
         size = 0
@@ -127,8 +135,9 @@
     can be used to render it in a HTML template.
     """
     _chunk_re = re.compile(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)')
+    _newline_marker = '\\ No newline at end of file\n'
 
-    def __init__(self, diff, differ='diff', format='udiff'):
+    def __init__(self, diff, differ='diff', format='gitdiff'):
         """
         :param diff:   a text in diff format or generator
         :param format: format of diff passed, `udiff` or `gitdiff`
@@ -171,7 +180,7 @@
 
     def _extract_rev(self, line1, line2):
         """
-        Extract the filename and revision hint from a line.
+        Extract the operation (A/M/D), filename and revision hint from a line.
         """
 
         try:
@@ -189,11 +198,15 @@
                 filename = (old_filename
                             if old_filename != '/dev/null' else new_filename)
 
-                return filename, new_rev, old_rev
+                operation = 'D' if new_filename == '/dev/null' else None
+                if not operation:
+                    operation = 'M' if old_filename != '/dev/null' else 'A'
+
+                return operation, filename, new_rev, old_rev
         except (ValueError, IndexError):
             pass
 
-        return None, None, None
+        return None, None, None, None
 
     def _parse_gitdiff(self, diffiterator):
         def line_decoder(l):
@@ -278,7 +291,7 @@
             do(line)
             do(next_)
 
-    def _parse_udiff(self):
+    def _parse_udiff(self, inline_diff=True):
         """
         Parse the diff an return data for the template.
         """
@@ -286,8 +299,6 @@
         files = []
         try:
             line = lineiter.next()
-            # skip first context
-            skipfirst = True
             while 1:
                 # continue until we found the old file
                 if not line.startswith('--- '):
@@ -295,13 +306,16 @@
                     continue
 
                 chunks = []
-                filename, old_rev, new_rev = \
+                stats = [0, 0]
+                operation, filename, old_rev, new_rev = \
                     self._extract_rev(line, lineiter.next())
                 files.append({
                     'filename':         filename,
                     'old_revision':     old_rev,
                     'new_revision':     new_rev,
-                    'chunks':           chunks
+                    'chunks':           chunks,
+                    'operation':        operation,
+                    'stats':            stats,
                 })
 
                 line = lineiter.next()
@@ -317,27 +331,33 @@
                         [int(x or 1) for x in match.groups()[:-1]]
                     old_line -= 1
                     new_line -= 1
-                    context = len(match.groups()) == 5
+                    gr = match.groups()
+                    context = len(gr) == 5
                     old_end += old_line
                     new_end += new_line
 
                     if context:
-                        if not skipfirst:
+                        # skip context only if it's first line
+                        if int(gr[0]) > 1:
                             lines.append({
                                 'old_lineno': '...',
                                 'new_lineno': '...',
                                 'action':     'context',
                                 'line':       line,
                             })
-                        else:
-                            skipfirst = False
 
                     line = lineiter.next()
+
                     while old_line < old_end or new_line < new_end:
                         if line:
-                            command, line = line[0], line[1:]
+                            command = line[0]
+                            if command in ['+', '-', ' ']:
+                                #only modify the line if it's actually a diff
+                                # thing
+                                line = line[1:]
                         else:
                             command = ' '
+
                         affects_old = affects_new = False
 
                         # ignore those if we don't expect them
@@ -346,51 +366,67 @@
                         elif command == '+':
                             affects_new = True
                             action = 'add'
+                            stats[0] += 1
                         elif command == '-':
                             affects_old = True
                             action = 'del'
+                            stats[1] += 1
                         else:
                             affects_old = affects_new = True
                             action = 'unmod'
 
-                        old_line += affects_old
-                        new_line += affects_new
-                        lines.append({
-                            'old_lineno':   affects_old and old_line or '',
-                            'new_lineno':   affects_new and new_line or '',
-                            'action':       action,
-                            'line':         line
-                        })
+                        if line != self._newline_marker:
+                            old_line += affects_old
+                            new_line += affects_new
+                            lines.append({
+                                'old_lineno':   affects_old and old_line or '',
+                                'new_lineno':   affects_new and new_line or '',
+                                'action':       action,
+                                'line':         line
+                            })
+
                         line = lineiter.next()
+                        if line == self._newline_marker:
+                            # we need to append to lines, since this is not
+                            # counted in the line specs of diff
+                            lines.append({
+                                'old_lineno':   '...',
+                                'new_lineno':   '...',
+                                'action':       'context',
+                                'line':         line
+                            })
 
         except StopIteration:
             pass
 
+        sorter = lambda info: {'A': 0, 'M': 1, 'D': 2}.get(info['operation'])
+        if inline_diff is False:
+            return sorted(files, key=sorter)
+
         # highlight inline changes
-        for _ in files:
-            for chunk in chunks:
+        for diff_data in files:
+            for chunk in diff_data['chunks']:
                 lineiter = iter(chunk)
-                #first = True
                 try:
                     while 1:
                         line = lineiter.next()
-                        if line['action'] != 'unmod':
+                        if line['action'] not in ['unmod', 'context']:
                             nextline = lineiter.next()
-                            if nextline['action'] == 'unmod' or \
+                            if nextline['action'] in ['unmod', 'context'] or \
                                nextline['action'] == line['action']:
                                 continue
                             self.differ(line, nextline)
                 except StopIteration:
                     pass
 
-        return files
+        return sorted(files, key=sorter)
 
-    def prepare(self):
+    def prepare(self, inline_diff=True):
         """
         Prepare the passed udiff for HTML rendering. It'l return a list
         of dicts
         """
-        return self._parse_udiff()
+        return self._parse_udiff(inline_diff=inline_diff)
 
     def _safe_id(self, idstring):
         """Make a string safe for including in an id attribute.
@@ -424,9 +460,9 @@
 
     def as_html(self, table_class='code-difftable', line_class='line',
                 new_lineno_class='lineno old', old_lineno_class='lineno new',
-                code_class='code', enable_comments=False):
+                code_class='code', enable_comments=False, diff_lines=None):
         """
-        Return udiff as html table with customized css classes
+        Return given diff as html table with customized css classes
         """
         def _link_to_if(condition, label, url):
             """
@@ -440,7 +476,8 @@
                 }
             else:
                 return label
-        diff_lines = self.prepare()
+        if diff_lines is None:
+            diff_lines = self.prepare()
         _html_empty = True
         _html = []
         _html.append('''<table class="%(table_class)s">\n''' % {
@@ -522,3 +559,78 @@
         Returns tuple of added, and removed lines for this instance
         """
         return self.adds, self.removes
+
+
+class InMemoryBundleRepo(bundlerepository):
+    def __init__(self, ui, path, bundlestream):
+        self._tempparent = None
+        localrepo.localrepository.__init__(self, ui, path)
+        self.ui.setconfig('phases', 'publish', False)
+
+        self.bundle = bundlestream
+
+        # dict with the mapping 'filename' -> position in the bundle
+        self.bundlefilespos = {}
+
+
+def differ(org_repo, org_ref, other_repo, other_ref, discovery_data=None):
+    """
+    General differ between branches, bookmarks or separate but releated
+    repositories
+
+    :param org_repo:
+    :type org_repo:
+    :param org_ref:
+    :type org_ref:
+    :param other_repo:
+    :type other_repo:
+    :param other_ref:
+    :type other_ref:
+    """
+
+    bundlerepo = None
+    ignore_whitespace = False
+    context = 3
+    org_repo = org_repo.scm_instance._repo
+    other_repo = other_repo.scm_instance._repo
+    opts = diffopts(git=True, ignorews=ignore_whitespace, context=context)
+    org_ref = org_ref[1]
+    other_ref = other_ref[1]
+
+    if org_repo != other_repo:
+
+        common, incoming, rheads = discovery_data
+        other_repo_peer = localrepo.locallegacypeer(other_repo.local())
+        # create a bundle (uncompressed if other repo is not local)
+        if other_repo_peer.capable('getbundle') and incoming:
+            # disable repo hooks here since it's just bundle !
+            # patch and reset hooks section of UI config to not run any
+            # hooks on fetching archives with subrepos
+            for k, _ in other_repo.ui.configitems('hooks'):
+                other_repo.ui.setconfig('hooks', k, None)
+
+            unbundle = other_repo.getbundle('incoming', common=common,
+                                            heads=rheads)
+
+            buf = BytesIO()
+            while True:
+                chunk = unbundle._stream.read(1024 * 4)
+                if not chunk:
+                    break
+                buf.write(chunk)
+
+            buf.seek(0)
+            # replace chunked _stream with data that can do tell() and seek()
+            unbundle._stream = buf
+
+            ui = make_ui('db')
+            bundlerepo = InMemoryBundleRepo(ui, path=org_repo.root,
+                                            bundlestream=unbundle)
+
+        return ''.join(patch.diff(bundlerepo or org_repo,
+                                  node1=org_repo[org_ref].node(),
+                                  node2=other_repo[other_ref].node(),
+                                  opts=opts))
+    else:
+        return ''.join(patch.diff(org_repo, node1=org_ref, node2=other_ref,
+                                  opts=opts))
--- a/rhodecode/lib/exceptions.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/exceptions.py	Sun Sep 02 21:19:54 2012 +0200
@@ -23,6 +23,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+from webob.exc import HTTPClientError
+
 
 class LdapUsernameError(Exception):
     pass
@@ -50,3 +52,20 @@
 
 class UsersGroupsAssignedException(Exception):
     pass
+
+
+class StatusChangeOnClosedPullRequestError(Exception):
+    pass
+
+
+class HTTPLockedRC(HTTPClientError):
+    """
+    Special Exception For locked Repos in RhodeCode
+    """
+    code = 423
+    title = explanation = 'Repository Locked'
+
+    def __init__(self, reponame, username, *args, **kwargs):
+        self.title = self.explanation = ('Repository `%s` locked by '
+                                         'user `%s`' % (reponame, username))
+        super(HTTPLockedRC, self).__init__(*args, **kwargs)
--- a/rhodecode/lib/ext_json.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/ext_json.py	Sun Sep 02 21:19:54 2012 +0200
@@ -60,7 +60,7 @@
 # Import simplejson
 try:
     # import simplejson initially
-    import simplejson as _sj
+    import simplejson
 
     def extended_encode(obj):
         try:
@@ -70,37 +70,42 @@
         raise TypeError("%r is not JSON serializable" % (obj,))
     # we handle decimals our own it makes unified behavior of json vs
     # simplejson
-    _sj.dumps = functools.partial(_sj.dumps, default=extended_encode,
-                                  use_decimal=False)
-    _sj.dump = functools.partial(_sj.dump, default=extended_encode,
-                                 use_decimal=False)
-    simplejson = _sj
-
+    simplejson.dumps = functools.partial(simplejson.dumps,
+                                         default=extended_encode,
+                                         use_decimal=False)
+    simplejson.dump = functools.partial(simplejson.dump,
+                                        default=extended_encode,
+                                        use_decimal=False)
 except ImportError:
     # no simplejson set it to None
-    _sj = None
+    simplejson = None
 
 
 try:
     # simplejson not found try out regular json module
-    import json as _json
+    import json
 
     # extended JSON encoder for json
-    class ExtendedEncoder(_json.JSONEncoder):
+    class ExtendedEncoder(json.JSONEncoder):
         def default(self, obj):
             try:
                 return _obj_dump(obj)
             except NotImplementedError:
                 pass
-            return _json.JSONEncoder.default(self, obj)
+            return json.JSONEncoder.default(self, obj)
     # monkey-patch JSON encoder to use extended version
-    _json.dumps = functools.partial(_json.dumps, cls=ExtendedEncoder)
-    _json.dump = functools.partial(_json.dump, cls=ExtendedEncoder)
-    stdlib = _json
+    json.dumps = functools.partial(json.dumps, cls=ExtendedEncoder)
+    json.dump = functools.partial(json.dump, cls=ExtendedEncoder)
+
 except ImportError:
-    _json = None
+    json = None
+
+stdlib = json
 
 # set all available json modules
-simplejson = _sj
-stdjson = _json
-json = _sj if _sj else _json
+if simplejson:
+    json = simplejson
+elif json:
+    json = json
+else:
+    raise ImportError('Could not find any json modules')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/graphmod.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,127 @@
+"""
+Modified mercurial DAG graph functions that re-uses VCS structure
+
+It allows to have a shared codebase for DAG generation for hg and git repos
+"""
+
+nullrev = -1
+
+
+def grandparent(parentrev_func, lowestrev, roots, head):
+    """
+    Return all ancestors of head in roots which revision is
+    greater or equal to lowestrev.
+    """
+    pending = set([head])
+    seen = set()
+    kept = set()
+    llowestrev = max(nullrev, lowestrev)
+    while pending:
+        r = pending.pop()
+        if r >= llowestrev and r not in seen:
+            if r in roots:
+                kept.add(r)
+            else:
+                pending.update([p for p in parentrev_func(r)])
+            seen.add(r)
+    return sorted(kept)
+
+
+def _dagwalker(repo, revs, alias):
+    if not revs:
+        return
+
+    if alias == 'hg':
+        cl = repo._repo.changelog.parentrevs
+        repo = repo
+    elif alias == 'git':
+        def cl(rev):
+            return [x.revision for x in repo[rev].parents()]
+        repo = repo
+
+    lowestrev = min(revs)
+    gpcache = {}
+
+    knownrevs = set(revs)
+    for rev in revs:
+        ctx = repo[rev]
+        parents = sorted(set([p.revision for p in ctx.parents
+                              if p.revision in knownrevs]))
+        mpars = [p.revision for p in ctx.parents if
+                 p.revision != nullrev and p.revision not in parents]
+
+        for mpar in mpars:
+            gp = gpcache.get(mpar)
+            if gp is None:
+                gp = gpcache[mpar] = grandparent(cl, lowestrev, revs, mpar)
+            if not gp:
+                parents.append(mpar)
+            else:
+                parents.extend(g for g in gp if g not in parents)
+
+        yield (ctx.revision, 'C', ctx, parents)
+
+
+def _colored(dag):
+    """annotates a DAG with colored edge information
+
+    For each DAG node this function emits tuples::
+
+      (id, type, data, (col, color), [(col, nextcol, color)])
+
+    with the following new elements:
+
+      - Tuple (col, color) with column and color index for the current node
+      - A list of tuples indicating the edges between the current node and its
+        parents.
+    """
+    seen = []
+    colors = {}
+    newcolor = 1
+
+    getconf = lambda rev: {}
+
+    for (cur, type, data, parents) in dag:
+
+        # Compute seen and next
+        if cur not in seen:
+            seen.append(cur)  # new head
+            colors[cur] = newcolor
+            newcolor += 1
+
+        col = seen.index(cur)
+        color = colors.pop(cur)
+        next = seen[:]
+
+        # Add parents to next
+        addparents = [p for p in parents if p not in next]
+        next[col:col + 1] = addparents
+
+        # Set colors for the parents
+        for i, p in enumerate(addparents):
+            if not i:
+                colors[p] = color
+            else:
+                colors[p] = newcolor
+                newcolor += 1
+
+        # Add edges to the graph
+        edges = []
+        for ecol, eid in enumerate(seen):
+            if eid in next:
+                bconf = getconf(eid)
+                edges.append((
+                    ecol, next.index(eid), colors[eid],
+                    bconf.get('width', -1),
+                    bconf.get('color', '')))
+            elif eid == cur:
+                for p in parents:
+                    bconf = getconf(p)
+                    edges.append((
+                        ecol, next.index(p), color,
+                        bconf.get('width', -1),
+                        bconf.get('color', '')))
+
+        # Yield and move on
+        yield (cur, type, data, (col, color), edges)
+        seen = next
--- a/rhodecode/lib/helpers.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/helpers.py	Sun Sep 02 21:19:54 2012 +0200
@@ -9,6 +9,7 @@
 import urllib
 import math
 import logging
+import re
 
 from datetime import datetime
 from pygments.formatters.html import HtmlFormatter
@@ -40,12 +41,31 @@
 from rhodecode.lib.annotate import annotate_highlight
 from rhodecode.lib.utils import repo_name_slug
 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
-    get_changeset_safe
+    get_changeset_safe, datetime_to_time, time_to_datetime
 from rhodecode.lib.markup_renderer import MarkupRenderer
+from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
+from rhodecode.lib.vcs.backends.base import BaseChangeset
+from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
+from rhodecode.model.changeset_status import ChangesetStatusModel
+from rhodecode.model.db import URL_SEP, Permission
 
 log = logging.getLogger(__name__)
 
 
+html_escape_table = {
+    "&": "&amp;",
+    '"': "&quot;",
+    "'": "&apos;",
+    ">": "&gt;",
+    "<": "&lt;",
+}
+
+
+def html_escape(text):
+    """Produce entities within text."""
+    return "".join(html_escape_table.get(c,c) for c in text)
+
+
 def shorter(text, size=20):
     postfix = '...'
     if len(text) > size:
@@ -105,7 +125,7 @@
 
     def __call__(self, field_name, form_errors):
         tmpl = """<span class="error_msg">%s</span>"""
-        if form_errors and form_errors.has_key(field_name):
+        if form_errors and field_name in form_errors:
             return literal(tmpl % form_errors.get(field_name))
 
 get_error = _GetError()
@@ -114,12 +134,15 @@
 class _ToolTip(object):
 
     def __call__(self, tooltip_title, trim_at=50):
-        """Special function just to wrap our text into nice formatted
+        """
+        Special function just to wrap our text into nice formatted
         autowrapped text
 
         :param tooltip_title:
         """
-        return escape(tooltip_title)
+        tooltip_title = escape(tooltip_title)
+        tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
+        return tooltip_title
 tooltip = _ToolTip()
 
 
@@ -130,7 +153,8 @@
             paths = safe_unicode(paths)
         url_l = [link_to(repo_name, url('files_home',
                                         repo_name=repo_name,
-                                        revision=rev, f_path=''))]
+                                        revision=rev, f_path=''),
+                         class_='ypjax-link')]
         paths_l = paths.split('/')
         for cnt, p in enumerate(paths_l):
             if p != '':
@@ -139,7 +163,8 @@
                                          repo_name=repo_name,
                                          revision=rev,
                                          f_path='/'.join(paths_l[:cnt + 1])
-                                         )
+                                         ),
+                                     class_='ypjax-link'
                                      )
                              )
 
@@ -333,7 +358,7 @@
 #==============================================================================
 from rhodecode.lib.vcs.utils import author_name, author_email
 from rhodecode.lib.utils2 import credentials_filter, age as _age
-from rhodecode.model.db import User
+from rhodecode.model.db import User, ChangesetStatus
 
 age = lambda  x: _age(x)
 capitalize = lambda x: x.capitalize()
@@ -342,6 +367,14 @@
 hide_credentials = lambda x: ''.join(credentials_filter(x))
 
 
+def fmt_date(date):
+    if date:
+        _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
+        return date.strftime(_fmt).decode('utf8')
+
+    return ""
+
+
 def is_git(repository):
     if hasattr(repository, 'alias'):
         _type = repository.alias
@@ -363,8 +396,14 @@
 
 
 def email_or_none(author):
+    # extract email from the commit string
     _email = email(author)
     if _email != '':
+        # check it against RhodeCode database, and use the MAIN email for this
+        # user
+        user = User.get_by_email(_email, case_insensitive=True, cache=True)
+        if user is not None:
+            return user.email
         return _email
 
     # See if it contains a username we can get an email from
@@ -377,9 +416,9 @@
     return None
 
 
-def person(author):
+def person(author, show_attr="username_and_name"):
     # attr to return from fetched user
-    person_getter = lambda usr: usr.username
+    person_getter = lambda usr: getattr(usr, show_attr)
 
     # Valid email in the attribute passed, see if they're in the system
     _email = email(author)
@@ -400,6 +439,39 @@
     return _author
 
 
+def person_by_id(id_, show_attr="username_and_name"):
+    # attr to return from fetched user
+    person_getter = lambda usr: getattr(usr, show_attr)
+
+    #maybe it's an ID ?
+    if str(id_).isdigit() or isinstance(id_, int):
+        id_ = int(id_)
+        user = User.get(id_)
+        if user is not None:
+            return person_getter(user)
+    return id_
+
+
+def desc_stylize(value):
+    """
+    converts tags from value into html equivalent
+
+    :param value:
+    """
+    value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
+                   '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
+    value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
+                   '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
+    value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z\-\/]*)\]',
+                   '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
+    value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/]*)\]',
+                   '<div class="metatag" tag="lang">\\2</div>', value)
+    value = re.sub(r'\[([a-z]+)\]',
+                  '<div class="metatag" tag="\\1">\\1</div>', value)
+
+    return value
+
+
 def bool2icon(value):
     """Returns True/False values represented as small html image of true/false
     icons
@@ -447,22 +519,30 @@
 
         repo = user_log.repository.scm_instance
 
-        message = lambda rev: rev.message
-        lnk = lambda rev, repo_name: (
-            link_to('r%s:%s' % (rev.revision, rev.short_id),
-                    url('changeset_home', repo_name=repo_name,
-                        revision=rev.raw_id),
-                    title=tooltip(message(rev)), class_='tooltip')
-        )
+        def lnk(rev, repo_name):
+
+            if isinstance(rev, BaseChangeset):
+                lbl = 'r%s:%s' % (rev.revision, rev.short_id)
+                _url = url('changeset_home', repo_name=repo_name,
+                           revision=rev.raw_id)
+                title = tooltip(rev.message)
+            else:
+                lbl = '%s' % rev
+                _url = '#'
+                title = _('Changeset not found')
+
+            return link_to(lbl, _url, title=title, class_='tooltip',)
 
         revs = []
         if len(filter(lambda v: v != '', revs_ids)) > 0:
-            # get only max revs_top_limit of changeset for performance/ui reasons
-            revs = [
-                x for x in repo.get_changesets(revs_ids[0],
-                                               revs_ids[:revs_top_limit][-1])
-            ]
-
+            for rev in revs_ids[:revs_top_limit]:
+                try:
+                    rev = repo.get_changeset(rev)
+                    revs.append(rev)
+                except ChangesetDoesNotExistError:
+                    log.error('cannot find revision %s in this repo' % rev)
+                    revs.append(rev)
+                    continue
         cs_links = []
         cs_links.append(" " + ', '.join(
             [lnk(rev, repo_name) for rev in revs[:revs_limit]]
@@ -526,22 +606,68 @@
         return _('fork name ') + str(link_to(action_params, url('summary_home',
                                           repo_name=repo_name,)))
 
-    action_map = {'user_deleted_repo': (_('[deleted] repository'), None),
-           'user_created_repo': (_('[created] repository'), None),
-           'user_created_fork': (_('[created] repository as fork'), None),
-           'user_forked_repo': (_('[forked] repository'), get_fork_name),
-           'user_updated_repo': (_('[updated] repository'), None),
-           'admin_deleted_repo': (_('[delete] repository'), None),
-           'admin_created_repo': (_('[created] repository'), None),
-           'admin_forked_repo': (_('[forked] repository'), None),
-           'admin_updated_repo': (_('[updated] repository'), None),
-           'push': (_('[pushed] into'), get_cs_links),
-           'push_local': (_('[committed via RhodeCode] into'), get_cs_links),
-           'push_remote': (_('[pulled from remote] into'), get_cs_links),
-           'pull': (_('[pulled] from'), None),
-           'started_following_repo': (_('[started following] repository'), None),
-           'stopped_following_repo': (_('[stopped following] repository'), None),
-            }
+    def get_user_name():
+        user_name = action_params
+        return user_name
+
+    def get_users_group():
+        group_name = action_params
+        return group_name
+
+    def get_pull_request():
+        pull_request_id = action_params
+        repo_name = user_log.repository.repo_name
+        return link_to(_('Pull request #%s') % pull_request_id,
+                    url('pullrequest_show', repo_name=repo_name,
+                    pull_request_id=pull_request_id))
+
+    # action : translated str, callback(extractor), icon
+    action_map = {
+    'user_deleted_repo':           (_('[deleted] repository'),
+                                    None, 'database_delete.png'),
+    'user_created_repo':           (_('[created] repository'),
+                                    None, 'database_add.png'),
+    'user_created_fork':           (_('[created] repository as fork'),
+                                    None, 'arrow_divide.png'),
+    'user_forked_repo':            (_('[forked] repository'),
+                                    get_fork_name, 'arrow_divide.png'),
+    'user_updated_repo':           (_('[updated] repository'),
+                                    None, 'database_edit.png'),
+    'admin_deleted_repo':          (_('[delete] repository'),
+                                    None, 'database_delete.png'),
+    'admin_created_repo':          (_('[created] repository'),
+                                    None, 'database_add.png'),
+    'admin_forked_repo':           (_('[forked] repository'),
+                                    None, 'arrow_divide.png'),
+    'admin_updated_repo':          (_('[updated] repository'),
+                                    None, 'database_edit.png'),
+    'admin_created_user':          (_('[created] user'),
+                                    get_user_name, 'user_add.png'),
+    'admin_updated_user':          (_('[updated] user'),
+                                    get_user_name, 'user_edit.png'),
+    'admin_created_users_group':   (_('[created] users group'),
+                                    get_users_group, 'group_add.png'),
+    'admin_updated_users_group':   (_('[updated] users group'),
+                                    get_users_group, 'group_edit.png'),
+    'user_commented_revision':     (_('[commented] on revision in repository'),
+                                    get_cs_links, 'comment_add.png'),
+    'user_commented_pull_request': (_('[commented] on pull request for'),
+                                    get_pull_request, 'comment_add.png'),
+    'user_closed_pull_request':    (_('[closed] pull request for'),
+                                    get_pull_request, 'tick.png'),
+    'push':                        (_('[pushed] into'),
+                                    get_cs_links, 'script_add.png'),
+    'push_local':                  (_('[committed via RhodeCode] into repository'),
+                                    get_cs_links, 'script_edit.png'),
+    'push_remote':                 (_('[pulled from remote] into repository'),
+                                    get_cs_links, 'connect.png'),
+    'pull':                        (_('[pulled] from'),
+                                    None, 'down_16.png'),
+    'started_following_repo':      (_('[started following] repository'),
+                                    None, 'heart_add.png'),
+    'stopped_following_repo':      (_('[stopped following] repository'),
+                                    None, 'heart_delete.png'),
+    }
 
     action_str = action_map.get(action, action)
     if feed:
@@ -556,36 +682,21 @@
     if callable(action_str[1]):
         action_params_func = action_str[1]
 
-    return [literal(action), action_params_func]
-
+    def action_parser_icon():
+        action = user_log.action
+        action_params = None
+        x = action.split(':')
 
-def action_parser_icon(user_log):
-    action = user_log.action
-    action_params = None
-    x = action.split(':')
-
-    if len(x) > 1:
-        action, action_params = x
+        if len(x) > 1:
+            action, action_params = x
 
-    tmpl = """<img src="%s%s" alt="%s"/>"""
-    map = {'user_deleted_repo':'database_delete.png',
-           'user_created_repo':'database_add.png',
-           'user_created_fork':'arrow_divide.png',
-           'user_forked_repo':'arrow_divide.png',
-           'user_updated_repo':'database_edit.png',
-           'admin_deleted_repo':'database_delete.png',
-           'admin_created_repo':'database_add.png',
-           'admin_forked_repo':'arrow_divide.png',
-           'admin_updated_repo':'database_edit.png',
-           'push':'script_add.png',
-           'push_local':'script_edit.png',
-           'push_remote':'connect.png',
-           'pull':'down_16.png',
-           'started_following_repo':'heart_add.png',
-           'stopped_following_repo':'heart_delete.png',
-            }
-    return literal(tmpl % ((url('/images/icons/')),
-                           map.get(action, action), action))
+        tmpl = """<img src="%s%s" alt="%s"/>"""
+        ico = action_map.get(action, ['', '', ''])[2]
+        return literal(tmpl % ((url('/images/icons/')), ico, action))
+
+    # returned callbacks we need to call to get
+    return [lambda: literal(action), action_params_func, action_parser_icon]
+
 
 
 #==============================================================================
@@ -600,6 +711,14 @@
 #==============================================================================
 
 def gravatar_url(email_address, size=30):
+    if(str2bool(config['app_conf'].get('use_gravatar')) and
+       config['app_conf'].get('alternative_gravatar_url')):
+        tmpl = config['app_conf'].get('alternative_gravatar_url', '')
+        tmpl = tmpl.replace('{email}', email_address)\
+                   .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest())\
+                   .replace('{size}', str(size))
+        return tmpl
+
     if (not str2bool(config['app_conf'].get('use_gravatar')) or
         not email_address or email_address == 'anonymous@rhodecode.org'):
         f = lambda a, l: min(l, key=lambda x: abs(x - a))
@@ -875,7 +994,6 @@
 
         return ''.join(links)
 
-
     # urlify changesets - extrac revisions and make link out of them
     text_ = urlify_changesets(escaper(text_), repository)
 
@@ -902,7 +1020,8 @@
                 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
                 if repository:
                     url = url.replace('{repo}', repository)
-
+                    repo_name = repository.split(URL_SEP)[-1]
+                    url = url.replace('{repo_name}', repo_name)
                 return tmpl % {
                      'pref': pref,
                      'cls': 'issue-tracker-link',
@@ -939,3 +1058,15 @@
     """
     return literal('<div class="rst-block">%s</div>' %
                    MarkupRenderer.rst_with_mentions(source))
+
+
+def changeset_status(repo, revision):
+    return ChangesetStatusModel().get_status(repo, revision)
+
+
+def changeset_status_lbl(changeset_status):
+    return dict(ChangesetStatus.STATUSES).get(changeset_status)
+
+
+def get_permission_name(key):
+    return dict(Permission.PERMS).get(key)
--- a/rhodecode/lib/hooks.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/hooks.py	Sun Sep 02 21:19:54 2012 +0200
@@ -24,13 +24,19 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import os
 import sys
+import binascii
+from inspect import isfunction
 
 from mercurial.scmutil import revrange
 from mercurial.node import nullrev
-from rhodecode import EXTENSIONS
+
 from rhodecode.lib import helpers as h
 from rhodecode.lib.utils import action_logger
-from inspect import isfunction
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
+from rhodecode.lib.compat import json
+from rhodecode.model.db import Repository, User
+from rhodecode.lib.utils2 import safe_str
+from rhodecode.lib.exceptions import HTTPLockedRC
 
 
 def _get_scm_size(alias, root_path):
@@ -81,6 +87,60 @@
     sys.stdout.write(msg)
 
 
+def pre_push(ui, repo, **kwargs):
+    # pre push function, currently used to ban pushing when
+    # repository is locked
+    try:
+        rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
+    except:
+        rc_extras = {}
+    extras = dict(repo.ui.configitems('rhodecode_extras'))
+
+    if 'username' in extras:
+        username = extras['username']
+        repository = extras['repository']
+        scm = extras['scm']
+        locked_by = extras['locked_by']
+    elif 'username' in rc_extras:
+        username = rc_extras['username']
+        repository = rc_extras['repository']
+        scm = rc_extras['scm']
+        locked_by = rc_extras['locked_by']
+    else:
+        raise Exception('Missing data in repo.ui and os.environ')
+
+    usr = User.get_by_username(username)
+    if locked_by[0] and usr.user_id != int(locked_by[0]):
+        locked_by = User.get(locked_by[0]).username
+        raise HTTPLockedRC(repository, locked_by)
+
+
+def pre_pull(ui, repo, **kwargs):
+    # pre push function, currently used to ban pushing when
+    # repository is locked
+    try:
+        rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
+    except:
+        rc_extras = {}
+    extras = dict(repo.ui.configitems('rhodecode_extras'))
+    if 'username' in extras:
+        username = extras['username']
+        repository = extras['repository']
+        scm = extras['scm']
+        locked_by = extras['locked_by']
+    elif 'username' in rc_extras:
+        username = rc_extras['username']
+        repository = rc_extras['repository']
+        scm = rc_extras['scm']
+        locked_by = rc_extras['locked_by']
+    else:
+        raise Exception('Missing data in repo.ui and os.environ')
+
+    if locked_by[0]:
+        locked_by = User.get(locked_by[0]).username
+        raise HTTPLockedRC(repository, locked_by)
+
+
 def log_pull_action(ui, repo, **kwargs):
     """
     Logs user last pull action
@@ -88,21 +148,40 @@
     :param ui:
     :param repo:
     """
-
+    try:
+        rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
+    except:
+        rc_extras = {}
     extras = dict(repo.ui.configitems('rhodecode_extras'))
-    username = extras['username']
-    repository = extras['repository']
-    scm = extras['scm']
+    if 'username' in extras:
+        username = extras['username']
+        repository = extras['repository']
+        scm = extras['scm']
+        make_lock = extras['make_lock']
+    elif 'username' in rc_extras:
+        username = rc_extras['username']
+        repository = rc_extras['repository']
+        scm = rc_extras['scm']
+        make_lock = rc_extras['make_lock']
+    else:
+        raise Exception('Missing data in repo.ui and os.environ')
+    user = User.get_by_username(username)
     action = 'pull'
-
-    action_logger(username, action, repository, extras['ip'], commit=True)
+    action_logger(user, action, repository, extras['ip'], commit=True)
     # extension hook call
+    from rhodecode import EXTENSIONS
     callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
 
     if isfunction(callback):
         kw = {}
         kw.update(extras)
         callback(**kw)
+
+    if make_lock is True:
+        Repository.lock(Repository.get_by_repo_name(repository), user.user_id)
+        #msg = 'Made lock on repo `%s`' % repository
+        #sys.stdout.write(msg)
+
     return 0
 
 
@@ -114,11 +193,26 @@
     :param repo: repo object containing the `ui` object
     """
 
+    try:
+        rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
+    except:
+        rc_extras = {}
+
     extras = dict(repo.ui.configitems('rhodecode_extras'))
-    username = extras['username']
-    repository = extras['repository']
-    action = extras['action'] + ':%s'
-    scm = extras['scm']
+    if 'username' in extras:
+        username = extras['username']
+        repository = extras['repository']
+        scm = extras['scm']
+        make_lock = extras['make_lock']
+    elif 'username' in rc_extras:
+        username = rc_extras['username']
+        repository = rc_extras['repository']
+        scm = rc_extras['scm']
+        make_lock = rc_extras['make_lock']
+    else:
+        raise Exception('Missing data in repo.ui and os.environ')
+
+    action = 'push' + ':%s'
 
     if scm == 'hg':
         node = kwargs['node']
@@ -134,21 +228,30 @@
                 return (len(repo) - 1, 0)
 
         stop, start = get_revs(repo, [node + ':'])
-
-        revs = (str(repo[r]) for r in xrange(start, stop + 1))
+        h = binascii.hexlify
+        revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
     elif scm == 'git':
-        revs = []
+        revs = kwargs.get('_git_revs', [])
+        if '_git_revs' in kwargs:
+            kwargs.pop('_git_revs')
 
     action = action % ','.join(revs)
 
     action_logger(username, action, repository, extras['ip'], commit=True)
 
     # extension hook call
+    from rhodecode import EXTENSIONS
     callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
     if isfunction(callback):
         kw = {'pushed_revs': revs}
         kw.update(extras)
         callback(**kw)
+
+    if make_lock is False:
+        Repository.unlock(Repository.get_by_repo_name(repository))
+        msg = 'Released lock on repo `%s`\n' % repository
+        sys.stdout.write(msg)
+
     return 0
 
 
@@ -178,7 +281,7 @@
      'repo_name'
 
     """
-
+    from rhodecode import EXTENSIONS
     callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
     if isfunction(callback):
         kw = {}
@@ -188,3 +291,88 @@
         return callback(**kw)
 
     return 0
+
+handle_git_pre_receive = (lambda repo_path, revs, env:
+    handle_git_receive(repo_path, revs, env, hook_type='pre'))
+handle_git_post_receive = (lambda repo_path, revs, env:
+    handle_git_receive(repo_path, revs, env, hook_type='post'))
+
+
+def handle_git_receive(repo_path, revs, env, hook_type='post'):
+    """
+    A really hacky method that is runned by git post-receive hook and logs
+    an push action together with pushed revisions. It's executed by subprocess
+    thus needs all info to be able to create a on the fly pylons enviroment,
+    connect to database and run the logging code. Hacky as sh*t but works.
+
+    :param repo_path:
+    :type repo_path:
+    :param revs:
+    :type revs:
+    :param env:
+    :type env:
+    """
+    from paste.deploy import appconfig
+    from sqlalchemy import engine_from_config
+    from rhodecode.config.environment import load_environment
+    from rhodecode.model import init_model
+    from rhodecode.model.db import RhodeCodeUi
+    from rhodecode.lib.utils import make_ui
+
+    path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
+    conf = appconfig('config:%s' % ini_name, relative_to=path)
+    load_environment(conf.global_conf, conf.local_conf)
+
+    engine = engine_from_config(conf, 'sqlalchemy.db1.')
+    init_model(engine)
+
+    baseui = make_ui('db')
+    # fix if it's not a bare repo
+    if repo_path.endswith('.git'):
+        repo_path = repo_path[:-4]
+    repo = Repository.get_by_full_path(repo_path)
+    _hooks = dict(baseui.configitems('hooks')) or {}
+
+    extras = json.loads(env['RHODECODE_EXTRAS'])
+    for k, v in extras.items():
+        baseui.setconfig('rhodecode_extras', k, v)
+    repo = repo.scm_instance
+    repo.ui = baseui
+
+    if hook_type == 'pre':
+        pre_push(baseui, repo)
+
+    # if push hook is enabled via web interface
+    elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH):
+
+        rev_data = []
+        for l in revs:
+            old_rev, new_rev, ref = l.split(' ')
+            _ref_data = ref.split('/')
+            if _ref_data[1] in ['tags', 'heads']:
+                rev_data.append({'old_rev': old_rev,
+                                 'new_rev': new_rev,
+                                 'ref': ref,
+                                 'type': _ref_data[1],
+                                 'name': _ref_data[2].strip()})
+
+        git_revs = []
+        for push_ref  in rev_data:
+            _type = push_ref['type']
+            if _type == 'heads':
+                if push_ref['old_rev'] == EmptyChangeset().raw_id:
+                    cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
+                    heads = repo.run_git_command(cmd)[0]
+                    heads = heads.replace(push_ref['ref'], '')
+                    heads = ' '.join(map(lambda c: c.strip('\n').strip(),
+                                         heads.splitlines()))
+                    cmd = (('log %(new_rev)s' % push_ref) +
+                           ' --reverse --pretty=format:"%H" --not ' + heads)
+                else:
+                    cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
+                           ' --reverse --pretty=format:"%H"')
+                git_revs += repo.run_git_command(cmd)[0].splitlines()
+            elif _type == 'tags':
+                git_revs += [push_ref['name']]
+
+        log_push_action(baseui, repo, _git_revs=git_revs)
--- a/rhodecode/lib/indexers/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/indexers/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -35,12 +35,12 @@
 from shutil import rmtree
 
 from whoosh.analysis import RegexTokenizer, LowercaseFilter, StopFilter
-from whoosh.fields import TEXT, ID, STORED, Schema, FieldType
+from whoosh.fields import TEXT, ID, STORED, NUMERIC, BOOLEAN, Schema, FieldType
 from whoosh.index import create_in, open_dir
 from whoosh.formats import Characters
 from whoosh.highlight import highlight, HtmlFormatter, ContextFragmenter
 
-from webhelpers.html.builder import escape
+from webhelpers.html.builder import escape, literal
 from sqlalchemy import engine_from_config
 
 from rhodecode.model import init_model
@@ -51,12 +51,14 @@
 from rhodecode.lib.utils import BasePasterCommand, Command, add_cache,\
     load_rcextensions
 
+log = logging.getLogger(__name__)
+
 # CUSTOM ANALYZER wordsplit + lowercase filter
 ANALYZER = RegexTokenizer(expression=r"\w+") | LowercaseFilter()
 
-
 #INDEX SCHEMA DEFINITION
 SCHEMA = Schema(
+    fileid=ID(unique=True),
     owner=TEXT(),
     repository=TEXT(stored=True),
     path=TEXT(stored=True),
@@ -70,6 +72,23 @@
 FORMATTER = HtmlFormatter('span', between='\n<span class="break">...</span>\n')
 FRAGMENTER = ContextFragmenter(200)
 
+CHGSETS_SCHEMA = Schema(
+    raw_id=ID(unique=True, stored=True),
+    date=NUMERIC(stored=True),
+    last=BOOLEAN(),
+    owner=TEXT(),
+    repository=ID(unique=True, stored=True),
+    author=TEXT(stored=True),
+    message=FieldType(format=Characters(), analyzer=ANALYZER,
+                      scorable=True, stored=True),
+    parents=TEXT(),
+    added=TEXT(),
+    removed=TEXT(),
+    changed=TEXT(),
+)
+
+CHGSET_IDX_NAME = 'CHGSET_INDEX'
+
 
 class MakeIndex(BasePasterCommand):
 
@@ -93,6 +112,8 @@
             if self.options.repo_location else RepoModel().repos_path
         repo_list = map(strip, self.options.repo_list.split(',')) \
             if self.options.repo_list else None
+        repo_update_list = map(strip, self.options.repo_update_list.split(',')) \
+            if self.options.repo_update_list else None
         load_rcextensions(config['here'])
         #======================================================================
         # WHOOSH DAEMON
@@ -103,7 +124,8 @@
             l = DaemonLock(file_=jn(dn(dn(index_location)), 'make_index.lock'))
             WhooshIndexingDaemon(index_location=index_location,
                                  repo_location=repo_location,
-                                 repo_list=repo_list,)\
+                                 repo_list=repo_list,
+                                 repo_update_list=repo_update_list)\
                 .run(full_index=self.options.full_index)
             l.release()
         except LockHeld:
@@ -119,7 +141,14 @@
                           action='store',
                           dest='repo_list',
                           help="Specifies a comma separated list of repositores "
-                                "to build index on OPTIONAL",
+                                "to build index on. If not given all repositories "
+                                "are scanned for indexing. OPTIONAL",
+                          )
+        self.parser.add_option('--update-only',
+                          action='store',
+                          dest='repo_update_list',
+                          help="Specifies a comma separated list of repositores "
+                                "to re-build index on. OPTIONAL",
                           )
         self.parser.add_option('-f',
                           action='store_true',
@@ -129,13 +158,15 @@
                           default=False)
 
 
-class ResultWrapper(object):
-    def __init__(self, search_type, searcher, matcher, highlight_items):
+class WhooshResultWrapper(object):
+    def __init__(self, search_type, searcher, matcher, highlight_items,
+                 repo_location):
         self.search_type = search_type
         self.searcher = searcher
         self.matcher = matcher
         self.highlight_items = highlight_items
         self.fragment_size = 200
+        self.repo_location = repo_location
 
     @LazyProperty
     def doc_ids(self):
@@ -178,13 +209,25 @@
 
     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('/')
+        log.debug('result: %s' % res)
+        if self.search_type == 'content':
+            full_repo_path = jn(self.repo_location, res['repository'])
+            f_path = res['path'].split(full_repo_path)[-1]
+            f_path = f_path.lstrip(os.sep)
+            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
+                      })
+        elif self.search_type == 'path':
+            full_repo_path = jn(self.repo_location, res['repository'])
+            f_path = res['path'].split(full_repo_path)[-1]
+            f_path = f_path.lstrip(os.sep)
+            res.update({'f_path': f_path})
+        elif self.search_type == 'message':
+            res.update({'message_hl': self.highlight(res['message'])})
 
-        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})
+        log.debug('result: %s' % res)
 
         return res
 
@@ -202,22 +245,23 @@
         :param size:
         """
         memory = [(0, 0)]
-        for span in self.matcher.spans():
-            start = span.startchar or 0
-            end = span.endchar or 0
-            start_offseted = max(0, start - self.fragment_size)
-            end_offseted = end + self.fragment_size
+        if self.matcher.supports('positions'):
+            for span in self.matcher.spans():
+                start = span.startchar or 0
+                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,)
+                if start_offseted < memory[-1][1]:
+                    start_offseted = memory[-1][1]
+                memory.append((start_offseted, end_offseted,))
+                yield (start_offseted, end_offseted,)
 
     def highlight(self, content, top=5):
-        if self.search_type != 'content':
+        if self.search_type not in ['content', 'message']:
             return ''
         hl = highlight(
-            text=escape(content),
+            text=content,
             terms=self.highlight_items,
             analyzer=ANALYZER,
             fragmenter=FRAGMENTER,
--- a/rhodecode/lib/indexers/daemon.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/indexers/daemon.py	Sun Sep 02 21:19:54 2012 +0200
@@ -22,6 +22,7 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from __future__ import with_statement
 
 import os
 import sys
@@ -41,23 +42,27 @@
 from rhodecode.config.conf import INDEX_EXTENSIONS
 from rhodecode.model.scm import ScmModel
 from rhodecode.lib.utils2 import safe_unicode
-from rhodecode.lib.indexers import SCHEMA, IDX_NAME
+from rhodecode.lib.indexers import SCHEMA, IDX_NAME, CHGSETS_SCHEMA, \
+    CHGSET_IDX_NAME
 
 from rhodecode.lib.vcs.exceptions import ChangesetError, RepositoryError, \
     NodeDoesNotExistError
 
-from whoosh.index import create_in, open_dir
+from whoosh.index import create_in, open_dir, exists_in
+from whoosh.query import *
+from whoosh.qparser import QueryParser
 
 log = logging.getLogger('whoosh_indexer')
 
 
 class WhooshIndexingDaemon(object):
     """
-    Daemon for atomic jobs
+    Daemon for atomic indexing jobs
     """
 
     def __init__(self, indexname=IDX_NAME, index_location=None,
-                 repo_location=None, sa=None, repo_list=None):
+                 repo_location=None, sa=None, repo_list=None,
+                 repo_update_list=None):
         self.indexname = indexname
 
         self.index_location = index_location
@@ -70,20 +75,37 @@
 
         self.repo_paths = ScmModel(sa).repo_scan(self.repo_location)
 
+        #filter repo list
         if repo_list:
-            filtered_repo_paths = {}
+            self.filtered_repo_paths = {}
             for repo_name, repo in self.repo_paths.items():
                 if repo_name in repo_list:
-                    filtered_repo_paths[repo_name] = repo
+                    self.filtered_repo_paths[repo_name] = repo
+
+            self.repo_paths = self.filtered_repo_paths
 
-            self.repo_paths = filtered_repo_paths
+        #filter update repo list
+        self.filtered_repo_update_paths = {}
+        if repo_update_list:
+            self.filtered_repo_update_paths = {}
+            for repo_name, repo in self.repo_paths.items():
+                if repo_name in repo_update_list:
+                    self.filtered_repo_update_paths[repo_name] = repo
+            self.repo_paths = self.filtered_repo_update_paths
 
-        self.initial = False
+        self.initial = True
         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
+        elif not exists_in(self.index_location, IDX_NAME):
+            log.info('Running full index build as the file content'
+                     ' index does not exist')
+        elif not exists_in(self.index_location, CHGSET_IDX_NAME):
+            log.info('Running full index build as the changeset'
+                     ' index does not exist')
+        else:
+            self.initial = False
 
     def get_paths(self, repo):
         """
@@ -93,11 +115,11 @@
         index_paths_ = set()
         try:
             tip = repo.get_changeset('tip')
-            for topnode, dirs, files in tip.walk('/'):
+            for _topnode, _dirs, files in tip.walk('/'):
                 for f in files:
                     index_paths_.add(jn(repo.path, f.path))
 
-        except RepositoryError, e:
+        except RepositoryError:
             log.debug(traceback.format_exc())
             pass
         return index_paths_
@@ -135,45 +157,136 @@
             u_content = u''
             indexed += 1
 
+        p = safe_unicode(path)
         writer.add_document(
+            fileid=p,
             owner=unicode(repo.contact),
             repository=safe_unicode(repo_name),
-            path=safe_unicode(path),
+            path=p,
             content=u_content,
             modtime=self.get_node_mtime(node),
             extension=node.extension
         )
         return indexed, indexed_w_content
 
-    def build_index(self):
-        if os.path.exists(self.index_location):
-            log.debug('removing previous index')
-            rmtree(self.index_location)
+    def index_changesets(self, writer, repo_name, repo, start_rev=None):
+        """
+        Add all changeset in the vcs repo starting at start_rev
+        to the index writer
+
+        :param writer: the whoosh index writer to add to
+        :param repo_name: name of the repository from whence the
+          changeset originates including the repository group
+        :param repo: the vcs repository instance to index changesets for,
+          the presumption is the repo has changesets to index
+        :param start_rev=None: the full sha id to start indexing from
+          if start_rev is None then index from the first changeset in
+          the repo
+        """
+
+        if start_rev is None:
+            start_rev = repo[0].raw_id
+
+        log.debug('indexing changesets in %s starting at rev: %s' %
+                  (repo_name, start_rev))
 
-        if not os.path.exists(self.index_location):
-            os.mkdir(self.index_location)
+        indexed = 0
+        for cs in repo.get_changesets(start=start_rev):
+            log.debug('    >> %s' % cs)
+            writer.add_document(
+                raw_id=unicode(cs.raw_id),
+                owner=unicode(repo.contact),
+                date=cs._timestamp,
+                repository=safe_unicode(repo_name),
+                author=cs.author,
+                message=cs.message,
+                last=cs.last,
+                added=u' '.join([safe_unicode(node.path) for node in cs.added]).lower(),
+                removed=u' '.join([safe_unicode(node.path) for node in cs.removed]).lower(),
+                changed=u' '.join([safe_unicode(node.path) for node in cs.changed]).lower(),
+                parents=u' '.join([cs.raw_id for cs in cs.parents]),
+            )
+            indexed += 1
+
+        log.debug('indexed %d changesets for repo %s' % (indexed, repo_name))
+        return indexed
+
+    def index_files(self, file_idx_writer, repo_name, repo):
+        """
+        Index files for given repo_name
+
+        :param file_idx_writer: the whoosh index writer to add to
+        :param repo_name: name of the repository we're indexing
+        :param repo: instance of vcs repo
+        """
+        i_cnt = iwc_cnt = 0
+        log.debug('building index for [%s]' % repo.path)
+        for idx_path in self.get_paths(repo):
+            i, iwc = self.add_doc(file_idx_writer, idx_path, repo, repo_name)
+            i_cnt += i
+            iwc_cnt += iwc
 
-        idx = create_in(self.index_location, SCHEMA, indexname=IDX_NAME)
-        writer = idx.writer()
-        log.debug('BUILDIN INDEX FOR EXTENSIONS %s' % INDEX_EXTENSIONS)
-        for repo_name, repo in self.repo_paths.items():
-            log.debug('building index @ %s' % repo.path)
-            i_cnt = iwc_cnt = 0
-            for idx_path in self.get_paths(repo):
-                i, iwc = self.add_doc(writer, idx_path, repo, repo_name)
-                i_cnt += i
-                iwc_cnt += iwc
-            log.debug('added %s files %s with content for repo %s' % (
-                         i_cnt + iwc_cnt, iwc_cnt, repo.path)
-            )
+        log.debug('added %s files %s with content for repo %s' %
+                  (i_cnt + iwc_cnt, iwc_cnt, repo.path))
+        return i_cnt, iwc_cnt
+
+    def update_changeset_index(self):
+        idx = open_dir(self.index_location, indexname=CHGSET_IDX_NAME)
+
+        with idx.searcher() as searcher:
+            writer = idx.writer()
+            writer_is_dirty = False
+            try:
+                indexed_total = 0
+                for repo_name, repo in self.repo_paths.items():
+                    # skip indexing if there aren't any revs in the repo
+                    num_of_revs = len(repo)
+                    if num_of_revs < 1:
+                        continue
+
+                    qp = QueryParser('repository', schema=CHGSETS_SCHEMA)
+                    q = qp.parse(u"last:t AND %s" % repo_name)
+
+                    results = searcher.search(q)
+
+                    # default to scanning the entire repo
+                    last_rev = 0
+                    start_id = None
 
-        log.debug('>> COMMITING CHANGES <<')
-        writer.commit(merge=True)
-        log.debug('>>> FINISHED BUILDING INDEX <<<')
+                    if len(results) > 0:
+                        # assuming that there is only one result, if not this
+                        # may require a full re-index.
+                        start_id = results[0]['raw_id']
+                        last_rev = repo.get_changeset(revision=start_id).revision
+
+                    # there are new changesets to index or a new repo to index
+                    if last_rev == 0 or num_of_revs > last_rev + 1:
+                        # delete the docs in the index for the previous
+                        # last changeset(s)
+                        for hit in results:
+                            q = qp.parse(u"last:t AND %s AND raw_id:%s" %
+                                            (repo_name, hit['raw_id']))
+                            writer.delete_by_query(q)
 
-    def update_index(self):
-        log.debug('STARTING INCREMENTAL INDEXING UPDATE FOR EXTENSIONS %s' %
-                  INDEX_EXTENSIONS)
+                        # index from the previous last changeset + all new ones
+                        indexed_total += self.index_changesets(writer,
+                                                repo_name, repo, start_id)
+                        writer_is_dirty = True
+                log.debug('indexed %s changesets for repo %s' % (
+                             indexed_total, repo_name)
+                )
+            finally:
+                if writer_is_dirty:
+                    log.debug('>> COMMITING CHANGES TO CHANGESET INDEX<<')
+                    writer.commit(merge=True)
+                    log.debug('>> COMMITTED CHANGES TO CHANGESET INDEX<<')
+                else:
+                    writer.cancel
+                    log.debug('>> NOTHING TO COMMIT<<')
+
+    def update_file_index(self):
+        log.debug((u'STARTING INCREMENTAL INDEXING UPDATE FOR EXTENSIONS %s '
+                   'AND REPOS %s') % (INDEX_EXTENSIONS, self.repo_paths.keys()))
 
         idx = open_dir(self.index_location, indexname=self.indexname)
         # The set of all paths in the index
@@ -181,57 +294,120 @@
         # The set of all paths we need to re-index
         to_index = set()
 
-        reader = idx.reader()
         writer = idx.writer()
+        writer_is_dirty = False
+        try:
+            with idx.reader() as reader:
+
+                # Loop over the stored fields in the index
+                for fields in reader.all_stored_fields():
+                    indexed_path = fields['path']
+                    indexed_repo_path = fields['repository']
+                    indexed_paths.add(indexed_path)
+
+                    if not indexed_repo_path in self.filtered_repo_update_paths:
+                        continue
 
-        # 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[indexed_repo_path]
+
+                    try:
+                        node = self.get_node(repo, indexed_path)
+                        # Check if this file was changed since it was indexed
+                        indexed_time = fields['modtime']
+                        mtime = self.get_node_mtime(node)
+                        if mtime > indexed_time:
+                            # The file has changed, delete it and add it to
+                            # the list of files to reindex
+                            log.debug(
+                                'adding to reindex list %s mtime: %s vs %s' % (
+                                    indexed_path, mtime, indexed_time)
+                            )
+                            writer.delete_by_term('fileid', indexed_path)
+                            writer_is_dirty = True
 
-            repo = self.repo_paths[fields['repository']]
+                            to_index.add(indexed_path)
+                    except (ChangesetError, NodeDoesNotExistError):
+                        # This file was deleted since it was indexed
+                        log.debug('removing from index %s' % indexed_path)
+                        writer.delete_by_term('path', indexed_path)
+                        writer_is_dirty = True
 
-            try:
-                node = self.get_node(repo, indexed_path)
-            except (ChangesetError, NodeDoesNotExistError):
-                # This file was deleted since it was indexed
-                log.debug('removing from index %s' % indexed_path)
-                writer.delete_by_term('path', indexed_path)
+            # Loop over the files in the filesystem
+            # Assume we have a function that gathers the filenames of the
+            # documents to be indexed
+            ri_cnt_total = 0  # indexed
+            riwc_cnt_total = 0  # indexed with content
+            for repo_name, repo in self.repo_paths.items():
+                # skip indexing if there aren't any revisions
+                if len(repo) < 1:
+                    continue
+                ri_cnt = 0   # indexed
+                riwc_cnt = 0  # indexed with content
+                for path in self.get_paths(repo):
+                    path = safe_unicode(path)
+                    if path in to_index or path not in indexed_paths:
 
+                        # This is either a file that's changed, or a new file
+                        # that wasn't indexed before. So index it!
+                        i, iwc = self.add_doc(writer, path, repo, repo_name)
+                        writer_is_dirty = True
+                        log.debug('re indexing %s' % path)
+                        ri_cnt += i
+                        ri_cnt_total += 1
+                        riwc_cnt += iwc
+                        riwc_cnt_total += iwc
+                log.debug('added %s files %s with content for repo %s' % (
+                             ri_cnt + riwc_cnt, riwc_cnt, repo.path)
+                )
+            log.debug('indexed %s files in total and %s with content' % (
+                        ri_cnt_total, riwc_cnt_total)
+            )
+        finally:
+            if writer_is_dirty:
+                log.debug('>> COMMITING CHANGES <<')
+                writer.commit(merge=True)
+                log.debug('>>> FINISHED REBUILDING INDEX <<<')
             else:
-                # Check if this file was changed since it was indexed
-                indexed_time = fields['modtime']
-                mtime = self.get_node_mtime(node)
-                if mtime > indexed_time:
-                    # The file has changed, delete it and add it to the list of
-                    # files to reindex
-                    log.debug('adding to reindex list %s' % indexed_path)
-                    writer.delete_by_term('path', indexed_path)
-                    to_index.add(indexed_path)
+                log.debug('>> NOTHING TO COMMIT<<')
+                writer.cancel()
+
+    def build_indexes(self):
+        if os.path.exists(self.index_location):
+            log.debug('removing previous index')
+            rmtree(self.index_location)
 
-        # Loop over the files in the filesystem
-        # Assume we have a function that gathers the filenames of the
-        # documents to be indexed
-        ri_cnt = riwc_cnt = 0
+        if not os.path.exists(self.index_location):
+            os.mkdir(self.index_location)
+
+        chgset_idx = create_in(self.index_location, CHGSETS_SCHEMA,
+                               indexname=CHGSET_IDX_NAME)
+        chgset_idx_writer = chgset_idx.writer()
+
+        file_idx = create_in(self.index_location, SCHEMA, indexname=IDX_NAME)
+        file_idx_writer = file_idx.writer()
+        log.debug('BUILDING INDEX FOR EXTENSIONS %s '
+                  'AND REPOS %s' % (INDEX_EXTENSIONS, self.repo_paths.keys()))
+
         for repo_name, repo in self.repo_paths.items():
-            for path in self.get_paths(repo):
-                if path in to_index or path not in indexed_paths:
-                    # This is either a file that's changed, or a new file
-                    # that wasn't indexed before. So index it!
-                    i, iwc = self.add_doc(writer, path, repo, repo_name)
-                    log.debug('re indexing %s' % path)
-                    ri_cnt += i
-                    riwc_cnt += iwc
-        log.debug('added %s files %s with content for repo %s' % (
-                     ri_cnt + riwc_cnt, riwc_cnt, repo.path)
-        )
+            # skip indexing if there aren't any revisions
+            if len(repo) < 1:
+                continue
+
+            self.index_files(file_idx_writer, repo_name, repo)
+            self.index_changesets(chgset_idx_writer, repo_name, repo)
+
         log.debug('>> COMMITING CHANGES <<')
-        writer.commit(merge=True)
-        log.debug('>>> FINISHED REBUILDING INDEX <<<')
+        file_idx_writer.commit(merge=True)
+        chgset_idx_writer.commit(merge=True)
+        log.debug('>>> FINISHED BUILDING INDEX <<<')
+
+    def update_indexes(self):
+        self.update_file_index()
+        self.update_changeset_index()
 
     def run(self, full_index=False):
         """Run daemon"""
         if full_index or self.initial:
-            self.build_index()
+            self.build_indexes()
         else:
-            self.update_index()
+            self.update_indexes()
--- a/rhodecode/lib/markup_renderer.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/markup_renderer.py	Sun Sep 02 21:19:54 2012 +0200
@@ -26,6 +26,7 @@
 
 import re
 import logging
+import traceback
 
 from rhodecode.lib.utils2 import safe_unicode, MENTIONS_REGEX
 
@@ -93,7 +94,7 @@
         return '<br />' + source.replace("\n", '<br />')
 
     @classmethod
-    def markdown(cls, source):
+    def markdown(cls, source, safe=True):
         source = safe_unicode(source)
         try:
             import markdown as __markdown
@@ -101,9 +102,15 @@
         except ImportError:
             log.warning('Install markdown to use this function')
             return cls.plain(source)
+        except Exception:
+            log.error(traceback.format_exc())
+            if safe:
+                return source
+            else:
+                raise
 
     @classmethod
-    def rst(cls, source):
+    def rst(cls, source, safe=True):
         source = safe_unicode(source)
         try:
             from docutils.core import publish_parts
@@ -125,6 +132,12 @@
         except ImportError:
             log.warning('Install docutils to use this function')
             return cls.plain(source)
+        except Exception:
+            log.error(traceback.format_exc())
+            if safe:
+                return source
+            else:
+                raise
 
     @classmethod
     def rst_with_mentions(cls, source):
--- a/rhodecode/lib/middleware/https_fixup.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/middleware/https_fixup.py	Sun Sep 02 21:19:54 2012 +0200
@@ -42,21 +42,20 @@
         middleware you should set this header inside your
         proxy ie. nginx, apache etc.
         """
+        # DETECT PROTOCOL !
+        if 'HTTP_X_URL_SCHEME' in environ:
+            proto = environ.get('HTTP_X_URL_SCHEME')
+        elif 'HTTP_X_FORWARDED_SCHEME' in environ:
+            proto = environ.get('HTTP_X_FORWARDED_SCHEME')
+        elif 'HTTP_X_FORWARDED_PROTO' in environ:
+            proto = environ.get('HTTP_X_FORWARDED_PROTO')
+        else:
+            proto = 'http'
+        org_proto = proto
 
+        # if we have force, just override
         if str2bool(self.config.get('force_https')):
             proto = 'https'
-        else:
-            if 'HTTP_X_URL_SCHEME' in environ:
-                proto = environ.get('HTTP_X_URL_SCHEME')
-            elif 'HTTP_X_FORWARDED_SCHEME' in environ:
-                proto = environ.get('HTTP_X_FORWARDED_SCHEME')
-            elif 'HTTP_X_FORWARDED_PROTO' in environ:
-                proto = environ.get('HTTP_X_FORWARDED_PROTO')
-            else:
-                proto = 'http'
-        if proto == 'https':
-            environ['wsgi.url_scheme'] = proto
-        else:
-            environ['wsgi.url_scheme'] = 'http'
 
-        return None
+        environ['wsgi.url_scheme'] = proto
+        environ['wsgi._org_proto'] = org_proto
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/middleware/pygrack.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,200 @@
+import os
+import socket
+import logging
+import subprocess
+
+from webob import Request, Response, exc
+
+from rhodecode.lib import subprocessio
+
+log = logging.getLogger(__name__)
+
+
+class FileWrapper(object):
+
+    def __init__(self, fd, content_length):
+        self.fd = fd
+        self.content_length = content_length
+        self.remain = content_length
+
+    def read(self, size):
+        if size <= self.remain:
+            try:
+                data = self.fd.read(size)
+            except socket.error:
+                raise IOError(self)
+            self.remain -= size
+        elif self.remain:
+            data = self.fd.read(self.remain)
+            self.remain = 0
+        else:
+            data = None
+        return data
+
+    def __repr__(self):
+        return '<FileWrapper %s len: %s, read: %s>' % (
+            self.fd, self.content_length, self.content_length - self.remain
+        )
+
+
+class GitRepository(object):
+    git_folder_signature = set(['config', 'head', 'info', 'objects', 'refs'])
+    commands = ['git-upload-pack', 'git-receive-pack']
+
+    def __init__(self, repo_name, content_path, extras):
+        files = set([f.lower() for f in os.listdir(content_path)])
+        if  not (self.git_folder_signature.intersection(files)
+                == self.git_folder_signature):
+            raise OSError('%s missing git signature' % content_path)
+        self.content_path = content_path
+        self.valid_accepts = ['application/x-%s-result' %
+                              c for c in self.commands]
+        self.repo_name = repo_name
+        self.extras = extras
+
+    def _get_fixedpath(self, path):
+        """
+        Small fix for repo_path
+
+        :param path:
+        :type path:
+        """
+        return path.split(self.repo_name, 1)[-1].strip('/')
+
+    def inforefs(self, request, environ):
+        """
+        WSGI Response producer for HTTP GET Git Smart
+        HTTP /info/refs request.
+        """
+
+        git_command = request.GET.get('service')
+        if git_command not in self.commands:
+            log.debug('command %s not allowed' % git_command)
+            return exc.HTTPMethodNotAllowed()
+
+        # note to self:
+        # please, resist the urge to add '\n' to git capture and increment
+        # line count by 1.
+        # The code in Git client not only does NOT need '\n', but actually
+        # blows up if you sprinkle "flush" (0000) as "0001\n".
+        # It reads binary, per number of bytes specified.
+        # if you do add '\n' as part of data, count it.
+        server_advert = '# service=%s' % git_command
+        packet_len = str(hex(len(server_advert) + 4)[2:].rjust(4, '0')).lower()
+        try:
+            out = subprocessio.SubprocessIOChunker(
+                r'git %s --stateless-rpc --advertise-refs "%s"' % (
+                                git_command[4:], self.content_path),
+                starting_values=[
+                    packet_len + server_advert + '0000'
+                ]
+            )
+        except EnvironmentError, e:
+            log.exception(e)
+            raise exc.HTTPExpectationFailed()
+        resp = Response()
+        resp.content_type = 'application/x-%s-advertisement' % str(git_command)
+        resp.charset = None
+        resp.app_iter = out
+        return resp
+
+    def backend(self, request, environ):
+        """
+        WSGI Response producer for HTTP POST Git Smart HTTP requests.
+        Reads commands and data from HTTP POST's body.
+        returns an iterator obj with contents of git command's
+        response to stdout
+        """
+        git_command = self._get_fixedpath(request.path_info)
+        if git_command not in self.commands:
+            log.debug('command %s not allowed' % git_command)
+            return exc.HTTPMethodNotAllowed()
+
+        if 'CONTENT_LENGTH' in environ:
+            inputstream = FileWrapper(environ['wsgi.input'],
+                                      request.content_length)
+        else:
+            inputstream = environ['wsgi.input']
+
+        try:
+            gitenv = os.environ
+            from rhodecode import CONFIG
+            from rhodecode.lib.compat import json
+            gitenv['RHODECODE_EXTRAS'] = json.dumps(self.extras)
+            # forget all configs
+            gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
+            # we need current .ini file used to later initialize rhodecode
+            # env and connect to db
+            gitenv['RHODECODE_CONFIG_FILE'] = CONFIG['__file__']
+            opts = dict(
+                env=gitenv,
+                cwd=os.getcwd()
+            )
+            out = subprocessio.SubprocessIOChunker(
+                r'git %s --stateless-rpc "%s"' % (git_command[4:],
+                                                  self.content_path),
+                inputstream=inputstream,
+                **opts
+            )
+        except EnvironmentError, e:
+            log.exception(e)
+            raise exc.HTTPExpectationFailed()
+
+        if git_command in [u'git-receive-pack']:
+            # updating refs manually after each push.
+            # Needed for pre-1.7.0.4 git clients using regular HTTP mode.
+            subprocess.call(u'git --git-dir "%s" '
+                            'update-server-info' % self.content_path,
+                            shell=True)
+
+        resp = Response()
+        resp.content_type = 'application/x-%s-result' % git_command.encode('utf8')
+        resp.charset = None
+        resp.app_iter = out
+        return resp
+
+    def __call__(self, environ, start_response):
+        request = Request(environ)
+        _path = self._get_fixedpath(request.path_info)
+        if _path.startswith('info/refs'):
+            app = self.inforefs
+        elif [a for a in self.valid_accepts if a in request.accept]:
+            app = self.backend
+        try:
+            resp = app(request, environ)
+        except exc.HTTPException, e:
+            resp = e
+            log.exception(e)
+        except Exception, e:
+            log.exception(e)
+            resp = exc.HTTPInternalServerError()
+        return resp(environ, start_response)
+
+
+class GitDirectory(object):
+
+    def __init__(self, repo_root, repo_name, extras):
+        repo_location = os.path.join(repo_root, repo_name)
+        if not os.path.isdir(repo_location):
+            raise OSError(repo_location)
+
+        self.content_path = repo_location
+        self.repo_name = repo_name
+        self.repo_location = repo_location
+        self.extras = extras
+
+    def __call__(self, environ, start_response):
+        content_path = self.content_path
+        try:
+            app = GitRepository(self.repo_name, content_path, self.extras)
+        except (AssertionError, OSError):
+            content_path = os.path.join(content_path, '.git')
+            if os.path.isdir(content_path):
+                app = GitRepository(self.repo_name, content_path, self.extras)
+            else:
+                return exc.HTTPNotFound()(environ, start_response)
+        return app(environ, start_response)
+
+
+def make_wsgi_app(repo_name, repo_root, extras):
+    return GitDirectory(repo_root, repo_name, extras)
--- a/rhodecode/lib/middleware/simplegit.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/middleware/simplegit.py	Sun Sep 02 21:19:54 2012 +0200
@@ -30,6 +30,9 @@
 import traceback
 
 from dulwich import server as dulserver
+from dulwich.web import LimitedInputFilter, GunzipFilter
+from rhodecode.lib.exceptions import HTTPLockedRC
+from rhodecode.lib.hooks import pre_pull
 
 
 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
@@ -62,22 +65,26 @@
 
 
 dulserver.DEFAULT_HANDLERS = {
+  #git-ls-remote, git-clone, git-fetch and git-pull
   'git-upload-pack': SimpleGitUploadPackHandler,
+  #git-push
   'git-receive-pack': dulserver.ReceivePackHandler,
 }
 
-from dulwich.repo import Repo
-from dulwich.web import make_wsgi_chain
+# not used for now until dulwich get's fixed
+#from dulwich.repo import Repo
+#from dulwich.web import make_wsgi_chain
 
 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
+from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
+    HTTPBadRequest, HTTPNotAcceptable
 
 from rhodecode.lib.utils2 import safe_str
 from rhodecode.lib.base import BaseVCSController
 from rhodecode.lib.auth import get_container_username
 from rhodecode.lib.utils import is_valid_repo, make_ui
-from rhodecode.model.db import User
-
-from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
+from rhodecode.lib.compat import json
+from rhodecode.model.db import User, RhodeCodeUi
 
 log = logging.getLogger(__name__)
 
@@ -97,9 +104,10 @@
 class SimpleGit(BaseVCSController):
 
     def _handle_request(self, environ, start_response):
-
         if not is_git(environ):
             return self.application(environ, start_response)
+        if not self._check_ssl(environ, start_response):
+            return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
 
         ipaddr = self._get_ip_addr(environ)
         username = None
@@ -117,7 +125,7 @@
             return HTTPInternalServerError()(environ, start_response)
 
         # quick check if that dir exists...
-        if is_valid_repo(repo_name, self.basepath) is False:
+        if is_valid_repo(repo_name, self.basepath, 'git') is False:
             return HTTPNotFound()(environ, start_response)
 
         #======================================================================
@@ -164,27 +172,30 @@
                 #==============================================================
                 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
                 #==============================================================
-                if action in ['pull', 'push']:
-                    try:
-                        user = self.__get_user(username)
-                        if user is None or not user.active:
-                            return HTTPForbidden()(environ, start_response)
-                        username = user.username
-                    except:
-                        log.error(traceback.format_exc())
-                        return HTTPInternalServerError()(environ,
-                                                         start_response)
+                try:
+                    user = self.__get_user(username)
+                    if user is None or not user.active:
+                        return HTTPForbidden()(environ, start_response)
+                    username = user.username
+                except:
+                    log.error(traceback.format_exc())
+                    return HTTPInternalServerError()(environ, start_response)
 
-                    #check permissions for this repository
-                    perm = self._check_permission(action, user, repo_name)
-                    if perm is not True:
-                        return HTTPForbidden()(environ, start_response)
+                #check permissions for this repository
+                perm = self._check_permission(action, user, repo_name)
+                if perm is not True:
+                    return HTTPForbidden()(environ, start_response)
+
+        # extras are injected into UI object and later available
+        # in hooks executed by rhodecode
         extras = {
             'ip': ipaddr,
             'username': username,
             'action': action,
             'repository': repo_name,
             'scm': 'git',
+            'make_lock': None,
+            'locked_by': [None, None]
         }
 
         #===================================================================
@@ -193,10 +204,24 @@
         repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
         log.debug('Repository path is %s' % repo_path)
 
+        # CHECK LOCKING only if it's not ANONYMOUS USER
+        if username != User.DEFAULT_USER:
+            log.debug('Checking locking on repository')
+            (make_lock,
+             locked,
+             locked_by) = self._check_locking_state(
+                            environ=environ, action=action,
+                            repo=repo_name, user_id=user.user_id
+                       )
+            # store the make_lock for later evaluation in hooks
+            extras.update({'make_lock': make_lock,
+                           'locked_by': locked_by})
+        # set the environ variables for this request
+        os.environ['RC_SCM_DATA'] = json.dumps(extras)
+        log.debug('HOOKS extras is %s' % extras)
         baseui = make_ui('db')
         self.__inject_extras(repo_path, baseui, extras)
 
-
         try:
             # invalidate cache on push
             if action == 'push':
@@ -204,24 +229,31 @@
             self._handle_githooks(repo_name, action, baseui, environ)
 
             log.info('%s action on GIT repo "%s"' % (action, repo_name))
-            app = self.__make_app(repo_name, repo_path)
+            app = self.__make_app(repo_name, repo_path, extras)
             return app(environ, start_response)
+        except HTTPLockedRC, e:
+            log.debug('Repositry LOCKED ret code 423!')
+            return e(environ, start_response)
         except Exception:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
 
-    def __make_app(self, repo_name, repo_path):
+    def __make_app(self, repo_name, repo_path, extras):
         """
         Make an wsgi application using dulserver
 
         :param repo_name: name of the repository
         :param repo_path: full path to the repository
         """
-        _d = {'/' + repo_name: Repo(repo_path)}
-        backend = dulserver.DictBackend(_d)
-        gitserve = make_wsgi_chain(backend)
 
-        return gitserve
+        from rhodecode.lib.middleware.pygrack import make_wsgi_app
+        app = make_wsgi_app(
+            repo_root=safe_str(self.basepath),
+            repo_name=repo_name,
+            extras=extras,
+        )
+        app = GunzipFilter(LimitedInputFilter(app))
+        return app
 
     def __get_repository(self, environ):
         """
@@ -265,8 +297,12 @@
         return op
 
     def _handle_githooks(self, repo_name, action, baseui, environ):
-        from rhodecode.lib.hooks import log_pull_action, log_push_action
+        """
+        Handles pull action, push is handled by post-receive hook
+        """
+        from rhodecode.lib.hooks import log_pull_action
         service = environ['QUERY_STRING'].split('=')
+
         if len(service) < 2:
             return
 
@@ -275,12 +311,11 @@
         _repo = _repo.scm_instance
         _repo._repo.ui = baseui
 
-        push_hook = 'pretxnchangegroup.push_logger'
-        pull_hook = 'preoutgoing.pull_logger'
         _hooks = dict(baseui.configitems('hooks')) or {}
-        if action == 'push' and _hooks.get(push_hook):
-            log_push_action(ui=baseui, repo=_repo._repo)
-        elif action == 'pull' and _hooks.get(pull_hook):
+        if action == 'pull':
+            # stupid git, emulate pre-pull hook !
+            pre_pull(ui=baseui, repo=_repo._repo)
+        if action == 'pull' and _hooks.get(RhodeCodeUi.HOOK_PULL):
             log_pull_action(ui=baseui, repo=_repo._repo)
 
     def __inject_extras(self, repo_path, baseui, extras={}):
--- a/rhodecode/lib/middleware/simplehg.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/middleware/simplehg.py	Sun Sep 02 21:19:54 2012 +0200
@@ -33,14 +33,17 @@
 from mercurial.hgweb import hgweb_mod
 
 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
+from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
+    HTTPBadRequest, HTTPNotAcceptable
 
 from rhodecode.lib.utils2 import safe_str
 from rhodecode.lib.base import BaseVCSController
 from rhodecode.lib.auth import get_container_username
 from rhodecode.lib.utils import make_ui, is_valid_repo, ui_sections
+from rhodecode.lib.compat import json
 from rhodecode.model.db import User
+from rhodecode.lib.exceptions import HTTPLockedRC
 
-from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 
 log = logging.getLogger(__name__)
 
@@ -68,9 +71,11 @@
     def _handle_request(self, environ, start_response):
         if not is_mercurial(environ):
             return self.application(environ, start_response)
+        if not self._check_ssl(environ, start_response):
+            return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
 
         ipaddr = self._get_ip_addr(environ)
-
+        username = None
         # skip passing error to error controller
         environ['pylons.status_code_redirect'] = True
 
@@ -84,7 +89,7 @@
             return HTTPInternalServerError()(environ, start_response)
 
         # quick check if that dir exists...
-        if is_valid_repo(repo_name, self.basepath) is False:
+        if is_valid_repo(repo_name, self.basepath, 'hg') is False:
             return HTTPNotFound()(environ, start_response)
 
         #======================================================================
@@ -131,21 +136,19 @@
                 #==============================================================
                 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
                 #==============================================================
-                if action in ['pull', 'push']:
-                    try:
-                        user = self.__get_user(username)
-                        if user is None or not user.active:
-                            return HTTPForbidden()(environ, start_response)
-                        username = user.username
-                    except:
-                        log.error(traceback.format_exc())
-                        return HTTPInternalServerError()(environ,
-                                                         start_response)
+                try:
+                    user = self.__get_user(username)
+                    if user is None or not user.active:
+                        return HTTPForbidden()(environ, start_response)
+                    username = user.username
+                except:
+                    log.error(traceback.format_exc())
+                    return HTTPInternalServerError()(environ, start_response)
 
-                    #check permissions for this repository
-                    perm = self._check_permission(action, user, repo_name)
-                    if perm is not True:
-                        return HTTPForbidden()(environ, start_response)
+                #check permissions for this repository
+                perm = self._check_permission(action, user, repo_name)
+                if perm is not True:
+                    return HTTPForbidden()(environ, start_response)
 
         # extras are injected into mercurial UI object and later available
         # in hg hooks executed by rhodecode
@@ -155,14 +158,31 @@
             'action': action,
             'repository': repo_name,
             'scm': 'hg',
+            'make_lock': None,
+            'locked_by': [None, None]
         }
-
         #======================================================================
         # MERCURIAL REQUEST HANDLING
         #======================================================================
         repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
         log.debug('Repository path is %s' % repo_path)
 
+        # CHECK LOCKING only if it's not ANONYMOUS USER
+        if username != User.DEFAULT_USER:
+            log.debug('Checking locking on repository')
+            (make_lock,
+             locked,
+             locked_by) = self._check_locking_state(
+                            environ=environ, action=action,
+                            repo=repo_name, user_id=user.user_id
+                       )
+            # store the make_lock for later evaluation in hooks
+            extras.update({'make_lock': make_lock,
+                           'locked_by': locked_by})
+
+        # set the environ variables for this request
+        os.environ['RC_SCM_DATA'] = json.dumps(extras)
+        log.debug('HOOKS extras is %s' % extras)
         baseui = make_ui('db')
         self.__inject_extras(repo_path, baseui, extras)
 
@@ -176,6 +196,9 @@
         except RepoError, e:
             if str(e).find('not found') != -1:
                 return HTTPNotFound()(environ, start_response)
+        except HTTPLockedRC, e:
+            log.debug('Repositry LOCKED ret code 423!')
+            return e(environ, start_response)
         except Exception:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
@@ -225,8 +248,11 @@
                 cmd = qry.split('=')[-1]
                 if cmd in mapping:
                     return mapping[cmd]
-                else:
-                    return 'pull'
+
+                return 'pull'
+
+        raise Exception('Unable to detect pull/push action !!'
+                        'Are you using non standard command or client ?')
 
     def __inject_extras(self, repo_path, baseui, extras={}):
         """
--- a/rhodecode/lib/pidlock.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/pidlock.py	Sun Sep 02 21:19:54 2012 +0200
@@ -8,6 +8,7 @@
 
 from rhodecode.lib.compat import kill
 
+
 class LockHeld(Exception):
     pass
 
@@ -123,6 +124,10 @@
         """
         if self.debug:
             print 'creating a file %s and pid: %s' % (pidfile, lockname)
+
+        dir_, file_ = os.path.split(pidfile)
+        if not os.path.isdir(dir_):
+            os.makedirs(dir_)
         pidfile = open(self.pidfile, "wb")
         pidfile.write(lockname)
         pidfile.close
--- a/rhodecode/lib/profiler.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/profiler.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,5 +1,7 @@
 from __future__ import with_statement
 
+import gc
+import objgraph
 import cProfile
 import pstats
 import cgi
@@ -26,7 +28,7 @@
             profiler.snapshot_stats()
 
             stats = pstats.Stats(profiler)
-            stats.sort_stats('cumulative')
+            stats.sort_stats('calls') #cummulative
 
             # Redirect output
             out = StringIO()
@@ -44,6 +46,11 @@
                          'border-top: 4px dashed red; padding: 1em;">')
                 resp += cgi.escape(out.getvalue(), True)
 
+                ct = objgraph.show_most_common_types()
+                print ct
+
+                resp += ct if ct else '---'
+
                 output = StringIO()
                 pprint.pprint(environ, output, depth=3)
 
--- a/rhodecode/lib/rcmail/message.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/rcmail/message.py	Sun Sep 02 21:19:54 2012 +0200
@@ -3,6 +3,7 @@
 from rhodecode.lib.rcmail.exceptions import BadHeaders
 from rhodecode.lib.rcmail.exceptions import InvalidMessage
 
+
 class Attachment(object):
     """
     Encapsulates file attachment information.
@@ -134,13 +135,13 @@
         """
 
         if not self.recipients:
-            raise InvalidMessage, "No recipients have been added"
+            raise InvalidMessage("No recipients have been added")
 
         if not self.body and not self.html:
-            raise InvalidMessage, "No body has been set"
+            raise InvalidMessage("No body has been set")
 
         if not self.sender:
-            raise InvalidMessage, "No sender address has been set"
+            raise InvalidMessage("No sender address has been set")
 
         if self.is_bad_headers():
             raise BadHeaders
--- a/rhodecode/lib/rcmail/response.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/rcmail/response.py	Sun Sep 02 21:19:54 2012 +0200
@@ -364,6 +364,7 @@
 
     return out
 
+
 class MIMEPart(MIMEBase):
     """
     A reimplementation of nearly everything in email.mime to be more useful
@@ -387,7 +388,8 @@
         self.set_payload(encoded, charset=charset)
 
     def extract_payload(self, mail):
-        if mail.body == None: return  # only None, '' is still ok
+        if mail.body == None:
+            return  # only None, '' is still ok
 
         ctype, ctype_params = mail.content_encoding['Content-Type']
         cdisp, cdisp_params = mail.content_encoding['Content-Disposition']
@@ -415,7 +417,8 @@
 
 
 def header_to_mime_encoding(value, not_email=False, separator=", "):
-    if not value: return ""
+    if not value:
+        return ""
 
     encoder = Charset(DEFAULT_ENCODING)
     if type(value) == list:
@@ -424,6 +427,7 @@
     else:
         return properly_encode_header(value, encoder, not_email)
 
+
 def properly_encode_header(value, encoder, not_email):
     """
     The only thing special (weird) about this function is that it tries
--- a/rhodecode/lib/rcmail/smtp_mailer.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/rcmail/smtp_mailer.py	Sun Sep 02 21:19:54 2012 +0200
@@ -21,11 +21,13 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
+import time
 import logging
 import smtplib
 from socket import sslerror
+from email.utils import formatdate
 from rhodecode.lib.rcmail.message import Message
+from rhodecode.lib.rcmail.utils import DNS_NAME
 
 
 class SmtpMailer(object):
@@ -59,14 +61,19 @@
 
         if isinstance(recipients, basestring):
             recipients = [recipients]
+        headers = {
+            'Date': formatdate(time.time())
+        }
         msg = Message(subject, recipients, body, html, self.mail_from,
-                      recipients_separator=", ")
+                      recipients_separator=", ", extra_headers=headers)
         raw_msg = msg.to_message()
 
         if self.ssl:
-            smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port)
+            smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port,
+                                         local_hostname=DNS_NAME.get_fqdn())
         else:
-            smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
+            smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port,
+                                     local_hostname=DNS_NAME.get_fqdn())
 
         if self.tls:
             smtp_serv.ehlo()
@@ -91,4 +98,4 @@
             smtp_serv.quit()
         except sslerror:
             # sslerror is raised in tls connections on closing sometimes
-            pass
+            smtp_serv.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/rcmail/utils.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,19 @@
+"""
+Email message and email sending related helper functions.
+"""
+
+import socket
+
+
+# Cache the hostname, but do it lazily: socket.getfqdn() can take a couple of
+# seconds, which slows down the restart of the server.
+class CachedDnsName(object):
+    def __str__(self):
+        return self.get_fqdn()
+
+    def get_fqdn(self):
+        if not hasattr(self, '_fqdn'):
+            self._fqdn = socket.getfqdn()
+        return self._fqdn
+
+DNS_NAME = CachedDnsName()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/lib/subprocessio.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,409 @@
+'''
+Module provides a class allowing to wrap communication over subprocess.Popen
+input, output, error streams into a meaningfull, non-blocking, concurrent
+stream processor exposing the output data as an iterator fitting to be a
+return value passed by a WSGI applicaiton to a WSGI server per PEP 3333.
+
+Copyright (c) 2011  Daniel Dotsenko <dotsa@hotmail.com>
+
+This file is part of git_http_backend.py Project.
+
+git_http_backend.py Project is free software: you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 2.1 of the License,
+or (at your option) any later version.
+
+git_http_backend.py Project is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with git_http_backend.py Project.
+If not, see <http://www.gnu.org/licenses/>.
+'''
+import os
+import subprocess
+import threading
+from rhodecode.lib.compat import deque, Event
+
+
+class StreamFeeder(threading.Thread):
+    """
+    Normal writing into pipe-like is blocking once the buffer is filled.
+    This thread allows a thread to seep data from a file-like into a pipe
+    without blocking the main thread.
+    We close inpipe once the end of the source stream is reached.
+    """
+    def __init__(self, source):
+        super(StreamFeeder, self).__init__()
+        self.daemon = True
+        filelike = False
+        self.bytes = bytes()
+        if type(source) in (type(''), bytes, bytearray):  # string-like
+            self.bytes = bytes(source)
+        else:  # can be either file pointer or file-like
+            if type(source) in (int, long):  # file pointer it is
+                ## converting file descriptor (int) stdin into file-like
+                try:
+                    source = os.fdopen(source, 'rb', 16384)
+                except Exception:
+                    pass
+            # let's see if source is file-like by now
+            try:
+                filelike = source.read
+            except Exception:
+                pass
+        if not filelike and not self.bytes:
+            raise TypeError("StreamFeeder's source object must be a readable "
+                            "file-like, a file descriptor, or a string-like.")
+        self.source = source
+        self.readiface, self.writeiface = os.pipe()
+
+    def run(self):
+        t = self.writeiface
+        if self.bytes:
+            os.write(t, self.bytes)
+        else:
+            s = self.source
+            b = s.read(4096)
+            while b:
+                os.write(t, b)
+                b = s.read(4096)
+        os.close(t)
+
+    @property
+    def output(self):
+        return self.readiface
+
+
+class InputStreamChunker(threading.Thread):
+    def __init__(self, source, target, buffer_size, chunk_size):
+
+        super(InputStreamChunker, self).__init__()
+
+        self.daemon = True  # die die die.
+
+        self.source = source
+        self.target = target
+        self.chunk_count_max = int(buffer_size / chunk_size) + 1
+        self.chunk_size = chunk_size
+
+        self.data_added = Event()
+        self.data_added.clear()
+
+        self.keep_reading = Event()
+        self.keep_reading.set()
+
+        self.EOF = Event()
+        self.EOF.clear()
+
+        self.go = Event()
+        self.go.set()
+
+    def stop(self):
+        self.go.clear()
+        self.EOF.set()
+        try:
+            # this is not proper, but is done to force the reader thread let
+            # go of the input because, if successful, .close() will send EOF
+            # down the pipe.
+            self.source.close()
+        except:
+            pass
+
+    def run(self):
+        s = self.source
+        t = self.target
+        cs = self.chunk_size
+        ccm = self.chunk_count_max
+        kr = self.keep_reading
+        da = self.data_added
+        go = self.go
+        b = s.read(cs)
+        while b and go.is_set():
+            if len(t) > ccm:
+                kr.clear()
+                kr.wait(2)
+#                # this only works on 2.7.x and up
+#                if not kr.wait(10):
+#                    raise Exception("Timed out while waiting for input to be read.")
+                # instead we'll use this
+                if len(t) > ccm + 3:
+                    raise IOError("Timed out while waiting for input from subprocess.")
+            t.append(b)
+            da.set()
+            b = s.read(cs)
+        self.EOF.set()
+        da.set()  # for cases when done but there was no input.
+
+
+class BufferedGenerator():
+    '''
+    Class behaves as a non-blocking, buffered pipe reader.
+    Reads chunks of data (through a thread)
+    from a blocking pipe, and attaches these to an array (Deque) of chunks.
+    Reading is halted in the thread when max chunks is internally buffered.
+    The .next() may operate in blocking or non-blocking fashion by yielding
+    '' if no data is ready
+    to be sent or by not returning until there is some data to send
+    When we get EOF from underlying source pipe we raise the marker to raise
+    StopIteration after the last chunk of data is yielded.
+    '''
+
+    def __init__(self, source, buffer_size=65536, chunk_size=4096,
+                 starting_values=[], bottomless=False):
+
+        if bottomless:
+            maxlen = int(buffer_size / chunk_size)
+        else:
+            maxlen = None
+
+        self.data = deque(starting_values, maxlen)
+
+        self.worker = InputStreamChunker(source, self.data, buffer_size,
+                                         chunk_size)
+        if starting_values:
+            self.worker.data_added.set()
+        self.worker.start()
+
+    ####################
+    # Generator's methods
+    ####################
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        while not len(self.data) and not self.worker.EOF.is_set():
+            self.worker.data_added.clear()
+            self.worker.data_added.wait(0.2)
+        if len(self.data):
+            self.worker.keep_reading.set()
+            return bytes(self.data.popleft())
+        elif self.worker.EOF.is_set():
+            raise StopIteration
+
+    def throw(self, type, value=None, traceback=None):
+        if not self.worker.EOF.is_set():
+            raise type(value)
+
+    def start(self):
+        self.worker.start()
+
+    def stop(self):
+        self.worker.stop()
+
+    def close(self):
+        try:
+            self.worker.stop()
+            self.throw(GeneratorExit)
+        except (GeneratorExit, StopIteration):
+            pass
+
+    def __del__(self):
+        self.close()
+
+    ####################
+    # Threaded reader's infrastructure.
+    ####################
+    @property
+    def input(self):
+        return self.worker.w
+
+    @property
+    def data_added_event(self):
+        return self.worker.data_added
+
+    @property
+    def data_added(self):
+        return self.worker.data_added.is_set()
+
+    @property
+    def reading_paused(self):
+        return not self.worker.keep_reading.is_set()
+
+    @property
+    def done_reading_event(self):
+        '''
+        Done_reding does not mean that the iterator's buffer is empty.
+        Iterator might have done reading from underlying source, but the read
+        chunks might still be available for serving through .next() method.
+
+        @return An Event class instance.
+        '''
+        return self.worker.EOF
+
+    @property
+    def done_reading(self):
+        '''
+        Done_reding does not mean that the iterator's buffer is empty.
+        Iterator might have done reading from underlying source, but the read
+        chunks might still be available for serving through .next() method.
+
+        @return An Bool value.
+        '''
+        return self.worker.EOF.is_set()
+
+    @property
+    def length(self):
+        '''
+        returns int.
+
+        This is the lenght of the que of chunks, not the length of
+        the combined contents in those chunks.
+
+        __len__() cannot be meaningfully implemented because this
+        reader is just flying throuh a bottomless pit content and
+        can only know the lenght of what it already saw.
+
+        If __len__() on WSGI server per PEP 3333 returns a value,
+        the responce's length will be set to that. In order not to
+        confuse WSGI PEP3333 servers, we will not implement __len__
+        at all.
+        '''
+        return len(self.data)
+
+    def prepend(self, x):
+        self.data.appendleft(x)
+
+    def append(self, x):
+        self.data.append(x)
+
+    def extend(self, o):
+        self.data.extend(o)
+
+    def __getitem__(self, i):
+        return self.data[i]
+
+
+class SubprocessIOChunker(object):
+    '''
+    Processor class wrapping handling of subprocess IO.
+
+    In a way, this is a "communicate()" replacement with a twist.
+
+    - We are multithreaded. Writing in and reading out, err are all sep threads.
+    - We support concurrent (in and out) stream processing.
+    - The output is not a stream. It's a queue of read string (bytes, not unicode)
+      chunks. The object behaves as an iterable. You can "for chunk in obj:" us.
+    - We are non-blocking in more respects than communicate()
+      (reading from subprocess out pauses when internal buffer is full, but
+       does not block the parent calling code. On the flip side, reading from
+       slow-yielding subprocess may block the iteration until data shows up. This
+       does not block the parallel inpipe reading occurring parallel thread.)
+
+    The purpose of the object is to allow us to wrap subprocess interactions into
+    and interable that can be passed to a WSGI server as the application's return
+    value. Because of stream-processing-ability, WSGI does not have to read ALL
+    of the subprocess's output and buffer it, before handing it to WSGI server for
+    HTTP response. Instead, the class initializer reads just a bit of the stream
+    to figure out if error ocurred or likely to occur and if not, just hands the
+    further iteration over subprocess output to the server for completion of HTTP
+    response.
+
+    The real or perceived subprocess error is trapped and raised as one of
+    EnvironmentError family of exceptions
+
+    Example usage:
+    #    try:
+    #        answer = SubprocessIOChunker(
+    #            cmd,
+    #            input,
+    #            buffer_size = 65536,
+    #            chunk_size = 4096
+    #            )
+    #    except (EnvironmentError) as e:
+    #        print str(e)
+    #        raise e
+    #
+    #    return answer
+
+
+    '''
+    def __init__(self, cmd, inputstream=None, buffer_size=65536,
+                 chunk_size=4096, starting_values=[], **kwargs):
+        '''
+        Initializes SubprocessIOChunker
+
+        :param cmd: A Subprocess.Popen style "cmd". Can be string or array of strings
+        :param inputstream: (Default: None) A file-like, string, or file pointer.
+        :param buffer_size: (Default: 65536) A size of total buffer per stream in bytes.
+        :param chunk_size: (Default: 4096) A max size of a chunk. Actual chunk may be smaller.
+        :param starting_values: (Default: []) An array of strings to put in front of output que.
+        '''
+
+        if inputstream:
+            input_streamer = StreamFeeder(inputstream)
+            input_streamer.start()
+            inputstream = input_streamer.output
+
+        if isinstance(cmd, (list, tuple)):
+            cmd = ' '.join(cmd)
+
+        _shell = kwargs.get('shell') or True
+        kwargs['shell'] = _shell
+        _p = subprocess.Popen(cmd,
+            bufsize=-1,
+            stdin=inputstream,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            **kwargs
+            )
+
+        bg_out = BufferedGenerator(_p.stdout, buffer_size, chunk_size, starting_values)
+        bg_err = BufferedGenerator(_p.stderr, 16000, 1, bottomless=True)
+
+        while not bg_out.done_reading and not bg_out.reading_paused and not bg_err.length:
+            # doing this until we reach either end of file, or end of buffer.
+            bg_out.data_added_event.wait(1)
+            bg_out.data_added_event.clear()
+
+        # at this point it's still ambiguous if we are done reading or just full buffer.
+        # Either way, if error (returned by ended process, or implied based on
+        # presence of stuff in stderr output) we error out.
+        # Else, we are happy.
+        _returncode = _p.poll()
+        if _returncode or (_returncode == None and bg_err.length):
+            try:
+                _p.terminate()
+            except:
+                pass
+            bg_out.stop()
+            bg_err.stop()
+            err = '%s' % ''.join(bg_err)
+            raise EnvironmentError("Subprocess exited due to an error:\n" + err)
+
+        self.process = _p
+        self.output = bg_out
+        self.error = bg_err
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        if self.process.poll():
+            err = '%s' % ''.join(self.error)
+            raise EnvironmentError("Subprocess exited due to an error:\n" + err)
+        return self.output.next()
+
+    def throw(self, type, value=None, traceback=None):
+        if self.output.length or not self.output.done_reading:
+            raise type(value)
+
+    def close(self):
+        try:
+            self.process.terminate()
+        except:
+            pass
+        try:
+            self.output.close()
+        except:
+            pass
+        try:
+            self.error.close()
+        except:
+            pass
+
+    def __del__(self):
+        self.close()
--- a/rhodecode/lib/utils.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/utils.py	Sun Sep 02 21:19:54 2012 +0200
@@ -51,8 +51,7 @@
 
 from rhodecode.model import meta
 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
-    UserLog, RepoGroup, RhodeCodeSetting, UserRepoGroupToPerm,\
-    CacheInvalidation
+    UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
 from rhodecode.model.meta import Session
 from rhodecode.model.repos_group import ReposGroupModel
 from rhodecode.lib.utils2 import safe_str, safe_unicode
@@ -129,7 +128,7 @@
     """
 
     if not sa:
-        sa = meta.Session
+        sa = meta.Session()
 
     try:
         if hasattr(user, 'user_id'):
@@ -146,13 +145,14 @@
             repo_name = repo.lstrip('/')
             repo_obj = Repository.get_by_repo_name(repo_name)
         else:
-            raise Exception('You have to provide repository to action logger')
+            repo_obj = None
+            repo_name = ''
 
         user_log = UserLog()
         user_log.user_id = user_obj.user_id
         user_log.action = safe_unicode(action)
 
-        user_log.repository_id = repo_obj.repo_id
+        user_log.repository = repo_obj
         user_log.repository_name = repo_name
 
         user_log.action_date = datetime.datetime.now()
@@ -203,19 +203,24 @@
     return _get_repos(path)
 
 
-def is_valid_repo(repo_name, base_path):
+def is_valid_repo(repo_name, base_path, scm=None):
     """
-    Returns True if given path is a valid repository False otherwise
+    Returns True if given path is a valid repository False otherwise.
+    If scm param is given also compare if given scm is the same as expected 
+    from scm parameter
 
     :param repo_name:
     :param base_path:
+    :param scm:
 
     :return True: if given path is a valid repository
     """
     full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
 
     try:
-        get_scm(full_path)
+        scm_ = get_scm(full_path)
+        if scm:
+            return scm_[0] == scm
         return True
     except VCSError:
         return False
@@ -234,6 +239,15 @@
     if is_valid_repo(repos_group_name, base_path):
         return False
 
+    try:
+        # we need to check bare git repos at higher level
+        # since we might match branches/hooks/info/objects or possible
+        # other things inside bare git repo
+        get_scm(os.path.dirname(full_path))
+        return False
+    except VCSError:
+        pass
+
     # check if it's a valid path
     if os.path.isdir(full_path):
         return True
@@ -266,7 +280,7 @@
                 'ui', 'web', ]
 
 
-def make_ui(read_from='file', path=None, checkpaths=True):
+def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
     """
     A function that will read python rc files or database
     and make an mercurial ui object from read options
@@ -296,7 +310,7 @@
                 baseui.setconfig(section, k, v)
 
     elif read_from == 'db':
-        sa = meta.Session
+        sa = meta.Session()
         ret = sa.query(RhodeCodeUi)\
             .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
             .all()
@@ -307,8 +321,12 @@
                 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()
+            if ui_.ui_key == 'push_ssl':
+                # force set push_ssl requirement to False, rhodecode
+                # handles that
+                baseui.setconfig(ui_.ui_section, ui_.ui_key, False)
+        if clear_session:
+            meta.Session.remove()
     return baseui
 
 
@@ -337,50 +355,6 @@
         ScmModel().mark_for_invalidation(name)
 
 
-class EmptyChangeset(BaseChangeset):
-    """
-    An dummy empty changeset. It's possible to pass hash when creating
-    an EmptyChangeset
-    """
-
-    def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
-                 alias=None):
-        self._empty_cs = cs
-        self.revision = -1
-        self.message = ''
-        self.author = ''
-        self.date = ''
-        self.repository = repo
-        self.requested_revision = requested_revision
-        self.alias = alias
-
-    @LazyProperty
-    def raw_id(self):
-        """
-        Returns raw string identifying this changeset, useful for web
-        representation.
-        """
-
-        return self._empty_cs
-
-    @LazyProperty
-    def branch(self):
-        return get_backend(self.alias).DEFAULT_BRANCH_NAME
-
-    @LazyProperty
-    def short_id(self):
-        return self.raw_id[:12]
-
-    def get_file_changeset(self, path):
-        return self
-
-    def get_file_content(self, path):
-        return u''
-
-    def get_file_size(self, path):
-        return 0
-
-
 def map_groups(path):
     """
     Given a full path to a repository, create all nested groups that this
@@ -389,7 +363,7 @@
 
     :param paths: full path to repository
     """
-    sa = meta.Session
+    sa = meta.Session()
     groups = path.split(Repository.url_sep())
     parent = None
     group = None
@@ -418,7 +392,8 @@
     return group
 
 
-def repo2db_mapper(initial_repo_list, remove_obsolete=False):
+def repo2db_mapper(initial_repo_list, remove_obsolete=False,
+                   install_git_hook=False):
     """
     maps all repos given in initial_repo_list, non existing repositories
     are created, if remove_obsolete is True it also check for db entries
@@ -426,9 +401,12 @@
 
     :param initial_repo_list: list of repositories found by scanning methods
     :param remove_obsolete: check for obsolete entries in database
+    :param install_git_hook: if this is True, also check and install githook
+        for a repo if missing
     """
     from rhodecode.model.repo import RepoModel
-    sa = meta.Session
+    from rhodecode.model.scm import ScmModel
+    sa = meta.Session()
     rm = RepoModel()
     user = sa.query(User).filter(User.admin == True).first()
     if user is None:
@@ -437,30 +415,45 @@
 
     for name, repo in initial_repo_list.items():
         group = map_groups(name)
-        if not rm.get_by_repo_name(name, cache=False):
-            log.info('repository %s not found creating default' % name)
+        db_repo = rm.get_by_repo_name(name)
+        # found repo that is on filesystem not in RhodeCode database
+        if not db_repo:
+            log.info('repository %s not found creating now' % name)
             added.append(name)
-            form_data = {
-             'repo_name': name,
-             'repo_name_full': name,
-             'repo_type': repo.alias,
-             'description': repo.description \
-                if repo.description != 'unknown' else '%s repository' % name,
-             'private': False,
-             'group_id': getattr(group, 'group_id', None)
-            }
-            rm.create(form_data, user, just_db=True)
+            desc = (repo.description
+                    if repo.description != 'unknown'
+                    else '%s repository' % name)
+            new_repo = rm.create_repo(
+                repo_name=name,
+                repo_type=repo.alias,
+                description=desc,
+                repos_group=getattr(group, 'group_id', None),
+                owner=user,
+                just_db=True
+            )
+            # we added that repo just now, and make sure it has githook
+            # installed
+            if new_repo.repo_type == 'git':
+                ScmModel().install_git_hook(new_repo.scm_instance)
+        elif install_git_hook:
+            if db_repo.repo_type == 'git':
+                ScmModel().install_git_hook(db_repo.scm_instance)
     sa.commit()
     removed = []
     if remove_obsolete:
         # remove from database those repositories that are not in the filesystem
         for repo in sa.query(Repository).all():
             if repo.repo_name not in initial_repo_list.keys():
-                log.debug("Removing non existing repository found in db %s" %
+                log.debug("Removing non existing repository found in db `%s`" %
                           repo.repo_name)
-                removed.append(repo.repo_name)
-                sa.delete(repo)
-                sa.commit()
+                try:
+                    sa.delete(repo)
+                    sa.commit()
+                    removed.append(repo.repo_name)
+                except:
+                    #don't hold further removals on error
+                    log.error(traceback.format_exc())
+                    sa.rollback()
 
     # clear cache keys
     log.debug("Clearing cache keys now...")
@@ -557,7 +550,7 @@
     install test repository into tmp dir
     """
     from rhodecode.lib.db_manage import DbManage
-    from rhodecode.tests import HG_REPO, TESTS_TMP_PATH
+    from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
 
     # PART ONE create db
     dbconf = config['sqlalchemy.db1.url']
@@ -576,7 +569,7 @@
     dbmanage.admin_prompt()
     dbmanage.create_permissions()
     dbmanage.populate_default_permissions()
-    Session.commit()
+    Session().commit()
     # PART TWO make test repo
     log.debug('making test vcs repositories')
 
@@ -592,12 +585,21 @@
         log.debug('remove %s' % data_path)
         shutil.rmtree(data_path)
 
-    #CREATE DEFAULT HG REPOSITORY
+    #CREATE DEFAULT TEST REPOS
     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()
 
+    cur_dir = dn(dn(abspath(__file__)))
+    tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
+    tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
+    tar.close()
+
+    #LOAD VCS test stuff
+    from rhodecode.tests.vcs import setup_package
+    setup_package()
+
 
 #==============================================================================
 # PASTER COMMANDS
--- a/rhodecode/lib/utils2.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/utils2.py	Sun Sep 02 21:19:54 2012 +0200
@@ -24,6 +24,9 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import re
+import time
+import datetime
+from pylons.i18n.translation import _, ungettext
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
 
@@ -270,7 +273,6 @@
                 context._query_start_time = time.time()
                 log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
 
-
             def after_cursor_execute(conn, cursor, statement,
                                     parameters, context, executemany):
                 total = time.time() - context._query_start_time
@@ -284,40 +286,76 @@
     return engine
 
 
-def age(curdate):
+def age(prevdate):
     """
     turns a datetime into an age string.
 
-    :param curdate: datetime object
+    :param prevdate: datetime object
     :rtype: unicode
     :returns: unicode words describing age
     """
 
-    from datetime import datetime
-    from webhelpers.date import time_ago_in_words
+    order = ['year', 'month', 'day', 'hour', 'minute', 'second']
+    deltas = {}
+
+    # Get date parts deltas
+    now = datetime.datetime.now()
+    for part in order:
+        deltas[part] = getattr(now, part) - getattr(prevdate, part)
+
+    # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00,
+    # not 1 hour, -59 minutes and -59 seconds)
+
+    for num, length in [(5, 60), (4, 60), (3, 24)]:  # seconds, minutes, hours
+        part = order[num]
+        carry_part = order[num - 1]
 
-    _ = lambda s: s
+        if deltas[part] < 0:
+            deltas[part] += length
+            deltas[carry_part] -= 1
 
-    if not curdate:
-        return ''
+    # Same thing for days except that the increment depends on the (variable)
+    # number of days in the month
+    month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+    if deltas['day'] < 0:
+        if prevdate.month == 2 and (prevdate.year % 4 == 0 and
+            (prevdate.year % 100 != 0 or prevdate.year % 400 == 0)):
+            deltas['day'] += 29
+        else:
+            deltas['day'] += month_lengths[prevdate.month - 1]
+
+        deltas['month'] -= 1
 
-    agescales = [(_(u"year"), 3600 * 24 * 365),
-                 (_(u"month"), 3600 * 24 * 30),
-                 (_(u"day"), 3600 * 24),
-                 (_(u"hour"), 3600),
-                 (_(u"minute"), 60),
-                 (_(u"second"), 1), ]
+    if deltas['month'] < 0:
+        deltas['month'] += 12
+        deltas['year'] -= 1
+
+    # Format the result
+    fmt_funcs = {
+        'year': lambda d: ungettext(u'%d year', '%d years', d) % d,
+        'month': lambda d: ungettext(u'%d month', '%d months', d) % d,
+        'day': lambda d: ungettext(u'%d day', '%d days', d) % d,
+        'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d,
+        'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d,
+        'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d,
+    }
 
-    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 '%s %s' % (time_ago_in_words(curdate,
-                                                agescales[pos][0]), _('ago'))
-        pos += 1
+    for i, part in enumerate(order):
+        value = deltas[part]
+        if value == 0:
+            continue
+
+        if i < 5:
+            sub_part = order[i + 1]
+            sub_value = deltas[sub_part]
+        else:
+            sub_value = 0
+
+        if sub_value == 0:
+            return _(u'%s ago') % fmt_funcs[part](value)
+
+        return _(u'%s and %s ago') % (fmt_funcs[part](value),
+            fmt_funcs[sub_part](sub_value))
 
     return _(u'just now')
 
@@ -379,6 +417,7 @@
     """
     from rhodecode.lib.vcs.backends.base import BaseRepository
     from rhodecode.lib.vcs.exceptions import RepositoryError
+    from rhodecode.lib.vcs.backends.base import EmptyChangeset
     if not isinstance(repo, BaseRepository):
         raise Exception('You must pass an Repository '
                         'object as first argument got %s', type(repo))
@@ -386,11 +425,24 @@
     try:
         cs = repo.get_changeset(rev)
     except RepositoryError:
-        from rhodecode.lib.utils import EmptyChangeset
         cs = EmptyChangeset(requested_revision=rev)
     return cs
 
 
+def datetime_to_time(dt):
+    if dt:
+        return time.mktime(dt.timetuple())
+
+
+def time_to_datetime(tm):
+    if tm:
+        if isinstance(tm, basestring):
+            try:
+                tm = float(tm)
+            except ValueError:
+                return
+        return datetime.datetime.fromtimestamp(tm)
+
 MENTIONS_REGEX = r'(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)(?:\s{1})'
 
 
@@ -405,3 +457,10 @@
         usrs.add(username)
 
     return sorted(list(usrs), key=lambda k: k.lower())
+
+
+class AttributeDict(dict):
+    def __getattr__(self, attr):
+        return self.get(attr, None)
+    __setattr__ = dict.__setitem__
+    __delattr__ = dict.__delitem__
--- a/rhodecode/lib/vcs/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -10,7 +10,7 @@
     :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak.
 """
 
-VERSION = (0, 2, 3, 'dev')
+VERSION = (0, 3, 0, 'dev')
 
 __version__ = '.'.join((str(each) for each in VERSION[:4]))
 
--- a/rhodecode/lib/vcs/backends/git/changeset.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/backends/git/changeset.py	Sun Sep 02 21:19:54 2012 +0200
@@ -9,7 +9,7 @@
 from rhodecode.lib.vcs.exceptions import VCSError
 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
 from rhodecode.lib.vcs.exceptions import ImproperArchiveTypeError
-from rhodecode.lib.vcs.backends.base import BaseChangeset
+from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
 from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, \
     RemovedFileNode, SubModuleNode
 from rhodecode.lib.vcs.utils import safe_unicode
@@ -25,17 +25,24 @@
     def __init__(self, repository, revision):
         self._stat_modes = {}
         self.repository = repository
-        self.raw_id = revision
-        self.revision = repository.revisions.index(revision)
 
-        self.short_id = self.raw_id[:12]
-        self.id = self.raw_id
         try:
-            commit = self.repository._repo.get_object(self.raw_id)
+            commit = self.repository._repo.get_object(revision)
+            if isinstance(commit, objects.Tag):
+                revision = commit.object[1]
+                commit = self.repository._repo.get_object(commit.object[1])
         except KeyError:
-            raise RepositoryError("Cannot get object with id %s" % self.raw_id)
+            raise RepositoryError("Cannot get object with id %s" % revision)
+        self.raw_id = revision
+        self.id = self.raw_id
+        self.short_id = self.raw_id[:12]
         self._commit = commit
+
         self._tree_id = commit.tree
+        self._commiter_property = 'committer'
+        self._date_property = 'commit_time'
+        self._date_tz_property = 'commit_timezone'
+        self.revision = repository.revisions.index(revision)
 
         self.message = safe_unicode(commit.message)
         #self.branch = None
@@ -45,12 +52,16 @@
 
     @LazyProperty
     def author(self):
-        return safe_unicode(self._commit.committer)
+        return safe_unicode(getattr(self._commit, self._commiter_property))
 
     @LazyProperty
     def date(self):
-        return date_fromtimestamp(self._commit.commit_time,
-                                  self._commit.commit_timezone)
+        return date_fromtimestamp(getattr(self._commit, self._date_property),
+                                  getattr(self._commit, self._date_tz_property))
+
+    @LazyProperty
+    def _timestamp(self):
+        return getattr(self._commit, self._date_property)
 
     @LazyProperty
     def status(self):
@@ -83,7 +94,7 @@
         if not path in self._paths:
             path = path.strip('/')
             # set root tree
-            tree = self.repository._repo[self._commit.tree]
+            tree = self.repository._repo[self._tree_id]
             if path == '':
                 self._paths[''] = tree.id
                 return tree.id
@@ -132,8 +143,7 @@
         return self._paths[path]
 
     def _get_kind(self, path):
-        id = self._get_id_for_path(path)
-        obj = self.repository._repo[id]
+        obj = self.repository._repo[self._get_id_for_path(path)]
         if isinstance(obj, objects.Blob):
             return NodeKind.FILE
         elif isinstance(obj, objects.Tree):
@@ -148,7 +158,7 @@
         Returns list of parents changesets.
         """
         return [self.repository.get_changeset(parent)
-            for parent in self._commit.parents]
+                for parent in self._commit.parents]
 
     def next(self, branch=None):
 
@@ -194,6 +204,13 @@
 
         return _prev(self, branch)
 
+    def diff(self, ignore_whitespace=True, context=3):
+        rev1 = self.parents[0] if self.parents else self.repository.EMPTY_CHANGESET
+        rev2 = self
+        return ''.join(self.repository.get_diff(rev1, rev2,
+                                    ignore_whitespace=ignore_whitespace,
+                                    context=context))
+
     def get_file_mode(self, path):
         """
         Returns stat mode of the file at the given ``path``.
@@ -254,10 +271,11 @@
         # --root ==> doesn't put '^' character for bounderies
         # -r sha ==> blames for the given revision
         so, se = self.repository.run_git_command(cmd)
+
         annotate = []
         for i, blame_line in enumerate(so.split('\n')[:-1]):
             ln_no = i + 1
-            id, line = re.split(r' \(.+?\) ', blame_line, 1)
+            id, line = re.split(r' ', blame_line, 1)
             annotate.append((ln_no, self.repository.get_changeset(id), line))
         return annotate
 
@@ -363,10 +381,10 @@
                 raise NodeDoesNotExistError("Cannot find one of parents' "
                     "directories for a given path: %s" % path)
 
-            als = self.repository.alias
             _GL = lambda m: m and objects.S_ISGITLINK(m)
             if _GL(self._stat_modes.get(path)):
-                node = SubModuleNode(path, url=None, changeset=id_, alias=als)
+                node = SubModuleNode(path, url=None, changeset=id_,
+                                     alias=self.repository.alias)
             else:
                 obj = self.repository._repo.get_object(id_)
 
@@ -392,39 +410,56 @@
         """
         Get's a fast accessible file changes for given changeset
         """
-
-        return self.added + self.changed
+        a, m, d = self._changes_cache
+        return list(a.union(m).union(d))
 
     @LazyProperty
     def _diff_name_status(self):
         output = []
         for parent in self.parents:
-            cmd = 'diff --name-status %s %s --encoding=utf8' % (parent.raw_id, self.raw_id)
+            cmd = 'diff --name-status %s %s --encoding=utf8' % (parent.raw_id,
+                                                                self.raw_id)
             so, se = self.repository.run_git_command(cmd)
             output.append(so.strip())
         return '\n'.join(output)
 
+    @LazyProperty
+    def _changes_cache(self):
+        added = set()
+        modified = set()
+        deleted = set()
+        _r = self.repository._repo
+
+        parents = self.parents
+        if not self.parents:
+            parents = [EmptyChangeset()]
+        for parent in parents:
+            if isinstance(parent, EmptyChangeset):
+                oid = None
+            else:
+                oid = _r[parent.raw_id].tree
+            changes = _r.object_store.tree_changes(oid, _r[self.raw_id].tree)
+            for (oldpath, newpath), (_, _), (_, _) in changes:
+                if newpath and oldpath:
+                    modified.add(newpath)
+                elif newpath and not oldpath:
+                    added.add(newpath)
+                elif not newpath and oldpath:
+                    deleted.add(oldpath)
+        return added, modified, deleted
+
     def _get_paths_for_status(self, status):
         """
         Returns sorted list of paths for given ``status``.
 
         :param status: one of: *added*, *modified* or *deleted*
         """
-        paths = set()
-        char = status[0].upper()
-        for line in self._diff_name_status.splitlines():
-            if not line:
-                continue
-
-            if line.startswith(char):
-                splitted = line.split(char, 1)
-                if not len(splitted) == 2:
-                    raise VCSError("Couldn't parse diff result:\n%s\n\n and "
-                        "particularly that line: %s" % (self._diff_name_status,
-                        line))
-                _path = splitted[1].strip()
-                paths.add(_path)
-        return sorted(paths)
+        a, m, d = self._changes_cache
+        return sorted({
+            'added': list(a),
+            'modified': list(m),
+            'deleted': list(d)}[status]
+        )
 
     @LazyProperty
     def added(self):
--- a/rhodecode/lib/vcs/backends/git/inmemory.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/backends/git/inmemory.py	Sun Sep 02 21:19:54 2012 +0200
@@ -83,7 +83,8 @@
                     curtree = newtree
                 parent[reversed_dirnames[-1]] = DIRMOD, curtree.id
             else:
-                parent.add(node.mode, node_path, blob.id)
+                parent.add(name=node_path, mode=node.mode, hexsha=blob.id)
+
             new_trees.append(parent)
             # Update ancestors
             for parent, tree, path in reversed([(a[1], b[1], b[0]) for a, b in
@@ -123,7 +124,7 @@
         commit.parents = [p._commit.id for p in self.parents if p]
         commit.author = commit.committer = safe_str(author)
         commit.encoding = ENCODING
-        commit.message = safe_str(message) + ' '
+        commit.message = safe_str(message)
 
         # Compute date
         if date is None:
@@ -148,6 +149,8 @@
         # Update vcs repository object & recreate dulwich repo
         self.repository.revisions.append(commit.id)
         self.repository._repo = Repo(self.repository.path)
+        # invalidate parsed refs after commit
+        self.repository._parsed_refs = self.repository._get_parsed_refs()
         tip = self.repository.get_changeset()
         self.reset()
         return tip
--- a/rhodecode/lib/vcs/backends/git/repository.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/backends/git/repository.py	Sun Sep 02 21:19:54 2012 +0200
@@ -13,6 +13,10 @@
 import re
 import time
 import posixpath
+import logging
+import traceback
+import urllib
+import urllib2
 from dulwich.repo import Repo, NotGitRepository
 #from dulwich.config import ConfigFile
 from string import Template
@@ -33,6 +37,10 @@
 from .changeset import GitChangeset
 from .inmemory import GitInMemoryChangeset
 from .config import ConfigFile
+from rhodecode.lib import subprocessio
+
+
+log = logging.getLogger(__name__)
 
 
 class GitRepository(BaseRepository):
@@ -66,6 +74,7 @@
                 'config'),
             abspath(get_user_home(), '.gitconfig'),
         ]
+        self.bare = self._repo.bare
 
     @LazyProperty
     def revisions(self):
@@ -94,28 +103,32 @@
             cmd = [cmd]
             _str_cmd = True
 
-        cmd = ['GIT_CONFIG_NOGLOBAL=1', 'git'] + _copts + cmd
+        gitenv = os.environ
+        # need to clean fix GIT_DIR !
+        if 'GIT_DIR' in gitenv:
+            del gitenv['GIT_DIR']
+        gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
+
+        cmd = ['git'] + _copts + cmd
         if _str_cmd:
             cmd = ' '.join(cmd)
         try:
             opts = dict(
-                shell=isinstance(cmd, basestring),
-                stdout=PIPE,
-                stderr=PIPE)
+                env=gitenv,
+                shell=False,
+            )
             if os.path.isdir(self.path):
                 opts['cwd'] = self.path
-            p = Popen(cmd, **opts)
-        except OSError, err:
+            p = subprocessio.SubprocessIOChunker(cmd, **opts)
+        except (EnvironmentError, OSError), err:
+            log.error(traceback.format_exc())
             raise RepositoryError("Couldn't run git command (%s).\n"
-                "Original error was:%s" % (cmd, err))
-        so, se = p.communicate()
-        if not se.startswith("fatal: bad default revision 'HEAD'") and \
-            p.returncode != 0:
-            raise RepositoryError("Couldn't run git command (%s).\n"
-                "stderr:\n%s" % (cmd, se))
-        return so, se
+                                  "Original error was:%s" % (cmd, err))
 
-    def _check_url(self, url):
+        return ''.join(p.output), ''.join(p.error)
+
+    @classmethod
+    def _check_url(cls, url):
         """
         Functon will check given url and try to verify if it's a valid
         link. Sometimes it may happened that mercurial will issue basic
@@ -124,9 +137,45 @@
 
         On failures it'll raise urllib2.HTTPError
         """
+        from mercurial.util import url as Url
 
-        #TODO: implement this
-        pass
+        # those authnadlers are patched for python 2.6.5 bug an
+        # infinit looping when given invalid resources
+        from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
+
+        # check first if it's not an local url
+        if os.path.isdir(url) or url.startswith('file:'):
+            return True
+
+        if('+' in url[:url.find('://')]):
+            url = url[url.find('+') + 1:]
+
+        handlers = []
+        test_uri, authinfo = Url(url).authinfo()
+        if not test_uri.endswith('info/refs'):
+            test_uri = test_uri.rstrip('/') + '/info/refs'
+        if authinfo:
+            #create a password manager
+            passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
+            passmgr.add_password(*authinfo)
+
+            handlers.extend((httpbasicauthhandler(passmgr),
+                             httpdigestauthhandler(passmgr)))
+
+        o = urllib2.build_opener(*handlers)
+        o.addheaders = [('User-Agent', 'git/1.7.8.0')]  # fake some git
+
+        q = {"service": 'git-upload-pack'}
+        qs = '?%s' % urllib.urlencode(q)
+        cu = "%s%s" % (test_uri, qs)
+        req = urllib2.Request(cu, None, {})
+
+        try:
+            resp = o.open(req)
+            return resp.code == 200
+        except Exception, e:
+            # means it cannot be cloned
+            raise urllib2.URLError("[%s] %s" % (url, e))
 
     def _get_repo(self, create, src_url=None, update_after_clone=False,
             bare=False):
@@ -137,7 +186,7 @@
                                   "given (clone operation creates repository)")
         try:
             if create and src_url:
-                self._check_url(src_url)
+                GitRepository._check_url(src_url)
                 self.clone(src_url, update_after_clone, bare)
                 return Repo(self.path)
             elif create:
@@ -152,15 +201,26 @@
             raise RepositoryError(err)
 
     def _get_all_revisions(self):
-        cmd = 'rev-list --all --date-order'
+        # we must check if this repo is not empty, since later command
+        # fails if it is. And it's cheaper to ask than throw the subprocess
+        # errors
+        try:
+            self._repo.head()
+        except KeyError:
+            return []
+        cmd = 'rev-list --all --reverse --date-order'
         try:
             so, se = self.run_git_command(cmd)
         except RepositoryError:
             # Can be raised for empty repositories
             return []
-        revisions = so.splitlines()
-        revisions.reverse()
-        return revisions
+        return so.splitlines()
+
+    def _get_all_revisions2(self):
+        #alternate implementation using dulwich
+        includes = [x[1][0] for x in self._parsed_refs.iteritems()
+                    if x[1][1] != 'T']
+        return [c.commit.id for c in self._repo.get_walker(include=includes)]
 
     def _get_revision(self, revision):
         """
@@ -186,7 +246,17 @@
                     "for this repository %s" % (revision, self))
 
         elif is_bstr(revision):
-            if not pattern.match(revision) or revision not in self.revisions:
+            # get by branch/tag name
+            _ref_revision = self._parsed_refs.get(revision)
+            _tags_shas = self.tags.values()
+            if _ref_revision:  # and _ref_revision[1] in ['H', 'RH', 'T']:
+                return _ref_revision[0]
+
+            # maybe it's a tag ? we don't have them in self.revisions
+            elif revision in _tags_shas:
+                return _tags_shas[_tags_shas.index(revision)]
+
+            elif not pattern.match(revision) or revision not in self.revisions:
                 raise ChangesetDoesNotExistError("Revision %r does not exist "
                     "for this repository %s" % (revision, self))
 
@@ -226,9 +296,10 @@
         try:
             return time.mktime(self.get_changeset().date.timetuple())
         except RepositoryError:
+            idx_loc = '' if self.bare else '.git'
             # fallback to filesystem
-            in_path = os.path.join(self.path, '.git', "index")
-            he_path = os.path.join(self.path, '.git', "HEAD")
+            in_path = os.path.join(self.path, idx_loc, "index")
+            he_path = os.path.join(self.path, idx_loc, "HEAD")
             if os.path.exists(in_path):
                 return os.stat(in_path).st_mtime
             else:
@@ -236,8 +307,9 @@
 
     @LazyProperty
     def description(self):
+        idx_loc = '' if self.bare else '.git'
         undefined_description = u'unknown'
-        description_path = os.path.join(self.path, '.git', 'description')
+        description_path = os.path.join(self.path, idx_loc, 'description')
         if os.path.isfile(description_path):
             return safe_unicode(open(description_path).read())
         else:
@@ -252,38 +324,24 @@
     def branches(self):
         if not self.revisions:
             return {}
-        refs = self._repo.refs.as_dict()
         sortkey = lambda ctx: ctx[0]
-        _branches = [('/'.join(ref.split('/')[2:]), head)
-            for ref, head in refs.items()
-            if ref.startswith('refs/heads/') and not ref.endswith('/HEAD')]
+        _branches = [(x[0], x[1][0])
+                     for x in self._parsed_refs.iteritems() if x[1][1] == 'H']
         return OrderedDict(sorted(_branches, key=sortkey, reverse=False))
 
-    def _heads(self, reverse=False):
-        refs = self._repo.get_refs()
-        heads = {}
-
-        for key, val in refs.items():
-            for ref_key in ['refs/heads/', 'refs/remotes/origin/']:
-                if key.startswith(ref_key):
-                    n = key[len(ref_key):]
-                    if n not in ['HEAD']:
-                        heads[n] = val
-
-        return heads if reverse else dict((y,x) for x,y in heads.iteritems())
+    @LazyProperty
+    def tags(self):
+        return self._get_tags()
 
     def _get_tags(self):
         if not self.revisions:
             return {}
+
         sortkey = lambda ctx: ctx[0]
-        _tags = [('/'.join(ref.split('/')[2:]), head) for ref, head in
-            self._repo.get_refs().items() if ref.startswith('refs/tags/')]
+        _tags = [(x[0], x[1][0])
+                 for x in self._parsed_refs.iteritems() if x[1][1] == 'T']
         return OrderedDict(sorted(_tags, key=sortkey, reverse=True))
 
-    @LazyProperty
-    def tags(self):
-        return self._get_tags()
-
     def tag(self, name, user, revision=None, message=None, date=None,
             **kwargs):
         """
@@ -304,6 +362,7 @@
             changeset.raw_id)
         self._repo.refs["refs/tags/%s" % name] = changeset._commit.id
 
+        self._parsed_refs = self._get_parsed_refs()
         self.tags = self._get_tags()
         return changeset
 
@@ -323,10 +382,42 @@
         tagpath = posixpath.join(self._repo.refs.path, 'refs', 'tags', name)
         try:
             os.remove(tagpath)
+            self._parsed_refs = self._get_parsed_refs()
             self.tags = self._get_tags()
         except OSError, e:
             raise RepositoryError(e.strerror)
 
+    @LazyProperty
+    def _parsed_refs(self):
+        return self._get_parsed_refs()
+
+    def _get_parsed_refs(self):
+        refs = self._repo.get_refs()
+        keys = [('refs/heads/', 'H'),
+                ('refs/remotes/origin/', 'RH'),
+                ('refs/tags/', 'T')]
+        _refs = {}
+        for ref, sha in refs.iteritems():
+            for k, type_ in keys:
+                if ref.startswith(k):
+                    _key = ref[len(k):]
+                    _refs[_key] = [sha, type_]
+                    break
+        return _refs
+
+    def _heads(self, reverse=False):
+        refs = self._repo.get_refs()
+        heads = {}
+
+        for key, val in refs.items():
+            for ref_key in ['refs/heads/', 'refs/remotes/origin/']:
+                if key.startswith(ref_key):
+                    n = key[len(ref_key):]
+                    if n not in ['HEAD']:
+                        heads[n] = val
+
+        return heads if reverse else dict((y, x) for x, y in heads.iteritems())
+
     def get_changeset(self, revision=None):
         """
         Returns ``GitChangeset`` object representing commit from git repository
@@ -429,6 +520,12 @@
         if ignore_whitespace:
             flags.append('-w')
 
+        if hasattr(rev1, 'raw_id'):
+            rev1 = getattr(rev1, 'raw_id')
+
+        if hasattr(rev2, 'raw_id'):
+            rev2 = getattr(rev2, 'raw_id')
+
         if rev1 == self.EMPTY_CHANGESET:
             rev2 = self.get_changeset(rev2).raw_id
             cmd = ' '.join(['show'] + flags + [rev2])
@@ -492,6 +589,17 @@
         # If error occurs run_git_command raises RepositoryError already
         self.run_git_command(cmd)
 
+    def fetch(self, url):
+        """
+        Tries to pull changes from external location.
+        """
+        url = self._get_url(url)
+        cmd = ['fetch']
+        cmd.append(url)
+        cmd = ' '.join(cmd)
+        # If error occurs run_git_command raises RepositoryError already
+        self.run_git_command(cmd)
+
     @LazyProperty
     def workdir(self):
         """
--- a/rhodecode/lib/vcs/backends/hg/changeset.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/backends/hg/changeset.py	Sun Sep 02 21:19:54 2012 +0200
@@ -12,8 +12,7 @@
 from rhodecode.lib.vcs.utils import safe_str, safe_unicode, date_fromtimestamp
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
 from rhodecode.lib.vcs.utils.paths import get_dirs_for_path
-
-from ...utils.hgcompat import archival, hex
+from rhodecode.lib.vcs.utils.hgcompat import archival, hex
 
 
 class MercurialChangeset(BaseChangeset):
@@ -53,6 +52,10 @@
         return date_fromtimestamp(*self._ctx.date())
 
     @LazyProperty
+    def _timestamp(self):
+        return self._ctx.date()[0]
+
+    @LazyProperty
     def status(self):
         """
         Returns modified, added, removed, deleted files for current changeset
@@ -136,6 +139,11 @@
 
         return _prev(self, branch)
 
+    def diff(self, ignore_whitespace=True, context=3):
+        return ''.join(self._ctx.diff(git=True,
+                                      ignore_whitespace=ignore_whitespace,
+                                      context=context))
+
     def _fix_path(self, path):
         """
         Paths are stored without trailing slash so we need to get rid off it if
--- a/rhodecode/lib/vcs/backends/hg/inmemory.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/backends/hg/inmemory.py	Sun Sep 02 21:19:54 2012 +0200
@@ -4,7 +4,7 @@
 from rhodecode.lib.vcs.backends.base import BaseInMemoryChangeset
 from rhodecode.lib.vcs.exceptions import RepositoryError
 
-from ...utils.hgcompat import memfilectx, memctx, hex, tolocal
+from rhodecode.lib.vcs.utils.hgcompat import memfilectx, memctx, hex, tolocal
 
 
 class MercurialInMemoryChangeset(BaseInMemoryChangeset):
@@ -32,7 +32,8 @@
         from .repository import MercurialRepository
         if not isinstance(message, unicode) or not isinstance(author, unicode):
             raise RepositoryError('Given message and author needs to be '
-                                  'an <unicode> instance')
+                                  'an <unicode> instance got %r & %r instead'
+                                  % (type(message), type(author)))
 
         if branch is None:
             branch = MercurialRepository.DEFAULT_BRANCH_NAME
--- a/rhodecode/lib/vcs/backends/hg/repository.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/backends/hg/repository.py	Sun Sep 02 21:19:54 2012 +0200
@@ -18,7 +18,7 @@
 from rhodecode.lib.vcs.utils.ordered_dict import OrderedDict
 from rhodecode.lib.vcs.utils.paths import abspath
 
-from ...utils.hgcompat import ui, nullid, match, patch, diffopts, clone, \
+from rhodecode.lib.vcs.utils.hgcompat import ui, nullid, match, patch, diffopts, clone, \
     get_contact, pull, localrepository, RepoLookupError, Abort, RepoError, hex
 
 
@@ -231,6 +231,12 @@
         :param context: How many lines before/after changed lines should be
           shown. Defaults to ``3``.
         """
+        if hasattr(rev1, 'raw_id'):
+            rev1 = getattr(rev1, 'raw_id')
+
+        if hasattr(rev2, 'raw_id'):
+            rev2 = getattr(rev2, 'raw_id')
+
         # Check if given revisions are present at repository (may raise
         # ChangesetDoesNotExistError)
         if rev1 != self.EMPTY_CHANGESET:
@@ -243,7 +249,8 @@
                                         ignorews=ignore_whitespace,
                                         context=context)))
 
-    def _check_url(self, url):
+    @classmethod
+    def _check_url(cls, url):
         """
         Function will check given url and try to verify if it's a valid
         link. Sometimes it may happened that mercurial will issue basic
@@ -264,6 +271,9 @@
         if os.path.isdir(url) or url.startswith('file:'):
             return True
 
+        if('+' in url[:url.find('://')]):
+            url = url[url.find('+') + 1:]
+
         handlers = []
         test_uri, authinfo = Url(url).authinfo()
 
@@ -290,7 +300,7 @@
             return resp.code == 200
         except Exception, e:
             # means it cannot be cloned
-            raise urllib2.URLError(e)
+            raise urllib2.URLError("[%s] %s" % (url, e))
 
     def _get_repo(self, create, src_url=None, update_after_clone=False):
         """
@@ -302,6 +312,7 @@
         location at given clone_point. Additionally it'll make update to
         working copy accordingly to ``update_after_clone`` flag
         """
+
         try:
             if src_url:
                 url = str(self._get_url(src_url))
@@ -309,12 +320,13 @@
                 if not update_after_clone:
                     opts.update({'noupdate': True})
                 try:
-                    self._check_url(url)
+                    MercurialRepository._check_url(url)
                     clone(self.baseui, url, self.path, **opts)
 #                except urllib2.URLError:
 #                    raise Abort("Got HTTP 404 error")
                 except Exception:
                     raise
+
                 # Don't try to create if we've already cloned repo
                 create = False
             return localrepository(self.baseui, self.path, create=create)
--- a/rhodecode/lib/vcs/backends/hg/workdir.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/backends/hg/workdir.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,7 +1,7 @@
 from rhodecode.lib.vcs.backends.base import BaseWorkdir
 from rhodecode.lib.vcs.exceptions import BranchDoesNotExistError
 
-from ...utils.hgcompat import hg_merge
+from rhodecode.lib.vcs.utils.hgcompat import hg_merge
 
 
 class MercurialWorkdir(BaseWorkdir):
--- a/rhodecode/lib/vcs/nodes.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/nodes.py	Sun Sep 02 21:19:54 2012 +0200
@@ -16,7 +16,7 @@
 from pygments import lexers
 
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
-from rhodecode.lib.vcs.utils import safe_unicode, safe_str
+from rhodecode.lib.vcs.utils import safe_unicode
 from rhodecode.lib.vcs.exceptions import NodeError
 from rhodecode.lib.vcs.exceptions import RemovedFileNodeError
 from rhodecode.lib.vcs.backends.base import EmptyChangeset
@@ -422,7 +422,7 @@
 
     def __repr__(self):
         return '<%s %r @ %s>' % (self.__class__.__name__, self.path,
-                                 self.changeset.short_id)
+                                 getattr(self.changeset, 'short_id', ''))
 
 
 class RemovedFileNode(FileNode):
@@ -431,8 +431,10 @@
     name, kind or state (or methods/attributes checking those two) would raise
     RemovedFileNodeError.
     """
-    ALLOWED_ATTRIBUTES = ['name', 'path', 'state', 'is_root', 'is_file',
-        'is_dir', 'kind', 'added', 'changed', 'not_changed', 'removed']
+    ALLOWED_ATTRIBUTES = [
+        'name', 'path', 'state', 'is_root', 'is_file', 'is_dir', 'kind',
+        'added', 'changed', 'not_changed', 'removed'
+    ]
 
     def __init__(self, path):
         """
@@ -557,7 +559,7 @@
 
     def __repr__(self):
         return '<%s %r @ %s>' % (self.__class__.__name__, self.path,
-                                 self.changeset.short_id)
+                                 getattr(self.changeset, 'short_id', ''))
 
 
 class RootNode(DirNode):
@@ -591,7 +593,7 @@
 
     def __repr__(self):
         return '<%s %r @ %s>' % (self.__class__.__name__, self.path,
-                                 self.changeset.short_id)
+                                 getattr(self.changeset, 'short_id', ''))
 
     def _extract_submodule_url(self):
         if self.alias == 'git':
--- a/rhodecode/lib/vcs/utils/hgcompat.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/utils/hgcompat.py	Sun Sep 02 21:19:54 2012 +0200
@@ -12,3 +12,6 @@
 from mercurial.mdiff import diffopts
 from mercurial.node import hex
 from mercurial.encoding import tolocal
+from mercurial import discovery
+from mercurial import localrepo
+from mercurial import scmutil
\ No newline at end of file
--- a/rhodecode/lib/vcs/utils/lazy.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/utils/lazy.py	Sun Sep 02 21:19:54 2012 +0200
@@ -17,11 +17,12 @@
 
     def __init__(self, func):
         self._func = func
+        self.__module__ = func.__module__
         self.__name__ = func.__name__
         self.__doc__ = func.__doc__
 
     def __get__(self, obj, klass=None):
         if obj is None:
-            return None
+            return self
         result = obj.__dict__[self.__name__] = self._func(obj)
         return result
--- a/rhodecode/lib/vcs/utils/paths.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/lib/vcs/utils/paths.py	Sun Sep 02 21:19:54 2012 +0200
@@ -29,8 +29,9 @@
                 pass
     return size
 
+
 def get_user_home():
     """
     Returns home path of the user.
     """
-    return os.getenv('HOME', os.getenv('USERPROFILE'))
+    return os.getenv('HOME', os.getenv('USERPROFILE')) or ''
--- a/rhodecode/model/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -42,8 +42,8 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import logging
-
 from rhodecode.model import meta
+from rhodecode.lib.utils2 import safe_str
 
 log = logging.getLogger(__name__)
 
@@ -68,11 +68,13 @@
     :param sa: If passed it reuses this session instead of creating a new one
     """
 
+    cls = None  # override in child class
+
     def __init__(self, sa=None):
         if sa is not None:
             self.sa = sa
         else:
-            self.sa = meta.Session
+            self.sa = meta.Session()
 
     def _get_instance(self, cls, instance, callback=None):
         """
@@ -85,7 +87,7 @@
 
         if isinstance(instance, cls):
             return instance
-        elif isinstance(instance, (int, long)) or str(instance).isdigit():
+        elif isinstance(instance, (int, long)) or safe_str(instance).isdigit():
             return cls.get(instance)
         else:
             if instance:
@@ -96,3 +98,42 @@
                     )
                 else:
                     return callback(instance)
+
+    def _get_user(self, user):
+        """
+        Helper method to get user by ID, or username fallback
+
+        :param user:
+        :type user: UserID, username, or User instance
+        """
+        from rhodecode.model.db import User
+        return self._get_instance(User, user,
+                                  callback=User.get_by_username)
+
+    def _get_repo(self, repository):
+        """
+        Helper method to get repository by ID, or repository name
+
+        :param repository:
+        :type repository: RepoID, repository name or Repository Instance
+        """
+        from rhodecode.model.db import Repository
+        return self._get_instance(Repository, repository,
+                                  callback=Repository.get_by_repo_name)
+
+    def _get_perm(self, permission):
+        """
+        Helper method to get permission by ID, or permission name
+
+        :param permission:
+        :type permission: PermissionID, permission_name or Permission instance
+        """
+        from rhodecode.model.db import Permission
+        return self._get_instance(Permission, permission,
+                                  callback=Permission.get_by_key)
+
+    def get_all(self):
+        """
+        Returns all instances of what is defined in `cls` class variable
+        """
+        return self.cls.getAll()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/changeset_status.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,189 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.changeset_status
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+    :created_on: Apr 30, 2012
+    :author: marcink
+    :copyright: (C) 2011-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+
+import logging
+from collections import  defaultdict
+
+from rhodecode.model import BaseModel
+from rhodecode.model.db import ChangesetStatus, PullRequest
+from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
+
+log = logging.getLogger(__name__)
+
+
+class ChangesetStatusModel(BaseModel):
+
+    cls = ChangesetStatus
+
+    def __get_changeset_status(self, changeset_status):
+        return self._get_instance(ChangesetStatus, changeset_status)
+
+    def __get_pull_request(self, pull_request):
+        return self._get_instance(PullRequest, pull_request)
+
+    def _get_status_query(self, repo, revision, pull_request,
+                          with_revisions=False):
+        repo = self._get_repo(repo)
+
+        q = ChangesetStatus.query()\
+            .filter(ChangesetStatus.repo == repo)
+        if not with_revisions:
+            q = q.filter(ChangesetStatus.version == 0)
+
+        if revision:
+            q = q.filter(ChangesetStatus.revision == revision)
+        elif pull_request:
+            pull_request = self.__get_pull_request(pull_request)
+            q = q.filter(ChangesetStatus.pull_request == pull_request)
+        else:
+            raise Exception('Please specify revision or pull_request')
+        q.order_by(ChangesetStatus.version.asc())
+        return q
+
+    def calculate_status(self, statuses_by_reviewers):
+        """
+        leading one wins, if number of occurences are equal than weaker wins
+
+        :param statuses_by_reviewers:
+        """
+        status = None
+        votes = defaultdict(int)
+        reviewers_number = len(statuses_by_reviewers)
+        for user, statuses in statuses_by_reviewers:
+            if statuses:
+                ver, latest = statuses[0]
+                votes[latest.status] += 1
+            else:
+                votes[ChangesetStatus.DEFAULT] += 1
+
+        if votes.get(ChangesetStatus.STATUS_APPROVED) == reviewers_number:
+            return ChangesetStatus.STATUS_APPROVED
+        else:
+            return ChangesetStatus.STATUS_UNDER_REVIEW
+
+    def get_statuses(self, repo, revision=None, pull_request=None,
+                     with_revisions=False):
+        q = self._get_status_query(repo, revision, pull_request,
+                                   with_revisions)
+        return q.all()
+
+    def get_status(self, repo, revision=None, pull_request=None):
+        """
+        Returns latest status of changeset for given revision or for given
+        pull request. Statuses are versioned inside a table itself and
+        version == 0 is always the current one
+
+        :param repo:
+        :type repo:
+        :param revision: 40char hash or None
+        :type revision: str
+        :param pull_request: pull_request reference
+        :type:
+        """
+        q = self._get_status_query(repo, revision, pull_request)
+
+        # need to use first here since there can be multiple statuses
+        # returned from pull_request
+        status = q.first()
+        status = status.status if status else status
+        st = status or ChangesetStatus.DEFAULT
+        return str(st)
+
+    def set_status(self, repo, status, user, comment, revision=None,
+                   pull_request=None, dont_allow_on_closed_pull_request=False):
+        """
+        Creates new status for changeset or updates the old ones bumping their
+        version, leaving the current status at
+
+        :param repo:
+        :type repo:
+        :param revision:
+        :type revision:
+        :param status:
+        :type status:
+        :param user:
+        :type user:
+        :param comment:
+        :type comment:
+        :param dont_allow_on_closed_pull_request: don't allow a status change
+            if last status was for pull request and it's closed. We shouldn't
+            mess around this manually
+        """
+        repo = self._get_repo(repo)
+
+        q = ChangesetStatus.query()
+
+        if revision:
+            q = q.filter(ChangesetStatus.repo == repo)
+            q = q.filter(ChangesetStatus.revision == revision)
+        elif pull_request:
+            pull_request = self.__get_pull_request(pull_request)
+            q = q.filter(ChangesetStatus.repo == pull_request.org_repo)
+            q = q.filter(ChangesetStatus.pull_request == pull_request)
+        cur_statuses = q.all()
+
+        #if statuses exists and last is associated with a closed pull request
+        # we need to check if we can allow this status change
+        if (dont_allow_on_closed_pull_request and cur_statuses
+            and getattr(cur_statuses[0].pull_request, 'status', '')
+                == PullRequest.STATUS_CLOSED):
+            raise StatusChangeOnClosedPullRequestError(
+                'Changing status on closed pull request is not allowed'
+            )
+
+        if cur_statuses:
+            for st in cur_statuses:
+                st.version += 1
+                self.sa.add(st)
+
+        def _create_status(user, repo, status, comment, revision, pull_request):
+            new_status = ChangesetStatus()
+            new_status.author = self._get_user(user)
+            new_status.repo = self._get_repo(repo)
+            new_status.status = status
+            new_status.comment = comment
+            new_status.revision = revision
+            new_status.pull_request = pull_request
+            return new_status
+
+        if revision:
+            new_status = _create_status(user=user, repo=repo, status=status,
+                           comment=comment, revision=revision,
+                           pull_request=None)
+            self.sa.add(new_status)
+            return new_status
+        elif pull_request:
+            #pull request can have more than one revision associated to it
+            #we need to create new version for each one
+            new_statuses = []
+            repo = pull_request.org_repo
+            for rev in pull_request.revisions:
+                new_status = _create_status(user=user, repo=repo,
+                                            status=status, comment=comment,
+                                            revision=rev,
+                                            pull_request=pull_request)
+                new_statuses.append(new_status)
+                self.sa.add(new_status)
+            return new_statuses
--- a/rhodecode/model/comment.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/comment.py	Sun Sep 02 21:19:54 2012 +0200
@@ -32,7 +32,8 @@
 from rhodecode.lib.utils2 import extract_mentioned_users, safe_unicode
 from rhodecode.lib import helpers as h
 from rhodecode.model import BaseModel
-from rhodecode.model.db import ChangesetComment, User, Repository, Notification
+from rhodecode.model.db import ChangesetComment, User, Repository, \
+    Notification, PullRequest
 from rhodecode.model.notification import NotificationModel
 
 log = logging.getLogger(__name__)
@@ -40,9 +41,14 @@
 
 class ChangesetCommentsModel(BaseModel):
 
+    cls = ChangesetComment
+
     def __get_changeset_comment(self, changeset_comment):
         return self._get_instance(ChangesetComment, changeset_comment)
 
+    def __get_pull_request(self, pull_request):
+        return self._get_instance(PullRequest, pull_request)
+
     def _extract_mentions(self, s):
         user_objects = []
         for username in extract_mentioned_users(s):
@@ -51,41 +57,60 @@
                 user_objects.append(user_obj)
         return user_objects
 
-    def create(self, text, repo_id, user_id, revision, f_path=None,
-               line_no=None):
+    def create(self, text, repo, user, revision=None, pull_request=None,
+               f_path=None, line_no=None, status_change=None):
         """
-        Creates new comment for changeset
+        Creates new comment for changeset or pull request.
+        IF status_change is not none this comment is associated with a
+        status change of changeset or changesets associated with pull request
 
         :param text:
-        :param repo_id:
-        :param user_id:
+        :param repo:
+        :param user:
         :param revision:
+        :param pull_request:
         :param f_path:
         :param line_no:
+        :param status_change:
         """
+        if not text:
+            return
 
-        if text:
-            repo = Repository.get(repo_id)
+        repo = self._get_repo(repo)
+        user = self._get_user(user)
+        comment = ChangesetComment()
+        comment.repo = repo
+        comment.author = user
+        comment.text = text
+        comment.f_path = f_path
+        comment.line_no = line_no
+
+        if revision:
             cs = repo.scm_instance.get_changeset(revision)
             desc = "%s - %s" % (cs.short_id, h.shorter(cs.message, 256))
             author_email = cs.author_email
-            comment = ChangesetComment()
-            comment.repo = repo
-            comment.user_id = user_id
             comment.revision = revision
-            comment.text = text
-            comment.f_path = f_path
-            comment.line_no = line_no
+        elif pull_request:
+            pull_request = self.__get_pull_request(pull_request)
+            comment.pull_request = pull_request
+            desc = pull_request.pull_request_id
+        else:
+            raise Exception('Please specify revision or pull_request_id')
 
-            self.sa.add(comment)
-            self.sa.flush()
-            # make notification
-            line = ''
+        self.sa.add(comment)
+        self.sa.flush()
+
+        # make notification
+        line = ''
+        body = text
+
+        #changeset
+        if revision:
             if line_no:
                 line = _('on line %s') % line_no
             subj = safe_unicode(
-                h.link_to('Re commit: %(commit_desc)s %(line)s' % \
-                          {'commit_desc': desc, 'line': line},
+                h.link_to('Re commit: %(desc)s %(line)s' % \
+                          {'desc': desc, 'line': line},
                           h.url('changeset_home', repo_name=repo.repo_name,
                                 revision=revision,
                                 anchor='comment-%s' % comment.comment_id,
@@ -93,31 +118,51 @@
                           )
                 )
             )
-
-            body = text
-
+            notification_type = Notification.TYPE_CHANGESET_COMMENT
             # get the current participants of this changeset
             recipients = ChangesetComment.get_users(revision=revision)
-
             # add changeset author if it's in rhodecode system
             recipients += [User.get_by_email(author_email)]
-
-            NotificationModel().create(
-              created_by=user_id, subject=subj, body=body,
-              recipients=recipients, type_=Notification.TYPE_CHANGESET_COMMENT
+        #pull request
+        elif pull_request:
+            subj = safe_unicode(
+                h.link_to('Re pull request: %(desc)s %(line)s' % \
+                          {'desc': desc, 'line': line},
+                          h.url('pullrequest_show',
+                                repo_name=pull_request.other_repo.repo_name,
+                                pull_request_id=pull_request.pull_request_id,
+                                anchor='comment-%s' % comment.comment_id,
+                                qualified=True,
+                          )
+                )
             )
 
-            mention_recipients = set(self._extract_mentions(body))\
-                                    .difference(recipients)
-            if mention_recipients:
-                subj = _('[Mention]') + ' ' + subj
-                NotificationModel().create(
-                    created_by=user_id, subject=subj, body=body,
-                    recipients=mention_recipients,
-                    type_=Notification.TYPE_CHANGESET_COMMENT
-                )
+            notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
+            # get the current participants of this pull request
+            recipients = ChangesetComment.get_users(pull_request_id=
+                                                pull_request.pull_request_id)
+            # add pull request author
+            recipients += [pull_request.author]
 
-            return comment
+        # create notification objects, and emails
+        NotificationModel().create(
+          created_by=user, subject=subj, body=body,
+          recipients=recipients, type_=notification_type,
+          email_kwargs={'status_change': status_change}
+        )
+
+        mention_recipients = set(self._extract_mentions(body))\
+                                .difference(recipients)
+        if mention_recipients:
+            subj = _('[Mention]') + ' ' + subj
+            NotificationModel().create(
+                created_by=user, subject=subj, body=body,
+                recipients=mention_recipients,
+                type_=notification_type,
+                email_kwargs={'status_change': status_change}
+            )
+
+        return comment
 
     def delete(self, comment):
         """
@@ -130,21 +175,48 @@
 
         return comment
 
-    def get_comments(self, repo_id, revision):
-        return ChangesetComment.query()\
+    def get_comments(self, repo_id, revision=None, pull_request=None):
+        """
+        Get's main comments based on revision or pull_request_id
+
+        :param repo_id:
+        :type repo_id:
+        :param revision:
+        :type revision:
+        :param pull_request:
+        :type pull_request:
+        """
+
+        q = ChangesetComment.query()\
                 .filter(ChangesetComment.repo_id == repo_id)\
-                .filter(ChangesetComment.revision == revision)\
                 .filter(ChangesetComment.line_no == None)\
-                .filter(ChangesetComment.f_path == None).all()
+                .filter(ChangesetComment.f_path == None)
+        if revision:
+            q = q.filter(ChangesetComment.revision == revision)
+        elif pull_request:
+            pull_request = self.__get_pull_request(pull_request)
+            q = q.filter(ChangesetComment.pull_request == pull_request)
+        else:
+            raise Exception('Please specify revision or pull_request')
+        q = q.order_by(ChangesetComment.created_on)
+        return q.all()
 
-    def get_inline_comments(self, repo_id, revision):
-        comments = self.sa.query(ChangesetComment)\
+    def get_inline_comments(self, repo_id, revision=None, pull_request=None):
+        q = self.sa.query(ChangesetComment)\
             .filter(ChangesetComment.repo_id == repo_id)\
-            .filter(ChangesetComment.revision == revision)\
             .filter(ChangesetComment.line_no != None)\
             .filter(ChangesetComment.f_path != None)\
             .order_by(ChangesetComment.comment_id.asc())\
-            .all()
+
+        if revision:
+            q = q.filter(ChangesetComment.revision == revision)
+        elif pull_request:
+            pull_request = self.__get_pull_request(pull_request)
+            q = q.filter(ChangesetComment.pull_request == pull_request)
+        else:
+            raise Exception('Please specify revision or pull_request_id')
+
+        comments = q.all()
 
         paths = defaultdict(lambda: defaultdict(list))
 
--- a/rhodecode/model/db.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/db.py	Sun Sep 02 21:19:54 2012 +0200
@@ -27,12 +27,18 @@
 import logging
 import datetime
 import traceback
+import hashlib
+import time
 from collections import defaultdict
 
 from sqlalchemy import *
 from sqlalchemy.ext.hybrid import hybrid_property
 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
+from sqlalchemy.exc import DatabaseError
 from beaker.cache import cache_region, region_invalidate
+from webob.exc import HTTPNotFound
+
+from pylons.i18n.translation import lazy_ugettext as _
 
 from rhodecode.lib.vcs import get_backend
 from rhodecode.lib.vcs.utils.helpers import get_scm
@@ -45,9 +51,8 @@
 from rhodecode.lib.caching_query import FromCache
 
 from rhodecode.model.meta import Base, Session
-import hashlib
 
-
+URL_SEP = '/'
 log = logging.getLogger(__name__)
 
 #==============================================================================
@@ -57,37 +62,6 @@
 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
 
 
-class ModelSerializer(json.JSONEncoder):
-    """
-    Simple Serializer for JSON,
-
-    usage::
-
-        to make object customized for serialization implement a __json__
-        method that will return a dict for serialization into json
-
-    example::
-
-        class Task(object):
-
-            def __init__(self, name, value):
-                self.name = name
-                self.value = value
-
-            def __json__(self):
-                return dict(name=self.name,
-                            value=self.value)
-
-    """
-
-    def default(self, obj):
-
-        if hasattr(obj, '__json__'):
-            return obj.__json__()
-        else:
-            return json.JSONEncoder.default(self, obj)
-
-
 class BaseModel(object):
     """
     Base Model for all classess
@@ -108,8 +82,13 @@
             d[k] = getattr(self, k)
 
         # also use __json__() if present to get additional fields
-        for k, val in getattr(self, '__json__', lambda: {})().iteritems():
-            d[k] = val
+        _json_attr = getattr(self, '__json__', None)
+        if _json_attr:
+            # update with attributes from __json__
+            if callable(_json_attr):
+                _json_attr = _json_attr()
+            for k, val in _json_attr.iteritems():
+                d[k] = val
         return d
 
     def get_appstruct(self):
@@ -130,7 +109,7 @@
 
     @classmethod
     def query(cls):
-        return Session.query(cls)
+        return Session().query(cls)
 
     @classmethod
     def get(cls, id_):
@@ -138,13 +117,21 @@
             return cls.query().get(id_)
 
     @classmethod
+    def get_or_404(cls, id_):
+        if id_:
+            res = cls.query().get(id_)
+            if not res:
+                raise HTTPNotFound
+            return res
+
+    @classmethod
     def getAll(cls):
         return cls.query().all()
 
     @classmethod
     def delete(cls, id_):
         obj = cls.query().get(id_)
-        Session.delete(obj)
+        Session().delete(obj)
 
     def __repr__(self):
         if hasattr(self, '__unicode__'):
@@ -152,16 +139,17 @@
             return safe_str(self.__unicode__())
         return '<DB:%s>' % (self.__class__.__name__)
 
+
 class RhodeCodeSetting(Base, BaseModel):
     __tablename__ = 'rhodecode_settings'
     __table_args__ = (
         UniqueConstraint('app_settings_name'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
     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=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
     def __init__(self, k='', v=''):
         self.app_settings_name = k
@@ -195,9 +183,16 @@
         )
 
     @classmethod
-    def get_by_name(cls, ldap_key):
+    def get_by_name(cls, key):
         return cls.query()\
-            .filter(cls.app_settings_name == ldap_key).scalar()
+            .filter(cls.app_settings_name == key).scalar()
+
+    @classmethod
+    def get_by_name_or_create(cls, key):
+        res = cls.get_by_name(key)
+        if not res:
+            res = cls(key)
+        return res
 
     @classmethod
     def get_app_settings(cls, cache=False):
@@ -222,7 +217,7 @@
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
-            fd.update({row.app_settings_name:row.app_settings_value})
+            fd.update({row.app_settings_name: row.app_settings_value})
 
         return fd
 
@@ -231,71 +226,82 @@
     __tablename__ = 'rhodecode_ui'
     __table_args__ = (
         UniqueConstraint('ui_key'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
 
     HOOK_UPDATE = 'changegroup.update'
     HOOK_REPO_SIZE = 'changegroup.repo_size'
-    HOOK_PUSH = 'pretxnchangegroup.push_logger'
-    HOOK_PULL = 'preoutgoing.pull_logger'
+    HOOK_PUSH = 'changegroup.push_logger'
+    HOOK_PRE_PUSH = 'prechangegroup.pre_push'
+    HOOK_PULL = 'outgoing.pull_logger'
+    HOOK_PRE_PULL = 'preoutgoing.pre_pull'
 
     ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
 
     @classmethod
     def get_by_key(cls, key):
-        return cls.query().filter(cls.ui_key == key)
+        return cls.query().filter(cls.ui_key == key).scalar()
 
     @classmethod
     def get_builtin_hooks(cls):
         q = cls.query()
-        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
-                                    cls.HOOK_REPO_SIZE,
-                                    cls.HOOK_PUSH, cls.HOOK_PULL]))
+        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
+                                     cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
+                                     cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
         return q.all()
 
     @classmethod
     def get_custom_hooks(cls):
         q = cls.query()
-        q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
-                                    cls.HOOK_REPO_SIZE,
-                                    cls.HOOK_PUSH, cls.HOOK_PULL]))
+        q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
+                                      cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
+                                      cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
         q = q.filter(cls.ui_section == 'hooks')
         return q.all()
 
     @classmethod
+    def get_repos_location(cls):
+        return cls.get_by_key('/').ui_value
+
+    @classmethod
     def create_or_update_hook(cls, key, val):
-        new_ui = cls.get_by_key(key).scalar() or cls()
+        new_ui = cls.get_by_key(key) or cls()
         new_ui.ui_section = 'hooks'
         new_ui.ui_active = True
         new_ui.ui_key = key
         new_ui.ui_value = val
 
-        Session.add(new_ui)
+        Session().add(new_ui)
 
 
 class User(Base, BaseModel):
     __tablename__ = 'users'
     __table_args__ = (
         UniqueConstraint('username'), UniqueConstraint('email'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        Index('u_username_idx', 'username'),
+        Index('u_email_idx', 'email'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
+    DEFAULT_USER = 'default'
+
     user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    active = Column("active", Boolean(), nullable=True, unique=None, default=None)
+    username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    active = Column("active", Boolean(), nullable=True, unique=None, default=True)
     admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
-    name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    _email = Column("email", String(255, 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)
-    ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
 
     user_log = relationship('UserLog', cascade='all')
     user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
@@ -312,6 +318,8 @@
     user_created_notifications = relationship('Notification', cascade='all')
     # comments created by this user
     user_comments = relationship('ChangesetComment', cascade='all')
+    #extra emails for this user
+    user_emails = relationship('UserEmailMap', cascade='all')
 
     @hybrid_property
     def email(self):
@@ -322,21 +330,35 @@
         self._email = val.lower() if val else None
 
     @property
+    def firstname(self):
+        # alias for future
+        return self.name
+
+    @property
+    def emails(self):
+        other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
+        return [self.email] + [x.email for x in other]
+
+    @property
+    def username_and_name(self):
+        return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
+
+    @property
     def full_name(self):
-        return '%s %s' % (self.name, self.lastname)
+        return '%s %s' % (self.firstname, self.lastname)
 
     @property
     def full_name_or_username(self):
-        return ('%s %s' % (self.name, self.lastname)
-                if (self.name and self.lastname) else self.username)
+        return ('%s %s' % (self.firstname, self.lastname)
+                if (self.firstname and self.lastname) else self.username)
 
     @property
     def full_contact(self):
-        return '%s %s <%s>' % (self.name, self.lastname, self.email)
+        return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
 
     @property
     def short_contact(self):
-        return '%s %s' % (self.name, self.lastname)
+        return '%s %s' % (self.firstname, self.lastname)
 
     @property
     def is_admin(self):
@@ -379,40 +401,105 @@
 
         if cache:
             q = q.options(FromCache("sql_cache_short",
-                                    "get_api_key_%s" % email))
-        return q.scalar()
+                                    "get_email_key_%s" % email))
+
+        ret = q.scalar()
+        if ret is None:
+            q = UserEmailMap.query()
+            # try fetching in alternate email map
+            if case_insensitive:
+                q = q.filter(UserEmailMap.email.ilike(email))
+            else:
+                q = q.filter(UserEmailMap.email == email)
+            q = q.options(joinedload(UserEmailMap.user))
+            if cache:
+                q = q.options(FromCache("sql_cache_short",
+                                        "get_email_map_key_%s" % email))
+            ret = getattr(q.scalar(), 'user', None)
+
+        return ret
 
     def update_lastlogin(self):
         """Update user lastlogin"""
         self.last_login = datetime.datetime.now()
-        Session.add(self)
+        Session().add(self)
         log.debug('updated user %s lastlogin' % self.username)
 
+    def get_api_data(self):
+        """
+        Common function for generating user related data for API
+        """
+        user = self
+        data = dict(
+            user_id=user.user_id,
+            username=user.username,
+            firstname=user.name,
+            lastname=user.lastname,
+            email=user.email,
+            emails=user.emails,
+            api_key=user.api_key,
+            active=user.active,
+            admin=user.admin,
+            ldap_dn=user.ldap_dn,
+            last_login=user.last_login,
+        )
+        return data
+
     def __json__(self):
-        return dict(
-            user_id=self.user_id,
-            first_name=self.name,
-            last_name=self.lastname,
-            email=self.email,
+        data = dict(
             full_name=self.full_name,
             full_name_or_username=self.full_name_or_username,
             short_contact=self.short_contact,
             full_contact=self.full_contact
         )
+        data.update(self.get_api_data())
+        return data
+
+
+class UserEmailMap(Base, BaseModel):
+    __tablename__ = 'user_email_map'
+    __table_args__ = (
+        Index('uem_email_idx', 'email'),
+        UniqueConstraint('email'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    __mapper_args__ = {}
+
+    email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
+    _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
+    user = relationship('User', lazy='joined')
+
+    @validates('_email')
+    def validate_email(self, key, email):
+        # check if this email is not main one
+        main_email = Session().query(User).filter(User.email == email).scalar()
+        if main_email is not None:
+            raise AttributeError('email %s is present is user table' % email)
+        return email
+
+    @hybrid_property
+    def email(self):
+        return self._email
+
+    @email.setter
+    def email(self, val):
+        self._email = val.lower() if val else None
 
 
 class UserLog(Base, BaseModel):
     __tablename__ = 'user_logs'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
     user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
-    repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    action = Column("action", UnicodeText(1200000, 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)
 
     @property
@@ -426,13 +513,14 @@
 class UsersGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
 
     users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
     users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
+    inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
 
     members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
     users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
@@ -464,11 +552,22 @@
                                     "get_users_group_%s" % users_group_id))
         return users_group.get(users_group_id)
 
+    def get_api_data(self):
+        users_group = self
+
+        data = dict(
+            users_group_id=users_group.users_group_id,
+            group_name=users_group.users_group_name,
+            active=users_group.users_group_active,
+        )
+
+        return data
+
 
 class UsersGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
 
@@ -488,20 +587,24 @@
     __tablename__ = 'repositories'
     __table_args__ = (
         UniqueConstraint('repo_name'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        Index('r_repo_name_idx', 'repo_name'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
 
     repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
-    clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
-    repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
+    repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
+    repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
     user_id = Column("user_id", Integer(), ForeignKey('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)
     enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
-    description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
+    landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
+    enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
+    _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
 
     fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
@@ -513,27 +616,58 @@
     users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
     stats = relationship('Statistics', cascade='all', uselist=False)
 
-    followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
+    followers = relationship('UserFollowing',
+                             primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
+                             cascade='all')
 
     logs = relationship('UserLog')
+    comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
+
+    pull_requests_org = relationship('PullRequest',
+                    primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
+                    cascade="all, delete, delete-orphan")
+
+    pull_requests_other = relationship('PullRequest',
+                    primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
+                    cascade="all, delete, delete-orphan")
 
     def __unicode__(self):
-        return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
+        return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
                                    self.repo_name)
 
+    @hybrid_property
+    def locked(self):
+        # always should return [user_id, timelocked]
+        if self._locked:
+            _lock_info = self._locked.split(':')
+            return int(_lock_info[0]), _lock_info[1]
+        return [None, None]
+
+    @locked.setter
+    def locked(self, val):
+        if val and isinstance(val, (list, tuple)):
+            self._locked = ':'.join(map(str, val))
+        else:
+            self._locked = None
+
     @classmethod
     def url_sep(cls):
-        return '/'
+        return URL_SEP
 
     @classmethod
     def get_by_repo_name(cls, repo_name):
-        q = Session.query(cls).filter(cls.repo_name == repo_name)
+        q = Session().query(cls).filter(cls.repo_name == repo_name)
         q = q.options(joinedload(Repository.fork))\
                 .options(joinedload(Repository.user))\
                 .options(joinedload(Repository.group))
         return q.scalar()
 
     @classmethod
+    def get_by_full_path(cls, repo_full_path):
+        repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
+        return cls.get_by_repo_name(repo_name.strip(URL_SEP))
+
+    @classmethod
     def get_repo_forks(cls, repo_id):
         return cls.query().filter(Repository.fork_id == repo_id)
 
@@ -544,12 +678,26 @@
 
         :param cls:
         """
-        q = Session.query(RhodeCodeUi)\
+        q = Session().query(RhodeCodeUi)\
             .filter(RhodeCodeUi.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
 
     @property
+    def forks(self):
+        """
+        Return forks of this repo
+        """
+        return Repository.get_repo_forks(self.repo_id)
+
+    @property
+    def parent(self):
+        """
+        Returns fork parent
+        """
+        return self.fork
+
+    @property
     def just_name(self):
         return self.repo_name.split(Repository.url_sep())[-1]
 
@@ -580,7 +728,7 @@
         Returns base full path for that repository means where it actually
         exists on a filesystem
         """
-        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
+        q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
                                               Repository.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -626,10 +774,26 @@
                 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)
+            if ui_.ui_key == 'push_ssl':
+                # force set push_ssl requirement to False, rhodecode
+                # handles that
+                baseui.setconfig(ui_.ui_section, ui_.ui_key, False)
 
         return baseui
 
     @classmethod
+    def inject_ui(cls, repo, extras={}):
+        from rhodecode.lib.vcs.backends.hg import MercurialRepository
+        from rhodecode.lib.vcs.backends.git import GitRepository
+        required = (MercurialRepository, GitRepository)
+        if not isinstance(repo, required):
+            raise Exception('repo must be instance of %s' % required)
+
+        # inject ui extra param to log this action via push logger
+        for k, v in extras.items():
+            repo._repo.ui.setconfig('rhodecode_extras', k, v)
+
+    @classmethod
     def is_valid(cls, repo_name):
         """
         returns True if given repo name is a valid filesystem repository
@@ -641,6 +805,39 @@
 
         return is_valid_repo(repo_name, cls.base_path())
 
+    def get_api_data(self):
+        """
+        Common function for generating repo api data
+
+        """
+        repo = self
+        data = dict(
+            repo_id=repo.repo_id,
+            repo_name=repo.repo_name,
+            repo_type=repo.repo_type,
+            clone_uri=repo.clone_uri,
+            private=repo.private,
+            created_on=repo.created_on,
+            description=repo.description,
+            landing_rev=repo.landing_rev,
+            owner=repo.user.username,
+            fork_of=repo.fork.repo_name if repo.fork else None
+        )
+
+        return data
+
+    @classmethod
+    def lock(cls, repo, user_id):
+        repo.locked = [user_id, time.time()]
+        Session().add(repo)
+        Session().commit()
+
+    @classmethod
+    def unlock(cls, repo):
+        repo.locked = None
+        Session().add(repo)
+        Session().commit()
+
     #==========================================================================
     # SCM PROPERTIES
     #==========================================================================
@@ -648,6 +845,13 @@
     def get_changeset(self, rev=None):
         return get_changeset_safe(self.scm_instance, rev)
 
+    def get_landing_changeset(self):
+        """
+        Returns landing changeset, or if that doesn't exist returns the tip
+        """
+        cs = self.get_changeset(self.landing_rev) or self.get_changeset()
+        return cs
+
     @property
     def tip(self):
         return self.get_changeset('tip')
@@ -660,7 +864,7 @@
     def last_change(self):
         return self.scm_instance.last_change
 
-    def comments(self, revisions=None):
+    def get_comments(self, revisions=None):
         """
         Returns comments for this repository grouped by revisions
 
@@ -675,6 +879,39 @@
             grouped[cmt.revision].append(cmt)
         return grouped
 
+    def statuses(self, revisions=None):
+        """
+        Returns statuses for this repository
+
+        :param revisions: list of revisions to get statuses for
+        :type revisions: list
+        """
+
+        statuses = ChangesetStatus.query()\
+            .filter(ChangesetStatus.repo == self)\
+            .filter(ChangesetStatus.version == 0)
+        if revisions:
+            statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
+        grouped = {}
+
+        #maybe we have open new pullrequest without a status ?
+        stat = ChangesetStatus.STATUS_UNDER_REVIEW
+        status_lbl = ChangesetStatus.get_status_lbl(stat)
+        for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
+            for rev in pr.revisions:
+                pr_id = pr.pull_request_id
+                pr_repo = pr.other_repo.repo_name
+                grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
+
+        for stat in statuses.all():
+            pr_id = pr_repo = None
+            if stat.pull_request:
+                pr_id = stat.pull_request.pull_request_id
+                pr_repo = stat.pull_request.other_repo.repo_name
+            grouped[stat.revision] = [str(stat.status), stat.status_lbl,
+                                      pr_id, pr_repo]
+        return grouped
+
     #==========================================================================
     # SCM CACHE INSTANCE
     #==========================================================================
@@ -693,18 +930,27 @@
     def scm_instance(self):
         return self.__get_instance()
 
-    @property
-    def scm_instance_cached(self):
+    def scm_instance_cached(self, cache_map=None):
         @cache_region('long_term')
         def _c(repo_name):
             return self.__get_instance()
         rn = self.repo_name
         log.debug('Getting cached instance of repo')
-        inv = self.invalidate
-        if inv is not None:
+
+        if cache_map:
+            # get using prefilled cache_map
+            invalidate_repo = cache_map[self.repo_name]
+            if invalidate_repo:
+                invalidate_repo = (None if invalidate_repo.cache_active
+                                   else invalidate_repo)
+        else:
+            # get from invalidate
+            invalidate_repo = self.invalidate
+
+        if invalidate_repo is not None:
             region_invalidate(_c, None, rn)
             # update our cache
-            CacheInvalidation.set_valid(inv.cache_key)
+            CacheInvalidation.set_valid(invalidate_repo.cache_key)
         return _c(rn)
 
     def __get_instance(self):
@@ -738,15 +984,16 @@
     __table_args__ = (
         UniqueConstraint('group_name', 'group_parent_id'),
         CheckConstraint('group_id != group_parent_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
     __mapper_args__ = {'order_by': 'group_name'}
 
     group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
+    group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
     group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
-    group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
     users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
@@ -776,7 +1023,7 @@
 
     @classmethod
     def url_sep(cls):
-        return '/'
+        return URL_SEP
 
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
@@ -853,6 +1100,24 @@
 
         return cnt + children_count(self)
 
+    def recursive_groups_and_repos(self):
+        """
+        Recursive return all groups, with repositories in those groups
+        """
+        all_ = []
+
+        def _get_members(root_gr):
+            for r in root_gr.repositories:
+                all_.append(r)
+            childs = root_gr.children.all()
+            if childs:
+                for gr in childs:
+                    all_.append(gr)
+                    _get_members(gr)
+
+        _get_members(self)
+        return [self] + all_
+
     def get_new_name(self, group_name):
         """
         returns new full group name based on parent and new name
@@ -867,12 +1132,55 @@
 class Permission(Base, BaseModel):
     __tablename__ = 'permissions'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        Index('p_perm_name_idx', 'permission_name'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
+    PERMS = [
+        ('repository.none', _('Repository no access')),
+        ('repository.read', _('Repository read access')),
+        ('repository.write', _('Repository write access')),
+        ('repository.admin', _('Repository admin access')),
+
+        ('group.none', _('Repositories Group no access')),
+        ('group.read', _('Repositories Group read access')),
+        ('group.write', _('Repositories Group write access')),
+        ('group.admin', _('Repositories Group admin access')),
+
+        ('hg.admin', _('RhodeCode Administrator')),
+        ('hg.create.none', _('Repository creation disabled')),
+        ('hg.create.repository', _('Repository creation enabled')),
+        ('hg.fork.none', _('Repository forking disabled')),
+        ('hg.fork.repository', _('Repository forking enabled')),
+        ('hg.register.none', _('Register disabled')),
+        ('hg.register.manual_activate', _('Register new user with RhodeCode '
+                                          'with manual activation')),
+
+        ('hg.register.auto_activate', _('Register new user with RhodeCode '
+                                        'with auto activation')),
+    ]
+
+    # defines which permissions are more important higher the more important
+    PERM_WEIGHTS = {
+        'repository.none': 0,
+        'repository.read': 1,
+        'repository.write': 3,
+        'repository.admin': 4,
+
+        'group.none': 0,
+        'group.read': 1,
+        'group.write': 3,
+        'group.admin': 4,
+
+        'hg.fork.none': 0,
+        'hg.fork.repository': 1,
+        'hg.create.none': 0,
+        'hg.create.repository':1
+    }
+
     permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
     def __unicode__(self):
         return u"<%s('%s:%s')>" % (
@@ -885,7 +1193,7 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session.query(UserRepoToPerm, Repository, cls)\
+        q = Session().query(UserRepoToPerm, Repository, cls)\
          .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
          .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
          .filter(UserRepoToPerm.user_id == default_user_id)
@@ -894,7 +1202,7 @@
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
          .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
          .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
@@ -906,7 +1214,7 @@
     __tablename__ = 'repo_to_perm'
     __table_args__ = (
         UniqueConstraint('user_id', 'repository_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
     repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -924,7 +1232,7 @@
         n.user = user
         n.repository = repository
         n.permission = permission
-        Session.add(n)
+        Session().add(n)
         return n
 
     def __unicode__(self):
@@ -935,7 +1243,7 @@
     __tablename__ = 'user_to_perm'
     __table_args__ = (
         UniqueConstraint('user_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
     user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -950,7 +1258,7 @@
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
         UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
     users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -968,7 +1276,7 @@
         n.users_group = users_group
         n.repository = repository
         n.permission = permission
-        Session.add(n)
+        Session().add(n)
         return n
 
     def __unicode__(self):
@@ -979,7 +1287,7 @@
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'permission_id',),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
     users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -994,7 +1302,7 @@
     __tablename__ = 'user_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('user_id', 'group_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
 
@@ -1012,7 +1320,7 @@
     __tablename__ = 'users_group_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'group_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
 
@@ -1030,7 +1338,7 @@
     __tablename__ = 'statistics'
     __table_args__ = (
          UniqueConstraint('repository_id'),
-         {'extend_existing': True, 'mysql_engine':'InnoDB',
+         {'extend_existing': True, 'mysql_engine': 'InnoDB',
           'mysql_charset': 'utf8'}
     )
     stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
@@ -1048,7 +1356,7 @@
     __table_args__ = (
         UniqueConstraint('user_id', 'follows_repository_id'),
         UniqueConstraint('user_id', 'follows_user_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
 
@@ -1072,12 +1380,13 @@
     __tablename__ = 'cache_invalidation'
     __table_args__ = (
         UniqueConstraint('cache_key'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        Index('key_idx', 'cache_key'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
     cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
-    cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    cache_args = Column("cache_args", String(255, 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=''):
@@ -1088,6 +1397,7 @@
     def __unicode__(self):
         return u"<%s('%s:%s')>" % (self.__class__.__name__,
                                   self.cache_id, self.cache_key)
+
     @classmethod
     def clear_cache(cls):
         cls.query().delete()
@@ -1112,15 +1422,15 @@
 
     @classmethod
     def _get_or_create_key(cls, key, prefix, org_key):
-        inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
+        inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
         if not inv_obj:
             try:
                 inv_obj = CacheInvalidation(key, org_key)
-                Session.add(inv_obj)
-                Session.commit()
+                Session().add(inv_obj)
+                Session().commit()
             except Exception:
                 log.error(traceback.format_exc())
-                Session.rollback()
+                Session().rollback()
         return inv_obj
 
     @classmethod
@@ -1148,7 +1458,7 @@
         """
 
         key, _prefix, _org_key = cls._get_key(key)
-        inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
+        inv_objs = Session().query(cls).filter(cls.cache_args == _org_key).all()
         log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
                                                              _org_key))
         try:
@@ -1156,11 +1466,11 @@
                 if inv_obj:
                     inv_obj.cache_active = False
 
-                Session.add(inv_obj)
-            Session.commit()
+                Session().add(inv_obj)
+            Session().commit()
         except Exception:
             log.error(traceback.format_exc())
-            Session.rollback()
+            Session().rollback()
 
     @classmethod
     def set_valid(cls, key):
@@ -1171,46 +1481,211 @@
         """
         inv_obj = cls.get_by_key(key)
         inv_obj.cache_active = True
-        Session.add(inv_obj)
-        Session.commit()
+        Session().add(inv_obj)
+        Session().commit()
+
+    @classmethod
+    def get_cache_map(cls):
+
+        class cachemapdict(dict):
+
+            def __init__(self, *args, **kwargs):
+                fixkey = kwargs.get('fixkey')
+                if fixkey:
+                    del kwargs['fixkey']
+                self.fixkey = fixkey
+                super(cachemapdict, self).__init__(*args, **kwargs)
+
+            def __getattr__(self, name):
+                key = name
+                if self.fixkey:
+                    key, _prefix, _org_key = cls._get_key(key)
+                if key in self.__dict__:
+                    return self.__dict__[key]
+                else:
+                    return self[key]
+
+            def __getitem__(self, key):
+                if self.fixkey:
+                    key, _prefix, _org_key = cls._get_key(key)
+                try:
+                    return super(cachemapdict, self).__getitem__(key)
+                except KeyError:
+                    return
+
+        cache_map = cachemapdict(fixkey=True)
+        for obj in cls.query().all():
+            cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
+        return cache_map
 
 
 class ChangesetComment(Base, BaseModel):
     __tablename__ = 'changeset_comments'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        Index('cc_revision_idx', 'revision'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
     comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
     repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
-    revision = Column('revision', String(40), nullable=False)
+    revision = Column('revision', String(40), nullable=True)
+    pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
     line_no = Column('line_no', Unicode(10), nullable=True)
+    hl_lines = Column('hl_lines', Unicode(512), nullable=True)
     f_path = Column('f_path', Unicode(1000), nullable=True)
     user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
     text = Column('text', Unicode(25000), nullable=False)
-    modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
+    created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
     author = relationship('User', lazy='joined')
     repo = relationship('Repository')
+    status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
+    pull_request = relationship('PullRequest', lazy='joined')
 
     @classmethod
-    def get_users(cls, revision):
+    def get_users(cls, revision=None, pull_request_id=None):
         """
-        Returns user associated with this changesetComment. ie those
+        Returns user associated with this ChangesetComment. ie those
         who actually commented
 
         :param cls:
         :param revision:
         """
-        return Session.query(User)\
-                .filter(cls.revision == revision)\
-                .join(ChangesetComment.author).all()
+        q = Session().query(User)\
+                .join(ChangesetComment.author)
+        if revision:
+            q = q.filter(cls.revision == revision)
+        elif pull_request_id:
+            q = q.filter(cls.pull_request_id == pull_request_id)
+        return q.all()
+
+
+class ChangesetStatus(Base, BaseModel):
+    __tablename__ = 'changeset_statuses'
+    __table_args__ = (
+        Index('cs_revision_idx', 'revision'),
+        Index('cs_version_idx', 'version'),
+        UniqueConstraint('repo_id', 'revision', 'version'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
+         'mysql_charset': 'utf8'}
+    )
+    STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
+    STATUS_APPROVED = 'approved'
+    STATUS_REJECTED = 'rejected'
+    STATUS_UNDER_REVIEW = 'under_review'
+
+    STATUSES = [
+        (STATUS_NOT_REVIEWED, _("Not Reviewed")),  # (no icon) and default
+        (STATUS_APPROVED, _("Approved")),
+        (STATUS_REJECTED, _("Rejected")),
+        (STATUS_UNDER_REVIEW, _("Under Review")),
+    ]
+
+    changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
+    repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
+    revision = Column('revision', String(40), nullable=False)
+    status = Column('status', String(128), nullable=False, default=DEFAULT)
+    changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
+    modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
+    version = Column('version', Integer(), nullable=False, default=0)
+    pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
+
+    author = relationship('User', lazy='joined')
+    repo = relationship('Repository')
+    comment = relationship('ChangesetComment', lazy='joined')
+    pull_request = relationship('PullRequest', lazy='joined')
+
+    def __unicode__(self):
+        return u"<%s('%s:%s')>" % (
+            self.__class__.__name__,
+            self.status, self.author
+        )
+
+    @classmethod
+    def get_status_lbl(cls, value):
+        return dict(cls.STATUSES).get(value)
+
+    @property
+    def status_lbl(self):
+        return ChangesetStatus.get_status_lbl(self.status)
+
+
+class PullRequest(Base, BaseModel):
+    __tablename__ = 'pull_requests'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+
+    STATUS_NEW = u'new'
+    STATUS_OPEN = u'open'
+    STATUS_CLOSED = u'closed'
+
+    pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
+    title = Column('title', Unicode(256), nullable=True)
+    description = Column('description', UnicodeText(10240), nullable=True)
+    status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
+    created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
+    _revisions = Column('revisions', UnicodeText(20500))  # 500 revisions max
+    org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
+    org_ref = Column('org_ref', Unicode(256), nullable=False)
+    other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
+    other_ref = Column('other_ref', Unicode(256), nullable=False)
+
+    @hybrid_property
+    def revisions(self):
+        return self._revisions.split(':')
+
+    @revisions.setter
+    def revisions(self, val):
+        self._revisions = ':'.join(val)
+
+    author = relationship('User', lazy='joined')
+    reviewers = relationship('PullRequestReviewers',
+                             cascade="all, delete, delete-orphan")
+    org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
+    other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
+    statuses = relationship('ChangesetStatus')
+    comments = relationship('ChangesetComment',
+                             cascade="all, delete, delete-orphan")
+
+    def is_closed(self):
+        return self.status == self.STATUS_CLOSED
+
+    def __json__(self):
+        return dict(
+          revisions=self.revisions
+        )
+
+
+class PullRequestReviewers(Base, BaseModel):
+    __tablename__ = 'pull_request_reviewers'
+    __table_args__ = (
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
+         'mysql_charset': 'utf8'},
+    )
+
+    def __init__(self, user=None, pull_request=None):
+        self.user = user
+        self.pull_request = pull_request
+
+    pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
+    pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
+    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
+
+    user = relationship('User')
+    pull_request = relationship('PullRequest')
 
 
 class Notification(Base, BaseModel):
     __tablename__ = 'notifications'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        Index('notification_type_idx', 'type'),
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
 
@@ -1218,10 +1693,12 @@
     TYPE_MESSAGE = u'message'
     TYPE_MENTION = u'mention'
     TYPE_REGISTRATION = u'registration'
+    TYPE_PULL_REQUEST = u'pull_request'
+    TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
 
     notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
     subject = Column('subject', Unicode(512), nullable=True)
-    body = Column('body', Unicode(50000), nullable=True)
+    body = Column('body', UnicodeText(50000), nullable=True)
     created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
     created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
     type_ = Column('type', Unicode(256))
@@ -1234,7 +1711,7 @@
     def recipients(self):
         return [x.user for x in UserNotification.query()\
                 .filter(UserNotification.notification == self)\
-                .order_by(UserNotification.user).all()]
+                .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
     def create(cls, created_by, subject, body, recipients, type_=None):
@@ -1252,7 +1729,7 @@
             assoc = UserNotification()
             assoc.notification = notification
             u.notifications.append(assoc)
-        Session.add(notification)
+        Session().add(notification)
         return notification
 
     @property
@@ -1265,7 +1742,7 @@
     __tablename__ = 'user_to_notification'
     __table_args__ = (
         UniqueConstraint('user_id', 'notification_id'),
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
     user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
@@ -1279,13 +1756,13 @@
 
     def mark_as_read(self):
         self.read = True
-        Session.add(self)
+        Session().add(self)
 
 
 class DbMigrateVersion(Base, BaseModel):
     __tablename__ = 'db_migrate_version'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine':'InnoDB',
+        {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'},
     )
     repository_id = Column('repository_id', String(250), primary_key=True)
--- a/rhodecode/model/forms.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/forms.py	Sun Sep 02 21:19:54 2012 +0200
@@ -19,573 +19,77 @@
 for SELECT use formencode.All(OneOf(list), Int())
 
 """
-import os
-import re
 import logging
-import traceback
 
 import formencode
 from formencode import All
-from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
-    Email, Bool, StringBoolean, Set
 
 from pylons.i18n.translation import _
-from webhelpers.pylonslib.secure_form import authentication_token
 
-from rhodecode.config.routing import ADMIN_PREFIX
-from rhodecode.lib.utils import repo_name_slug
-from rhodecode.lib.auth import authenticate, get_crypt_password
-from rhodecode.lib.exceptions import LdapImportError
-from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
+from rhodecode.model import validators as v
 from rhodecode import BACKENDS
 
 log = logging.getLogger(__name__)
 
 
-#this is needed to translate the messages using _() in validators
-class State_obj(object):
-    _ = staticmethod(_)
-
-
-#==============================================================================
-# VALIDATORS
-#==============================================================================
-class ValidAuthToken(formencode.validators.FancyValidator):
-    messages = {'invalid_token': _('Token mismatch')}
-
-    def validate_python(self, value, state):
-
-        if value != authentication_token():
-            raise formencode.Invalid(
-                self.message('invalid_token',
-                             state, search_number=value),
-                value,
-                state
-            )
-
-
-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 unique
-            old_un = None
-            if edit:
-                old_un = User.get(old_data.get('user_id')).username
-
-            if old_un != value or not edit:
-                if User.get_by_username(value, case_insensitive=True):
-                    raise formencode.Invalid(_('This username already '
-                                               'exists') , value, state)
-
-            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, periods or dashes and must begin with '
-                      'alphanumeric character'),
-                    value,
-                    state
-                )
-
-    return _ValidUsername
-
-
-def ValidUsersGroup(edit, old_data):
-
-    class _ValidUsersGroup(formencode.validators.FancyValidator):
-
-        def validate_python(self, value, state):
-            if value in ['default']:
-                raise formencode.Invalid(_('Invalid group name'), value, state)
-            #check if group is unique
-            old_ugname = None
-            if edit:
-                old_ugname = UsersGroup.get(
-                            old_data.get('users_group_id')).users_group_name
-
-            if old_ugname != value or not edit:
-                if UsersGroup.get_by_group_name(value, cache=False,
-                                               case_insensitive=True):
-                    raise formencode.Invalid(_('This users group '
-                                               'already exists'), value,
-                                             state)
-
-            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
-                raise formencode.Invalid(
-                    _('RepoGroup name may only contain  alphanumeric characters '
-                      'underscores, periods or dashes and must begin with '
-                      'alphanumeric character'),
-                    value,
-                    state
-                )
-
-    return _ValidUsersGroup
-
-
-def ValidReposGroup(edit, old_data):
-    class _ValidReposGroup(formencode.validators.FancyValidator):
-
-        def validate_python(self, value, state):
-            # TODO WRITE VALIDATIONS
-            group_name = value.get('group_name')
-            group_parent_id = value.get('group_parent_id')
-
-            # slugify repo group just in case :)
-            slug = repo_name_slug(group_name)
-
-            # check for parent of self
-            parent_of_self = lambda: (
-                old_data['group_id'] == int(group_parent_id)
-                if group_parent_id else False
-            )
-            if edit and parent_of_self():
-                    e_dict = {
-                        'group_parent_id': _('Cannot assign this group as parent')
-                    }
-                    raise formencode.Invalid('', value, state,
-                                             error_dict=e_dict)
-
-            old_gname = None
-            if edit:
-                old_gname = RepoGroup.get(old_data.get('group_id')).group_name
-
-            if old_gname != group_name or not edit:
-
-                # check group
-                gr = RepoGroup.query()\
-                      .filter(RepoGroup.group_name == slug)\
-                      .filter(RepoGroup.group_parent_id == group_parent_id)\
-                      .scalar()
-
-                if gr:
-                    e_dict = {
-                        'group_name': _('This group already exists')
-                    }
-                    raise formencode.Invalid('', value, state,
-                                             error_dict=e_dict)
-
-                # check for same repo
-                repo = Repository.query()\
-                      .filter(Repository.repo_name == slug)\
-                      .scalar()
-
-                if repo:
-                    e_dict = {
-                        'group_name': _('Repository with this name already exists')
-                    }
-                    raise formencode.Invalid('', value, state,
-                                             error_dict=e_dict)
-
-    return _ValidReposGroup
-
-
-class ValidPassword(formencode.validators.FancyValidator):
-
-    def to_python(self, value, state):
-
-        if not value:
-            return
-
-        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):
-
-        pass_val = value.get('password') or value.get('new_password')
-        if pass_val != value['password_confirmation']:
-            e_dict = {'password_confirmation':
-                   _('Passwords 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 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 = User.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 failed to authenticate' % 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):
-        try:
-            User.query().filter(User.active == True)\
-                .filter(User.username == value).one()
-        except Exception:
-            raise formencode.Invalid(_('This username is not valid'),
-                                     value, state)
-        return value
-
-
-def ValidRepoName(edit, old_data):
-    class _ValidRepoName(formencode.validators.FancyValidator):
-        def to_python(self, value, state):
-
-            repo_name = value.get('repo_name')
-
-            slug = repo_name_slug(repo_name)
-            if slug in [ADMIN_PREFIX, '']:
-                e_dict = {'repo_name': _('This repository name is disallowed')}
-                raise formencode.Invalid('', value, state, error_dict=e_dict)
-
-            if value.get('repo_group'):
-                gr = RepoGroup.get(value.get('repo_group'))
-                group_path = gr.full_path
-                # value needs to be aware of group name in order to check
-                # db key This is an actual just the name to store in the
-                # database
-                repo_name_full = group_path + RepoGroup.url_sep() + repo_name
-
-            else:
-                group_path = ''
-                repo_name_full = repo_name
-
-            value['repo_name_full'] = repo_name_full
-            rename = old_data.get('repo_name') != repo_name_full
-            create = not edit
-            if  rename or create:
-
-                if group_path != '':
-                    if Repository.get_by_repo_name(repo_name_full):
-                        e_dict = {
-                            'repo_name': _('This repository already exists in '
-                                           'a group "%s"') % gr.group_name
-                        }
-                        raise formencode.Invalid('', value, state,
-                                                 error_dict=e_dict)
-                elif RepoGroup.get_by_group_name(repo_name_full):
-                        e_dict = {
-                            'repo_name': _('There is a group with this name '
-                                           'already "%s"') % repo_name_full
-                        }
-                        raise formencode.Invalid('', value, state,
-                                                 error_dict=e_dict)
-
-                elif Repository.get_by_repo_name(repo_name_full):
-                        e_dict = {'repo_name': _('This repository '
-                                                'already exists')}
-                        raise formencode.Invalid('', value, state,
-                                                 error_dict=e_dict)
-
-            return value
-
-    return _ValidRepoName
-
-
-def ValidForkName(*args, **kwargs):
-    return ValidRepoName(*args, **kwargs)
-
-
-def SlugifyName():
-    class _SlugifyName(formencode.validators.FancyValidator):
-
-        def to_python(self, value, state):
-            return repo_name_slug(value)
-
-    return _SlugifyName
-
-
-def ValidCloneUri():
-    from rhodecode.lib.utils import make_ui
-
-    def url_handler(repo_type, url, proto, ui=None):
-        if repo_type == 'hg':
-            from mercurial.httprepo import httprepository, httpsrepository
-            if proto == 'https':
-                httpsrepository(make_ui('db'), url).capabilities
-            elif proto == 'http':
-                httprepository(make_ui('db'), url).capabilities
-        elif repo_type == 'git':
-            #TODO: write a git url validator
-            pass
-
-    class _ValidCloneUri(formencode.validators.FancyValidator):
-
-        def to_python(self, value, state):
-
-            repo_type = value.get('repo_type')
-            url = value.get('clone_uri')
-            e_dict = {'clone_uri': _('invalid clone url')}
-
-            if not url:
-                pass
-            elif url.startswith('https'):
-                try:
-                    url_handler(repo_type, url, 'https', make_ui('db'))
-                except Exception:
-                    log.error(traceback.format_exc())
-                    raise formencode.Invalid('', value, state, error_dict=e_dict)
-            elif url.startswith('http'):
-                try:
-                    url_handler(repo_type, url, 'http', make_ui('db'))
-                except Exception:
-                    log.error(traceback.format_exc())
-                    raise formencode.Invalid('', value, state, error_dict=e_dict)
-            else:
-                e_dict = {'clone_uri': _('Invalid clone url, provide a '
-                                         'valid clone http\s url')}
-                raise formencode.Invalid('', value, state, error_dict=e_dict)
-
-            return value
-
-    return _ValidCloneUri
-
-
-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
-
-
-def ValidPerms(type_='repo'):
-    if type_ == 'group':
-        EMPTY_PERM = 'group.none'
-    elif type_ == 'repo':
-        EMPTY_PERM = 'repository.none'
-
-    class _ValidPerms(formencode.validators.FancyValidator):
-        messages = {
-            'perm_new_member_name':
-                _('This username or users group name is not valid')
-        }
-
-        def to_python(self, value, state):
-            perms_update = []
-            perms_new = []
-            # build a list of permission to update and new permission to create
-            for k, v in value.items():
-                # means new added member to permissions
-                if k.startswith('perm_new_member'):
-                    new_perm = value.get('perm_new_member', False)
-                    new_member = value.get('perm_new_member_name', False)
-                    new_type = value.get('perm_new_member_type')
-
-                    if new_member and new_perm:
-                        if (new_member, new_perm, new_type) not in perms_new:
-                            perms_new.append((new_member, new_perm, new_type))
-                elif k.startswith('u_perm_') or k.startswith('g_perm_'):
-                    member = k[7:]
-                    t = {'u': 'user',
-                         'g': 'users_group'
-                    }[k[0]]
-                    if member == 'default':
-                        if value.get('private'):
-                            # set none for default when updating to private repo
-                            v = EMPTY_PERM
-                    perms_update.append((member, v, t))
-
-            value['perms_updates'] = perms_update
-            value['perms_new'] = perms_new
-
-            # update permissions
-            for k, v, t in perms_new:
-                try:
-                    if t is 'user':
-                        self.user_db = User.query()\
-                            .filter(User.active == True)\
-                            .filter(User.username == k).one()
-                    if t is 'users_group':
-                        self.user_db = UsersGroup.query()\
-                            .filter(UsersGroup.users_group_active == True)\
-                            .filter(UsersGroup.users_group_name == k).one()
-
-                except Exception:
-                    msg = self.message('perm_new_member_name',
-                                         state=State_obj)
-                    raise formencode.Invalid(
-                        msg, value, state, error_dict={'perm_new_member_name': msg}
-                    )
-            return value
-    return _ValidPerms
-
-
-class ValidSettings(formencode.validators.FancyValidator):
-
-    def to_python(self, value, state):
-        # settings  form can't edit user
-        if 'user' in value:
-            del['value']['user']
-        return value
-
-
-class ValidPath(formencode.validators.FancyValidator):
-    def to_python(self, value, state):
-
-        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') or '').lower() != value:
-                user = User.get_by_email(value, case_insensitive=True)
-                if user:
-                    raise formencode.Invalid(
-                        _("This e-mail address is already taken"), value, state
-                    )
-            return value
-
-    return _UniqSystemEmail
-
-
-class ValidSystemEmail(formencode.validators.FancyValidator):
-    def to_python(self, value, state):
-        value = value.lower()
-        user = User.get_by_email(value, case_insensitive=True)
-        if  user is None:
-            raise formencode.Invalid(
-                _("This e-mail address doesn't exist."), value, state
-            )
-
-        return value
-
-
-class LdapLibValidator(formencode.validators.FancyValidator):
-
-    def to_python(self, value, state):
-
-        try:
-            import ldap
-        except ImportError:
-            raise LdapImportError
-        return value
-
-
-class AttrLoginValidator(formencode.validators.FancyValidator):
-
-    def to_python(self, value, state):
-
-        if not value or not isinstance(value, (str, unicode)):
-            raise formencode.Invalid(
-                _("The LDAP Login attribute of the CN must be specified - "
-                  "this is the name of the attribute that is equivalent "
-                  "to 'username'"), value, state
-            )
-
-        return value
-
-
-#==============================================================================
-# FORMS
-#==============================================================================
 class LoginForm(formencode.Schema):
     allow_extra_fields = True
     filter_extra_fields = True
-    username = UnicodeString(
+    username = v.UnicodeString(
         strip=True,
         min=1,
         not_empty=True,
         messages={
-           'empty': _('Please enter a login'),
-           'tooShort': _('Enter a value %(min)i characters long or more')}
+           'empty': _(u'Please enter a login'),
+           'tooShort': _(u'Enter a value %(min)i characters long or more')}
     )
 
-    password = UnicodeString(
+    password = v.UnicodeString(
         strip=False,
         min=3,
         not_empty=True,
         messages={
-            'empty': _('Please enter a password'),
-            'tooShort': _('Enter %(min)i characters or more')}
+            'empty': _(u'Please enter a password'),
+            'tooShort': _(u'Enter %(min)i characters or more')}
     )
 
-    remember = StringBoolean(if_missing=False)
+    remember = v.StringBoolean(if_missing=False)
 
-    chained_validators = [ValidAuth]
+    chained_validators = [v.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(v.UnicodeString(strip=True, min=1, not_empty=True),
+                       v.ValidUsername(edit, old_data))
         if edit:
-            new_password = All(UnicodeString(strip=False, min=6, not_empty=False))
-            password_confirmation = All(UnicodeString(strip=False, min=6,
-                                                      not_empty=False))
-            admin = StringBoolean(if_missing=False)
+            new_password = All(
+                v.ValidPassword(),
+                v.UnicodeString(strip=False, min=6, not_empty=False)
+            )
+            password_confirmation = All(
+                v.ValidPassword(),
+                v.UnicodeString(strip=False, min=6, not_empty=False),
+            )
+            admin = v.StringBoolean(if_missing=False)
         else:
-            password = All(UnicodeString(strip=False, min=6, not_empty=True))
-            password_confirmation = All(UnicodeString(strip=False, min=6,
-                                                      not_empty=False))
+            password = All(
+                v.ValidPassword(),
+                v.UnicodeString(strip=False, min=6, not_empty=True)
+            )
+            password_confirmation = All(
+                v.ValidPassword(),
+                v.UnicodeString(strip=False, min=6, not_empty=False)
+            )
 
-        active = StringBoolean(if_missing=False)
-        name = UnicodeString(strip=True, min=1, not_empty=False)
-        lastname = UnicodeString(strip=True, min=1, not_empty=False)
-        email = All(Email(not_empty=True), UniqSystemEmail(old_data))
+        active = v.StringBoolean(if_missing=False)
+        firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
+        lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
+        email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
 
-        chained_validators = [ValidPasswordsMatch, ValidPassword]
+        chained_validators = [v.ValidPasswordsMatch()]
 
     return _UserForm
 
@@ -595,15 +99,18 @@
         allow_extra_fields = True
         filter_extra_fields = True
 
-        users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
-                       ValidUsersGroup(edit, old_data))
+        users_group_name = All(
+            v.UnicodeString(strip=True, min=1, not_empty=True),
+            v.ValidUsersGroup(edit, old_data)
+        )
 
-        users_group_active = StringBoolean(if_missing=False)
+        users_group_active = v.StringBoolean(if_missing=False)
 
         if edit:
-            users_group_members = OneOf(available_members, hideList=False,
-                                        testValueList=True,
-                                        if_missing=None, not_empty=False)
+            users_group_members = v.OneOf(
+                available_members, hideList=False, testValueList=True,
+                if_missing=None, not_empty=False
+            )
 
     return _UsersGroupForm
 
@@ -613,15 +120,16 @@
         allow_extra_fields = True
         filter_extra_fields = False
 
-        group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
-                               SlugifyName())
-        group_description = UnicodeString(strip=True, min=1,
+        group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
+                               v.SlugifyName())
+        group_description = v.UnicodeString(strip=True, min=1,
                                                 not_empty=True)
-        group_parent_id = OneOf(available_groups, hideList=False,
+        group_parent_id = v.OneOf(available_groups, hideList=False,
                                         testValueList=True,
                                         if_missing=None, not_empty=False)
-
-        chained_validators = [ValidReposGroup(edit, old_data), ValidPerms('group')]
+        enable_locking = v.StringBoolean(if_missing=False)
+        chained_validators = [v.ValidReposGroup(edit, old_data),
+                              v.ValidPerms('group')]
 
     return _ReposGroupForm
 
@@ -630,16 +138,24 @@
     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=False, min=6, not_empty=True))
-        password_confirmation = All(UnicodeString(strip=False, min=6, not_empty=True))
-        active = StringBoolean(if_missing=False)
-        name = UnicodeString(strip=True, min=1, not_empty=False)
-        lastname = UnicodeString(strip=True, min=1, not_empty=False)
-        email = All(Email(not_empty=True), UniqSystemEmail(old_data))
+        username = All(
+            v.ValidUsername(edit, old_data),
+            v.UnicodeString(strip=True, min=1, not_empty=True)
+        )
+        password = All(
+            v.ValidPassword(),
+            v.UnicodeString(strip=False, min=6, not_empty=True)
+        )
+        password_confirmation = All(
+            v.ValidPassword(),
+            v.UnicodeString(strip=False, min=6, not_empty=True)
+        )
+        active = v.StringBoolean(if_missing=False)
+        firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
+        lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
+        email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
 
-        chained_validators = [ValidPasswordsMatch, ValidPassword]
+        chained_validators = [v.ValidPasswordsMatch()]
 
     return _RegisterForm
 
@@ -648,67 +164,71 @@
     class _PasswordResetForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
-        email = All(ValidSystemEmail(), Email(not_empty=True))
+        email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
     return _PasswordResetForm
 
 
 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
-             repo_groups=[]):
+             repo_groups=[], landing_revs=[]):
     class _RepoForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
-                        SlugifyName())
-        clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False))
-        repo_group = OneOf(repo_groups, hideList=True)
-        repo_type = OneOf(supported_backends)
-        description = UnicodeString(strip=True, min=1, not_empty=True)
-        private = StringBoolean(if_missing=False)
-        enable_statistics = StringBoolean(if_missing=False)
-        enable_downloads = StringBoolean(if_missing=False)
+        repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
+                        v.SlugifyName())
+        clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
+        repo_group = v.OneOf(repo_groups, hideList=True)
+        repo_type = v.OneOf(supported_backends)
+        description = v.UnicodeString(strip=True, min=1, not_empty=False)
+        private = v.StringBoolean(if_missing=False)
+        enable_statistics = v.StringBoolean(if_missing=False)
+        enable_downloads = v.StringBoolean(if_missing=False)
+        enable_locking = v.StringBoolean(if_missing=False)
+        landing_rev = v.OneOf(landing_revs, hideList=True)
 
         if edit:
             #this is repo owner
-            user = All(UnicodeString(not_empty=True), ValidRepoUser)
+            user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
 
-        chained_validators = [ValidCloneUri()(),
-                              ValidRepoName(edit, old_data),
-                              ValidPerms()]
+        chained_validators = [v.ValidCloneUri(),
+                              v.ValidRepoName(edit, old_data),
+                              v.ValidPerms()]
     return _RepoForm
 
 
 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
-                 repo_groups=[]):
+                 repo_groups=[], landing_revs=[]):
     class _RepoForkForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
-                        SlugifyName())
-        repo_group = OneOf(repo_groups, hideList=True)
-        repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
-        description = UnicodeString(strip=True, min=1, not_empty=True)
-        private = StringBoolean(if_missing=False)
-        copy_permissions = StringBoolean(if_missing=False)
-        update_after_clone = StringBoolean(if_missing=False)
-        fork_parent_id = UnicodeString()
-        chained_validators = [ValidForkName(edit, old_data)]
+        repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
+                        v.SlugifyName())
+        repo_group = v.OneOf(repo_groups, hideList=True)
+        repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
+        description = v.UnicodeString(strip=True, min=1, not_empty=True)
+        private = v.StringBoolean(if_missing=False)
+        copy_permissions = v.StringBoolean(if_missing=False)
+        update_after_clone = v.StringBoolean(if_missing=False)
+        fork_parent_id = v.UnicodeString()
+        chained_validators = [v.ValidForkName(edit, old_data)]
+        landing_rev = v.OneOf(landing_revs, hideList=True)
 
     return _RepoForkForm
 
 
-def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
-                     repo_groups=[]):
+def RepoSettingsForm(edit=False, old_data={},
+                     supported_backends=BACKENDS.keys(), repo_groups=[],
+                     landing_revs=[]):
     class _RepoForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
-                        SlugifyName())
-        description = UnicodeString(strip=True, min=1, not_empty=True)
-        repo_group = OneOf(repo_groups, hideList=True)
-        private = StringBoolean(if_missing=False)
-
-        chained_validators = [ValidRepoName(edit, old_data), ValidPerms(),
-                              ValidSettings]
+        repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
+                        v.SlugifyName())
+        description = v.UnicodeString(strip=True, min=1, not_empty=True)
+        repo_group = v.OneOf(repo_groups, hideList=True)
+        private = v.StringBoolean(if_missing=False)
+        landing_rev = v.OneOf(landing_revs, hideList=True)
+        chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
+                              v.ValidSettings()]
     return _RepoForm
 
 
@@ -716,58 +236,108 @@
     class _ApplicationSettingsForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
-        rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
-        rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
+        rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
+        rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
+        rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
 
     return _ApplicationSettingsForm
 
 
+def ApplicationVisualisationForm():
+    class _ApplicationVisualisationForm(formencode.Schema):
+        allow_extra_fields = True
+        filter_extra_fields = False
+        rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
+        rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
+        rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
+
+    return _ApplicationVisualisationForm
+
+
 def ApplicationUiSettingsForm():
     class _ApplicationUiSettingsForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = False
-        web_push_ssl = OneOf(['true', 'false'], if_missing='false')
-        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)
+        web_push_ssl = v.StringBoolean(if_missing=False)
+        paths_root_path = All(
+            v.ValidPath(),
+            v.UnicodeString(strip=True, min=1, not_empty=True)
+        )
+        hooks_changegroup_update = v.StringBoolean(if_missing=False)
+        hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
+        hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
+        hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
+
+        extensions_largefiles = v.StringBoolean(if_missing=False)
+        extensions_hgsubversion = v.StringBoolean(if_missing=False)
+        extensions_hggit = v.StringBoolean(if_missing=False)
 
     return _ApplicationUiSettingsForm
 
 
-def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
+def DefaultPermissionsForm(perms_choices, register_choices, create_choices,
+                           fork_choices):
     class _DefaultPermissionsForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
-        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)
+        overwrite_default = v.StringBoolean(if_missing=False)
+        anonymous = v.StringBoolean(if_missing=False)
+        default_perm = v.OneOf(perms_choices)
+        default_register = v.OneOf(register_choices)
+        default_create = v.OneOf(create_choices)
+        default_fork = v.OneOf(fork_choices)
 
     return _DefaultPermissionsForm
 
 
-def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
+def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
+                     tls_kind_choices):
     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_tls_kind = OneOf(tls_kind_choices)
-        ldap_tls_reqcert = OneOf(tls_reqcert_choices)
-        ldap_dn_user = UnicodeString(strip=True,)
-        ldap_dn_pass = UnicodeString(strip=True,)
-        ldap_base_dn = UnicodeString(strip=True,)
-        ldap_filter = UnicodeString(strip=True,)
-        ldap_search_scope = OneOf(search_scope_choices)
-        ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
-        ldap_attr_firstname = UnicodeString(strip=True,)
-        ldap_attr_lastname = UnicodeString(strip=True,)
-        ldap_attr_email = UnicodeString(strip=True,)
+        ldap_active = v.StringBoolean(if_missing=False)
+        ldap_host = v.UnicodeString(strip=True,)
+        ldap_port = v.Number(strip=True,)
+        ldap_tls_kind = v.OneOf(tls_kind_choices)
+        ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
+        ldap_dn_user = v.UnicodeString(strip=True,)
+        ldap_dn_pass = v.UnicodeString(strip=True,)
+        ldap_base_dn = v.UnicodeString(strip=True,)
+        ldap_filter = v.UnicodeString(strip=True,)
+        ldap_search_scope = v.OneOf(search_scope_choices)
+        ldap_attr_login = All(
+            v.AttrLoginValidator(),
+            v.UnicodeString(strip=True,)
+        )
+        ldap_attr_firstname = v.UnicodeString(strip=True,)
+        ldap_attr_lastname = v.UnicodeString(strip=True,)
+        ldap_attr_email = v.UnicodeString(strip=True,)
 
     return _LdapSettingsForm
+
+
+def UserExtraEmailForm():
+    class _UserExtraEmailForm(formencode.Schema):
+        email = All(v.UniqSystemEmail(), v.Email)
+
+    return _UserExtraEmailForm
+
+
+def PullRequestForm():
+    class _PullRequestForm(formencode.Schema):
+        allow_extra_fields = True
+        filter_extra_fields = True
+
+        user = v.UnicodeString(strip=True, required=True)
+        org_repo = v.UnicodeString(strip=True, required=True)
+        org_ref = v.UnicodeString(strip=True, required=True)
+        other_repo = v.UnicodeString(strip=True, required=True)
+        other_ref = v.UnicodeString(strip=True, required=True)
+        revisions = All(v.NotReviewedRevisions()(), v.UniqueList(not_empty=True))
+        review_members = v.UniqueList(not_empty=True)
+
+        pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
+        pullrequest_desc = v.UnicodeString(strip=True, required=False)
+
+    return _PullRequestForm
\ No newline at end of file
--- a/rhodecode/model/notification.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/notification.py	Sun Sep 02 21:19:54 2012 +0200
@@ -27,12 +27,10 @@
 import os
 import logging
 import traceback
-import datetime
 
 from pylons.i18n.translation import _
 
 import rhodecode
-from rhodecode.config.conf import DATETIME_FORMAT
 from rhodecode.lib import helpers as h
 from rhodecode.model import BaseModel
 from rhodecode.model.db import Notification, User, UserNotification
@@ -42,8 +40,7 @@
 
 class NotificationModel(BaseModel):
 
-    def __get_user(self, user):
-        return self._get_instance(User, user, callback=User.get_by_username)
+    cls = Notification
 
     def __get_notification(self, notification):
         if isinstance(notification, Notification):
@@ -77,12 +74,12 @@
         if recipients and not getattr(recipients, '__iter__', False):
             raise Exception('recipients must be a list of iterable')
 
-        created_by_obj = self.__get_user(created_by)
+        created_by_obj = self._get_user(created_by)
 
         if recipients:
             recipients_objs = []
             for u in recipients:
-                obj = self.__get_user(u)
+                obj = self._get_user(u)
                 if obj:
                     recipients_objs.append(obj)
             recipients_objs = set(recipients_objs)
@@ -103,11 +100,15 @@
         if with_email is False:
             return notif
 
-        # send email with notification
-        for rec in recipients_objs:
+        #don't send email to person who created this comment
+        rec_objs = set(recipients_objs).difference(set([created_by_obj]))
+
+        # send email with notification to all other participants
+        for rec in rec_objs:
             email_subject = NotificationModel().make_description(notif, False)
             type_ = type_
             email_body = body
+            ## this is passed into template
             kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)}
             kwargs.update(email_kwargs)
             email_body_html = EmailNotificationModel()\
@@ -122,7 +123,7 @@
         # we don't want to remove actual notification just the assignment
         try:
             notification = self.__get_notification(notification)
-            user = self.__get_user(user)
+            user = self._get_user(user)
             if notification and user:
                 obj = UserNotification.query()\
                         .filter(UserNotification.user == user)\
@@ -135,30 +136,73 @@
             log.error(traceback.format_exc())
             raise
 
-    def get_for_user(self, user):
-        user = self.__get_user(user)
-        return user.notifications
+    def get_for_user(self, user, filter_=None):
+        """
+        Get mentions for given user, filter them if filter dict is given
+
+        :param user:
+        :type user:
+        :param filter:
+        """
+        user = self._get_user(user)
+
+        q = UserNotification.query()\
+            .filter(UserNotification.user == user)\
+            .join((Notification, UserNotification.notification_id ==
+                                 Notification.notification_id))
+
+        if filter_:
+            q = q.filter(Notification.type_.in_(filter_))
+
+        return q.all()
 
-    def mark_all_read_for_user(self, user):
-        user = self.__get_user(user)
-        UserNotification.query()\
-            .filter(UserNotification.read==False)\
-            .update({'read': True})
+    def mark_read(self, user, notification):
+        try:
+            notification = self.__get_notification(notification)
+            user = self._get_user(user)
+            if notification and user:
+                obj = UserNotification.query()\
+                        .filter(UserNotification.user == user)\
+                        .filter(UserNotification.notification
+                                == notification)\
+                        .one()
+                obj.read = True
+                self.sa.add(obj)
+                return True
+        except Exception:
+            log.error(traceback.format_exc())
+            raise
+
+    def mark_all_read_for_user(self, user, filter_=None):
+        user = self._get_user(user)
+        q = UserNotification.query()\
+            .filter(UserNotification.user == user)\
+            .filter(UserNotification.read == False)\
+            .join((Notification, UserNotification.notification_id ==
+                                 Notification.notification_id))
+        if filter_:
+            q = q.filter(Notification.type_.in_(filter_))
+
+        # this is a little inefficient but sqlalchemy doesn't support
+        # update on joined tables :(
+        for obj in q.all():
+            obj.read = True
+            self.sa.add(obj)
 
     def get_unread_cnt_for_user(self, user):
-        user = self.__get_user(user)
+        user = self._get_user(user)
         return UserNotification.query()\
                 .filter(UserNotification.read == False)\
                 .filter(UserNotification.user == user).count()
 
     def get_unread_for_user(self, user):
-        user = self.__get_user(user)
+        user = self._get_user(user)
         return [x.notification for x in UserNotification.query()\
                 .filter(UserNotification.read == False)\
                 .filter(UserNotification.user == user).all()]
 
     def get_user_notification(self, user, notification):
-        user = self.__get_user(user)
+        user = self._get_user(user)
         notification = self.__get_notification(notification)
 
         return UserNotification.query()\
@@ -170,20 +214,23 @@
         Creates a human readable description based on properties
         of notification object
         """
-
+        #alias
+        _n = notification
         _map = {
-            notification.TYPE_CHANGESET_COMMENT: _('commented on commit'),
-            notification.TYPE_MESSAGE: _('sent message'),
-            notification.TYPE_MENTION: _('mentioned you'),
-            notification.TYPE_REGISTRATION: _('registered in RhodeCode')
+            _n.TYPE_CHANGESET_COMMENT: _('commented on commit'),
+            _n.TYPE_MESSAGE: _('sent message'),
+            _n.TYPE_MENTION: _('mentioned you'),
+            _n.TYPE_REGISTRATION: _('registered in RhodeCode'),
+            _n.TYPE_PULL_REQUEST: _('opened new pull request'),
+            _n.TYPE_PULL_REQUEST_COMMENT: _('commented on pull request')
         }
 
-        tmpl = "%(user)s %(action)s %(when)s"
+        # action == _map string
+        tmpl = "%(user)s %(action)s at %(when)s"
         if show_age:
             when = h.age(notification.created_on)
         else:
-            DTF = lambda d: datetime.datetime.strftime(d, DATETIME_FORMAT)
-            when = DTF(notification.created_on)
+            when = h.fmt_date(notification.created_on)
 
         data = dict(
             user=notification.created_by_user.username,
@@ -197,6 +244,7 @@
     TYPE_CHANGESET_COMMENT = Notification.TYPE_CHANGESET_COMMENT
     TYPE_PASSWORD_RESET = 'passoword_link'
     TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
+    TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST
     TYPE_DEFAULT = 'default'
 
     def __init__(self):
--- a/rhodecode/model/permission.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/permission.py	Sun Sep 02 21:19:54 2012 +0200
@@ -31,7 +31,8 @@
 from rhodecode.lib.caching_query import FromCache
 
 from rhodecode.model import BaseModel
-from rhodecode.model.db import User, Permission, UserToPerm, UserRepoToPerm
+from rhodecode.model.db import User, Permission, UserToPerm, UserRepoToPerm,\
+    UserRepoGroupToPerm
 
 log = logging.getLogger(__name__)
 
@@ -41,6 +42,8 @@
     Permissions model for RhodeCode
     """
 
+    cls = Permission
+
     def get_permission(self, permission_id, cache=False):
         """
         Get's permissions by id
@@ -74,8 +77,8 @@
                                 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'
+        if len(u2p) != 4:
+            raise Exception('Defined: %s should be 4  permissions for default'
                             ' user. This should not happen please verify'
                             ' your database' % len(u2p))
 
@@ -87,23 +90,38 @@
                                        form_result['default_perm'])
                     self.sa.add(p)
 
-                if p.permission.permission_name.startswith('hg.register.'):
+                elif 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.'):
+                elif p.permission.permission_name.startswith('hg.create.'):
                     p.permission = self.get_permission_by_name(
                                         form_result['default_create'])
                     self.sa.add(p)
 
+                elif p.permission.permission_name.startswith('hg.fork.'):
+                    p.permission = self.get_permission_by_name(
+                                        form_result['default_fork'])
+                    self.sa.add(p)
+
+            _def_name = form_result['default_perm'].split('repository.')[-1]
             #stage 2 update all default permissions for repos if checked
             if form_result['overwrite_default'] == True:
+                _def = self.get_permission_by_name('repository.' + _def_name)
+                # repos
                 for r2p in self.sa.query(UserRepoToPerm)\
-                               .filter(UserRepoToPerm.user == perm_user).all():
-                    r2p.permission = self.get_permission_by_name(
-                                         form_result['default_perm'])
+                               .filter(UserRepoToPerm.user == perm_user)\
+                               .all():
+                    r2p.permission = _def
                     self.sa.add(r2p)
+                # groups
+                _def = self.get_permission_by_name('group.' + _def_name)
+                for g2p in self.sa.query(UserRepoGroupToPerm)\
+                               .filter(UserRepoGroupToPerm.user == perm_user)\
+                               .all():
+                    g2p.permission = _def
+                    self.sa.add(g2p)
 
             # stage 3 set anonymous access
             if perm_user.username == 'default':
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/pull_request.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,249 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.pull_request
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    pull request model for RhodeCode
+
+    :created_on: Jun 6, 2012
+    :author: marcink
+    :copyright: (C) 2012-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import logging
+import binascii
+import datetime
+
+from pylons.i18n.translation import _
+
+from rhodecode.model.meta import Session
+from rhodecode.lib import helpers as h
+from rhodecode.model import BaseModel
+from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification
+from rhodecode.model.notification import NotificationModel
+from rhodecode.lib.utils2 import safe_unicode
+
+from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil
+
+log = logging.getLogger(__name__)
+
+
+class PullRequestModel(BaseModel):
+
+    cls = PullRequest
+
+    def __get_pull_request(self, pull_request):
+        return self._get_instance(PullRequest, pull_request)
+
+    def get_all(self, repo):
+        repo = self._get_repo(repo)
+        return PullRequest.query().filter(PullRequest.other_repo == repo).all()
+
+    def create(self, created_by, org_repo, org_ref, other_repo,
+               other_ref, revisions, reviewers, title, description=None):
+
+        created_by_user = self._get_user(created_by)
+        org_repo = self._get_repo(org_repo)
+        other_repo = self._get_repo(other_repo)
+
+        new = PullRequest()
+        new.org_repo = org_repo
+        new.org_ref = org_ref
+        new.other_repo = other_repo
+        new.other_ref = other_ref
+        new.revisions = revisions
+        new.title = title
+        new.description = description
+        new.author = created_by_user
+        self.sa.add(new)
+        Session().flush()
+        #members
+        for member in reviewers:
+            _usr = self._get_user(member)
+            reviewer = PullRequestReviewers(_usr, new)
+            self.sa.add(reviewer)
+
+        #notification to reviewers
+        notif = NotificationModel()
+
+        subject = safe_unicode(
+            h.link_to(
+              _('%(user)s wants you to review pull request #%(pr_id)s') % \
+                {'user': created_by_user.username,
+                 'pr_id': new.pull_request_id},
+              h.url('pullrequest_show', repo_name=other_repo.repo_name,
+                    pull_request_id=new.pull_request_id,
+                    qualified=True,
+              )
+            )
+        )
+        body = description
+        notif.create(created_by=created_by_user, subject=subject, body=body,
+                     recipients=reviewers,
+                     type_=Notification.TYPE_PULL_REQUEST,)
+
+        return new
+
+    def update_reviewers(self, pull_request, reviewers_ids):
+        reviewers_ids = set(reviewers_ids)
+        pull_request = self.__get_pull_request(pull_request)
+        current_reviewers = PullRequestReviewers.query()\
+                            .filter(PullRequestReviewers.pull_request==
+                                   pull_request)\
+                            .all()
+        current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
+
+        to_add = reviewers_ids.difference(current_reviewers_ids)
+        to_remove = current_reviewers_ids.difference(reviewers_ids)
+
+        log.debug("Adding %s reviewers" % to_add)
+        log.debug("Removing %s reviewers" % to_remove)
+
+        for uid in to_add:
+            _usr = self._get_user(uid)
+            reviewer = PullRequestReviewers(_usr, pull_request)
+            self.sa.add(reviewer)
+
+        for uid in to_remove:
+            reviewer = PullRequestReviewers.query()\
+                    .filter(PullRequestReviewers.user_id==uid,
+                            PullRequestReviewers.pull_request==pull_request)\
+                    .scalar()
+            if reviewer:
+                self.sa.delete(reviewer)
+
+    def delete(self, pull_request):
+        pull_request = self.__get_pull_request(pull_request)
+        Session().delete(pull_request)
+
+    def close_pull_request(self, pull_request):
+        pull_request = self.__get_pull_request(pull_request)
+        pull_request.status = PullRequest.STATUS_CLOSED
+        pull_request.updated_on = datetime.datetime.now()
+        self.sa.add(pull_request)
+
+    def _get_changesets(self, org_repo, org_ref, other_repo, other_ref,
+                        discovery_data):
+        """
+        Returns a list of changesets that are incoming from org_repo@org_ref
+        to other_repo@other_ref
+
+        :param org_repo:
+        :type org_repo:
+        :param org_ref:
+        :type org_ref:
+        :param other_repo:
+        :type other_repo:
+        :param other_ref:
+        :type other_ref:
+        :param tmp:
+        :type tmp:
+        """
+        changesets = []
+        #case two independent repos
+        common, incoming, rheads = discovery_data
+        if org_repo != other_repo and incoming:
+            revs = org_repo._repo.changelog.findmissing(common, rheads)
+
+            for cs in reversed(map(binascii.hexlify, revs)):
+                changesets.append(org_repo.get_changeset(cs))
+        else:
+            _revset_predicates = {
+                    'branch': 'branch',
+                    'book': 'bookmark',
+                    'tag': 'tag',
+                    'rev': 'id',
+                }
+
+            revs = [
+                "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
+                    _revset_predicates[org_ref[0]], org_ref[1],
+                    _revset_predicates[other_ref[0]], other_ref[1]
+               )
+            ]
+
+            out = scmutil.revrange(org_repo._repo, revs)
+            for cs in reversed(out):
+                changesets.append(org_repo.get_changeset(cs))
+
+        return changesets
+
+    def _get_discovery(self, org_repo, org_ref, other_repo, other_ref):
+        """
+        Get's mercurial discovery data used to calculate difference between
+        repos and refs
+
+        :param org_repo:
+        :type org_repo:
+        :param org_ref:
+        :type org_ref:
+        :param other_repo:
+        :type other_repo:
+        :param other_ref:
+        :type other_ref:
+        """
+
+        _org_repo = org_repo._repo
+        org_rev_type, org_rev = org_ref
+
+        _other_repo = other_repo._repo
+        other_rev_type, other_rev = other_ref
+
+        log.debug('Doing discovery for %s@%s vs %s@%s' % (
+                        org_repo, org_ref, other_repo, other_ref)
+        )
+        #log.debug('Filter heads are %s[%s]' % ('', org_ref[1]))
+        org_peer = localrepo.locallegacypeer(_org_repo.local())
+        tmp = discovery.findcommonincoming(
+                  repo=_other_repo,  # other_repo we check for incoming
+                  remote=org_peer,  # org_repo source for incoming
+                  heads=[_other_repo[other_rev].node(),
+                         _org_repo[org_rev].node()],
+                  force=False
+        )
+        return tmp
+
+    def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
+        """
+        Returns a tuple of incomming changesets, and discoverydata cache
+
+        :param org_repo:
+        :type org_repo:
+        :param org_ref:
+        :type org_ref:
+        :param other_repo:
+        :type other_repo:
+        :param other_ref:
+        :type other_ref:
+        """
+
+        if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
+            raise Exception('org_ref must be a two element list/tuple')
+
+        if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
+            raise Exception('other_ref must be a two element list/tuple')
+
+        discovery_data = self._get_discovery(org_repo.scm_instance,
+                                           org_ref,
+                                           other_repo.scm_instance,
+                                           other_ref)
+        cs_ranges = self._get_changesets(org_repo.scm_instance,
+                                         org_ref,
+                                         other_repo.scm_instance,
+                                         other_ref,
+                                         discovery_data)
+
+        return cs_ranges, discovery_data
--- a/rhodecode/model/repo.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/repo.py	Sun Sep 02 21:19:54 2012 +0200
@@ -22,6 +22,7 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from __future__ import with_statement
 import os
 import shutil
 import logging
@@ -45,25 +46,17 @@
 
 class RepoModel(BaseModel):
 
-    def __get_user(self, user):
-        return self._get_instance(User, user, callback=User.get_by_username)
+    cls = Repository
+    URL_SEPARATOR = Repository.url_sep()
 
     def __get_users_group(self, users_group):
         return self._get_instance(UsersGroup, users_group,
                                   callback=UsersGroup.get_by_group_name)
 
-    def __get_repos_group(self, repos_group):
+    def _get_repos_group(self, repos_group):
         return self._get_instance(RepoGroup, repos_group,
                                   callback=RepoGroup.get_by_group_name)
 
-    def __get_repo(self, repository):
-        return self._get_instance(Repository, repository,
-                                  callback=Repository.get_by_repo_name)
-
-    def __get_perm(self, permission):
-        return self._get_instance(Permission, permission,
-                                  callback=Permission.get_by_key)
-
     @LazyProperty
     def repos_path(self):
         """
@@ -83,7 +76,7 @@
         return repo.scalar()
 
     def get_repo(self, repository):
-        return self.__get_repo(repository)
+        return self._get_repo(repository)
 
     def get_by_repo_name(self, repo_name, cache=False):
         repo = self.sa.query(Repository)\
@@ -209,37 +202,45 @@
             log.error(traceback.format_exc())
             raise
 
-    def create(self, form_data, cur_user, just_db=False, fork=False):
+    def create_repo(self, repo_name, repo_type, description, owner,
+                    private=False, clone_uri=None, repos_group=None,
+                    landing_rev='tip', just_db=False, fork_of=None,
+                    copy_fork_permissions=False):
+        """
+        Create repository
+
+        """
         from rhodecode.model.scm import ScmModel
 
+        owner = self._get_user(owner)
+        fork_of = self._get_repo(fork_of)
+        repos_group = self._get_repos_group(repos_group)
         try:
-            if fork:
-                fork_parent_id = form_data['fork_parent_id']
 
             # repo name is just a name of repository
             # while repo_name_full is a full qualified name that is combined
             # with name and path of group
-            repo_name = form_data['repo_name']
-            repo_name_full = form_data['repo_name_full']
+            repo_name_full = repo_name
+            repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
 
             new_repo = Repository()
             new_repo.enable_statistics = False
+            new_repo.repo_name = repo_name_full
+            new_repo.repo_type = repo_type
+            new_repo.user = owner
+            new_repo.group = repos_group
+            new_repo.description = description or repo_name
+            new_repo.private = private
+            new_repo.clone_uri = clone_uri
+            new_repo.landing_rev = landing_rev
 
-            for k, v in form_data.items():
-                if k == 'repo_name':
-                    v = repo_name_full
-                if k == 'repo_group':
-                    k = 'group_id'
-                if k == 'description':
-                    v = v or repo_name
+            if repos_group:
+                new_repo.enable_locking = repos_group.enable_locking
 
-                setattr(new_repo, k, v)
-
-            if fork:
-                parent_repo = Repository.get(fork_parent_id)
+            if fork_of:
+                parent_repo = fork_of
                 new_repo.fork = parent_repo
 
-            new_repo.user_id = cur_user.user_id
             self.sa.add(new_repo)
 
             def _create_default_perms():
@@ -251,7 +252,7 @@
                         default = p.permission.permission_name
                         break
 
-                default_perm = 'repository.none' if form_data['private'] else default
+                default_perm = 'repository.none' if private else default
 
                 repo_to_perm.permission_id = self.sa.query(Permission)\
                         .filter(Permission.permission_name == default_perm)\
@@ -262,9 +263,9 @@
 
                 self.sa.add(repo_to_perm)
 
-            if fork:
-                if form_data.get('copy_permissions'):
-                    repo = Repository.get(fork_parent_id)
+            if fork_of:
+                if copy_fork_permissions:
+                    repo = fork_of
                     user_perms = UserRepoToPerm.query()\
                         .filter(UserRepoToPerm.repository == repo).all()
                     group_perms = UsersGroupRepoToPerm.query()\
@@ -283,20 +284,45 @@
                 _create_default_perms()
 
             if not just_db:
-                self.__create_repo(repo_name, form_data['repo_type'],
-                                   form_data['repo_group'],
-                                   form_data['clone_uri'])
+                self.__create_repo(repo_name, repo_type,
+                                   repos_group,
+                                   clone_uri)
                 log_create_repository(new_repo.get_dict(),
-                                      created_by=cur_user.username)
+                                      created_by=owner.username)
 
             # now automatically start following this repository as owner
             ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
-                                                    cur_user.user_id)
+                                                    owner.user_id)
             return new_repo
         except:
             log.error(traceback.format_exc())
             raise
 
+    def create(self, form_data, cur_user, just_db=False, fork=None):
+        """
+        Backward compatibility function, just a wrapper on top of create_repo
+
+        :param form_data:
+        :param cur_user:
+        :param just_db:
+        :param fork:
+        """
+
+        repo_name = form_data['repo_name_full']
+        repo_type = form_data['repo_type']
+        description = form_data['description']
+        owner = cur_user
+        private = form_data['private']
+        clone_uri = form_data.get('clone_uri')
+        repos_group = form_data['repo_group']
+        landing_rev = form_data['landing_rev']
+        copy_fork_permissions = form_data.get('copy_permissions')
+        fork_of = form_data.get('fork_parent_id')
+        return self.create_repo(
+            repo_name, repo_type, description, owner, private, clone_uri,
+            repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
+        )
+
     def create_fork(self, form_data, cur_user):
         """
         Simple wrapper into executing celery task for fork creation
@@ -308,13 +334,14 @@
         run_task(tasks.create_repo_fork, form_data, cur_user)
 
     def delete(self, repo):
-        repo = self.__get_repo(repo)
-        try:
-            self.sa.delete(repo)
-            self.__delete_repo(repo)
-        except:
-            log.error(traceback.format_exc())
-            raise
+        repo = self._get_repo(repo)
+        if repo:
+            try:
+                self.sa.delete(repo)
+                self.__delete_repo(repo)
+            except:
+                log.error(traceback.format_exc())
+                raise
 
     def grant_user_permission(self, repo, user, perm):
         """
@@ -325,9 +352,9 @@
         :param user: Instance of User, user_id or username
         :param perm: Instance of Permission, or permission_name
         """
-        user = self.__get_user(user)
-        repo = self.__get_repo(repo)
-        permission = self.__get_perm(perm)
+        user = self._get_user(user)
+        repo = self._get_repo(repo)
+        permission = self._get_perm(perm)
 
         # check if we have that permission already
         obj = self.sa.query(UserRepoToPerm)\
@@ -350,8 +377,8 @@
         :param user: Instance of User, user_id or username
         """
 
-        user = self.__get_user(user)
-        repo = self.__get_repo(repo)
+        user = self._get_user(user)
+        repo = self._get_repo(repo)
 
         obj = self.sa.query(UserRepoToPerm)\
             .filter(UserRepoToPerm.repository == repo)\
@@ -369,9 +396,9 @@
             or users group name
         :param perm: Instance of Permission, or permission_name
         """
-        repo = self.__get_repo(repo)
+        repo = self._get_repo(repo)
         group_name = self.__get_users_group(group_name)
-        permission = self.__get_perm(perm)
+        permission = self._get_perm(perm)
 
         # check if we have that permission already
         obj = self.sa.query(UsersGroupRepoToPerm)\
@@ -396,7 +423,7 @@
         :param group_name: Instance of UserGroup, users_group_id,
             or users group name
         """
-        repo = self.__get_repo(repo)
+        repo = self._get_repo(repo)
         group_name = self.__get_users_group(group_name)
 
         obj = self.sa.query(UsersGroupRepoToPerm)\
@@ -421,7 +448,7 @@
             log.error(traceback.format_exc())
             raise
 
-    def __create_repo(self, repo_name, alias, new_parent_id, clone_uri=False):
+    def __create_repo(self, repo_name, alias, parent, clone_uri=False):
         """
         makes repository on filesystem. It's group aware means it'll create
         a repository within a group, and alter the paths accordingly of
@@ -433,11 +460,10 @@
         :param clone_uri:
         """
         from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
+        from rhodecode.model.scm import ScmModel
 
-        if new_parent_id:
-            paths = RepoGroup.get(new_parent_id)\
-                .full_path.split(RepoGroup.url_sep())
-            new_parent_path = os.sep.join(paths)
+        if parent:
+            new_parent_path = os.sep.join(parent.full_path_splitted)
         else:
             new_parent_path = ''
 
@@ -458,8 +484,14 @@
                 )
         )
         backend = get_backend(alias)
-
-        backend(repo_path, create=True, src_url=clone_uri)
+        if alias == 'hg':
+            backend(repo_path, create=True, src_url=clone_uri)
+        elif alias == 'git':
+            r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
+            # add rhodecode hook into this repo
+            ScmModel().install_git_hook(repo=r)
+        else:
+            raise Exception('Undefined alias %s' % alias)
 
     def __rename_repo(self, old, new):
         """
@@ -489,11 +521,18 @@
         """
         rm_path = os.path.join(self.repos_path, repo.repo_name)
         log.info("Removing %s" % (rm_path))
-        # disable hg/git
+        # disable hg/git internal that it doesn't get detected as repo
         alias = repo.repo_type
-        shutil.move(os.path.join(rm_path, '.%s' % alias),
-                    os.path.join(rm_path, 'rm__.%s' % alias))
+
+        bare = getattr(repo.scm_instance, 'bare', False)
+
+        if not bare:
+            # skip this for bare git repos
+            shutil.move(os.path.join(rm_path, '.%s' % alias),
+                        os.path.join(rm_path, 'rm__.%s' % alias))
         # disable repo
-        _d = 'rm__%s__%s' % (datetime.now().strftime('%Y%m%d_%H%M%S_%f'),
+        _now = datetime.now()
+        _ms = str(_now.microsecond).rjust(6, '0')
+        _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
                              repo.repo_name)
         shutil.move(rm_path, os.path.join(self.repos_path, _d))
--- a/rhodecode/model/repo_permission.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/repo_permission.py	Sun Sep 02 21:19:54 2012 +0200
@@ -26,28 +26,19 @@
 
 import logging
 from rhodecode.model import BaseModel
-from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission,\
-    User, Repository
+from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, \
+    Permission
 
 log = logging.getLogger(__name__)
 
 
 class RepositoryPermissionModel(BaseModel):
 
-    def __get_user(self, user):
-        return self._get_instance(User, user, callback=User.get_by_username)
-
-    def __get_repo(self, repository):
-        return self._get_instance(Repository, repository,
-                                  callback=Repository.get_by_repo_name)
-
-    def __get_perm(self, permission):
-        return self._get_instance(Permission, permission,
-                                  callback=Permission.get_by_key)
+    cls = UserRepoToPerm
 
     def get_user_permission(self, repository, user):
-        repository = self.__get_repo(repository)
-        user = self.__get_user(user)
+        repository = self._get_repo(repository)
+        user = self._get_user(user)
 
         return UserRepoToPerm.query() \
                 .filter(UserRepoToPerm.user == user) \
--- a/rhodecode/model/repos_group.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/repos_group.py	Sun Sep 02 21:19:54 2012 +0200
@@ -39,28 +39,23 @@
 
 class ReposGroupModel(BaseModel):
 
-    def __get_user(self, user):
-        return self._get_instance(User, user, callback=User.get_by_username)
+    cls = RepoGroup
 
     def __get_users_group(self, users_group):
         return self._get_instance(UsersGroup, users_group,
                                   callback=UsersGroup.get_by_group_name)
 
-    def __get_repos_group(self, repos_group):
+    def _get_repos_group(self, repos_group):
         return self._get_instance(RepoGroup, repos_group,
                                   callback=RepoGroup.get_by_group_name)
 
-    def __get_perm(self, permission):
-        return self._get_instance(Permission, permission,
-                                  callback=Permission.get_by_key)
-
     @LazyProperty
     def repos_path(self):
         """
         Get's the repositories root path from database
         """
 
-        q = RhodeCodeUi.get_by_key('/').one()
+        q = RhodeCodeUi.get_by_key('/')
         return q.ui_value
 
     def _create_default_perms(self, new_group):
@@ -134,11 +129,11 @@
             # delete only if that path really exists
             os.rmdir(rm_path)
 
-    def create(self, group_name, group_description, parent, just_db=False):
+    def create(self, group_name, group_description, parent=None, just_db=False):
         try:
             new_repos_group = RepoGroup()
             new_repos_group.group_description = group_description
-            new_repos_group.parent_group = self.__get_repos_group(parent)
+            new_repos_group.parent_group = self._get_repos_group(parent)
             new_repos_group.group_name = new_repos_group.get_new_name(group_name)
 
             self.sa.add(new_repos_group)
@@ -188,11 +183,20 @@
             repos_group.group_description = form_data['group_description']
             repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
             repos_group.group_parent_id = form_data['group_parent_id']
+            repos_group.enable_locking = form_data['enable_locking']
             repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
             new_path = repos_group.full_path
 
             self.sa.add(repos_group)
 
+            # iterate over all members of this groups and set the locking !
+            # this can be potentially heavy operation
+
+            for obj in repos_group.recursive_groups_and_repos():
+                #set the value from it's parent
+                obj.enable_locking = repos_group.enable_locking
+                self.sa.add(obj)
+
             # we need to get all repositories from this new group and
             # rename them accordingly to new group path
             for r in repos_group.repositories:
@@ -206,13 +210,13 @@
             log.error(traceback.format_exc())
             raise
 
-    def delete(self, users_group_id):
+    def delete(self, repos_group):
+        repos_group = self._get_repos_group(repos_group)
         try:
-            users_group = RepoGroup.get(users_group_id)
-            self.sa.delete(users_group)
-            self.__delete_group(users_group)
+            self.sa.delete(repos_group)
+            self.__delete_group(repos_group)
         except:
-            log.error(traceback.format_exc())
+            log.exception('Error removing repos_group %s' % repos_group)
             raise
 
     def grant_user_permission(self, repos_group, user, perm):
@@ -226,9 +230,9 @@
         :param perm: Instance of Permission, or permission_name
         """
 
-        repos_group = self.__get_repos_group(repos_group)
-        user = self.__get_user(user)
-        permission = self.__get_perm(perm)
+        repos_group = self._get_repos_group(repos_group)
+        user = self._get_user(user)
+        permission = self._get_perm(perm)
 
         # check if we have that permission already
         obj = self.sa.query(UserRepoGroupToPerm)\
@@ -252,8 +256,8 @@
         :param user: Instance of User, user_id or username
         """
 
-        repos_group = self.__get_repos_group(repos_group)
-        user = self.__get_user(user)
+        repos_group = self._get_repos_group(repos_group)
+        user = self._get_user(user)
 
         obj = self.sa.query(UserRepoGroupToPerm)\
             .filter(UserRepoGroupToPerm.user == user)\
@@ -272,9 +276,9 @@
             or users group name
         :param perm: Instance of Permission, or permission_name
         """
-        repos_group = self.__get_repos_group(repos_group)
+        repos_group = self._get_repos_group(repos_group)
         group_name = self.__get_users_group(group_name)
-        permission = self.__get_perm(perm)
+        permission = self._get_perm(perm)
 
         # check if we have that permission already
         obj = self.sa.query(UsersGroupRepoGroupToPerm)\
@@ -300,7 +304,7 @@
         :param group_name: Instance of UserGroup, users_group_id,
             or users group name
         """
-        repos_group = self.__get_repos_group(repos_group)
+        repos_group = self._get_repos_group(repos_group)
         group_name = self.__get_users_group(group_name)
 
         obj = self.sa.query(UsersGroupRepoGroupToPerm)\
--- a/rhodecode/model/scm.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/scm.py	Sun Sep 02 21:19:54 2012 +0200
@@ -22,26 +22,35 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from __future__ import with_statement
 import os
+import re
 import time
 import traceback
 import logging
 import cStringIO
+import pkg_resources
+from os.path import dirname as dn, join as jn
 
+from sqlalchemy import func
+from pylons.i18n.translation import _
+
+import rhodecode
 from rhodecode.lib.vcs import get_backend
 from rhodecode.lib.vcs.exceptions import RepositoryError
 from rhodecode.lib.vcs.utils.lazy import LazyProperty
 from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
 from rhodecode import BACKENDS
 from rhodecode.lib import helpers as h
 from rhodecode.lib.utils2 import safe_str, safe_unicode
 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
-    action_logger, EmptyChangeset, REMOVED_REPO_PAT
+    action_logger, REMOVED_REPO_PAT
 from rhodecode.model import BaseModel
 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
-    UserFollowing, UserLog, User, RepoGroup
+    UserFollowing, UserLog, User, RepoGroup, PullRequest
 
 log = logging.getLogger(__name__)
 
@@ -63,6 +72,10 @@
 
 
 class CachedRepoList(object):
+    """
+    Cached repo list, uses in-memory cache after initialization, that is
+    super fast
+    """
 
     def __init__(self, db_repo_list, repos_path, order_by=None):
         self.db_repo_list = db_repo_list
@@ -77,8 +90,12 @@
         return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
 
     def __iter__(self):
+        # pre-propagated cache_map to save executing select statements
+        # for each repo
+        cache_map = CacheInvalidation.get_cache_map()
+
         for dbr in self.db_repo_list:
-            scmr = dbr.scm_instance_cached
+            scmr = dbr.scm_instance_cached(cache_map)
             # check permission at this level
             if not HasRepoPermissionAny(
                 'repository.read', 'repository.write', 'repository.admin'
@@ -99,7 +116,7 @@
             tmp_d['name'] = dbr.repo_name
             tmp_d['name_sort'] = tmp_d['name'].lower()
             tmp_d['description'] = dbr.description
-            tmp_d['description_sort'] = tmp_d['description']
+            tmp_d['description_sort'] = tmp_d['description'].lower()
             tmp_d['last_change'] = last_change
             tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
             tmp_d['tip'] = tip.raw_id
@@ -116,6 +133,29 @@
             yield tmp_d
 
 
+class SimpleCachedRepoList(CachedRepoList):
+    """
+    Lighter version of CachedRepoList without the scm initialisation
+    """
+
+    def __iter__(self):
+        for dbr in self.db_repo_list:
+            # check permission at this level
+            if not HasRepoPermissionAny(
+                'repository.read', 'repository.write', 'repository.admin'
+            )(dbr.repo_name, 'get repo check'):
+                continue
+
+            tmp_d = {}
+            tmp_d['name'] = dbr.repo_name
+            tmp_d['name_sort'] = tmp_d['name'].lower()
+            tmp_d['description'] = dbr.description
+            tmp_d['description_sort'] = tmp_d['description'].lower()
+            tmp_d['dbrepo'] = dbr.get_dict()
+            tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
+            yield tmp_d
+
+
 class GroupList(object):
 
     def __init__(self, db_repo_group_list):
@@ -147,7 +187,7 @@
         cls = Repository
         if isinstance(instance, cls):
             return instance
-        elif isinstance(instance, int) or str(instance).isdigit():
+        elif isinstance(instance, int) or safe_str(instance).isdigit():
             return cls.get(instance)
         elif isinstance(instance, basestring):
             return cls.get_by_repo_name(instance)
@@ -208,21 +248,29 @@
 
         return repos
 
-    def get_repos(self, all_repos=None, sort_key=None):
+    def get_repos(self, all_repos=None, sort_key=None, simple=False):
         """
         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: list of repository names as strings
             give specific repositories list, good for filtering
+
+        :param sort_key: initial sorting of repos
+        :param simple: use SimpleCachedList - one without the SCM info
         """
         if all_repos is None:
             all_repos = self.sa.query(Repository)\
                         .filter(Repository.group_id == None)\
-                        .order_by(Repository.repo_name).all()
-
-        repo_iter = CachedRepoList(all_repos, repos_path=self.repos_path,
-                                   order_by=sort_key)
+                        .order_by(func.lower(Repository.repo_name)).all()
+        if simple:
+            repo_iter = SimpleCachedRepoList(all_repos,
+                                             repos_path=self.repos_path,
+                                             order_by=sort_key)
+        else:
+            repo_iter = CachedRepoList(all_repos,
+                                       repos_path=self.repos_path,
+                                       order_by=sort_key)
 
         return repo_iter
 
@@ -314,29 +362,33 @@
 
         return f is not None
 
-    def get_followers(self, repo_id):
-        if not isinstance(repo_id, int):
-            repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
+    def get_followers(self, repo):
+        repo = self._get_repo(repo)
 
         return self.sa.query(UserFollowing)\
-                .filter(UserFollowing.follows_repo_id == repo_id).count()
+                .filter(UserFollowing.follows_repository == repo).count()
 
-    def get_forks(self, repo_id):
-        if not isinstance(repo_id, int):
-            repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
+    def get_forks(self, repo):
+        repo = self._get_repo(repo)
+        return self.sa.query(Repository)\
+                .filter(Repository.fork == repo).count()
 
-        return self.sa.query(Repository)\
-                .filter(Repository.fork_id == repo_id).count()
+    def get_pull_requests(self, repo):
+        repo = self._get_repo(repo)
+        return self.sa.query(PullRequest)\
+                .filter(PullRequest.other_repo == repo).count()
 
     def mark_as_fork(self, repo, fork, user):
         repo = self.__get_repo(repo)
         fork = self.__get_repo(fork)
+        if fork and repo.repo_id == fork.repo_id:
+            raise Exception("Cannot set repository as fork of itself")
         repo.fork = fork
         self.sa.add(repo)
         return repo
 
-    def pull_changes(self, repo_name, username):
-        dbrepo = Repository.get_by_repo_name(repo_name)
+    def pull_changes(self, repo, username):
+        dbrepo = self.__get_repo(repo)
         clone_uri = dbrepo.clone_uri
         if not clone_uri:
             raise Exception("This repository doesn't have a clone uri")
@@ -347,22 +399,28 @@
                 'ip': '',
                 'username': username,
                 'action': 'push_remote',
-                'repository': repo_name,
+                'repository': dbrepo.repo_name,
                 'scm': repo.alias,
             }
+            Repository.inject_ui(repo, extras=extras)
 
-            # inject ui extra param to log this action via push logger
-            for k, v in extras.items():
-                repo._repo.ui.setconfig('rhodecode_extras', k, v)
-
-            repo.pull(clone_uri)
-            self.mark_for_invalidation(repo_name)
+            if repo.alias == 'git':
+                repo.fetch(clone_uri)
+            else:
+                repo.pull(clone_uri)
+            self.mark_for_invalidation(dbrepo.repo_name)
         except:
             log.error(traceback.format_exc())
             raise
 
     def commit_change(self, repo, repo_name, cs, user, author, message,
                       content, f_path):
+        """
+        Commits changes
+
+        :param repo: SCM instance
+
+        """
 
         if repo.alias == 'hg':
             from rhodecode.lib.vcs.backends.hg import \
@@ -385,12 +443,10 @@
                        author=author,
                        parents=[cs], branch=cs.branch)
 
-        new_cs = tip.short_id
-        action = 'push_local:%s' % new_cs
-
+        action = 'push_local:%s' % tip.raw_id
         action_logger(user, action, repo_name)
-
         self.mark_for_invalidation(repo_name)
+        return tip
 
     def create_node(self, repo, repo_name, cs, user, author, message, content,
                       f_path):
@@ -425,12 +481,11 @@
         tip = m.commit(message=message,
                        author=author,
                        parents=parents, branch=cs.branch)
-        new_cs = tip.short_id
-        action = 'push_local:%s' % new_cs
 
+        action = 'push_local:%s' % tip.raw_id
         action_logger(user, action, repo_name)
-
         self.mark_for_invalidation(repo_name)
+        return tip
 
     def get_nodes(self, repo_name, revision, root_path='/', flat=True):
         """
@@ -464,3 +519,93 @@
 
     def get_unread_journal(self):
         return self.sa.query(UserLog).count()
+
+    def get_repo_landing_revs(self, repo=None):
+        """
+        Generates select option with tags branches and bookmarks (for hg only)
+        grouped by type
+
+        :param repo:
+        :type repo:
+        """
+
+        hist_l = []
+        choices = []
+        repo = self.__get_repo(repo)
+        hist_l.append(['tip', _('latest tip')])
+        choices.append('tip')
+        if not repo:
+            return choices, hist_l
+
+        repo = repo.scm_instance
+
+        branches_group = ([(k, k) for k, v in
+                           repo.branches.iteritems()], _("Branches"))
+        hist_l.append(branches_group)
+        choices.extend([x[0] for x in branches_group[0]])
+
+        if repo.alias == 'hg':
+            bookmarks_group = ([(k, k) for k, v in
+                                repo.bookmarks.iteritems()], _("Bookmarks"))
+            hist_l.append(bookmarks_group)
+            choices.extend([x[0] for x in bookmarks_group[0]])
+
+        tags_group = ([(k, k) for k, v in
+                       repo.tags.iteritems()], _("Tags"))
+        hist_l.append(tags_group)
+        choices.extend([x[0] for x in tags_group[0]])
+
+        return choices, hist_l
+
+    def install_git_hook(self, repo, force_create=False):
+        """
+        Creates a rhodecode hook inside a git repository
+
+        :param repo: Instance of VCS repo
+        :param force_create: Create even if same name hook exists
+        """
+
+        loc = jn(repo.path, 'hooks')
+        if not repo.bare:
+            loc = jn(repo.path, '.git', 'hooks')
+        if not os.path.isdir(loc):
+            os.makedirs(loc)
+
+        tmpl_post = pkg_resources.resource_string(
+            'rhodecode', jn('config', 'post_receive_tmpl.py')
+        )
+        tmpl_pre = pkg_resources.resource_string(
+            'rhodecode', jn('config', 'pre_receive_tmpl.py')
+        )
+
+        for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]:
+            _hook_file = jn(loc, '%s-receive' % h_type)
+            _rhodecode_hook = False
+            log.debug('Installing git hook in repo %s' % repo)
+            if os.path.exists(_hook_file):
+                # let's take a look at this hook, maybe it's rhodecode ?
+                log.debug('hook exists, checking if it is from rhodecode')
+                _HOOK_VER_PAT = re.compile(r'^RC_HOOK_VER')
+                with open(_hook_file, 'rb') as f:
+                    data = f.read()
+                    matches = re.compile(r'(?:%s)\s*=\s*(.*)'
+                                         % 'RC_HOOK_VER').search(data)
+                    if matches:
+                        try:
+                            ver = matches.groups()[0]
+                            log.debug('got %s it is rhodecode' % (ver))
+                            _rhodecode_hook = True
+                        except:
+                            log.error(traceback.format_exc())
+            else:
+                # there is no hook in this dir, so we want to create one
+                _rhodecode_hook = True
+
+            if _rhodecode_hook or force_create:
+                log.debug('writing %s hook file !' % h_type)
+                with open(_hook_file, 'wb') as f:
+                    tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
+                    f.write(tmpl)
+                os.chmod(_hook_file, 0755)
+            else:
+                log.debug('skipping writing hook file')
--- a/rhodecode/model/user.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/user.py	Sun Sep 02 21:19:54 2012 +0200
@@ -25,48 +25,31 @@
 
 import logging
 import traceback
-
+import itertools
 from pylons import url
 from pylons.i18n.translation import _
 
+from sqlalchemy.exc import DatabaseError
+from sqlalchemy.orm import joinedload
+
 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
 from rhodecode.lib.caching_query import FromCache
-
 from rhodecode.model import BaseModel
 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
     UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
-    Notification, RepoGroup, UserRepoGroupToPerm, UsersGroup,\
-    UsersGroupRepoGroupToPerm
+    Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
+    UserEmailMap
 from rhodecode.lib.exceptions import DefaultUserException, \
     UserOwnsReposException
 
-from sqlalchemy.exc import DatabaseError
-
-from sqlalchemy.orm import joinedload
 
 log = logging.getLogger(__name__)
 
-
-PERM_WEIGHTS = {
-    'repository.none': 0,
-    'repository.read': 1,
-    'repository.write': 3,
-    'repository.admin': 4,
-    'group.none': 0,
-    'group.read': 1,
-    'group.write': 3,
-    'group.admin': 4,
-}
+PERM_WEIGHTS = Permission.PERM_WEIGHTS
 
 
 class UserModel(BaseModel):
-
-    def __get_user(self, user):
-        return self._get_instance(User, user, callback=User.get_by_username)
-
-    def __get_perm(self, permission):
-        return self._get_instance(Permission, permission,
-                                  callback=Permission.get_by_key)
+    cls = User
 
     def get(self, user_id, cache=False):
         user = self.sa.query(User)
@@ -76,7 +59,7 @@
         return user.get(user_id)
 
     def get_user(self, user):
-        return self.__get_user(user)
+        return self._get_user(user)
 
     def get_by_username(self, username, cache=False, case_insensitive=False):
 
@@ -90,13 +73,21 @@
                                           "get_user_%s" % username))
         return user.scalar()
 
+    def get_by_email(self, email, cache=False, case_insensitive=False):
+        return User.get_by_email(email, case_insensitive, cache)
+
     def get_by_api_key(self, api_key, cache=False):
         return User.get_by_api_key(api_key, cache)
 
     def create(self, form_data):
+        from rhodecode.lib.auth import get_crypt_password
         try:
             new_user = User()
             for k, v in form_data.items():
+                if k == 'password':
+                    v = get_crypt_password(v)
+                if k == 'firstname':
+                    k = 'name'
                 setattr(new_user, k, v)
 
             new_user.api_key = generate_api_key(form_data['username'])
@@ -106,8 +97,8 @@
             log.error(traceback.format_exc())
             raise
 
-    def create_or_update(self, username, password, email, name, lastname,
-                         active=True, admin=False, ldap_dn=None):
+    def create_or_update(self, username, password, email, firstname='',
+                         lastname='', active=True, admin=False, ldap_dn=None):
         """
         Creates a new instance if not found, or updates current one
 
@@ -115,7 +106,7 @@
         :param password:
         :param email:
         :param active:
-        :param name:
+        :param firstname:
         :param lastname:
         :param active:
         :param admin:
@@ -129,19 +120,23 @@
         if user is None:
             log.debug('creating new user %s' % username)
             new_user = User()
+            edit = False
         else:
             log.debug('updating user %s' % username)
             new_user = user
+            edit = True
 
         try:
             new_user.username = username
             new_user.admin = admin
-            new_user.password = get_crypt_password(password)
-            new_user.api_key = generate_api_key(username)
+            # set password only if creating an user or password is changed
+            if edit is False or user.password != password:
+                new_user.password = get_crypt_password(password)
+                new_user.api_key = generate_api_key(username)
             new_user.email = email
             new_user.active = active
             new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
-            new_user.name = name
+            new_user.name = firstname
             new_user.lastname = lastname
             self.sa.add(new_user)
             return new_user
@@ -252,6 +247,7 @@
             raise
 
     def update(self, user_id, form_data):
+        from rhodecode.lib.auth import get_crypt_password
         try:
             user = self.get(user_id, cache=False)
             if user.username == 'default':
@@ -260,29 +256,56 @@
                                   " crucial for entire application"))
 
             for k, v in form_data.items():
-                if k == 'new_password' and v != '':
-                    user.password = v
+                if k == 'new_password' and v:
+                    user.password = get_crypt_password(v)
                     user.api_key = generate_api_key(user.username)
                 else:
+                    if k == 'firstname':
+                        k = 'name'
                     setattr(user, k, v)
+            self.sa.add(user)
+        except:
+            log.error(traceback.format_exc())
+            raise
 
+    def update_user(self, user, **kwargs):
+        from rhodecode.lib.auth import get_crypt_password
+        try:
+            user = self._get_user(user)
+            if user.username == 'default':
+                raise DefaultUserException(
+                    _("You can't Edit this user since it's"
+                      " crucial for entire application")
+                )
+
+            for k, v in kwargs.items():
+                if k == 'password' and v:
+                    v = get_crypt_password(v)
+                    user.api_key = generate_api_key(user.username)
+
+                setattr(user, k, v)
             self.sa.add(user)
+            return user
         except:
             log.error(traceback.format_exc())
             raise
 
     def update_my_account(self, user_id, form_data):
+        from rhodecode.lib.auth import get_crypt_password
         try:
             user = self.get(user_id, cache=False)
             if user.username == 'default':
                 raise DefaultUserException(
-                                _("You can't Edit this user since it's"
-                                  " crucial for entire application"))
+                    _("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 != '':
-                    user.password = v
+                if k == 'new_password' and v:
+                    user.password = get_crypt_password(v)
                     user.api_key = generate_api_key(user.username)
                 else:
+                    if k == 'firstname':
+                        k = 'name'
                     if k not in ['admin', 'active']:
                         setattr(user, k, v)
 
@@ -292,7 +315,7 @@
             raise
 
     def delete(self, user):
-        user = self.__get_user(user)
+        user = self._get_user(user)
 
         try:
             if user.username == 'default':
@@ -399,11 +422,11 @@
             return user
 
         #==================================================================
-        # set default permissions first for repositories and groups
+        # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS
         #==================================================================
         uid = user.user_id
 
-        # default global permissions
+        # default global permissions taken fron the default user
         default_global_perms = self.sa.query(UserToPerm)\
             .filter(UserToPerm.user_id == default_user_id)
 
@@ -431,25 +454,89 @@
             p = perm.Permission.permission_name
             user.permissions[GK][rg_k] = p
 
-        #==================================================================
-        # overwrite defaults with user permissions if any found
-        #==================================================================
+        #======================================================================
+        # !! OVERRIDE GLOBALS !! with user permissions if any found
+        #======================================================================
+        # those can be configured from groups or users explicitly
+        _configurable = set(['hg.fork.none', 'hg.fork.repository',
+                             'hg.create.none', 'hg.create.repository'])
 
-        # user global permissions
+        # USER GROUPS comes first
+        # users group global permissions
+        user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
+            .options(joinedload(UsersGroupToPerm.permission))\
+            .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
+                   UsersGroupMember.users_group_id))\
+            .filter(UsersGroupMember.user_id == uid)\
+            .order_by(UsersGroupToPerm.users_group_id)\
+            .all()
+        #need to group here by groups since user can be in more than one group
+        _grouped = [[x, list(y)] for x, y in
+                    itertools.groupby(user_perms_from_users_groups,
+                                      lambda x:x.users_group)]
+        for gr, perms in _grouped:
+            # since user can be in multiple groups iterate over them and
+            # select the lowest permissions first (more explicit)
+            ##TODO: do this^^
+            if not gr.inherit_default_permissions:
+                # NEED TO IGNORE all configurable permissions and
+                # replace them with explicitly set
+                user.permissions[GLOBAL] = user.permissions[GLOBAL]\
+                                                .difference(_configurable)
+            for perm in perms:
+                user.permissions[GLOBAL].add(perm.permission.permission_name)
+
+        # user specific global permissions
         user_perms = self.sa.query(UserToPerm)\
                 .options(joinedload(UserToPerm.permission))\
                 .filter(UserToPerm.user_id == uid).all()
 
-        for perm in user_perms:
-            user.permissions[GLOBAL].add(perm.permission.permission_name)
+        if not user.inherit_default_permissions:
+            # NEED TO IGNORE all configurable permissions and
+            # replace them with explicitly set
+            user.permissions[GLOBAL] = user.permissions[GLOBAL]\
+                                            .difference(_configurable)
+
+            for perm in user_perms:
+                user.permissions[GLOBAL].add(perm.permission.permission_name)
+
+        #======================================================================
+        # !! REPO PERMISSIONS !!
+        #======================================================================
+        #======================================================================
+        # check if user is part of user groups for this repository and
+        # fill in (or NOT replace with higher `or 1` permissions
+        #======================================================================
+        # users group for repositories permissions
+        user_repo_perms_from_users_groups = \
+         self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
+            .join((Repository, UsersGroupRepoToPerm.repository_id ==
+                   Repository.repo_id))\
+            .join((Permission, UsersGroupRepoToPerm.permission_id ==
+                   Permission.permission_id))\
+            .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
+                   UsersGroupMember.users_group_id))\
+            .filter(UsersGroupMember.user_id == uid)\
+            .all()
+
+        for perm in user_repo_perms_from_users_groups:
+            r_k = perm.UsersGroupRepoToPerm.repository.repo_name
+            p = perm.Permission.permission_name
+            cur_perm = user.permissions[RK][r_k]
+            # overwrite permission only if it's greater than permission
+            # given from other sources
+            if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1:  # disable check
+                user.permissions[RK][r_k] = p
 
         # user explicit permissions for repositories
         user_repo_perms = \
          self.sa.query(UserRepoToPerm, Permission, Repository)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
-         .filter(UserRepoToPerm.user_id == uid)\
-         .all()
+            .join((Repository, UserRepoToPerm.repository_id ==
+                   Repository.repo_id))\
+            .join((Permission, UserRepoToPerm.permission_id ==
+                   Permission.permission_id))\
+            .filter(UserRepoToPerm.user_id == uid)\
+            .all()
 
         for perm in user_repo_perms:
             # set admin if owner
@@ -460,40 +547,6 @@
                 p = perm.Permission.permission_name
             user.permissions[RK][r_k] = p
 
-        # USER GROUP
-        #==================================================================
-        # check if user is part of user groups for this repository and
-        # fill in (or replace with higher) permissions
-        #==================================================================
-
-        # users group global
-        user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
-            .options(joinedload(UsersGroupToPerm.permission))\
-            .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
-                   UsersGroupMember.users_group_id))\
-            .filter(UsersGroupMember.user_id == uid).all()
-
-        for perm in user_perms_from_users_groups:
-            user.permissions[GLOBAL].add(perm.permission.permission_name)
-
-        # users group for repositories permissions
-        user_repo_perms_from_users_groups = \
-         self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
-         .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
-         .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
-         .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
-         .filter(UsersGroupMember.user_id == uid)\
-         .all()
-
-        for perm in user_repo_perms_from_users_groups:
-            r_k = perm.UsersGroupRepoToPerm.repository.repo_name
-            p = perm.Permission.permission_name
-            cur_perm = user.permissions[RK][r_k]
-            # overwrite permission only if it's greater than permission
-            # given from other sources
-            if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
-                user.permissions[RK][r_k] = p
-
         # REPO GROUP
         #==================================================================
         # get access for this user for repos group and override defaults
@@ -541,11 +594,8 @@
         return user
 
     def has_perm(self, user, perm):
-        if not isinstance(perm, Permission):
-            raise Exception('perm needs to be an instance of Permission class '
-                            'got %s instead' % type(perm))
-
-        user = self.__get_user(user)
+        perm = self._get_perm(perm)
+        user = self._get_user(user)
 
         return UserToPerm.query().filter(UserToPerm.user == user)\
             .filter(UserToPerm.permission == perm).scalar() is not None
@@ -557,8 +607,8 @@
         :param user:
         :param perm:
         """
-        user = self.__get_user(user)
-        perm = self.__get_perm(perm)
+        user = self._get_user(user)
+        perm = self._get_perm(perm)
         # if this permission is already granted skip it
         _perm = UserToPerm.query()\
             .filter(UserToPerm.user == user)\
@@ -578,8 +628,8 @@
         :param user:
         :param perm:
         """
-        user = self.__get_user(user)
-        perm = self.__get_perm(perm)
+        user = self._get_user(user)
+        perm = self._get_perm(perm)
 
         obj = UserToPerm.query()\
                 .filter(UserToPerm.user == user)\
@@ -587,3 +637,33 @@
                 .scalar()
         if obj:
             self.sa.delete(obj)
+
+    def add_extra_email(self, user, email):
+        """
+        Adds email address to UserEmailMap
+
+        :param user:
+        :param email:
+        """
+        from rhodecode.model import forms
+        form = forms.UserExtraEmailForm()()
+        data = form.to_python(dict(email=email))
+        user = self._get_user(user)
+
+        obj = UserEmailMap()
+        obj.user = user
+        obj.email = data['email']
+        self.sa.add(obj)
+        return obj
+
+    def delete_extra_email(self, user, email_id):
+        """
+        Removes email address from UserEmailMap
+
+        :param user:
+        :param email_id:
+        """
+        user = self._get_user(user)
+        obj = UserEmailMap.query().get(email_id)
+        if obj:
+            self.sa.delete(obj)
--- a/rhodecode/model/users_group.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/model/users_group.py	Sun Sep 02 21:19:54 2012 +0200
@@ -37,20 +37,18 @@
 
 class UsersGroupModel(BaseModel):
 
-    def __get_user(self, user):
-        return self._get_instance(User, user, callback=User.get_by_username)
+    cls = UsersGroup
 
     def __get_users_group(self, users_group):
         return self._get_instance(UsersGroup, users_group,
                                   callback=UsersGroup.get_by_group_name)
 
-    def __get_perm(self, permission):
-        return self._get_instance(Permission, permission,
-                                  callback=Permission.get_by_key)
-
     def get(self, users_group_id, cache=False):
         return UsersGroup.get(users_group_id)
 
+    def get_group(self, users_group):
+        return self.__get_users_group(users_group)
+
     def get_by_name(self, name, cache=False, case_insensitive=False):
         return UsersGroup.get_by_group_name(name, cache, case_insensitive)
 
@@ -115,7 +113,7 @@
 
     def add_user_to_group(self, users_group, user):
         users_group = self.__get_users_group(users_group)
-        user = self.__get_user(user)
+        user = self._get_user(user)
 
         for m in users_group.members:
             u = m.user
@@ -138,7 +136,7 @@
 
     def remove_user_from_group(self, users_group, user):
         users_group = self.__get_users_group(users_group)
-        user = self.__get_user(user)
+        user = self._get_user(user)
 
         users_group_member = None
         for m in users_group.members:
@@ -160,17 +158,15 @@
 
     def has_perm(self, users_group, perm):
         users_group = self.__get_users_group(users_group)
-        perm = self.__get_perm(perm)
+        perm = self._get_perm(perm)
 
         return UsersGroupToPerm.query()\
             .filter(UsersGroupToPerm.users_group == users_group)\
             .filter(UsersGroupToPerm.permission == perm).scalar() is not None
 
     def grant_perm(self, users_group, perm):
-        if not isinstance(perm, Permission):
-            raise Exception('perm needs to be an instance of Permission class')
-
         users_group = self.__get_users_group(users_group)
+        perm = self._get_perm(perm)
 
         # if this permission is already granted skip it
         _perm = UsersGroupToPerm.query()\
@@ -187,7 +183,7 @@
 
     def revoke_perm(self, users_group, perm):
         users_group = self.__get_users_group(users_group)
-        perm = self.__get_perm(perm)
+        perm = self._get_perm(perm)
 
         obj = UsersGroupToPerm.query()\
             .filter(UsersGroupToPerm.users_group == users_group)\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/validators.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,676 @@
+"""
+Set of generic validators
+"""
+import os
+import re
+import formencode
+import logging
+from collections import defaultdict
+from pylons.i18n.translation import _
+from webhelpers.pylonslib.secure_form import authentication_token
+
+from formencode.validators import (
+    UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
+    NotEmpty
+)
+from rhodecode.lib.compat import OrderedSet
+from rhodecode.lib.utils import repo_name_slug
+from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\
+    ChangesetStatus
+from rhodecode.lib.exceptions import LdapImportError
+from rhodecode.config.routing import ADMIN_PREFIX
+
+# silence warnings and pylint
+UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
+    NotEmpty
+
+log = logging.getLogger(__name__)
+
+
+class UniqueList(formencode.FancyValidator):
+    """
+    Unique List !
+    """
+    messages = dict(
+        empty=_('Value cannot be an empty list'),
+        missing_value=_('Value cannot be an empty list'),
+    )
+
+    def _to_python(self, value, state):
+        if isinstance(value, list):
+            return value
+        elif isinstance(value, set):
+            return list(value)
+        elif isinstance(value, tuple):
+            return list(value)
+        elif value is None:
+            return []
+        else:
+            return [value]
+
+    def empty_value(self, value):
+        return []
+
+
+class StateObj(object):
+    """
+    this is needed to translate the messages using _() in validators
+    """
+    _ = staticmethod(_)
+
+
+def M(self, key, state=None, **kwargs):
+    """
+    returns string from self.message based on given key,
+    passed kw params are used to substitute %(named)s params inside
+    translated strings
+
+    :param msg:
+    :param state:
+    """
+    if state is None:
+        state = StateObj()
+    else:
+        state._ = staticmethod(_)
+    #inject validator into state object
+    return self.message(key, state, **kwargs)
+
+
+def ValidUsername(edit=False, old_data={}):
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'username_exists': _(u'Username "%(username)s" already exists'),
+            'system_invalid_username':
+                _(u'Username "%(username)s" is forbidden'),
+            'invalid_username':
+                _(u'Username may only contain alphanumeric characters '
+                  'underscores, periods or dashes and must begin with '
+                  'alphanumeric character')
+        }
+
+        def validate_python(self, value, state):
+            if value in ['default', 'new_user']:
+                msg = M(self, 'system_invalid_username', state, username=value)
+                raise formencode.Invalid(msg, value, state)
+            #check if user is unique
+            old_un = None
+            if edit:
+                old_un = User.get(old_data.get('user_id')).username
+
+            if old_un != value or not edit:
+                if User.get_by_username(value, case_insensitive=True):
+                    msg = M(self, 'username_exists', state, username=value)
+                    raise formencode.Invalid(msg, value, state)
+
+            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
+                msg = M(self, 'invalid_username', state)
+                raise formencode.Invalid(msg, value, state)
+    return _validator
+
+
+def ValidRepoUser():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_username': _(u'Username %(username)s is not valid')
+        }
+
+        def validate_python(self, value, state):
+            try:
+                User.query().filter(User.active == True)\
+                    .filter(User.username == value).one()
+            except Exception:
+                msg = M(self, 'invalid_username', state, username=value)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(username=msg)
+                )
+
+    return _validator
+
+
+def ValidUsersGroup(edit=False, old_data={}):
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_group': _(u'Invalid users group name'),
+            'group_exist': _(u'Users group "%(usersgroup)s" already exists'),
+            'invalid_usersgroup_name':
+                _(u'users group name may only contain  alphanumeric '
+                  'characters underscores, periods or dashes and must begin '
+                  'with alphanumeric character')
+        }
+
+        def validate_python(self, value, state):
+            if value in ['default']:
+                msg = M(self, 'invalid_group', state)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(users_group_name=msg)
+                )
+            #check if group is unique
+            old_ugname = None
+            if edit:
+                old_id = old_data.get('users_group_id')
+                old_ugname = UsersGroup.get(old_id).users_group_name
+
+            if old_ugname != value or not edit:
+                is_existing_group = UsersGroup.get_by_group_name(value,
+                                                        case_insensitive=True)
+                if is_existing_group:
+                    msg = M(self, 'group_exist', state, usersgroup=value)
+                    raise formencode.Invalid(msg, value, state,
+                        error_dict=dict(users_group_name=msg)
+                    )
+
+            if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
+                msg = M(self, 'invalid_usersgroup_name', state)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(users_group_name=msg)
+                )
+
+    return _validator
+
+
+def ValidReposGroup(edit=False, old_data={}):
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'group_parent_id': _(u'Cannot assign this group as parent'),
+            'group_exists': _(u'Group "%(group_name)s" already exists'),
+            'repo_exists':
+                _(u'Repository with name "%(group_name)s" already exists')
+        }
+
+        def validate_python(self, value, state):
+            # TODO WRITE VALIDATIONS
+            group_name = value.get('group_name')
+            group_parent_id = value.get('group_parent_id')
+
+            # slugify repo group just in case :)
+            slug = repo_name_slug(group_name)
+
+            # check for parent of self
+            parent_of_self = lambda: (
+                old_data['group_id'] == int(group_parent_id)
+                if group_parent_id else False
+            )
+            if edit and parent_of_self():
+                msg = M(self, 'group_parent_id', state)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(group_parent_id=msg)
+                )
+
+            old_gname = None
+            if edit:
+                old_gname = RepoGroup.get(old_data.get('group_id')).group_name
+
+            if old_gname != group_name or not edit:
+
+                # check group
+                gr = RepoGroup.query()\
+                      .filter(RepoGroup.group_name == slug)\
+                      .filter(RepoGroup.group_parent_id == group_parent_id)\
+                      .scalar()
+
+                if gr:
+                    msg = M(self, 'group_exists', state, group_name=slug)
+                    raise formencode.Invalid(msg, value, state,
+                            error_dict=dict(group_name=msg)
+                    )
+
+                # check for same repo
+                repo = Repository.query()\
+                      .filter(Repository.repo_name == slug)\
+                      .scalar()
+
+                if repo:
+                    msg = M(self, 'repo_exists', state, group_name=slug)
+                    raise formencode.Invalid(msg, value, state,
+                            error_dict=dict(group_name=msg)
+                    )
+
+    return _validator
+
+
+def ValidPassword():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_password':
+                _(u'Invalid characters (non-ascii) in password')
+        }
+
+        def validate_python(self, value, state):
+            try:
+                (value or '').decode('ascii')
+            except UnicodeError:
+                msg = M(self, 'invalid_password', state)
+                raise formencode.Invalid(msg, value, state,)
+    return _validator
+
+
+def ValidPasswordsMatch():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'password_mismatch': _(u'Passwords do not match'),
+        }
+
+        def validate_python(self, value, state):
+
+            pass_val = value.get('password') or value.get('new_password')
+            if pass_val != value['password_confirmation']:
+                msg = M(self, 'password_mismatch', state)
+                raise formencode.Invalid(msg, value, state,
+                     error_dict=dict(password_confirmation=msg)
+                )
+    return _validator
+
+
+def ValidAuth():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_password': _(u'invalid password'),
+            'invalid_username': _(u'invalid user name'),
+            'disabled_account': _(u'Your account is disabled')
+        }
+
+        def validate_python(self, value, state):
+            from rhodecode.lib.auth import authenticate
+
+            password = value['password']
+            username = value['username']
+
+            if not authenticate(username, password):
+                user = User.get_by_username(username)
+                if user and user.active is False:
+                    log.warning('user %s is disabled' % username)
+                    msg = M(self, 'disabled_account', state)
+                    raise formencode.Invalid(msg, value, state,
+                        error_dict=dict(username=msg)
+                    )
+                else:
+                    log.warning('user %s failed to authenticate' % username)
+                    msg = M(self, 'invalid_username', state)
+                    msg2 = M(self, 'invalid_password', state)
+                    raise formencode.Invalid(msg, value, state,
+                        error_dict=dict(username=msg, password=msg2)
+                    )
+    return _validator
+
+
+def ValidAuthToken():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_token': _(u'Token mismatch')
+        }
+
+        def validate_python(self, value, state):
+            if value != authentication_token():
+                msg = M(self, 'invalid_token', state)
+                raise formencode.Invalid(msg, value, state)
+    return _validator
+
+
+def ValidRepoName(edit=False, old_data={}):
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_repo_name':
+                _(u'Repository name %(repo)s is disallowed'),
+            'repository_exists':
+                _(u'Repository named %(repo)s already exists'),
+            'repository_in_group_exists': _(u'Repository "%(repo)s" already '
+                                            'exists in group "%(group)s"'),
+            'same_group_exists': _(u'Repositories group with name "%(repo)s" '
+                                   'already exists')
+        }
+
+        def _to_python(self, value, state):
+            repo_name = repo_name_slug(value.get('repo_name', ''))
+            repo_group = value.get('repo_group')
+            if repo_group:
+                gr = RepoGroup.get(repo_group)
+                group_path = gr.full_path
+                group_name = gr.group_name
+                # value needs to be aware of group name in order to check
+                # db key This is an actual just the name to store in the
+                # database
+                repo_name_full = group_path + RepoGroup.url_sep() + repo_name
+            else:
+                group_name = group_path = ''
+                repo_name_full = repo_name
+
+            value['repo_name'] = repo_name
+            value['repo_name_full'] = repo_name_full
+            value['group_path'] = group_path
+            value['group_name'] = group_name
+            return value
+
+        def validate_python(self, value, state):
+
+            repo_name = value.get('repo_name')
+            repo_name_full = value.get('repo_name_full')
+            group_path = value.get('group_path')
+            group_name = value.get('group_name')
+
+            if repo_name in [ADMIN_PREFIX, '']:
+                msg = M(self, 'invalid_repo_name', state, repo=repo_name)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(repo_name=msg)
+                )
+
+            rename = old_data.get('repo_name') != repo_name_full
+            create = not edit
+            if rename or create:
+
+                if group_path != '':
+                    if Repository.get_by_repo_name(repo_name_full):
+                        msg = M(self, 'repository_in_group_exists', state,
+                                repo=repo_name, group=group_name)
+                        raise formencode.Invalid(msg, value, state,
+                            error_dict=dict(repo_name=msg)
+                        )
+                elif RepoGroup.get_by_group_name(repo_name_full):
+                        msg = M(self, 'same_group_exists', state,
+                                repo=repo_name)
+                        raise formencode.Invalid(msg, value, state,
+                            error_dict=dict(repo_name=msg)
+                        )
+
+                elif Repository.get_by_repo_name(repo_name_full):
+                        msg = M(self, 'repository_exists', state,
+                                repo=repo_name)
+                        raise formencode.Invalid(msg, value, state,
+                            error_dict=dict(repo_name=msg)
+                        )
+            return value
+    return _validator
+
+
+def ValidForkName(*args, **kwargs):
+    return ValidRepoName(*args, **kwargs)
+
+
+def SlugifyName():
+    class _validator(formencode.validators.FancyValidator):
+
+        def _to_python(self, value, state):
+            return repo_name_slug(value)
+
+        def validate_python(self, value, state):
+            pass
+
+    return _validator
+
+
+def ValidCloneUri():
+    from rhodecode.lib.utils import make_ui
+
+    def url_handler(repo_type, url, ui=None):
+        if repo_type == 'hg':
+            from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
+            from mercurial.httppeer import httppeer
+            if url.startswith('http'):
+                ## initially check if it's at least the proper URL
+                ## or does it pass basic auth
+                MercurialRepository._check_url(url)
+                httppeer(ui, url)._capabilities()
+            elif url.startswith('svn+http'):
+                from hgsubversion.svnrepo import svnremoterepo
+                svnremoterepo(ui, url).capabilities
+            elif url.startswith('git+http'):
+                raise NotImplementedError()
+
+        elif repo_type == 'git':
+            from rhodecode.lib.vcs.backends.git.repository import GitRepository
+            if url.startswith('http'):
+                ## initially check if it's at least the proper URL
+                ## or does it pass basic auth
+                GitRepository._check_url(url)
+            elif url.startswith('svn+http'):
+                raise NotImplementedError()
+            elif url.startswith('hg+http'):
+                raise NotImplementedError()
+
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'clone_uri': _(u'invalid clone url'),
+            'invalid_clone_uri': _(u'Invalid clone url, provide a '
+                                    'valid clone http(s)/svn+http(s) url')
+        }
+
+        def validate_python(self, value, state):
+            repo_type = value.get('repo_type')
+            url = value.get('clone_uri')
+
+            if not url:
+                pass
+            else:
+                try:
+                    url_handler(repo_type, url, make_ui('db', clear_session=False))
+                except Exception:
+                    log.exception('Url validation failed')
+                    msg = M(self, 'clone_uri')
+                    raise formencode.Invalid(msg, value, state,
+                        error_dict=dict(clone_uri=msg)
+                    )
+    return _validator
+
+
+def ValidForkType(old_data={}):
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_fork_type': _(u'Fork have to be the same type as parent')
+        }
+
+        def validate_python(self, value, state):
+            if old_data['repo_type'] != value:
+                msg = M(self, 'invalid_fork_type', state)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(repo_type=msg)
+                )
+    return _validator
+
+
+def ValidPerms(type_='repo'):
+    if type_ == 'group':
+        EMPTY_PERM = 'group.none'
+    elif type_ == 'repo':
+        EMPTY_PERM = 'repository.none'
+
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'perm_new_member_name':
+                _(u'This username or users group name is not valid')
+        }
+
+        def to_python(self, value, state):
+            perms_update = OrderedSet()
+            perms_new = OrderedSet()
+            # build a list of permission to update and new permission to create
+
+            #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
+            new_perms_group = defaultdict(dict)
+            for k, v in value.copy().iteritems():
+                if k.startswith('perm_new_member'):
+                    del value[k]
+                    _type, part = k.split('perm_new_member_')
+                    args = part.split('_')
+                    if len(args) == 1:
+                        new_perms_group[args[0]]['perm'] = v
+                    elif len(args) == 2:
+                        _key, pos = args
+                        new_perms_group[pos][_key] = v
+
+            # fill new permissions in order of how they were added
+            for k in sorted(map(int, new_perms_group.keys())):
+                perm_dict = new_perms_group[str(k)]
+                new_member = perm_dict['name']
+                new_perm = perm_dict['perm']
+                new_type = perm_dict['type']
+                if new_member and new_perm and new_type:
+                    perms_new.add((new_member, new_perm, new_type))
+
+            for k, v in value.iteritems():
+                if k.startswith('u_perm_') or k.startswith('g_perm_'):
+                    member = k[7:]
+                    t = {'u': 'user',
+                         'g': 'users_group'
+                    }[k[0]]
+                    if member == 'default':
+                        if value.get('private'):
+                            # set none for default when updating to
+                            # private repo
+                            v = EMPTY_PERM
+                    perms_update.add((member, v, t))
+
+            value['perms_updates'] = list(perms_update)
+            value['perms_new'] = list(perms_new)
+
+            # update permissions
+            for k, v, t in perms_new:
+                try:
+                    if t is 'user':
+                        self.user_db = User.query()\
+                            .filter(User.active == True)\
+                            .filter(User.username == k).one()
+                    if t is 'users_group':
+                        self.user_db = UsersGroup.query()\
+                            .filter(UsersGroup.users_group_active == True)\
+                            .filter(UsersGroup.users_group_name == k).one()
+
+                except Exception:
+                    log.exception('Updated permission failed')
+                    msg = M(self, 'perm_new_member_type', state)
+                    raise formencode.Invalid(msg, value, state,
+                        error_dict=dict(perm_new_member_name=msg)
+                    )
+            return value
+    return _validator
+
+
+def ValidSettings():
+    class _validator(formencode.validators.FancyValidator):
+        def _to_python(self, value, state):
+            # settings  form can't edit user
+            if 'user' in value:
+                del value['user']
+            return value
+
+        def validate_python(self, value, state):
+            pass
+    return _validator
+
+
+def ValidPath():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_path': _(u'This is not a valid path')
+        }
+
+        def validate_python(self, value, state):
+            if not os.path.isdir(value):
+                msg = M(self, 'invalid_path', state)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(paths_root_path=msg)
+                )
+    return _validator
+
+
+def UniqSystemEmail(old_data={}):
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'email_taken': _(u'This e-mail address is already taken')
+        }
+
+        def _to_python(self, value, state):
+            return value.lower()
+
+        def validate_python(self, value, state):
+            if (old_data.get('email') or '').lower() != value:
+                user = User.get_by_email(value, case_insensitive=True)
+                if user:
+                    msg = M(self, 'email_taken', state)
+                    raise formencode.Invalid(msg, value, state,
+                        error_dict=dict(email=msg)
+                    )
+    return _validator
+
+
+def ValidSystemEmail():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
+        }
+
+        def _to_python(self, value, state):
+            return value.lower()
+
+        def validate_python(self, value, state):
+            user = User.get_by_email(value, case_insensitive=True)
+            if user is None:
+                msg = M(self, 'non_existing_email', state, email=value)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(email=msg)
+                )
+
+    return _validator
+
+
+def LdapLibValidator():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+
+        }
+
+        def validate_python(self, value, state):
+            try:
+                import ldap
+                ldap  # pyflakes silence !
+            except ImportError:
+                raise LdapImportError()
+
+    return _validator
+
+
+def AttrLoginValidator():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'invalid_cn':
+                  _(u'The LDAP Login attribute of the CN must be specified - '
+                    'this is the name of the attribute that is equivalent '
+                    'to "username"')
+        }
+
+        def validate_python(self, value, state):
+            if not value or not isinstance(value, (str, unicode)):
+                msg = M(self, 'invalid_cn', state)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(ldap_attr_login=msg)
+                )
+
+    return _validator
+
+
+def NotReviewedRevisions():
+    class _validator(formencode.validators.FancyValidator):
+        messages = {
+            'rev_already_reviewed':
+                  _(u'Revisions %(revs)s are already part of pull request '
+                    'or have set status')
+        }
+
+        def validate_python(self, value, state):
+            # check revisions if they are not reviewed, or a part of another
+            # pull request
+            statuses = ChangesetStatus.query()\
+                .filter(ChangesetStatus.revision.in_(value)).all()
+            errors = []
+            for cs in statuses:
+                if cs.pull_request_id:
+                    errors.append(['pull_req', cs.revision[:12]])
+                elif cs.status:
+                    errors.append(['status', cs.revision[:12]])
+
+            if errors:
+                revs = ','.join([x[1] for x in errors])
+                msg = M(self, 'rev_already_reviewed', state, revs=revs)
+                raise formencode.Invalid(msg, value, state,
+                    error_dict=dict(revisions=revs)
+                )
+
+    return _validator
--- a/rhodecode/public/css/codemirror.css	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/public/css/codemirror.css	Sun Sep 02 21:19:54 2012 +0200
@@ -1,14 +1,57 @@
 .CodeMirror {
-  overflow: auto;
-  height: 450px;
   line-height: 1em;
   font-family: monospace;
-  _position: relative; /* IE6 hack */
-  margin:20px;
+
+  /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
+  position: relative;
+  /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
+  overflow: hidden;
+}
+
+.CodeMirror-scroll {
+  overflow-x: auto;
+  overflow-y: hidden;
+  height: 300px;
+  /* This is needed to prevent an IE[67] bug where the scrolled content
+     is visible outside of the scrolling box. */
+  position: relative;
+  outline: none;
+}
+
+/* Vertical scrollbar */
+.CodeMirror-scrollbar {
+  float: right;
+  overflow-x: hidden;
+  overflow-y: scroll;
+
+  /* This corrects for the 1px gap introduced to the left of the scrollbar
+     by the rule for .CodeMirror-scrollbar-inner. */
+  margin-left: -1px;
+}
+.CodeMirror-scrollbar-inner {
+  /* This needs to have a nonzero width in order for the scrollbar to appear
+     in Firefox and IE9. */
+  width: 1px;
+}
+.CodeMirror-scrollbar.cm-sb-overlap {
+  /* Ensure that the scrollbar appears in Lion, and that it overlaps the content
+     rather than sitting to the right of it. */
+  position: absolute;
+  z-index: 1;
+  float: none;
+  right: 0;
+  min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-nonoverlap {
+  min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-ie7 {
+  min-width: 18px;
 }
 
 .CodeMirror-gutter {
   position: absolute; left: 0; top: 0;
+  z-index: 10;
   background-color: #f7f7f7;
   border-right: 1px solid #eee;
   min-width: 2em;
@@ -18,9 +61,16 @@
   color: #aaa;
   text-align: right;
   padding: .4em .2em .4em .4em;
+  white-space: pre !important;
 }
 .CodeMirror-lines {
   padding: .4em;
+  white-space: pre;
+  cursor: text;
+}
+.CodeMirror-lines * {
+  /* Necessary for throw-scrolling to decelerate properly on Safari. */
+  pointer-events: none;
 }
 
 .CodeMirror pre {
@@ -30,26 +80,89 @@
   border-radius: 0;
   border-width: 0; margin: 0; padding: 0; background: transparent;
   font-family: inherit;
+  font-size: inherit;
+  padding: 0; margin: 0;
+  white-space: pre;
+  word-wrap: normal;
+  line-height: inherit;
+  color: inherit;
 }
 
-.CodeMirror-cursor {
+.CodeMirror-wrap pre {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  word-break: normal;
+}
+.CodeMirror-wrap .CodeMirror-scroll {
+  overflow-x: hidden;
+}
+
+.CodeMirror textarea {
+  outline: none !important;
+}
+
+.CodeMirror pre.CodeMirror-cursor {
   z-index: 10;
   position: absolute;
   visibility: hidden;
-  border-left: 1px solid black !important;
+  border-left: 1px solid black;
+  border-right: none;
+  width: 0;
 }
-.CodeMirror-focused .CodeMirror-cursor {
+.cm-keymap-fat-cursor pre.CodeMirror-cursor {
+  width: auto;
+  border: 0;
+  background: transparent;
+  background: rgba(0, 200, 0, .4);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
+}
+/* Kludge to turn off filter in ie9+, which also accepts rgba */
+.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
+.CodeMirror-focused pre.CodeMirror-cursor {
   visibility: visible;
 }
 
-span.CodeMirror-selected {
-  background: #ccc !important;
-  color: HighlightText !important;
-}
-.CodeMirror-focused span.CodeMirror-selected {
-  background: Highlight !important;
+div.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
+
+.CodeMirror-searching {
+  background: #ffa;
+  background: rgba(255, 255, 0, .4);
 }
 
-.CodeMirror-matchingbracket {color: #0f0 !important;}
-.CodeMirror-nonmatchingbracket {color: #f22 !important;}
-.CodeMirror-gutter-text{color: #003367 !important;}
\ No newline at end of file
+/* Default theme */
+
+.cm-s-default span.cm-keyword {color: #708;}
+.cm-s-default span.cm-atom {color: #219;}
+.cm-s-default span.cm-number {color: #164;}
+.cm-s-default span.cm-def {color: #00f;}
+.cm-s-default span.cm-variable {color: black;}
+.cm-s-default span.cm-variable-2 {color: #05a;}
+.cm-s-default span.cm-variable-3 {color: #085;}
+.cm-s-default span.cm-property {color: black;}
+.cm-s-default span.cm-operator {color: black;}
+.cm-s-default span.cm-comment {color: #a50;}
+.cm-s-default span.cm-string {color: #a11;}
+.cm-s-default span.cm-string-2 {color: #f50;}
+.cm-s-default span.cm-meta {color: #555;}
+.cm-s-default span.cm-error {color: #f00;}
+.cm-s-default span.cm-qualifier {color: #555;}
+.cm-s-default span.cm-builtin {color: #30a;}
+.cm-s-default span.cm-bracket {color: #cc7;}
+.cm-s-default span.cm-tag {color: #170;}
+.cm-s-default span.cm-attribute {color: #00c;}
+.cm-s-default span.cm-header {color: blue;}
+.cm-s-default span.cm-quote {color: #090;}
+.cm-s-default span.cm-hr {color: #999;}
+.cm-s-default span.cm-link {color: #00c;}
+
+span.cm-header, span.cm-strong {font-weight: bold;}
+span.cm-em {font-style: italic;}
+span.cm-emstrong {font-style: italic; font-weight: bold;}
+span.cm-link {text-decoration: underline;}
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
--- a/rhodecode/public/css/style.css	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/public/css/style.css	Sun Sep 02 21:19:54 2012 +0200
@@ -220,6 +220,28 @@
     margin-top: 5px;
 }
 
+.empty_data{
+    color:#B9B9B9;	
+}
+
+a.permalink{
+	visibility: hidden;
+}
+
+a.permalink:hover{
+	text-decoration: none;
+}
+
+h1:hover > a.permalink,
+h2:hover > a.permalink,
+h3:hover > a.permalink,
+h4:hover > a.permalink,
+h5:hover > a.permalink,
+h6:hover > a.permalink,
+div:hover > a.permalink {
+    visibility: visible;
+}
+
 #header {
 	margin: 0;
 	padding: 0 10px;
@@ -232,7 +254,7 @@
 	-moz-border-radius: 0px 0px 8px 8px;
 	border-radius: 0px 0px 8px 8px;
 	height: 37px;
-    background-color: #003B76;
+    background-color: #003B76;    
     background-repeat: repeat-x;
     background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
     background-image: -moz-linear-gradient(top, #003b76, #00376e);
@@ -330,6 +352,11 @@
     z-index: auto !important;
 }
 
+.header-pos-fix{
+	margin-top: -44px;
+	padding-top: 44px;
+}
+
 #header #header-inner #home a {
 	height: 40px;
 	width: 46px;
@@ -631,6 +658,15 @@
 	padding: 12px 9px 7px 24px;
 }
 
+#header #header-inner #quick li ul li a.pull_request,#header #header-inner #quick li ul li a.pull_request:hover
+    {
+    background: #FFF url("../images/icons/arrow_join.png") no-repeat 4px
+        9px;
+    width: 167px;
+    margin: 0;
+    padding: 12px 9px 7px 24px;
+}
+
 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover
 	{
 	background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
@@ -1065,6 +1101,10 @@
 	color: #FFFFFF;
 }
 
+#content div.box div.title .link-white.current{
+    color: #BFE3FF;
+}
+
 #content div.box div.title ul.links li {
 	list-style: none;
 	float: left;
@@ -1398,7 +1438,8 @@
 	margin: 0 0 0 0px;
 }
 
-#content div.box div.form div.fields div.field div.input input {
+#content div.box div.form div.fields div.field div.input input,
+.reviewer_ac input {
 	background: #FFF;
 	border-top: 1px solid #b3b3b3;
 	border-left: 1px solid #b3b3b3;
@@ -1518,12 +1559,21 @@
 	padding: 5px 5px 5px 0;
 }
 
-#content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus
+#content div.box div.form div.fields div.field input[type=text]:focus,
+#content div.box div.form div.fields div.field input[type=password]:focus,
+#content div.box div.form div.fields div.field input[type=file]:focus,
+#content div.box div.form div.fields div.field textarea:focus,
+#content div.box div.form div.fields div.field select:focus,
+.reviewer_ac input:focus
 	{
 	background: #f6f6f6;
 	border-color: #666;
 }
 
+.reviewer_ac {
+	padding:10px
+}
+
 div.form div.fields div.field div.button {
 	margin: 0;
 	padding: 0 0 0 8px;
@@ -1689,7 +1739,12 @@
 	float: right;
 }
 
-#content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot
+#content div.box div.pagination-wh a,
+#content div.box div.pagination-wh span.pager_dotdot,
+#content div.box div.pagination-wh span.yui-pg-previous,
+#content div.box div.pagination-wh span.yui-pg-last,
+#content div.box div.pagination-wh span.yui-pg-next,
+#content div.box div.pagination-wh span.yui-pg-first
 	{
 	height: 1%;
 	float: left;
@@ -1777,6 +1832,81 @@
 	
 }
 
+#summary .metatag {
+    display: inline-block;
+    padding: 3px 5px;
+    margin-bottom: 3px;
+    margin-right: 1px;
+    border-radius: 5px;
+}
+
+#content div.box #summary p {
+    margin-bottom: -5px;
+        width: 600px;
+        white-space: pre-wrap;
+}
+
+#content div.box #summary p:last-child {
+    margin-bottom: 9px;
+}
+
+#content div.box #summary p:first-of-type {
+    margin-top: 9px;
+}
+
+ .metatag {
+    display: inline-block;
+    margin-right: 1px;
+    -webkit-border-radius: 4px 4px 4px 4px;
+    -khtml-border-radius: 4px 4px 4px 4px;
+    -moz-border-radius: 4px 4px 4px 4px;
+    border-radius: 4px 4px 4px 4px;
+    
+    border: solid 1px #9CF;
+    padding: 2px 3px 2px 3px !important;
+    background-color: #DEF;    
+}
+
+.metatag[tag="dead"] {
+	background-color: #E44;
+}
+
+.metatag[tag="stale"] {
+    background-color: #EA4;
+}
+
+.metatag[tag="featured"] {
+	background-color: #AEA;
+}
+
+.metatag[tag="requires"] { 
+	background-color: #9CF;
+}
+
+.metatag[tag="recommends"] { 
+	background-color: #BDF; 
+}
+
+.metatag[tag="lang"] { 
+    background-color: #FAF474; 
+}
+
+.metatag[tag="license"] {
+    border: solid 1px #9CF;
+    background-color: #DEF;
+    target-new: tab !important;
+}
+.metatag[tag="see"] {
+    border: solid 1px #CBD;
+    background-color: #EDF;
+}
+
+a.metatag[tag="license"]:hover {
+    background-color: #003367;
+    color: #FFF;
+    text-decoration: none;
+}
+
 #summary .desc {
 	white-space: pre;
 	width: 100%;
@@ -1923,7 +2053,7 @@
     padding: 4px;
     position: absolute;
     width: 278px;
-    
+    background-color: #003B76;
     background-repeat: repeat-x;
     background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
     background-image: -moz-linear-gradient(top, #003b76, #00376e);
@@ -2247,6 +2377,20 @@
 	padding: 5px !important;
 }
 
+.file_history{
+	padding-top:10px;
+	font-size:16px;
+}
+.file_author{
+	float: left;
+}
+
+.file_author .item{
+	float:left;
+	padding:5px;
+	color: #888;
+}
+
 .tablerow0 {
 	background-color: #F8F8F8;
 }
@@ -2333,7 +2477,7 @@
     padding: 2px 0px 2px 0px;
 }
 
-.cs_files .cs_added {
+.cs_files .cs_added,.cs_files .cs_A {
 	background: url("../images/icons/page_white_add.png") no-repeat scroll
 		3px;
 	height: 16px;
@@ -2342,7 +2486,7 @@
 	text-align: left;
 }
 
-.cs_files .cs_changed {
+.cs_files .cs_changed,.cs_files .cs_M {
 	background: url("../images/icons/page_white_edit.png") no-repeat scroll
 		3px;
 	height: 16px;
@@ -2351,7 +2495,7 @@
 	text-align: left;
 }
 
-.cs_files .cs_removed {
+.cs_files .cs_removed,.cs_files .cs_D {
 	background: url("../images/icons/page_white_delete.png") no-repeat
 		scroll 3px;
 	height: 16px;
@@ -2447,6 +2591,31 @@
     font-weight: bold !important;
 }
 
+.changeset-status-container{
+    padding-right: 5px;
+    margin-top:1px;
+    float:right;
+    height:14px;
+}
+.code-header .changeset-status-container{
+	float:left;
+	padding:2px 0px 0px 2px;
+}
+.changeset-status-container .changeset-status-lbl{
+	color: rgb(136, 136, 136);
+    float: left;
+    padding: 3px 4px 0px 0px
+}
+.code-header .changeset-status-container .changeset-status-lbl{
+    float: left;
+    padding: 0px 4px 0px 0px;   
+}
+.changeset-status-container .changeset-status-ico{
+    float: left;
+}
+.code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico{
+    float: left;
+}
 .right .comments-container{
 	padding-right: 5px;
 	margin-top:1px;
@@ -2815,6 +2984,13 @@
 	box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 }
 
+.mentions-container{
+	width: 90% !important;
+}
+.mentions-container .yui-ac-content{
+	width: 100% !important;
+}
+
 .ac {
 	vertical-align: top;
 }
@@ -2925,6 +3101,13 @@
 	text-align: left;
 }
 
+.accept_icon {
+    background: url("../images/icons/accept.png") no-repeat scroll 3px;
+    padding-left: 20px;
+    padding-top: 0px;
+    text-align: left;
+}
+
 .edit_icon {
 	background: url("../images/icons/folder_edit.png") no-repeat scroll 3px;
 	padding-left: 20px;
@@ -3042,6 +3225,10 @@
 	
 }
 
+.error_red {
+	color:red;
+}
+
 .error_msg {
 	background-color: #c43c35;
 	background-repeat: repeat-x;
@@ -3228,6 +3415,11 @@
 .ui-btn.xsmall{
     padding: 1px 2px 1px 1px;
 }
+
+.ui-btn.large{
+	padding: 6px 12px;
+}
+
 .ui-btn.clone{
 	padding: 5px 2px 6px 1px;
 	margin: 0px -4px 3px 0px;
@@ -3268,6 +3460,7 @@
 
 
 .ui-btn.blue{
+  color:#fff;
   background-color: #339bb9;
   background-repeat: repeat-x;
   background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
@@ -3297,6 +3490,10 @@
   border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);	
 }
 
+.ui-btn.active{
+    font-weight: bold;
+}
+
 ins,div.options a:hover {
 	text-decoration: none;
 }
@@ -3452,12 +3649,14 @@
 	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
-	{
-	color: #000;
-	font-size: 11px;
-	font-weight: 700;
-	margin: 0;
+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 {
+	/*color: #000;*/
+    font-size: 11px;
+    font-weight: 700;
+    margin: 0;
 }
 
 input.ui-button {
@@ -3687,6 +3886,26 @@
 	padding:0px 0px 0px 10px;
 }
 
+.reviewers_member{
+    height: 15px;
+    padding:0px 0px 0px 10px;	
+}
+
+.emails_wrap{
+	padding: 0px 20px;
+}
+
+.emails_wrap .email_entry{
+    height: 30px;
+    padding:0px 0px 0px 10px;
+}
+.emails_wrap .email_entry .email{
+	float: left
+}
+.emails_wrap .email_entry .email_action{
+	float: left
+}
+
 /*README STYLE*/
 
 div.readme {
@@ -3891,6 +4110,7 @@
     background: #f8f8f8;
     padding: 4px;
     border-bottom: 1px solid #ddd;
+    height: 18px;
 }
 
 .comments .comment .meta img {
@@ -3899,9 +4119,13 @@
 
 .comments .comment .meta .user {
     font-weight: bold;
+    float: left;
+    padding: 4px 2px 2px 2px;
 }
 
 .comments .comment .meta .date {
+	float: left;
+	padding:4px 4px 0px 4px;
 }
 
 .comments .comment .text {
@@ -3920,6 +4144,11 @@
 
 /** comment form **/
 
+.status-block{
+    height:80px;
+    clear:both	
+}
+
 .comment-form .clearfix{
 	background: #EEE;
     -webkit-border-radius: 4px;
@@ -4089,6 +4318,7 @@
     background: #f8f8f8;
     padding: 4px;
     border-bottom: 1px solid #ddd;
+    height: 20px;
 }
 
 .inline-comments .comment .meta img {
@@ -4097,9 +4327,13 @@
 
 .inline-comments .comment .meta .user {
     font-weight: bold;
+    float:left;
+    padding: 3px;
 }
 
 .inline-comments .comment .meta .date {
+    float:left;
+    padding: 3px;
 }
 
 .inline-comments .comment .text {
@@ -4161,7 +4395,7 @@
     background: none repeat scroll 0 0 transparent;
     padding: 0px 0px 0px 8px;	
 }
-.notification-header .desc.unread{
+.notification-list .container .notification-header .desc{
     font-weight: bold;
     font-size: 17px;
 }
@@ -4178,6 +4412,11 @@
     padding-top: 8px;
     cursor: pointer;
 }
+.notification-header .read-notifications{
+    float: right;
+    padding-top: 8px;
+    cursor: pointer;
+}
 .notification-subject{
     clear:both;
     border-bottom: 1px solid #eee;
@@ -4190,6 +4429,15 @@
 }
 
 /****
+PULL REQUESTS
+*****/
+.pullrequests_section_head {
+   padding:10px 10px 10px 0px;
+   font-size:16px;
+   font-weight: bold;
+}
+
+/****
   PERMS
 *****/
 #perms .perms_section_head {
Binary file rhodecode/public/images/arrow_right_64.png has changed
Binary file rhodecode/public/images/icons/flag_status_approved.png has changed
Binary file rhodecode/public/images/icons/flag_status_not_reviewed.png has changed
Binary file rhodecode/public/images/icons/flag_status_rejected.png has changed
Binary file rhodecode/public/images/icons/flag_status_under_review.png has changed
--- a/rhodecode/public/js/codemirror.js	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/public/js/codemirror.js	Sun Sep 02 21:19:54 2012 +0200
@@ -4,7 +4,7 @@
 
 // CodeMirror is the only global var we claim
 var CodeMirror = (function() {
-  // This is the function that produces an editor instance. It's
+  // This is the function that produces an editor instance. Its
   // closure is used to store the editor state.
   function CodeMirror(place, givenOptions) {
     // Determine effective options based on given values and defaults.
@@ -13,41 +13,65 @@
       if (defaults.hasOwnProperty(opt))
         options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
 
-    var targetDocument = options["document"];
     // The element in which the editor lives.
-    var wrapper = targetDocument.createElement("div");
-    wrapper.className = "CodeMirror";
+    var wrapper = document.createElement("div");
+    wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
     // This mess creates the base DOM structure for the editor.
     wrapper.innerHTML =
-      '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
-        '<textarea style="position: absolute; width: 10000px;" wrap="off" ' +
+      '<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
+        '<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' +
           'autocorrect="off" autocapitalize="off"></textarea></div>' +
-      '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
+      '<div class="CodeMirror-scrollbar">' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
+        '<div class="CodeMirror-scrollbar-inner">' + // The empty scrollbar content, used solely for managing the scrollbar thumb.
+      '</div></div>' + // This must be before the scroll area because it's float-right.
+      '<div class="CodeMirror-scroll" tabindex="-1">' +
         '<div style="position: relative">' + // Set to the height of the text, causes scrolling
-          '<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
           '<div style="position: relative">' + // Moved around its parent to cover visible view
             '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
             // Provides positioning relative to (visible) text origin
-            '<div class="CodeMirror-lines"><div style="position: relative" draggable="true">' +
+            '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
+              // Used to measure text size
+              '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden;"></div>' +
               '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
-              '<div></div>' + // This DIV contains the actual code
+              '<pre class="CodeMirror-cursor" style="visibility: hidden">&#160;</pre>' + // Used to force a width
+              '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
             '</div></div></div></div></div>';
     if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
     // I've never seen more elegant code in my life.
     var inputDiv = wrapper.firstChild, input = inputDiv.firstChild,
         scroller = wrapper.lastChild, code = scroller.firstChild,
-        measure = code.firstChild, mover = measure.nextSibling,
-        gutter = mover.firstChild, gutterText = gutter.firstChild,
-        lineSpace = gutter.nextSibling.firstChild,
-        cursor = lineSpace.firstChild, lineDiv = cursor.nextSibling;
-    if (options.tabindex != null) input.tabindex = options.tabindex;
+        mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
+        lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
+        cursor = measure.nextSibling, widthForcer = cursor.nextSibling,
+        selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling,
+        scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild;
+    themeChanged(); keyMapChanged();
+    // Needed to hide big blue blinking cursor on Mobile Safari
+    if (ios) input.style.width = "0px";
+    if (!webkit) scroller.draggable = true;
+    lineSpace.style.outline = "none";
+    if (options.tabindex != null) input.tabIndex = options.tabindex;
+    if (options.autofocus) focusInput();
     if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
+    // Needed to handle Tab key in KHTML
+    if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
+
+    // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and 
+    // make it overlap the content. (But we only do this if the scrollbar doesn't already
+    // have a natural width. If the mouse is plugged in or the user sets the system pref
+    // to always show scrollbars, the scrollbar shouldn't overlap.)
+    if (mac_geLion) {
+      scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap");
+    } else if (ie_lt8) {
+      // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+      scrollbar.className += " cm-sb-ie7";
+    }
 
     // Check for problem with IE innerHTML not working when we have a
     // P (or similar) parent node.
     try { stringWidth("x"); }
     catch (e) {
-      if (e.message.match(/unknown runtime/i))
+      if (e.message.match(/runtime/i))
         e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
       throw e;
     }
@@ -55,34 +79,32 @@
     // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
     var poll = new Delayed(), highlight = new Delayed(), blinker;
 
-    // mode holds a mode API object. lines an array of Line objects
-    // (see Line constructor), work an array of lines that should be
-    // parsed, and history the undo history (instance of History
-    // constructor).
-    var mode, lines = [new Line("")], work, focused;
+    // mode holds a mode API object. doc is the tree of Line objects,
+    // work an array of lines that should be parsed, and history the
+    // undo history (instance of History constructor).
+    var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused;
     loadMode();
     // The selection. These are always maintained to point at valid
     // positions. Inverted is used to remember that the user is
     // selecting bottom-to-top.
     var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
     // Selection-related flags. shiftSelecting obviously tracks
-    // whether the user is holding shift. reducedSelection is a hack
-    // to get around the fact that we can't create inverted
-    // selections. See below.
-    var shiftSelecting, reducedSelection, lastClick, lastDoubleClick, draggingText;
+    // whether the user is holding shift.
+    var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText,
+        overwrite = false, suppressEdits = false;
     // Variables used by startOperation/endOperation to track what
     // happened during the operation.
-    var updateInput, changes, textChanged, selectionChanged, leaveInputAlone, gutterDirty;
+    var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone,
+        gutterDirty, callbacks;
     // Current visible range (may be bigger than the view window).
-    var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
-    // editing will hold an object describing the things we put in the
-    // textarea, to help figure out whether something changed.
-    // bracketHighlighted is used to remember that a backet has been
+    var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
+    // bracketHighlighted is used to remember that a bracket has been
     // marked.
-    var editing, bracketHighlighted;
+    var bracketHighlighted;
     // Tracks the maximum line length so that the horizontal scrollbar
     // can be kept static when scrolling.
-    var maxLine = "", maxWidth;
+    var maxLine = "", updateMaxLine = false, maxLineChanged = true;
+    var tabCache = {};
 
     // Initialize the content.
     operation(function(){setValue(options.value || ""); updateInput = false;})();
@@ -91,38 +113,53 @@
     // Register our event handlers.
     connect(scroller, "mousedown", operation(onMouseDown));
     connect(scroller, "dblclick", operation(onDoubleClick));
-    connect(lineSpace, "dragstart", onDragStart);
+    connect(lineSpace, "selectstart", e_preventDefault);
     // Gecko browsers fire contextmenu *after* opening the menu, at
     // which point we can't mess with it anymore. Context menu is
     // handled in onMouseDown for Gecko.
     if (!gecko) connect(scroller, "contextmenu", onContextMenu);
-    connect(scroller, "scroll", function() {
-      updateDisplay([]);
-      if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
-      if (options.onScroll) options.onScroll(instance);
-    });
+    connect(scroller, "scroll", onScroll);
+    connect(scrollbar, "scroll", onScroll);
+    connect(scrollbar, "mousedown", function() {setTimeout(focusInput, 0);});
+    connect(scroller, "mousewheel", onMouseWheel);
+    connect(scroller, "DOMMouseScroll", onMouseWheel);
     connect(window, "resize", function() {updateDisplay(true);});
     connect(input, "keyup", operation(onKeyUp));
-    connect(input, "input", function() {fastPoll(curKeyId);});
+    connect(input, "input", fastPoll);
     connect(input, "keydown", operation(onKeyDown));
     connect(input, "keypress", operation(onKeyPress));
     connect(input, "focus", onFocus);
     connect(input, "blur", onBlur);
 
-    connect(scroller, "dragenter", e_stop);
-    connect(scroller, "dragover", e_stop);
-    connect(scroller, "drop", operation(onDrop));
+    if (options.dragDrop) {
+      connect(scroller, "dragstart", onDragStart);
+      function drag_(e) {
+        if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
+        e_stop(e);
+      }
+      connect(scroller, "dragenter", drag_);
+      connect(scroller, "dragover", drag_);
+      connect(scroller, "drop", operation(onDrop));
+    }
     connect(scroller, "paste", function(){focusInput(); fastPoll();});
-    connect(input, "paste", function(){fastPoll();});
-    connect(input, "cut", function(){fastPoll();});
+    connect(input, "paste", fastPoll);
+    connect(input, "cut", operation(function(){
+      if (!options.readOnly) replaceSelection("");
+    }));
+
+    // Needed to handle Tab key in KHTML
+    if (khtml) connect(code, "mouseup", function() {
+        if (document.activeElement == input) input.blur();
+        focusInput();
+    });
 
     // IE throws unspecified error in certain cases, when
     // trying to access activeElement before onload
-    var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
-    if (hasFocus) setTimeout(onFocus, 20);
+    var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { }
+    if (hasFocus || options.autofocus) setTimeout(onFocus, 20);
     else onBlur();
 
-    function isLine(l) {return l >= 0 && l < lines.length;}
+    function isLine(l) {return l >= 0 && l < doc.size;}
     // The instance object that we'll return. Mostly calls out to
     // local functions in the CodeMirror function. Some do some extra
     // range checking and/or clipping. operation is used to wrap the
@@ -133,47 +170,74 @@
       setValue: operation(setValue),
       getSelection: getSelection,
       replaceSelection: operation(replaceSelection),
-      focus: function(){focusInput(); onFocus(); fastPoll();},
+      focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
       setOption: function(option, value) {
+        var oldVal = options[option];
         options[option] = value;
-        if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber")
-          operation(gutterChanged)();
-        else if (option == "mode" || option == "indentUnit") loadMode();
-        else if (option == "readOnly" && value == "nocursor") input.blur();
-        else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
+        if (option == "mode" || option == "indentUnit") loadMode();
+        else if (option == "readOnly" && value == "nocursor") {onBlur(); input.blur();}
+        else if (option == "readOnly" && !value) {resetInput(true);}
+        else if (option == "theme") themeChanged();
+        else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
+        else if (option == "tabSize") updateDisplay(true);
+        else if (option == "keyMap") keyMapChanged();
+        if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
+          gutterChanged();
+          updateDisplay(true);
+        }
       },
       getOption: function(option) {return options[option];},
       undo: operation(undo),
       redo: operation(redo),
       indentLine: operation(function(n, dir) {
-        if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
+        if (typeof dir != "string") {
+          if (dir == null) dir = options.smartIndent ? "smart" : "prev";
+          else dir = dir ? "add" : "subtract";
+        }
+        if (isLine(n)) indentLine(n, dir);
       }),
+      indentSelection: operation(indentSelected),
       historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
       clearHistory: function() {history = new History();},
       matchBrackets: operation(function(){matchBrackets(true);}),
-      getTokenAt: function(pos) {
+      getTokenAt: operation(function(pos) {
         pos = clipPos(pos);
-        return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
-      },
+        return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), pos.ch);
+      }),
       getStateAfter: function(line) {
-        line = clipLine(line == null ? lines.length - 1: line);
+        line = clipLine(line == null ? doc.size - 1: line);
         return getStateBefore(line + 1);
       },
-      cursorCoords: function(start){
+      cursorCoords: function(start, mode) {
         if (start == null) start = sel.inverted;
-        return pageCoords(start ? sel.from : sel.to);
+        return this.charCoords(start ? sel.from : sel.to, mode);
       },
-      charCoords: function(pos){return pageCoords(clipPos(pos));},
+      charCoords: function(pos, mode) {
+        pos = clipPos(pos);
+        if (mode == "local") return localCoords(pos, false);
+        if (mode == "div") return localCoords(pos, true);
+        return pageCoords(pos);
+      },
       coordsChar: function(coords) {
         var off = eltOffset(lineSpace);
-        var line = clipLine(Math.min(lines.length - 1, showingFrom + Math.floor((coords.y - off.top) / lineHeight())));
-        return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
+        return coordsChar(coords.x - off.left, coords.y - off.top);
       },
-      getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
       markText: operation(markText),
+      setBookmark: setBookmark,
+      findMarksAt: findMarksAt,
       setMarker: operation(addGutterMarker),
       clearMarker: operation(removeGutterMarker),
       setLineClass: operation(setLineClass),
+      hideLine: operation(function(h) {return setLineHidden(h, true);}),
+      showLine: operation(function(h) {return setLineHidden(h, false);}),
+      onDeleteLine: function(line, f) {
+        if (typeof line == "number") {
+          if (!isLine(line)) return null;
+          line = getLine(line);
+        }
+        (line.handlers || (line.handlers = [])).push(f);
+        return line;
+      },
       lineInfo: lineInfo,
       addWidget: function(pos, node, scroll, vert, horiz) {
         pos = localCoords(clipPos(pos));
@@ -182,7 +246,7 @@
         code.appendChild(node);
         if (vert == "over") top = pos.y;
         else if (vert == "near") {
-          var vspace = Math.max(scroller.offsetHeight, lines.length * lineHeight()),
+          var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()),
               hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
           if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
             top = pos.y - node.offsetHeight;
@@ -203,20 +267,24 @@
           scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
       },
 
-      lineCount: function() {return lines.length;},
+      lineCount: function() {return doc.size;},
+      clipPos: clipPos,
       getCursor: function(start) {
         if (start == null) start = sel.inverted;
         return copyPos(start ? sel.from : sel.to);
       },
       somethingSelected: function() {return !posEq(sel.from, sel.to);},
-      setCursor: operation(function(line, ch) {
-        if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
-        else setCursor(line, ch);
+      setCursor: operation(function(line, ch, user) {
+        if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch, user);
+        else setCursor(line, ch, user);
       }),
-      setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
-      getLine: function(line) {if (isLine(line)) return lines[line].text;},
+      setSelection: operation(function(from, to, user) {
+        (user ? setSelectionUser : setSelection)(clipPos(from), clipPos(to || from));
+      }),
+      getLine: function(line) {if (isLine(line)) return getLine(line).text;},
+      getLineHandle: function(line) {if (isLine(line)) return getLine(line);},
       setLine: operation(function(line, text) {
-        if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: lines[line].text.length});
+        if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
       }),
       removeLine: operation(function(line) {
         if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
@@ -224,44 +292,99 @@
       replaceRange: operation(replaceRange),
       getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
 
-      coordsFromIndex: function(index) {        
-        var total = lines.length, pos = 0, line, ch, len;
-        
-        for (line = 0; line < total; line++) {
-          len = lines[line].text.length + 1;
-          if (pos + len > index) { ch = index - pos; break; }
-          pos += len;
+      triggerOnKeyDown: operation(onKeyDown),
+      execCommand: function(cmd) {return commands[cmd](instance);},
+      // Stuff used by commands, probably not much use to outside code.
+      moveH: operation(moveH),
+      deleteH: operation(deleteH),
+      moveV: operation(moveV),
+      toggleOverwrite: function() {
+        if(overwrite){
+          overwrite = false;
+          cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
+        } else {
+          overwrite = true;
+          cursor.className += " CodeMirror-overwrite";
         }
-        return clipPos({line: line, ch: ch});
+      },
+
+      posFromIndex: function(off) {
+        var lineNo = 0, ch;
+        doc.iter(0, doc.size, function(line) {
+          var sz = line.text.length + 1;
+          if (sz > off) { ch = off; return true; }
+          off -= sz;
+          ++lineNo;
+        });
+        return clipPos({line: lineNo, ch: ch});
+      },
+      indexFromPos: function (coords) {
+        if (coords.line < 0 || coords.ch < 0) return 0;
+        var index = coords.ch;
+        doc.iter(0, coords.line, function (line) {
+          index += line.text.length + 1;
+        });
+        return index;
+      },
+      scrollTo: function(x, y) {
+        if (x != null) scroller.scrollLeft = x;
+        if (y != null) scrollbar.scrollTop = y;
+        updateDisplay([]);
+      },
+      getScrollInfo: function() {
+        return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
+                height: scrollbar.scrollHeight, width: scroller.scrollWidth};
       },
 
       operation: function(f){return operation(f)();},
-      refresh: function(){updateDisplay(true);},
+      compoundChange: function(f){return compoundChange(f);},
+      refresh: function(){
+        updateDisplay(true);
+        if (scrollbar.scrollHeight > lastScrollTop)
+          scrollbar.scrollTop = lastScrollTop;
+      },
       getInputField: function(){return input;},
       getWrapperElement: function(){return wrapper;},
       getScrollerElement: function(){return scroller;},
       getGutterElement: function(){return gutter;}
     };
 
+    function getLine(n) { return getLineAt(doc, n); }
+    function updateLineHeight(line, height) {
+      gutterDirty = true;
+      var diff = height - line.height;
+      for (var n = line; n; n = n.parent) n.height += diff;
+    }
+
     function setValue(code) {
       var top = {line: 0, ch: 0};
-      updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
+      updateLines(top, {line: doc.size - 1, ch: getLine(doc.size-1).text.length},
                   splitLines(code), top, top);
       updateInput = true;
     }
-    function getValue(code) {
+    function getValue() {
       var text = [];
-      for (var i = 0, l = lines.length; i < l; ++i)
-        text.push(lines[i].text);
+      doc.iter(0, doc.size, function(line) { text.push(line.text); });
       return text.join("\n");
     }
 
+    function onScroll(e) {
+      if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) {
+        lastScrollTop = scrollbar.scrollTop;
+        lastScrollLeft = scroller.scrollLeft;
+        updateDisplay([]);
+        if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
+        if (options.onScroll) options.onScroll(instance);
+      }
+    }
+
     function onMouseDown(e) {
+      setShift(e_prop(e, "shiftKey"));
       // Check whether this is a click in a widget
       for (var n = e_target(e); n != wrapper; n = n.parentNode)
         if (n.parentNode == code && n != mover) return;
 
-      // First, see if this is a click in the gutter
+      // See if this is a click in the gutter
       for (var n = e_target(e); n != wrapper; n = n.parentNode)
         if (n.parentNode == gutterText) {
           if (options.onGutterClick)
@@ -277,6 +400,8 @@
         return;
       case 2:
         if (start) setCursor(start.line, start.ch, true);
+        setTimeout(focusInput, 20);
+        e_preventDefault(e);
         return;
       }
       // For button 1, if it was clicked inside the editor
@@ -287,29 +412,36 @@
       if (!focused) onFocus();
 
       var now = +new Date;
-      if (lastDoubleClick > now - 400) {
+      if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
         e_preventDefault(e);
+        setTimeout(focusInput, 20);
         return selectLine(start.line);
-      } else if (lastClick > now - 400) {
-        lastDoubleClick = now;
+      } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
+        lastDoubleClick = {time: now, pos: start};
         e_preventDefault(e);
         return selectWordAt(start);
-      } else { lastClick = now; }
+      } else { lastClick = {time: now, pos: start}; }
 
       var last = start, going;
-      if (dragAndDrop && !posEq(sel.from, sel.to) &&
+      if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
           !posLess(start, sel.from) && !posLess(sel.to, start)) {
         // Let the drag handler handle this.
-        var up = connect(targetDocument, "mouseup", operation(function(e2) {
+        if (webkit) scroller.draggable = true;
+        function dragEnd(e2) {
+          if (webkit) scroller.draggable = false;
           draggingText = false;
-          up();
+          up(); drop();
           if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
             e_preventDefault(e2);
             setCursor(start.line, start.ch, true);
             focusInput();
           }
-        }), true);
+        }
+        var up = connect(document, "mouseup", operation(dragEnd), true);
+        var drop = connect(scroller, "drop", operation(dragEnd), true);
         draggingText = true;
+        // IE's approach to draggable
+        if (scroller.dragDrop) scroller.dragDrop();
         return;
       }
       e_preventDefault(e);
@@ -328,12 +460,7 @@
         }
       }
 
-      var move = connect(targetDocument, "mousemove", operation(function(e) {
-        clearTimeout(going);
-        e_preventDefault(e);
-        extend(e);
-      }), true);
-      var up = connect(targetDocument, "mouseup", operation(function(e) {
+      function done(e) {
         clearTimeout(going);
         var cur = posFromMouse(e);
         if (cur) setSelectionUser(start, cur);
@@ -341,16 +468,26 @@
         focusInput();
         updateInput = true;
         move(); up();
+      }
+      var move = connect(document, "mousemove", operation(function(e) {
+        clearTimeout(going);
+        e_preventDefault(e);
+        if (!ie && !e_button(e)) done(e);
+        else extend(e);
       }), true);
+      var up = connect(document, "mouseup", operation(done), true);
     }
     function onDoubleClick(e) {
+      for (var n = e_target(e); n != wrapper; n = n.parentNode)
+        if (n.parentNode == gutterText) return e_preventDefault(e);
       var start = posFromMouse(e);
       if (!start) return;
-      lastDoubleClick = +new Date;
+      lastDoubleClick = {time: +new Date, pos: start};
       e_preventDefault(e);
       selectWordAt(start);
     }
     function onDrop(e) {
+      if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
       e.preventDefault();
       var pos = posFromMouse(e, true), files = e.dataTransfer.files;
       if (!pos || options.readOnly) return;
@@ -360,102 +497,147 @@
           reader.onload = function() {
             text[i] = reader.result;
             if (++read == n) {
-	      pos = clipPos(pos);
-	      var end = replaceRange(text.join(""), pos, pos);
-	      setSelectionUser(pos, end);
-	    }
+              pos = clipPos(pos);
+              operation(function() {
+                var end = replaceRange(text.join(""), pos, pos);
+                setSelectionUser(pos, end);
+              })();
+            }
           };
           reader.readAsText(file);
         }
         var n = files.length, text = Array(n), read = 0;
         for (var i = 0; i < n; ++i) loadFile(files[i], i);
-      }
-      else {
+      } else {
+        // Don't do a replace if the drop happened inside of the selected text.
+        if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
         try {
           var text = e.dataTransfer.getData("Text");
           if (text) {
-	    var end = replaceRange(text, pos, pos);
-	    var curFrom = sel.from, curTo = sel.to;
-	    setSelectionUser(pos, end);
-            if (draggingText) replaceRange("", curFrom, curTo);
-	    focusInput();
-	  }
+            compoundChange(function() {
+              var curFrom = sel.from, curTo = sel.to;
+              setSelectionUser(pos, pos);
+              if (draggingText) replaceRange("", curFrom, curTo);
+              replaceSelection(text);
+              focusInput();
+            });
+          }
         }
         catch(e){}
       }
     }
     function onDragStart(e) {
       var txt = getSelection();
-      // This will reset escapeElement
-      htmlEscape(txt);
-      e.dataTransfer.setDragImage(escapeElement, 0, 0);
       e.dataTransfer.setData("Text", txt);
+      
+      // Use dummy image instead of default browsers image.
+      if (gecko || chrome || opera) {
+        var img = document.createElement('img');
+        img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
+        e.dataTransfer.setDragImage(img, 0, 0);
+      }
     }
+
+    function doHandleBinding(bound, dropShift) {
+      if (typeof bound == "string") {
+        bound = commands[bound];
+        if (!bound) return false;
+      }
+      var prevShift = shiftSelecting;
+      try {
+        if (options.readOnly) suppressEdits = true;
+        if (dropShift) shiftSelecting = null;
+        bound(instance);
+      } catch(e) {
+        if (e != Pass) throw e;
+        return false;
+      } finally {
+        shiftSelecting = prevShift;
+        suppressEdits = false;
+      }
+      return true;
+    }
+    function handleKeyBinding(e) {
+      // Handle auto keymap transitions
+      var startMap = getKeyMap(options.keyMap), next = startMap.auto;
+      clearTimeout(maybeTransition);
+      if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
+        if (getKeyMap(options.keyMap) == startMap) {
+          options.keyMap = (next.call ? next.call(null, instance) : next);
+        }
+      }, 50);
+
+      var name = keyNames[e_prop(e, "keyCode")], handled = false;
+      if (name == null || e.altGraphKey) return false;
+      if (e_prop(e, "altKey")) name = "Alt-" + name;
+      if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
+      if (e_prop(e, "metaKey")) name = "Cmd-" + name;
+
+      var stopped = false;
+      function stop() { stopped = true; }
+
+      if (e_prop(e, "shiftKey")) {
+        handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
+                            function(b) {return doHandleBinding(b, true);}, stop)
+               || lookupKey(name, options.extraKeys, options.keyMap, function(b) {
+                 if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
+               }, stop);
+      } else {
+        handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
+      }
+      if (stopped) handled = false;
+      if (handled) {
+        e_preventDefault(e);
+        restartBlink();
+        if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
+      }
+      return handled;
+    }
+    function handleCharBinding(e, ch) {
+      var handled = lookupKey("'" + ch + "'", options.extraKeys,
+                              options.keyMap, function(b) { return doHandleBinding(b, true); });
+      if (handled) {
+        e_preventDefault(e);
+        restartBlink();
+      }
+      return handled;
+    }
+
+    var lastStoppedKey = null, maybeTransition;
     function onKeyDown(e) {
       if (!focused) onFocus();
-
-      var code = e.keyCode;
+      if (ie && e.keyCode == 27) { e.returnValue = false; }
+      if (pollingFast) { if (readInput()) pollingFast = false; }
+      if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
+      var code = e_prop(e, "keyCode");
       // IE does strange things with escape.
-      if (ie && code == 27) { e.returnValue = false; }
-      // Tries to detect ctrl on non-mac, cmd on mac.
-      var mod = (mac ? e.metaKey : e.ctrlKey) && !e.altKey, anyMod = e.ctrlKey || e.altKey || e.metaKey;
-      if (code == 16 || e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
-      else shiftSelecting = null;
+      setShift(code == 16 || e_prop(e, "shiftKey"));
       // First give onKeyEvent option a chance to handle this.
-      if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
-
-      if (code == 33 || code == 34) {scrollPage(code == 34); return e_preventDefault(e);} // page up/down
-      if (mod && ((code == 36 || code == 35) || // ctrl-home/end
-                  mac && (code == 38 || code == 40))) { // cmd-up/down
-        scrollEnd(code == 36 || code == 38); return e_preventDefault(e);
+      var handled = handleKeyBinding(e);
+      if (opera) {
+        lastStoppedKey = handled ? code : null;
+        // Opera has no cut event... we try to at least catch the key combo
+        if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
+          replaceSelection("");
       }
-      if (mod && code == 65) {selectAll(); return e_preventDefault(e);} // ctrl-a
-      if (!options.readOnly) {
-        if (!anyMod && code == 13) {return;} // enter
-        if (!anyMod && code == 9 && handleTab(e.shiftKey)) return e_preventDefault(e); // tab
-        if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
-        if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
+    }
+    function onKeyPress(e) {
+      if (pollingFast) readInput();
+      if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
+      var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
+      if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
+      if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
+      var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
+      if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
+        if (mode.electricChars.indexOf(ch) > -1)
+          setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
       }
-      if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
-
-      // Key id to use in the movementKeys map. We also pass it to
-      // fastPoll in order to 'self learn'. We need this because
-      // reducedSelection, the hack where we collapse the selection to
-      // its start when it is inverted and a movement key is pressed
-      // (and later restore it again), shouldn't be used for
-      // non-movement keys.
-      curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
-      if (sel.inverted && movementKeys[curKeyId] === true) {
-        var range = selRange(input);
-        if (range) {
-          reducedSelection = {anchor: range.start};
-          setSelRange(input, range.start, range.start);
-        }
-      }
-      // Don't save the key as a movementkey unless it had a modifier
-      if (!mod && !e.altKey) curKeyId = null;
-      fastPoll(curKeyId);
+      if (handleCharBinding(e, ch)) return;
+      fastPoll();
     }
     function onKeyUp(e) {
       if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
-      if (reducedSelection) {
-        reducedSelection = null;
-        updateInput = true;
-      }
-      if (e.keyCode == 16) shiftSelecting = null;
-    }
-    function onKeyPress(e) {
-      if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
-      if (options.electricChars && mode.electricChars) {
-        var ch = String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode);
-        if (mode.electricChars.indexOf(ch) > -1)
-          setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 50);
-      }
-      var code = e.keyCode;
-      // Re-stop tab and enter. Necessary on some browsers.
-      if (code == 13) {if (!options.readOnly) handleEnter(); e_preventDefault(e);}
-      else if (!e.ctrlKey && !e.altKey && !e.metaKey && code == 9 && options.tabMode != "default") e_preventDefault(e);
-      else fastPoll(curKeyId);
+      if (e_prop(e, "keyCode") == 16) shiftSelecting = null;
     }
 
     function onFocus() {
@@ -463,9 +645,9 @@
       if (!focused) {
         if (options.onFocus) options.onFocus(instance);
         focused = true;
-        if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
-          wrapper.className += " CodeMirror-focused";
-        if (!leaveInputAlone) prepareInput();
+        if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
+          scroller.className += " CodeMirror-focused";
+        if (!leaveInputAlone) resetInput(true);
       }
       slowPoll();
       restartBlink();
@@ -474,90 +656,149 @@
       if (focused) {
         if (options.onBlur) options.onBlur(instance);
         focused = false;
-        wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
+        if (bracketHighlighted)
+          operation(function(){
+            if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
+          })();
+        scroller.className = scroller.className.replace(" CodeMirror-focused", "");
       }
       clearInterval(blinker);
       setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
     }
 
+    function chopDelta(delta) {
+      // Make sure we always scroll a little bit for any nonzero delta.
+      if (delta > 0.0 && delta < 1.0) return 1;
+      else if (delta > -1.0 && delta < 0.0) return -1;
+      else return Math.round(delta);
+    }
+
+    function onMouseWheel(e) {
+      var deltaX = 0, deltaY = 0;
+      if (e.type == "DOMMouseScroll") { // Firefox
+        var delta = -e.detail * 8.0;
+        if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta;
+        else if (e.axis == e.VERTICAL_AXIS) deltaY = delta;
+      } else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit
+        deltaX = e.wheelDeltaX / 3.0;
+        deltaY = e.wheelDeltaY / 3.0;
+      } else if (e.wheelDelta !== undefined) { // IE or Opera
+        deltaY = e.wheelDelta / 3.0;
+      }
+
+      var scrolled = false;
+      deltaX = chopDelta(deltaX);
+      deltaY = chopDelta(deltaY);
+      if ((deltaX > 0 && scroller.scrollLeft > 0) ||
+          (deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) {
+        scroller.scrollLeft -= deltaX;
+        scrolled = true;
+      }
+      if ((deltaY > 0 && scrollbar.scrollTop > 0) ||
+          (deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) {
+        scrollbar.scrollTop -= deltaY;
+        scrolled = true;
+      }
+      if (scrolled) e_stop(e);
+    }
+
     // Replace the range from from to to by the strings in newText.
     // Afterwards, set the selection to selFrom, selTo.
     function updateLines(from, to, newText, selFrom, selTo) {
+      if (suppressEdits) return;
       if (history) {
         var old = [];
-        for (var i = from.line, e = to.line + 1; i < e; ++i) old.push(lines[i].text);
+        doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); });
         history.addChange(from.line, newText.length, old);
         while (history.done.length > options.undoDepth) history.done.shift();
       }
       updateLinesNoUndo(from, to, newText, selFrom, selTo);
     }
     function unredoHelper(from, to) {
-      var change = from.pop();
-      if (change) {
+      if (!from.length) return;
+      var set = from.pop(), out = [];
+      for (var i = set.length - 1; i >= 0; i -= 1) {
+        var change = set[i];
         var replaced = [], end = change.start + change.added;
-        for (var i = change.start; i < end; ++i) replaced.push(lines[i].text);
-        to.push({start: change.start, added: change.old.length, old: replaced});
-        var pos = clipPos({line: change.start + change.old.length - 1,
-                           ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
-        updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: lines[end-1].text.length}, change.old, pos, pos);
-        updateInput = true;
+        doc.iter(change.start, end, function(line) { replaced.push(line.text); });
+        out.push({start: change.start, added: change.old.length, old: replaced});
+        var pos = {line: change.start + change.old.length - 1,
+                   ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
+        updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
       }
+      updateInput = true;
+      to.push(out);
     }
     function undo() {unredoHelper(history.done, history.undone);}
     function redo() {unredoHelper(history.undone, history.done);}
 
     function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
+      if (suppressEdits) return;
       var recomputeMaxLength = false, maxLineLength = maxLine.length;
-      for (var i = from.line; i <= to.line; ++i) {
-        if (lines[i].text.length == maxLineLength) {recomputeMaxLength = true; break;}
-      }
+      if (!options.lineWrapping)
+        doc.iter(from.line, to.line + 1, function(line) {
+          if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
+        });
+      if (from.line != to.line || newText.length > 1) gutterDirty = true;
 
-      var nlines = to.line - from.line, firstLine = lines[from.line], lastLine = lines[to.line];
+      var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line);
       // First adjust the line structure, taking some care to leave highlighting intact.
-      if (firstLine == lastLine) {
+      if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") {
+        // This is a whole-line replace. Treated specially to make
+        // sure line objects move the way they are supposed to.
+        var added = [], prevLine = null;
+        if (from.line) {
+          prevLine = getLine(from.line - 1);
+          prevLine.fixMarkEnds(lastLine);
+        } else lastLine.fixMarkStarts();
+        for (var i = 0, e = newText.length - 1; i < e; ++i)
+          added.push(Line.inheritMarks(newText[i], prevLine));
+        if (nlines) doc.remove(from.line, nlines, callbacks);
+        if (added.length) doc.insert(from.line, added);
+      } else if (firstLine == lastLine) {
         if (newText.length == 1)
           firstLine.replace(from.ch, to.ch, newText[0]);
         else {
           lastLine = firstLine.split(to.ch, newText[newText.length-1]);
-          var spliceargs = [from.line + 1, nlines];
           firstLine.replace(from.ch, null, newText[0]);
+          firstLine.fixMarkEnds(lastLine);
+          var added = [];
           for (var i = 1, e = newText.length - 1; i < e; ++i)
-            spliceargs.push(Line.inheritMarks(newText[i], firstLine));
-          spliceargs.push(lastLine);
-          lines.splice.apply(lines, spliceargs);
+            added.push(Line.inheritMarks(newText[i], firstLine));
+          added.push(lastLine);
+          doc.insert(from.line + 1, added);
         }
-      }
-      else if (newText.length == 1) {
+      } else if (newText.length == 1) {
         firstLine.replace(from.ch, null, newText[0]);
         lastLine.replace(null, to.ch, "");
         firstLine.append(lastLine);
-        lines.splice(from.line + 1, nlines);
-      }
-      else {
-        var spliceargs = [from.line + 1, nlines - 1];
+        doc.remove(from.line + 1, nlines, callbacks);
+      } else {
+        var added = [];
         firstLine.replace(from.ch, null, newText[0]);
         lastLine.replace(null, to.ch, newText[newText.length-1]);
+        firstLine.fixMarkEnds(lastLine);
         for (var i = 1, e = newText.length - 1; i < e; ++i)
-          spliceargs.push(Line.inheritMarks(newText[i], firstLine));
-        lines.splice.apply(lines, spliceargs);
+          added.push(Line.inheritMarks(newText[i], firstLine));
+        if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks);
+        doc.insert(from.line + 1, added);
       }
-
-
-      for (var i = from.line, e = i + newText.length; i < e; ++i) {
-        var l = lines[i].text;
-        if (l.length > maxLineLength) {
-          maxLine = l; maxLineLength = l.length; maxWidth = null;
-          recomputeMaxLength = false;
-        }
-      }
-      if (recomputeMaxLength) {
-        maxLineLength = 0; maxLine = ""; maxWidth = null;
-        for (var i = 0, e = lines.length; i < e; ++i) {
-          var l = lines[i].text;
-          if (l.length > maxLineLength) {
-            maxLineLength = l.length; maxLine = l;
+      if (options.lineWrapping) {
+        var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
+        doc.iter(from.line, from.line + newText.length, function(line) {
+          if (line.hidden) return;
+          var guess = Math.ceil(line.text.length / perLine) || 1;
+          if (guess != line.height) updateLineHeight(line, guess);
+        });
+      } else {
+        doc.iter(from.line, from.line + newText.length, function(line) {
+          var l = line.text;
+          if (!line.hidden && l.length > maxLineLength) {
+            maxLine = l; maxLineLength = l.length; maxLineChanged = true;
+            recomputeMaxLength = false;
           }
-        }
+        });
+        if (recomputeMaxLength) updateMaxLine = true;
       }
 
       // Add these lines to the work array, so that they will be
@@ -568,24 +809,64 @@
         if (task < from.line) newWork.push(task);
         else if (task > to.line) newWork.push(task + lendiff);
       }
-      if (newText.length < 5) {
-        highlightLines(from.line, from.line + newText.length);
-        newWork.push(from.line + newText.length);
-      } else {
-        newWork.push(from.line);
-      }
+      var hlEnd = from.line + Math.min(newText.length, 500);
+      highlightLines(from.line, hlEnd);
+      newWork.push(hlEnd);
       work = newWork;
       startWorker(100);
       // Remember that these lines changed, for updating the display
       changes.push({from: from.line, to: to.line + 1, diff: lendiff});
-      textChanged = {from: from, to: to, text: newText};
+      var changeObj = {from: from, to: to, text: newText};
+      if (textChanged) {
+        for (var cur = textChanged; cur.next; cur = cur.next) {}
+        cur.next = changeObj;
+      } else textChanged = changeObj;
 
       // Update the selection
       function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
-      setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line));
+      setSelection(clipPos(selFrom), clipPos(selTo),
+                   updateLine(sel.from.line), updateLine(sel.to.line));
+    }
 
-      // Make sure the scroll-size div has the correct height.
-      code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
+    function updateVerticalScroll(scrollTop) {
+      var th = textHeight(), virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight;
+      scrollbar.style.height = scrollbarHeight + "px";
+      if (scroller.clientHeight)
+        scrollbarInner.style.height = virtualHeight + "px";
+      // Position the mover div to align with the current virtual scroll position
+      if (scrollTop != null) scrollbar.scrollTop = scrollTop;
+      mover.style.top = (displayOffset * th - scrollbar.scrollTop) + "px";
+      scrollbar.style.display = (virtualHeight > scrollbarHeight) ? "block" : "none";
+    }
+  
+    // On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring 
+    // the width of a div with a scrollbar in it. If the width is <= 1, then
+    // the mouse isn't plugged in and scrollbars should overlap the content.
+    function overlapScrollbars() {
+      var tmpSb = document.createElement('div'),
+          tmpSbInner = document.createElement('div');
+      tmpSb.className = "CodeMirror-scrollbar";
+      tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;";
+      tmpSbInner.className = "CodeMirror-scrollbar-inner";
+      tmpSbInner.style.height = "200px";
+      tmpSb.appendChild(tmpSbInner);
+
+      document.body.appendChild(tmpSb);
+      var result = (tmpSb.offsetWidth <= 1);
+      document.body.removeChild(tmpSb);
+      return result;
+    }
+
+    function computeMaxLength() {
+      var maxLineLength = 0; 
+      maxLine = ""; maxLineChanged = true;
+      doc.iter(0, doc.size, function(line) {
+        var l = line.text;
+        if (!line.hidden && l.length > maxLineLength) {
+          maxLineLength = l.length; maxLine = l;
+        }
+      });
+      updateMaxLine = false;
     }
 
     function replaceRange(code, from, to) {
@@ -623,10 +904,10 @@
 
     function getRange(from, to) {
       var l1 = from.line, l2 = to.line;
-      if (l1 == l2) return lines[l1].text.slice(from.ch, to.ch);
-      var code = [lines[l1].text.slice(from.ch)];
-      for (var i = l1 + 1; i < l2; ++i) code.push(lines[i].text);
-      code.push(lines[l2].text.slice(0, to.ch));
+      if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
+      var code = [getLine(l1).text.slice(from.ch)];
+      doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
+      code.push(getLine(l2).text.slice(0, to.ch));
       return code.join("\n");
     }
     function getSelection() {
@@ -636,115 +917,56 @@
     var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
     function slowPoll() {
       if (pollingFast) return;
-      poll.set(2000, function() {
+      poll.set(options.pollInterval, function() {
         startOperation();
         readInput();
         if (focused) slowPoll();
         endOperation();
       });
     }
-    function fastPoll(keyId) {
+    function fastPoll() {
       var missed = false;
       pollingFast = true;
       function p() {
         startOperation();
         var changed = readInput();
-        if (changed && keyId) {
-          if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
-          if (changed == "changed") movementKeys[keyId] = false;
-        }
-        if (!changed && !missed) {missed = true; poll.set(80, p);}
+        if (!changed && !missed) {missed = true; poll.set(60, p);}
         else {pollingFast = false; slowPoll();}
         endOperation();
       }
       poll.set(20, p);
     }
 
-    // Inspects the textarea, compares its state (content, selection)
-    // to the data in the editing variable, and updates the editor
-    // content or cursor if something changed.
+    // Previnput is a hack to work with IME. If we reset the textarea
+    // on every change, that breaks IME. So we look for changes
+    // compared to the previous content instead. (Modern browsers have
+    // events that indicate IME taking place, but these are not widely
+    // supported or compatible enough yet to rely on.)
+    var prevInput = "";
     function readInput() {
-      if (leaveInputAlone || !focused) return;
-      var changed = false, text = input.value, sr = selRange(input);
-      if (!sr) return false;
-      var changed = editing.text != text, rs = reducedSelection;
-      var moved = changed || sr.start != editing.start || sr.end != (rs ? editing.start : editing.end);
-      if (!moved && !rs) return false;
-      if (changed) {
-        shiftSelecting = reducedSelection = null;
-        if (options.readOnly) {updateInput = true; return "changed";}
-      }
-
-      // Compute selection start and end based on start/end offsets in textarea
-      function computeOffset(n, startLine) {
-        var pos = 0;
-        for (;;) {
-          var found = text.indexOf("\n", pos);
-          if (found == -1 || (text.charAt(found-1) == "\r" ? found - 1 : found) >= n)
-            return {line: startLine, ch: n - pos};
-          ++startLine;
-          pos = found + 1;
-        }
-      }
-      var from = computeOffset(sr.start, editing.from),
-          to = computeOffset(sr.end, editing.from);
-      // Here we have to take the reducedSelection hack into account,
-      // so that you can, for example, press shift-up at the start of
-      // your selection and have the right thing happen.
-      if (rs) {
-        var head = sr.start == rs.anchor ? to : from;
-        var tail = shiftSelecting ? sel.to : sr.start == rs.anchor ? from : to;
-        if (sel.inverted = posLess(head, tail)) { from = head; to = tail; }
-        else { reducedSelection = null; from = tail; to = head; }
-      }
-
-      // In some cases (cursor on same line as before), we don't have
-      // to update the textarea content at all.
-      if (from.line == to.line && from.line == sel.from.line && from.line == sel.to.line && !shiftSelecting)
-        updateInput = false;
-
-      // Magic mess to extract precise edited range from the changed
-      // string.
-      if (changed) {
-        var start = 0, end = text.length, len = Math.min(end, editing.text.length);
-        var c, line = editing.from, nl = -1;
-        while (start < len && (c = text.charAt(start)) == editing.text.charAt(start)) {
-          ++start;
-          if (c == "\n") {line++; nl = start;}
-        }
-        var ch = nl > -1 ? start - nl : start, endline = editing.to - 1, edend = editing.text.length;
-        for (;;) {
-          c = editing.text.charAt(edend);
-          if (text.charAt(end) != c) {++end; ++edend; break;}
-          if (c == "\n") endline--;
-          if (edend <= start || end <= start) break;
-          --end; --edend;
-        }
-        var nl = editing.text.lastIndexOf("\n", edend - 1), endch = nl == -1 ? edend : edend - nl - 1;
-        updateLines({line: line, ch: ch}, {line: endline, ch: endch}, splitLines(text.slice(start, end)), from, to);
-        if (line != endline || from.line != line) updateInput = true;
-      }
-      else setSelection(from, to);
-
-      editing.text = text; editing.start = sr.start; editing.end = sr.end;
-      return changed ? "changed" : moved ? "moved" : false;
+      if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false;
+      var text = input.value;
+      if (text == prevInput) return false;
+      shiftSelecting = null;
+      var same = 0, l = Math.min(prevInput.length, text.length);
+      while (same < l && prevInput[same] == text[same]) ++same;
+      if (same < prevInput.length)
+        sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)};
+      else if (overwrite && posEq(sel.from, sel.to))
+        sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
+      replaceSelection(text.slice(same), "end");
+      if (text.length > 1000) { input.value = prevInput = ""; }
+      else prevInput = text;
+      return true;
+    }
+    function resetInput(user) {
+      if (!posEq(sel.from, sel.to)) {
+        prevInput = "";
+        input.value = getSelection();
+        selectInput(input);
+      } else if (user) prevInput = input.value = "";
     }
 
-    // Set the textarea content and selection range to match the
-    // editor state.
-    function prepareInput() {
-      var text = [];
-      var from = Math.max(0, sel.from.line - 1), to = Math.min(lines.length, sel.to.line + 2);
-      for (var i = from; i < to; ++i) text.push(lines[i].text);
-      text = input.value = text.join(lineSep);
-      var startch = sel.from.ch, endch = sel.to.ch;
-      for (var i = from; i < sel.from.line; ++i)
-        startch += lineSep.length + lines[i].text.length;
-      for (var i = from; i < sel.to.line; ++i)
-        endch += lineSep.length + lines[i].text.length;
-      editing = {text: text, from: from, to: to, start: startch, end: endch};
-      setSelRange(input, startch, reducedSelection ? startch : endch);
-    }
     function focusInput() {
       if (options.readOnly != "nocursor") input.focus();
     }
@@ -752,59 +974,156 @@
     function scrollEditorIntoView() {
       if (!cursor.getBoundingClientRect) return;
       var rect = cursor.getBoundingClientRect();
+      // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
+      if (ie && rect.top == rect.bottom) return;
       var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
-      if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
+      if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView();
     }
     function scrollCursorIntoView() {
+      var coords = calculateCursorCoords();
+      return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
+    }
+    function calculateCursorCoords() {
       var cursor = localCoords(sel.inverted ? sel.from : sel.to);
-      return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
+      var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
+      return {x: x, y: cursor.y, yBot: cursor.yBot};
     }
     function scrollIntoView(x1, y1, x2, y2) {
-      var pl = paddingLeft(), pt = paddingTop(), lh = lineHeight();
+      var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false;
+      if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;}
+      if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;}
+      if (scrolled && options.onScroll) options.onScroll(instance);
+    }
+    function calculateScrollPos(x1, y1, x2, y2) {
+      var pl = paddingLeft(), pt = paddingTop();
       y1 += pt; y2 += pt; x1 += pl; x2 += pl;
-      var screen = scroller.clientHeight, screentop = scroller.scrollTop, scrolled = false, result = true;
-      if (y1 < screentop) {scroller.scrollTop = Math.max(0, y1 - 2*lh); scrolled = true;}
-      else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;}
+      var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
+      var atTop = y1 < paddingTop() + 10;
+      if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
+      else if (y2 > screentop + screen) result.scrollTop = y2 - screen;
 
       var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
       var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
-      if (x1 < screenleft + gutterw) {
-        if (x1 < 50) x1 = 0;
-        scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw);
-        scrolled = true;
+      var atLeft = x1 < gutterw + pl + 10;
+      if (x1 < screenleft + gutterw || atLeft) {
+        if (atLeft) x1 = 0;
+        result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
+      } else if (x2 > screenw + screenleft - 3) {
+        result.scrollLeft = x2 + 10 - screenw;
       }
-      else if (x2 > screenw + screenleft) {
-        scroller.scrollLeft = x2 + 10 - screenw;
-        scrolled = true;
-        if (x2 > code.clientWidth) result = false;
-      }
-      if (scrolled && options.onScroll) options.onScroll(instance);
       return result;
     }
 
-    function visibleLines() {
-      var lh = lineHeight(), top = scroller.scrollTop - paddingTop();
-      return {from: Math.min(lines.length, Math.max(0, Math.floor(top / lh))),
-              to: Math.min(lines.length, Math.ceil((top + scroller.clientHeight) / lh))};
+    function visibleLines(scrollTop) {
+      var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
+      var fromHeight = Math.max(0, Math.floor(top / lh));
+      var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
+      return {from: lineAtHeight(doc, fromHeight),
+              to: lineAtHeight(doc, toHeight)};
     }
     // Uses a set of changes plus the current scroll position to
     // determine which DOM updates have to be made, and makes the
     // updates.
-    function updateDisplay(changes) {
+    function updateDisplay(changes, suppressCallback, scrollTop) {
       if (!scroller.clientWidth) {
-        showingFrom = showingTo = 0;
+        showingFrom = showingTo = displayOffset = 0;
+        return;
+      }
+      // Compute the new visible window
+      // If scrollTop is specified, use that to determine which lines
+      // to render instead of the current scrollbar position.
+      var visible = visibleLines(scrollTop);
+      // Bail out if the visible area is already rendered and nothing changed.
+      if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
+        updateVerticalScroll(scrollTop);
+        return;
+      }
+      var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
+      if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
+      if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
+
+      // Create a range of theoretically intact lines, and punch holes
+      // in that using the change info.
+      var intact = changes === true ? [] :
+        computeIntact([{from: showingFrom, to: showingTo, domStart: 0}], changes);
+      // Clip off the parts that won't be visible
+      var intactLines = 0;
+      for (var i = 0; i < intact.length; ++i) {
+        var range = intact[i];
+        if (range.from < from) {range.domStart += (from - range.from); range.from = from;}
+        if (range.to > to) range.to = to;
+        if (range.from >= range.to) intact.splice(i--, 1);
+        else intactLines += range.to - range.from;
+      }
+      if (intactLines == to - from && from == showingFrom && to == showingTo) {
+        updateVerticalScroll(scrollTop);
         return;
       }
-      // First create a range of theoretically intact lines, and punch
-      // holes in that using the change info.
-      var intact = changes === true ? [] : [{from: showingFrom, to: showingTo, domStart: 0}];
+      intact.sort(function(a, b) {return a.domStart - b.domStart;});
+
+      var th = textHeight(), gutterDisplay = gutter.style.display;
+      lineDiv.style.display = "none";
+      patchDisplay(from, to, intact);
+      lineDiv.style.display = gutter.style.display = "";
+
+      var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
+      // This is just a bogus formula that detects when the editor is
+      // resized or the font size changes.
+      if (different) lastSizeC = scroller.clientHeight + th;
+      showingFrom = from; showingTo = to;
+      displayOffset = heightAtLine(doc, from);
+
+      // Since this is all rather error prone, it is honoured with the
+      // only assertion in the whole file.
+      if (lineDiv.childNodes.length != showingTo - showingFrom)
+        throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
+                        " nodes=" + lineDiv.childNodes.length);
+
+      function checkHeights() {
+        var curNode = lineDiv.firstChild, heightChanged = false;
+        doc.iter(showingFrom, showingTo, function(line) {
+          if (!line.hidden) {
+            var height = Math.round(curNode.offsetHeight / th) || 1;
+            if (line.height != height) {
+              updateLineHeight(line, height);
+              gutterDirty = heightChanged = true;
+            }
+          }
+          curNode = curNode.nextSibling;
+        });
+        return heightChanged;
+      }
+
+      if (options.lineWrapping) {
+        // Guess whether we're going to need the scrollbar, so that we don't end up changing the linewrapping
+        // after the scrollbar appears (during updateVerticalScroll()). Only do this if the scrollbar is
+        // appearing (if it's disappearing, we don't have to worry about the scroll position, and there are
+        // issues on IE7 if we turn it off too early).
+        var virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight;
+        if (virtualHeight > scrollbarHeight) scrollbar.style.display = "block";
+        checkHeights();
+      }
+
+      gutter.style.display = gutterDisplay;
+      if (different || gutterDirty) {
+        // If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
+        updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
+      }
+      updateSelection();
+      updateVerticalScroll(scrollTop);
+      if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
+      return true;
+    }
+
+    function computeIntact(intact, changes) {
       for (var i = 0, l = changes.length || 0; i < l; ++i) {
         var change = changes[i], intact2 = [], diff = change.diff || 0;
         for (var j = 0, l2 = intact.length; j < l2; ++j) {
           var range = intact[j];
-          if (change.to <= range.from)
-            intact2.push({from: range.from + diff, to: range.to + diff, domStart: range.domStart});
-          else if (range.to <= change.from)
+          if (change.to <= range.from && change.diff)
+            intact2.push({from: range.from + diff, to: range.to + diff,
+                          domStart: range.domStart});
+          else if (change.to <= range.from || change.from >= range.to)
             intact2.push(range);
           else {
             if (change.from > range.from)
@@ -816,168 +1135,130 @@
         }
         intact = intact2;
       }
-
-      // Then, determine which lines we'd want to see, and which
-      // updates have to be made to get there.
-      var visible = visibleLines();
-      var from = Math.min(showingFrom, Math.max(visible.from - 3, 0)),
-          to = Math.min(lines.length, Math.max(showingTo, visible.to + 3)),
-          updates = [], domPos = 0, domEnd = showingTo - showingFrom, pos = from, changedLines = 0;
-
-      for (var i = 0, l = intact.length; i < l; ++i) {
-        var range = intact[i];
-        if (range.to <= from) continue;
-        if (range.from >= to) break;
-        if (range.domStart > domPos || range.from > pos) {
-          updates.push({from: pos, to: range.from, domSize: range.domStart - domPos, domStart: domPos});
-          changedLines += range.from - pos;
-        }
-        pos = range.to;
-        domPos = range.domStart + (range.to - range.from);
-      }
-      if (domPos != domEnd || pos != to) {
-        changedLines += Math.abs(to - pos);
-        updates.push({from: pos, to: to, domSize: domEnd - domPos, domStart: domPos});
-        if (to - pos != domEnd - domPos) gutterDirty = true;
-      }
-
-      if (!updates.length) return;
-      lineDiv.style.display = "none";
-      // If more than 30% of the screen needs update, just do a full
-      // redraw (which is quicker than patching)
-      if (changedLines > (visible.to - visible.from) * .3)
-        refreshDisplay(from = Math.max(visible.from - 10, 0), to = Math.min(visible.to + 7, lines.length));
-      // Otherwise, only update the stuff that needs updating.
-      else
-        patchDisplay(updates);
-      lineDiv.style.display = "";
-
-      // Position the mover div to align with the lines it's supposed
-      // to be showing (which will cover the visible display)
-      var different = from != showingFrom || to != showingTo || lastHeight != scroller.clientHeight;
-      showingFrom = from; showingTo = to;
-      mover.style.top = (from * lineHeight()) + "px";
-      if (different) {
-        lastHeight = scroller.clientHeight;
-        code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
-      }
-      if (different || gutterDirty) updateGutter();
-
-      if (maxWidth == null) maxWidth = stringWidth(maxLine);
-      if (maxWidth > scroller.clientWidth) {
-        lineSpace.style.width = maxWidth + "px";
-        // Needed to prevent odd wrapping/hiding of widgets placed in here.
-        code.style.width = "";
-        code.style.width = scroller.scrollWidth + "px";
-      } else {
-        lineSpace.style.width = code.style.width = "";
-      }
-
-      // Since this is all rather error prone, it is honoured with the
-      // only assertion in the whole file.
-      if (lineDiv.childNodes.length != showingTo - showingFrom)
-        throw new Error("BAD PATCH! " + JSON.stringify(updates) + " size=" + (showingTo - showingFrom) +
-                        " nodes=" + lineDiv.childNodes.length);
-      updateCursor();
+      return intact;
     }
 
-    function refreshDisplay(from, to) {
-      var html = [], start = {line: from, ch: 0}, inSel = posLess(sel.from, start) && !posLess(sel.to, start);
-      for (var i = from; i < to; ++i) {
-        var ch1 = null, ch2 = null;
-        if (inSel) {
-          ch1 = 0;
-          if (sel.to.line == i) {inSel = false; ch2 = sel.to.ch;}
+    function patchDisplay(from, to, intact) {
+      // The first pass removes the DOM nodes that aren't intact.
+      if (!intact.length) lineDiv.innerHTML = "";
+      else {
+        function killNode(node) {
+          var tmp = node.nextSibling;
+          node.parentNode.removeChild(node);
+          return tmp;
         }
-        else if (sel.from.line == i) {
-          if (sel.to.line == i) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
-          else {inSel = true; ch1 = sel.from.ch;}
+        var domPos = 0, curNode = lineDiv.firstChild, n;
+        for (var i = 0; i < intact.length; ++i) {
+          var cur = intact[i];
+          while (cur.domStart > domPos) {curNode = killNode(curNode); domPos++;}
+          for (var j = 0, e = cur.to - cur.from; j < e; ++j) {curNode = curNode.nextSibling; domPos++;}
         }
-        html.push(lines[i].getHTML(ch1, ch2, true));
+        while (curNode) curNode = killNode(curNode);
       }
-      lineDiv.innerHTML = html.join("");
-    }
-    function patchDisplay(updates) {
-      // Slightly different algorithm for IE (badInnerHTML), since
-      // there .innerHTML on PRE nodes is dumb, and discards
-      // whitespace.
-      var sfrom = sel.from.line, sto = sel.to.line, off = 0,
-          scratch = badInnerHTML && targetDocument.createElement("div");
-      for (var i = 0, e = updates.length; i < e; ++i) {
-        var rec = updates[i];
-        var extra = (rec.to - rec.from) - rec.domSize;
-        var nodeAfter = lineDiv.childNodes[rec.domStart + rec.domSize + off] || null;
-        if (badInnerHTML)
-          for (var j = Math.max(-extra, rec.domSize); j > 0; --j)
-            lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
-        else if (extra) {
-          for (var j = Math.max(0, extra); j > 0; --j)
-            lineDiv.insertBefore(targetDocument.createElement("pre"), nodeAfter);
-          for (var j = Math.max(0, -extra); j > 0; --j)
-            lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
+      // This pass fills in the lines that actually changed.
+      var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
+      var scratch = document.createElement("div");
+      doc.iter(from, to, function(line) {
+        if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
+        if (!nextIntact || nextIntact.from > j) {
+          if (line.hidden) var html = scratch.innerHTML = "<pre></pre>";
+          else {
+            var html = '<pre' + (line.className ? ' class="' + line.className + '"' : '') + '>'
+              + line.getHTML(makeTab) + '</pre>';
+            // Kludge to make sure the styled element lies behind the selection (by z-index)
+            if (line.bgClassName)
+              html = '<div style="position: relative"><pre class="' + line.bgClassName +
+              '" style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2">&#160;</pre>' + html + "</div>";
+          }
+          scratch.innerHTML = html;
+          lineDiv.insertBefore(scratch.firstChild, curNode);
+        } else {
+          curNode = curNode.nextSibling;
         }
-        var node = lineDiv.childNodes[rec.domStart + off], inSel = sfrom < rec.from && sto >= rec.from;
-        for (var j = rec.from; j < rec.to; ++j) {
-          var ch1 = null, ch2 = null;
-          if (inSel) {
-            ch1 = 0;
-            if (sto == j) {inSel = false; ch2 = sel.to.ch;}
-          }
-          else if (sfrom == j) {
-            if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
-            else {inSel = true; ch1 = sel.from.ch;}
-          }
-          if (badInnerHTML) {
-            scratch.innerHTML = lines[j].getHTML(ch1, ch2, true);
-            lineDiv.insertBefore(scratch.firstChild, nodeAfter);
-          }
-          else {
-            node.innerHTML = lines[j].getHTML(ch1, ch2, false);
-            node.className = lines[j].className || "";
-            node = node.nextSibling;
-          }
-        }
-        off += extra;
-      }
+        ++j;
+      });
     }
 
     function updateGutter() {
       if (!options.gutter && !options.lineNumbers) return;
       var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
       gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
-      var html = [];
-      for (var i = showingFrom; i < Math.max(showingTo, showingFrom + 1); ++i) {
-        var marker = lines[i].gutterMarker;
-        var text = options.lineNumbers ? i + options.firstLineNumber : null;
-        if (marker && marker.text)
-          text = marker.text.replace("%N%", text != null ? text : "");
-        else if (text == null)
-          text = "\u00a0";
-        html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text, "</pre>");
-      }
+      var html = [], i = showingFrom, normalNode;
+      doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
+        if (line.hidden) {
+          html.push("<pre></pre>");
+        } else {
+          var marker = line.gutterMarker;
+          var text = options.lineNumbers ? i + options.firstLineNumber : null;
+          if (marker && marker.text)
+            text = marker.text.replace("%N%", text != null ? text : "");
+          else if (text == null)
+            text = "\u00a0";
+          html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text);
+          for (var j = 1; j < line.height; ++j) html.push("<br/>&#160;");
+          html.push("</pre>");
+          if (!marker) normalNode = i;
+        }
+        ++i;
+      });
       gutter.style.display = "none";
       gutterText.innerHTML = html.join("");
-      var minwidth = String(lines.length).length, firstNode = gutterText.firstChild, val = eltText(firstNode), pad = "";
-      while (val.length + pad.length < minwidth) pad += "\u00a0";
-      if (pad) firstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
+      // Make sure scrolling doesn't cause number gutter size to pop
+      if (normalNode != null && options.lineNumbers) {
+        var node = gutterText.childNodes[normalNode - showingFrom];
+        var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
+        while (val.length + pad.length < minwidth) pad += "\u00a0";
+        if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
+      }
       gutter.style.display = "";
+      var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2;
       lineSpace.style.marginLeft = gutter.offsetWidth + "px";
       gutterDirty = false;
+      return resized;
     }
-    function updateCursor() {
-      var head = sel.inverted ? sel.from : sel.to, lh = lineHeight();
-      var x = charX(head.line, head.ch);
-      var top = head.line * lh - scroller.scrollTop;
-      inputDiv.style.top = Math.max(Math.min(top, scroller.offsetHeight), 0) + "px";
-      inputDiv.style.left = (x - scroller.scrollLeft) + "px";
-      if (posEq(sel.from, sel.to)) {
-        cursor.style.top = (head.line - showingFrom) * lh + "px";
-        cursor.style.left = x + "px";
+    function updateSelection() {
+      var collapsed = posEq(sel.from, sel.to);
+      var fromPos = localCoords(sel.from, true);
+      var toPos = collapsed ? fromPos : localCoords(sel.to, true);
+      var headPos = sel.inverted ? fromPos : toPos, th = textHeight();
+      var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv);
+      inputDiv.style.top = Math.max(0, Math.min(scroller.offsetHeight, headPos.y + lineOff.top - wrapOff.top)) + "px";
+      inputDiv.style.left = Math.max(0, Math.min(scroller.offsetWidth, headPos.x + lineOff.left - wrapOff.left)) + "px";
+      if (collapsed) {
+        cursor.style.top = headPos.y + "px";
+        cursor.style.left = (options.lineWrapping ? Math.min(headPos.x, lineSpace.offsetWidth) : headPos.x) + "px";
         cursor.style.display = "";
+        selectionDiv.style.display = "none";
+      } else {
+        var sameLine = fromPos.y == toPos.y, html = "";
+        var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
+        var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
+        function add(left, top, right, height) {
+          var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
+                                  : "right: " + right + "px";
+          html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left +
+            'px; top: ' + top + 'px; ' + rstyle + '; height: ' + height + 'px"></div>';
+        }
+        if (sel.from.ch && fromPos.y >= 0) {
+          var right = sameLine ? clientWidth - toPos.x : 0;
+          add(fromPos.x, fromPos.y, right, th);
+        }
+        var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
+        var middleHeight = Math.min(toPos.y, clientHeight) - middleStart;
+        if (middleHeight > 0.2 * th)
+          add(0, middleStart, 0, middleHeight);
+        if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th)
+          add(0, toPos.y, clientWidth - toPos.x, th);
+        selectionDiv.innerHTML = html;
+        cursor.style.display = "none";
+        selectionDiv.style.display = "";
       }
-      else cursor.style.display = "none";
     }
 
+    function setShift(val) {
+      if (val) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
+      else shiftSelecting = null;
+    }
     function setSelectionUser(from, to) {
       var sh = shiftSelecting && clipPos(shiftSelecting);
       if (sh) {
@@ -985,130 +1266,166 @@
         else if (posLess(to, sh)) to = sh;
       }
       setSelection(from, to);
+      userSelChange = true;
     }
     // Update the selection. Last two args are only used by
     // updateLines, since they have to be expressed in the line
     // numbers before the update.
     function setSelection(from, to, oldFrom, oldTo) {
+      goalColumn = null;
+      if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
       if (posEq(sel.from, from) && posEq(sel.to, to)) return;
       if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
 
+      // Skip over hidden lines.
+      if (from.line != oldFrom) {
+        var from1 = skipHidden(from, oldFrom, sel.from.ch);
+        // If there is no non-hidden line left, force visibility on current line
+        if (!from1) setLineHidden(from.line, false);
+        else from = from1;
+      }
+      if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
+
       if (posEq(from, to)) sel.inverted = false;
       else if (posEq(from, sel.to)) sel.inverted = false;
       else if (posEq(to, sel.from)) sel.inverted = true;
 
-      // Some ugly logic used to only mark the lines that actually did
-      // see a change in selection as changed, rather than the whole
-      // selected range.
-      if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
-      if (posEq(from, to)) {
-        if (!posEq(sel.from, sel.to))
-          changes.push({from: oldFrom, to: oldTo + 1});
-      }
-      else if (posEq(sel.from, sel.to)) {
-        changes.push({from: from.line, to: to.line + 1});
-      }
-      else {
-        if (!posEq(from, sel.from)) {
-          if (from.line < oldFrom)
-            changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1});
-          else
-            changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1});
-        }
-        if (!posEq(to, sel.to)) {
-          if (to.line < oldTo)
-            changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1});
-          else
-            changes.push({from: Math.max(from.line, oldTo), to: to.line + 1});
+      if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
+        var head = sel.inverted ? from : to;
+        if (head.line != sel.from.line && sel.from.line < doc.size) {
+          var oldLine = getLine(sel.from.line);
+          if (/^\s+$/.test(oldLine.text))
+            setTimeout(operation(function() {
+              if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
+                var no = lineNo(oldLine);
+                replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
+              }
+            }, 10));
         }
       }
+
       sel.from = from; sel.to = to;
       selectionChanged = true;
     }
+    function skipHidden(pos, oldLine, oldCh) {
+      function getNonHidden(dir) {
+        var lNo = pos.line + dir, end = dir == 1 ? doc.size : -1;
+        while (lNo != end) {
+          var line = getLine(lNo);
+          if (!line.hidden) {
+            var ch = pos.ch;
+            if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
+            return {line: lNo, ch: ch};
+          }
+          lNo += dir;
+        }
+      }
+      var line = getLine(pos.line);
+      var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
+      if (!line.hidden) return pos;
+      if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
+      else return getNonHidden(-1) || getNonHidden(1);
+    }
     function setCursor(line, ch, user) {
       var pos = clipPos({line: line, ch: ch || 0});
       (user ? setSelectionUser : setSelection)(pos, pos);
     }
 
-    function clipLine(n) {return Math.max(0, Math.min(n, lines.length-1));}
+    function clipLine(n) {return Math.max(0, Math.min(n, doc.size-1));}
     function clipPos(pos) {
       if (pos.line < 0) return {line: 0, ch: 0};
-      if (pos.line >= lines.length) return {line: lines.length-1, ch: lines[lines.length-1].text.length};
-      var ch = pos.ch, linelen = lines[pos.line].text.length;
+      if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc.size-1).text.length};
+      var ch = pos.ch, linelen = getLine(pos.line).text.length;
       if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
       else if (ch < 0) return {line: pos.line, ch: 0};
       else return pos;
     }
 
-    function scrollPage(down) {
-      var linesPerPage = Math.floor(scroller.clientHeight / lineHeight()), head = sel.inverted ? sel.from : sel.to;
-      setCursor(head.line + (Math.max(linesPerPage - 1, 1) * (down ? 1 : -1)), head.ch, true);
-    }
-    function scrollEnd(top) {
-      var pos = top ? {line: 0, ch: 0} : {line: lines.length - 1, ch: lines[lines.length-1].text.length};
-      setSelectionUser(pos, pos);
+    function findPosH(dir, unit) {
+      var end = sel.inverted ? sel.from : sel.to, line = end.line, ch = end.ch;
+      var lineObj = getLine(line);
+      function findNextLine() {
+        for (var l = line + dir, e = dir < 0 ? -1 : doc.size; l != e; l += dir) {
+          var lo = getLine(l);
+          if (!lo.hidden) { line = l; lineObj = lo; return true; }
+        }
+      }
+      function moveOnce(boundToLine) {
+        if (ch == (dir < 0 ? 0 : lineObj.text.length)) {
+          if (!boundToLine && findNextLine()) ch = dir < 0 ? lineObj.text.length : 0;
+          else return false;
+        } else ch += dir;
+        return true;
+      }
+      if (unit == "char") moveOnce();
+      else if (unit == "column") moveOnce(true);
+      else if (unit == "word") {
+        var sawWord = false;
+        for (;;) {
+          if (dir < 0) if (!moveOnce()) break;
+          if (isWordChar(lineObj.text.charAt(ch))) sawWord = true;
+          else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;}
+          if (dir > 0) if (!moveOnce()) break;
+        }
+      }
+      return {line: line, ch: ch};
     }
-    function selectAll() {
-      var endLine = lines.length - 1;
-      setSelection({line: 0, ch: 0}, {line: endLine, ch: lines[endLine].text.length});
+    function moveH(dir, unit) {
+      var pos = dir < 0 ? sel.from : sel.to;
+      if (shiftSelecting || posEq(sel.from, sel.to)) pos = findPosH(dir, unit);
+      setCursor(pos.line, pos.ch, true);
+    }
+    function deleteH(dir, unit) {
+      if (!posEq(sel.from, sel.to)) replaceRange("", sel.from, sel.to);
+      else if (dir < 0) replaceRange("", findPosH(dir, unit), sel.to);
+      else replaceRange("", sel.from, findPosH(dir, unit));
+      userSelChange = true;
     }
+    var goalColumn = null;
+    function moveV(dir, unit) {
+      var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true);
+      if (goalColumn != null) pos.x = goalColumn;
+      if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
+      else if (unit == "line") dist = textHeight();
+      var target = coordsChar(pos.x, pos.y + dist * dir + 2);
+      if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
+      setCursor(target.line, target.ch, true);
+      goalColumn = pos.x;
+    }
+
     function selectWordAt(pos) {
-      var line = lines[pos.line].text;
+      var line = getLine(pos.line).text;
       var start = pos.ch, end = pos.ch;
-      while (start > 0 && /\w/.test(line.charAt(start - 1))) --start;
-      while (end < line.length && /\w/.test(line.charAt(end))) ++end;
+      while (start > 0 && isWordChar(line.charAt(start - 1))) --start;
+      while (end < line.length && isWordChar(line.charAt(end))) ++end;
       setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
     }
     function selectLine(line) {
-      setSelectionUser({line: line, ch: 0}, {line: line, ch: lines[line].text.length});
-    }
-    function handleEnter() {
-      replaceSelection("\n", "end");
-      if (options.enterMode != "flat")
-        indentLine(sel.from.line, options.enterMode == "keep" ? "prev" : "smart");
+      setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
     }
-    function handleTab(shift) {
-      function indentSelected(mode) {
-        if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
-        var e = sel.to.line - (sel.to.ch ? 0 : 1);
-        for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
-      }
-      shiftSelecting = null;
-      switch (options.tabMode) {
-      case "default":
-        return false;
-      case "indent":
-        indentSelected("smart");
-        break;
-      case "classic":
-        if (posEq(sel.from, sel.to)) {
-          if (shift) indentLine(sel.from.line, "smart");
-          else replaceSelection("\t", "end");
-          break;
-        }
-      case "shift":
-        indentSelected(shift ? "subtract" : "add");
-        break;
-      }
-      return true;
-    }
-    function smartHome() {
-      var firstNonWS = Math.max(0, lines[sel.from.line].text.search(/\S/));
-      setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
+    function indentSelected(mode) {
+      if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
+      var e = sel.to.line - (sel.to.ch ? 0 : 1);
+      for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
     }
 
     function indentLine(n, how) {
+      if (!how) how = "add";
       if (how == "smart") {
         if (!mode.indent) how = "prev";
         else var state = getStateBefore(n);
       }
 
-      var line = lines[n], curSpace = line.indentation(), curSpaceString = line.text.match(/^\s*/)[0], indentation;
+      var line = getLine(n), curSpace = line.indentation(options.tabSize),
+          curSpaceString = line.text.match(/^\s*/)[0], indentation;
+      if (how == "smart") {
+        indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
+        if (indentation == Pass) how = "prev";
+      }
       if (how == "prev") {
-        if (n) indentation = lines[n-1].indentation();
+        if (n) indentation = getLine(n-1).indentation(options.tabSize);
         else indentation = 0;
       }
-      else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length));
       else if (how == "add") indentation = curSpace + options.indentUnit;
       else if (how == "subtract") indentation = curSpace - options.indentUnit;
       indentation = Math.max(0, indentation);
@@ -1117,11 +1434,10 @@
       if (!diff) {
         if (sel.from.line != n && sel.to.line != n) return;
         var indentString = curSpaceString;
-      }
-      else {
+      } else {
         var indentString = "", pos = 0;
         if (options.indentWithTabs)
-          for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
+          for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
         while (pos < indentation) {++pos; indentString += " ";}
       }
 
@@ -1130,8 +1446,7 @@
 
     function loadMode() {
       mode = CodeMirror.getMode(options, options.mode);
-      for (var i = 0, l = lines.length; i < l; ++i)
-        lines[i].stateAfter = null;
+      doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
       work = [0];
       startWorker();
     }
@@ -1141,35 +1456,56 @@
       if (visible) gutterDirty = true;
       else lineDiv.parentNode.style.marginLeft = 0;
     }
-
-    function markText(from, to, className) {
-      from = clipPos(from); to = clipPos(to);
-      var set = [];
-      function add(line, from, to, className) {
-        mark = lines[line].addMark(from, to, className, set);
+    function wrappingChanged(from, to) {
+      if (options.lineWrapping) {
+        wrapper.className += " CodeMirror-wrap";
+        var perLine = scroller.clientWidth / charWidth() - 3;
+        doc.iter(0, doc.size, function(line) {
+          if (line.hidden) return;
+          var guess = Math.ceil(line.text.length / perLine) || 1;
+          if (guess != 1) updateLineHeight(line, guess);
+        });
+        lineSpace.style.width = code.style.width = "";
+        widthForcer.style.left = "";
+      } else {
+        wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
+        maxLine = ""; maxLineChanged = true;
+        doc.iter(0, doc.size, function(line) {
+          if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
+          if (line.text.length > maxLine.length) maxLine = line.text;
+        });
       }
-      if (from.line == to.line) add(from.line, from.ch, to.ch, className);
-      else {
-        add(from.line, from.ch, null, className);
-        for (var i = from.line + 1, e = to.line; i < e; ++i)
-          add(i, 0, null, className);
-        add(to.line, 0, to.ch, className);
-      }
-      changes.push({from: from.line, to: to.line + 1});
-      return new TextMarker(set);
+      changes.push({from: 0, to: doc.size});
+    }
+    function makeTab(col) {
+      var w = options.tabSize - col % options.tabSize, cached = tabCache[w];
+      if (cached) return cached;
+      for (var str = '<span class="cm-tab">', i = 0; i < w; ++i) str += " ";
+      return (tabCache[w] = {html: str + "</span>", width: w});
+    }
+    function themeChanged() {
+      scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
+        options.theme.replace(/(^|\s)\s*/g, " cm-s-");
+    }
+    function keyMapChanged() {
+      var style = keyMap[options.keyMap].style;
+      wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
+        (style ? " cm-keymap-" + style : "");
     }
 
-    function TextMarker(set) { this.set = set; }
+    function TextMarker() { this.set = []; }
     TextMarker.prototype.clear = operation(function() {
+      var min = Infinity, max = -Infinity;
       for (var i = 0, e = this.set.length; i < e; ++i) {
-        var mk = this.set[i].marked;
-        for (var j = 0; j < mk.length; ++j) {
-          if (mk[j].set == this.set) mk.splice(j--, 1);
-        }
+        var line = this.set[i], mk = line.marked;
+        if (!mk || !line.parent) continue;
+        var lineN = lineNo(line);
+        min = Math.min(min, lineN); max = Math.max(max, lineN);
+        for (var j = 0; j < mk.length; ++j)
+          if (mk[j].marker == this) mk.splice(j--, 1);
       }
-      // We don't know the exact lines that changed. Refreshing is
-      // cheaper than finding them.
-      changes.push({from: 0, to: lines.length});
+      if (min != Infinity)
+        changes.push({from: min, to: max + 1});
     });
     TextMarker.prototype.find = function() {
       var from, to;
@@ -1177,10 +1513,10 @@
         var line = this.set[i], mk = line.marked;
         for (var j = 0; j < mk.length; ++j) {
           var mark = mk[j];
-          if (mark.set == this.set) {
+          if (mark.marker == this) {
             if (mark.from != null || mark.to != null) {
-              var found = indexOf(lines, line);
-              if (found > -1) {
+              var found = lineNo(line);
+              if (found != null) {
                 if (mark.from != null) from = {line: found, ch: mark.from};
                 if (mark.to != null) to = {line: found, ch: mark.to};
               }
@@ -1191,45 +1527,113 @@
       return {from: from, to: to};
     };
 
+    function markText(from, to, className) {
+      from = clipPos(from); to = clipPos(to);
+      var tm = new TextMarker();
+      if (!posLess(from, to)) return tm;
+      function add(line, from, to, className) {
+        getLine(line).addMark(new MarkedText(from, to, className, tm));
+      }
+      if (from.line == to.line) add(from.line, from.ch, to.ch, className);
+      else {
+        add(from.line, from.ch, null, className);
+        for (var i = from.line + 1, e = to.line; i < e; ++i)
+          add(i, null, null, className);
+        add(to.line, null, to.ch, className);
+      }
+      changes.push({from: from.line, to: to.line + 1});
+      return tm;
+    }
+
+    function setBookmark(pos) {
+      pos = clipPos(pos);
+      var bm = new Bookmark(pos.ch);
+      getLine(pos.line).addMark(bm);
+      return bm;
+    }
+
+    function findMarksAt(pos) {
+      pos = clipPos(pos);
+      var markers = [], marked = getLine(pos.line).marked;
+      if (!marked) return markers;
+      for (var i = 0, e = marked.length; i < e; ++i) {
+        var m = marked[i];
+        if ((m.from == null || m.from <= pos.ch) &&
+            (m.to == null || m.to >= pos.ch))
+          markers.push(m.marker || m);
+      }
+      return markers;
+    }
+
     function addGutterMarker(line, text, className) {
-      if (typeof line == "number") line = lines[clipLine(line)];
+      if (typeof line == "number") line = getLine(clipLine(line));
       line.gutterMarker = {text: text, style: className};
       gutterDirty = true;
       return line;
     }
     function removeGutterMarker(line) {
-      if (typeof line == "number") line = lines[clipLine(line)];
+      if (typeof line == "number") line = getLine(clipLine(line));
       line.gutterMarker = null;
       gutterDirty = true;
     }
-    function setLineClass(line, className) {
-      if (typeof line == "number") {
-        var no = line;
-        line = lines[clipLine(line)];
-      }
-      else {
-        var no = indexOf(lines, line);
-        if (no == -1) return null;
-      }
-      if (line.className != className) {
-        line.className = className;
-        changes.push({from: no, to: no + 1});
-      }
+
+    function changeLine(handle, op) {
+      var no = handle, line = handle;
+      if (typeof handle == "number") line = getLine(clipLine(handle));
+      else no = lineNo(handle);
+      if (no == null) return null;
+      if (op(line, no)) changes.push({from: no, to: no + 1});
+      else return null;
       return line;
     }
+    function setLineClass(handle, className, bgClassName) {
+      return changeLine(handle, function(line) {
+        if (line.className != className || line.bgClassName != bgClassName) {
+          line.className = className;
+          line.bgClassName = bgClassName;
+          return true;
+        }
+      });
+    }
+    function setLineHidden(handle, hidden) {
+      return changeLine(handle, function(line, no) {
+        if (line.hidden != hidden) {
+          line.hidden = hidden;
+          if (!options.lineWrapping) {
+            var l = line.text;
+            if (hidden && l.length == maxLine.length) {
+              updateMaxLine = true;
+            } else if (!hidden && l.length > maxLine.length) {
+              maxLine = l; maxWidth = null; updateMaxLine = false;
+            }
+          }
+          updateLineHeight(line, hidden ? 0 : 1);
+          var fline = sel.from.line, tline = sel.to.line;
+          if (hidden && (fline == no || tline == no)) {
+            var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
+            var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
+            // Can't hide the last visible line, we'd have no place to put the cursor
+            if (!to) return;
+            setSelection(from, to);
+          }
+          return (gutterDirty = true);
+        }
+      });
+    }
 
     function lineInfo(line) {
       if (typeof line == "number") {
+        if (!isLine(line)) return null;
         var n = line;
-        line = lines[line];
+        line = getLine(line);
         if (!line) return null;
-      }
-      else {
-        var n = indexOf(lines, line);
-        if (n == -1) return null;
+      } else {
+        var n = lineNo(line);
+        if (n == null) return null;
       }
       var marker = line.gutterMarker;
-      return {line: n, text: line.text, markerText: marker && marker.text, markerClass: marker && marker.style};
+      return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
+              markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
     }
 
     function stringWidth(str) {
@@ -1239,21 +1643,15 @@
     }
     // These are used to go from pixel positions to character
     // positions, taking varying character widths into account.
-    function charX(line, pos) {
-      if (pos == 0) return 0;
-      measure.innerHTML = "<pre><span>" + lines[line].getHTML(null, null, false, pos) + "</span></pre>";
-      return measure.firstChild.firstChild.offsetWidth;
-    }
     function charFromX(line, x) {
       if (x <= 0) return 0;
-      var lineObj = lines[line], text = lineObj.text;
+      var lineObj = getLine(line), text = lineObj.text;
       function getX(len) {
-        measure.innerHTML = "<pre><span>" + lineObj.getHTML(null, null, false, len) + "</span></pre>";
-        return measure.firstChild.firstChild.offsetWidth;
+        return measureLine(lineObj, len).left;
       }
       var from = 0, fromX = 0, to = text.length, toX;
       // Guess a suitable upper bound for our search.
-      var estimated = Math.min(to, Math.ceil(x / stringWidth("x")));
+      var estimated = Math.min(to, Math.ceil(x / charWidth()));
       for (;;) {
         var estX = getX(estimated);
         if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
@@ -1272,20 +1670,95 @@
       }
     }
 
+    var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16);
+    function measureLine(line, ch) {
+      if (ch == 0) return {top: 0, left: 0};
+      var wbr = options.lineWrapping && ch < line.text.length &&
+                spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
+      measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch, tempId, wbr) + "</pre>";
+      var elt = document.getElementById(tempId);
+      var top = elt.offsetTop, left = elt.offsetLeft;
+      // Older IEs report zero offsets for spans directly after a wrap
+      if (ie && top == 0 && left == 0) {
+        var backup = document.createElement("span");
+        backup.innerHTML = "x";
+        elt.parentNode.insertBefore(backup, elt.nextSibling);
+        top = backup.offsetTop;
+      }
+      return {top: top, left: left};
+    }
     function localCoords(pos, inLineWrap) {
-      var lh = lineHeight(), line = pos.line - (inLineWrap ? showingFrom : 0);
-      return {x: charX(pos.line, pos.ch), y: line * lh, yBot: (line + 1) * lh};
+      var x, lh = textHeight(), y = lh * (heightAtLine(doc, pos.line) - (inLineWrap ? displayOffset : 0));
+      if (pos.ch == 0) x = 0;
+      else {
+        var sp = measureLine(getLine(pos.line), pos.ch);
+        x = sp.left;
+        if (options.lineWrapping) y += Math.max(0, sp.top);
+      }
+      return {x: x, y: y, yBot: y + lh};
+    }
+    // Coords must be lineSpace-local
+    function coordsChar(x, y) {
+      if (y < 0) y = 0;
+      var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th);
+      var lineNo = lineAtHeight(doc, heightPos);
+      if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length};
+      var lineObj = getLine(lineNo), text = lineObj.text;
+      var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;
+      if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0};
+      function getX(len) {
+        var sp = measureLine(lineObj, len);
+        if (tw) {
+          var off = Math.round(sp.top / th);
+          return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth);
+        }
+        return sp.left;
+      }
+      var from = 0, fromX = 0, to = text.length, toX;
+      // Guess a suitable upper bound for our search.
+      var estimated = Math.min(to, Math.ceil((x + innerOff * scroller.clientWidth * .9) / cw));
+      for (;;) {
+        var estX = getX(estimated);
+        if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
+        else {toX = estX; to = estimated; break;}
+      }
+      if (x > toX) return {line: lineNo, ch: to};
+      // Try to guess a suitable lower bound as well.
+      estimated = Math.floor(to * 0.8); estX = getX(estimated);
+      if (estX < x) {from = estimated; fromX = estX;}
+      // Do a binary search between these bounds.
+      for (;;) {
+        if (to - from <= 1) return {line: lineNo, ch: (toX - x > x - fromX) ? from : to};
+        var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
+        if (middleX > x) {to = middle; toX = middleX;}
+        else {from = middle; fromX = middleX;}
+      }
     }
     function pageCoords(pos) {
       var local = localCoords(pos, true), off = eltOffset(lineSpace);
       return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
     }
 
-    function lineHeight() {
-      var nlines = lineDiv.childNodes.length;
-      if (nlines) return (lineDiv.offsetHeight / nlines) || 1;
-      measure.innerHTML = "<pre>x</pre>";
-      return measure.firstChild.offsetHeight || 1;
+    var cachedHeight, cachedHeightFor, measureText;
+    function textHeight() {
+      if (measureText == null) {
+        measureText = "<pre>";
+        for (var i = 0; i < 49; ++i) measureText += "x<br/>";
+        measureText += "x</pre>";
+      }
+      var offsetHeight = lineDiv.clientHeight;
+      if (offsetHeight == cachedHeightFor) return cachedHeight;
+      cachedHeightFor = offsetHeight;
+      measure.innerHTML = measureText;
+      cachedHeight = measure.firstChild.offsetHeight / 50 || 1;
+      measure.innerHTML = "";
+      return cachedHeight;
+    }
+    var cachedWidth, cachedWidthFor = 0;
+    function charWidth() {
+      if (scroller.clientWidth == cachedWidthFor) return cachedWidth;
+      cachedWidthFor = scroller.clientWidth;
+      return (cachedWidth = stringWidth("x"));
     }
     function paddingTop() {return lineSpace.offsetTop;}
     function paddingLeft() {return lineSpace.offsetLeft;}
@@ -1300,12 +1773,11 @@
       if (!liberal && (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight))
         return null;
       var offL = eltOffset(lineSpace, true);
-      var line = showingFrom + Math.floor((y - offL.top) / lineHeight());
-      return clipPos({line: line, ch: charFromX(clipLine(line), x - offL.left)});
+      return coordsChar(x - offL.left, y - offL.top);
     }
     function onContextMenu(e) {
-      var pos = posFromMouse(e);
-      if (!pos || window.opera) return; // Opera is difficult.
+      var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
+      if (!pos || opera) return; // Opera is difficult.
       if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
         operation(setCursor)(pos.line, pos.ch);
 
@@ -1317,14 +1789,15 @@
       leaveInputAlone = true;
       var val = input.value = getSelection();
       focusInput();
-      setSelRange(input, 0, input.value.length);
+      selectInput(input);
       function rehide() {
         var newVal = splitLines(input.value).join("\n");
-        if (newVal != val) operation(replaceSelection)(newVal, "end");
+        if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
         inputDiv.style.position = "relative";
         input.style.cssText = oldCSS;
+        if (ie_lt9) scrollbar.scrollTop = scrollPos;
         leaveInputAlone = false;
-        prepareInput();
+        resetInput(true);
         slowPoll();
       }
 
@@ -1334,8 +1807,7 @@
           mouseup();
           setTimeout(rehide, 20);
         }, true);
-      }
-      else {
+      } else {
         setTimeout(rehide, 50);
       }
     }
@@ -1352,7 +1824,7 @@
 
     var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
     function matchBrackets(autoclear) {
-      var head = sel.inverted ? sel.from : sel.to, line = lines[head.line], pos = head.ch - 1;
+      var head = sel.inverted ? sel.from : sel.to, line = getLine(head.line), pos = head.ch - 1;
       var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
       if (!match) return;
       var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles;
@@ -1365,7 +1837,7 @@
         var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
         for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
           var text = st[i];
-          if (st[i+1] != null && st[i+1] != style) {pos += d * text.length; continue;}
+          if (st[i+1] != style) {pos += d * text.length; continue;}
           for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
             if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
               var match = matching[cur];
@@ -1376,8 +1848,8 @@
           }
         }
       }
-      for (var i = head.line, e = forward ? Math.min(i + 100, lines.length) : Math.max(-1, i - 100); i != e; i+=d) {
-        var line = lines[i], first = i == head.line;
+      for (var i = head.line, e = forward ? Math.min(i + 100, doc.size) : Math.max(-1, i - 100); i != e; i+=d) {
+        var line = getLine(i), first = i == head.line;
         var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length);
         if (found) break;
       }
@@ -1399,9 +1871,9 @@
       var minindent, minline;
       for (var search = n, lim = n - 40; search > lim; --search) {
         if (search == 0) return 0;
-        var line = lines[search-1];
+        var line = getLine(search-1);
         if (line.stateAfter) return search;
-        var indented = line.indentation();
+        var indented = line.indentation(options.tabSize);
         if (minline == null || minindent > indented) {
           minline = search - 1;
           minindent = indented;
@@ -1410,56 +1882,62 @@
       return minline;
     }
     function getStateBefore(n) {
-      var start = findStartLine(n), state = start && lines[start-1].stateAfter;
+      var start = findStartLine(n), state = start && getLine(start-1).stateAfter;
       if (!state) state = startState(mode);
       else state = copyState(mode, state);
-      for (var i = start; i < n; ++i) {
-        var line = lines[i];
-        line.highlight(mode, state);
+      doc.iter(start, n, function(line) {
+        line.highlight(mode, state, options.tabSize);
         line.stateAfter = copyState(mode, state);
-      }
-      changes.push({from: start, to: n});
-      if (n < lines.length && !lines[n].stateAfter) work.push(n);
+      });
+      if (start < n) changes.push({from: start, to: n});
+      if (n < doc.size && !getLine(n).stateAfter) work.push(n);
       return state;
     }
     function highlightLines(start, end) {
       var state = getStateBefore(start);
-      for (var i = start; i < end; ++i) {
-        var line = lines[i];
-        line.highlight(mode, state);
+      doc.iter(start, end, function(line) {
+        line.highlight(mode, state, options.tabSize);
         line.stateAfter = copyState(mode, state);
-      }
+      });
     }
     function highlightWorker() {
       var end = +new Date + options.workTime;
       var foundWork = work.length;
       while (work.length) {
-        if (!lines[showingFrom].stateAfter) var task = showingFrom;
+        if (!getLine(showingFrom).stateAfter) var task = showingFrom;
         else var task = work.pop();
-        if (task >= lines.length) continue;
-        var start = findStartLine(task), state = start && lines[start-1].stateAfter;
+        if (task >= doc.size) continue;
+        var start = findStartLine(task), state = start && getLine(start-1).stateAfter;
         if (state) state = copyState(mode, state);
         else state = startState(mode);
 
-        var unchanged = 0, compare = mode.compareStates, realChange = false;
-        for (var i = start, l = lines.length; i < l; ++i) {
-          var line = lines[i], hadState = line.stateAfter;
+        var unchanged = 0, compare = mode.compareStates, realChange = false,
+            i = start, bail = false;
+        doc.iter(i, doc.size, function(line) {
+          var hadState = line.stateAfter;
           if (+new Date > end) {
             work.push(i);
             startWorker(options.workDelay);
             if (realChange) changes.push({from: task, to: i + 1});
-            return;
+            return (bail = true);
           }
-          var changed = line.highlight(mode, state);
+          var changed = line.highlight(mode, state, options.tabSize);
           if (changed) realChange = true;
           line.stateAfter = copyState(mode, state);
+          var done = null;
           if (compare) {
-            if (hadState && compare(hadState, state)) break;
-          } else {
+            var same = hadState && compare(hadState, state);
+            if (same != Pass) done = !!same;
+          }
+          if (done == null) {
             if (changed !== false || !hadState) unchanged = 0;
-            else if (++unchanged > 3) break;
+            else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
+              done = true;
           }
-        }
+          if (done) return true;
+          ++i;
+        });
+        if (bail) return;
         if (realChange) changes.push({from: task, to: i + 1});
       }
       if (foundWork && options.onHighlightComplete)
@@ -1475,35 +1953,44 @@
     // be awkward, slow, and error-prone), but instead updates are
     // batched and then all combined and executed at once.
     function startOperation() {
-      updateInput = null; changes = []; textChanged = selectionChanged = false;
+      updateInput = userSelChange = textChanged = null;
+      changes = []; selectionChanged = false; callbacks = [];
     }
     function endOperation() {
-      var reScroll = false;
-      if (selectionChanged) reScroll = !scrollCursorIntoView();
-      if (changes.length) updateDisplay(changes);
+      if (updateMaxLine) computeMaxLength();
+      if (maxLineChanged && !options.lineWrapping) {
+        widthForcer.style.left = stringWidth(maxLine) + "px";
+        maxLineChanged = false;
+      }
+      var newScrollPos, updated;
+      if (selectionChanged) {
+        var coords = calculateCursorCoords();
+        newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
+      }
+      if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null));
       else {
-        if (selectionChanged) updateCursor();
+        if (selectionChanged) updateSelection();
         if (gutterDirty) updateGutter();
       }
-      if (reScroll) scrollCursorIntoView();
+      if (newScrollPos) scrollCursorIntoView();
       if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
 
-      // updateInput can be set to a boolean value to force/prevent an
-      // update.
       if (focused && !leaveInputAlone &&
           (updateInput === true || (updateInput !== false && selectionChanged)))
-        prepareInput();
+        resetInput(userSelChange);
 
       if (selectionChanged && options.matchBrackets)
         setTimeout(operation(function() {
           if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
-          matchBrackets(false);
+          if (posEq(sel.from, sel.to)) matchBrackets(false);
         }), 20);
-      var tc = textChanged; // textChanged can be reset by cursoractivity callback
-      if (selectionChanged && options.onCursorActivity)
+      var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
+      if (textChanged && options.onChange && instance)
+        options.onChange(instance, textChanged);
+      if (sc && options.onCursorActivity)
         options.onCursorActivity(instance);
-      if (tc && options.onChange && instance)
-        options.onChange(instance, tc);
+      for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
+      if (updated && options.onUpdate) options.onUpdate(instance);
     }
     var nestedOperation = 0;
     function operation(f) {
@@ -1515,120 +2002,11 @@
       };
     }
 
-    function SearchCursor(query, pos, caseFold) {
-      this.atOccurrence = false;
-      if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
-
-      if (pos && typeof pos == "object") pos = clipPos(pos);
-      else pos = {line: 0, ch: 0};
-      this.pos = {from: pos, to: pos};
-
-      // The matches method is filled in based on the type of query.
-      // It takes a position and a direction, and returns an object
-      // describing the next occurrence of the query, or null if no
-      // more matches were found.
-      if (typeof query != "string") // Regexp match
-        this.matches = function(reverse, pos) {
-          if (reverse) {
-            var line = lines[pos.line].text.slice(0, pos.ch), match = line.match(query), start = 0;
-            while (match) {
-              var ind = line.indexOf(match[0]);
-              start += ind;
-              line = line.slice(ind + 1);
-              var newmatch = line.match(query);
-              if (newmatch) match = newmatch;
-              else break;
-              start++;
-            }
-          }
-          else {
-            var line = lines[pos.line].text.slice(pos.ch), match = line.match(query),
-                start = match && pos.ch + line.indexOf(match[0]);
-          }
-          if (match)
-            return {from: {line: pos.line, ch: start},
-                    to: {line: pos.line, ch: start + match[0].length},
-                    match: match};
-        };
-      else { // String query
-        if (caseFold) query = query.toLowerCase();
-        var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
-        var target = query.split("\n");
-        // Different methods for single-line and multi-line queries
-        if (target.length == 1)
-          this.matches = function(reverse, pos) {
-            var line = fold(lines[pos.line].text), len = query.length, match;
-            if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
-                        : (match = line.indexOf(query, pos.ch)) != -1)
-              return {from: {line: pos.line, ch: match},
-                      to: {line: pos.line, ch: match + len}};
-          };
-        else
-          this.matches = function(reverse, pos) {
-            var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(lines[ln].text);
-            var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
-            if (reverse ? offsetA >= pos.ch || offsetA != match.length
-                        : offsetA <= pos.ch || offsetA != line.length - match.length)
-              return;
-            for (;;) {
-              if (reverse ? !ln : ln == lines.length - 1) return;
-              line = fold(lines[ln += reverse ? -1 : 1].text);
-              match = target[reverse ? --idx : ++idx];
-              if (idx > 0 && idx < target.length - 1) {
-                if (line != match) return;
-                else continue;
-              }
-              var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
-              if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
-                return;
-              var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
-              return {from: reverse ? end : start, to: reverse ? start : end};
-            }
-          };
-      }
+    function compoundChange(f) {
+      history.startCompound();
+      try { return f(); } finally { history.endCompound(); }
     }
 
-    SearchCursor.prototype = {
-      findNext: function() {return this.find(false);},
-      findPrevious: function() {return this.find(true);},
-
-      find: function(reverse) {
-        var self = this, pos = clipPos(reverse ? this.pos.from : this.pos.to);
-        function savePosAndFail(line) {
-          var pos = {line: line, ch: 0};
-          self.pos = {from: pos, to: pos};
-          self.atOccurrence = false;
-          return false;
-        }
-
-        for (;;) {
-          if (this.pos = this.matches(reverse, pos)) {
-            this.atOccurrence = true;
-            return this.pos.match || true;
-          }
-          if (reverse) {
-            if (!pos.line) return savePosAndFail(0);
-            pos = {line: pos.line-1, ch: lines[pos.line-1].text.length};
-          }
-          else {
-            if (pos.line == lines.length - 1) return savePosAndFail(lines.length);
-            pos = {line: pos.line+1, ch: 0};
-          }
-        }
-      },
-
-      from: function() {if (this.atOccurrence) return copyPos(this.pos.from);},
-      to: function() {if (this.atOccurrence) return copyPos(this.pos.to);},
-
-      replace: function(newText) {
-        var self = this;
-        if (this.atOccurrence)
-          operation(function() {
-            self.pos.to = replaceRange(newText, self.pos.from, self.pos.to);
-          })();
-      }
-    };
-
     for (var ext in extensions)
       if (extensions.propertyIsEnumerable(ext) &&
           !instance.propertyIsEnumerable(ext))
@@ -1643,51 +2021,66 @@
     theme: "default",
     indentUnit: 2,
     indentWithTabs: false,
-    tabMode: "classic",
-    enterMode: "indent",
+    smartIndent: true,
+    tabSize: 4,
+    keyMap: "default",
+    extraKeys: null,
     electricChars: true,
+    autoClearEmptyLines: false,
     onKeyEvent: null,
+    onDragEvent: null,
+    lineWrapping: false,
     lineNumbers: false,
     gutter: false,
     fixedGutter: false,
     firstLineNumber: 1,
     readOnly: false,
-    smartHome: true,
+    dragDrop: true,
     onChange: null,
     onCursorActivity: null,
     onGutterClick: null,
     onHighlightComplete: null,
+    onUpdate: null,
     onFocus: null, onBlur: null, onScroll: null,
     matchBrackets: false,
     workTime: 100,
     workDelay: 200,
+    pollInterval: 100,
     undoDepth: 40,
     tabindex: null,
-    document: window.document
+    autofocus: null
   };
 
+  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
+  var mac = ios || /Mac/.test(navigator.platform);
+  var win = /Win/.test(navigator.platform);
+
   // Known modes, by name and by MIME
-  var modes = {}, mimeModes = {};
+  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
   CodeMirror.defineMode = function(name, mode) {
     if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
+    if (arguments.length > 2) {
+      mode.dependencies = [];
+      for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
+    }
     modes[name] = mode;
   };
   CodeMirror.defineMIME = function(mime, spec) {
     mimeModes[mime] = spec;
   };
-  CodeMirror.getMode = function(options, spec) {
+  CodeMirror.resolveMode = function(spec) {
     if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
       spec = mimeModes[spec];
-    if (typeof spec == "string")
-      var mname = spec, config = {};
-    else if (spec != null)
-      var mname = spec.name, config = spec;
-    var mfactory = modes[mname];
-    if (!mfactory) {
-      if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
-      return CodeMirror.getMode(options, "text/plain");
-    }
-    return mfactory(options, config || {});
+    else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
+      return CodeMirror.resolveMode("application/xml");
+    if (typeof spec == "string") return {name: spec};
+    else return spec || {name: "null"};
+  };
+  CodeMirror.getMode = function(options, spec) {
+    var spec = CodeMirror.resolveMode(spec);
+    var mfactory = modes[spec.name];
+    if (!mfactory) return CodeMirror.getMode(options, "text/plain");
+    return mfactory(options, spec);
   };
   CodeMirror.listModes = function() {
     var list = [];
@@ -1702,16 +2095,137 @@
     return list;
   };
 
-  var extensions = {};
+  var extensions = CodeMirror.extensions = {};
   CodeMirror.defineExtension = function(name, func) {
     extensions[name] = func;
   };
 
+  var commands = CodeMirror.commands = {
+    selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
+    killLine: function(cm) {
+      var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
+      if (!sel && cm.getLine(from.line).length == from.ch) cm.replaceRange("", from, {line: from.line + 1, ch: 0});
+      else cm.replaceRange("", from, sel ? to : {line: from.line});
+    },
+    deleteLine: function(cm) {var l = cm.getCursor().line; cm.replaceRange("", {line: l, ch: 0}, {line: l});},
+    undo: function(cm) {cm.undo();},
+    redo: function(cm) {cm.redo();},
+    goDocStart: function(cm) {cm.setCursor(0, 0, true);},
+    goDocEnd: function(cm) {cm.setSelection({line: cm.lineCount() - 1}, null, true);},
+    goLineStart: function(cm) {cm.setCursor(cm.getCursor().line, 0, true);},
+    goLineStartSmart: function(cm) {
+      var cur = cm.getCursor();
+      var text = cm.getLine(cur.line), firstNonWS = Math.max(0, text.search(/\S/));
+      cm.setCursor(cur.line, cur.ch <= firstNonWS && cur.ch ? 0 : firstNonWS, true);
+    },
+    goLineEnd: function(cm) {cm.setSelection({line: cm.getCursor().line}, null, true);},
+    goLineUp: function(cm) {cm.moveV(-1, "line");},
+    goLineDown: function(cm) {cm.moveV(1, "line");},
+    goPageUp: function(cm) {cm.moveV(-1, "page");},
+    goPageDown: function(cm) {cm.moveV(1, "page");},
+    goCharLeft: function(cm) {cm.moveH(-1, "char");},
+    goCharRight: function(cm) {cm.moveH(1, "char");},
+    goColumnLeft: function(cm) {cm.moveH(-1, "column");},
+    goColumnRight: function(cm) {cm.moveH(1, "column");},
+    goWordLeft: function(cm) {cm.moveH(-1, "word");},
+    goWordRight: function(cm) {cm.moveH(1, "word");},
+    delCharLeft: function(cm) {cm.deleteH(-1, "char");},
+    delCharRight: function(cm) {cm.deleteH(1, "char");},
+    delWordLeft: function(cm) {cm.deleteH(-1, "word");},
+    delWordRight: function(cm) {cm.deleteH(1, "word");},
+    indentAuto: function(cm) {cm.indentSelection("smart");},
+    indentMore: function(cm) {cm.indentSelection("add");},
+    indentLess: function(cm) {cm.indentSelection("subtract");},
+    insertTab: function(cm) {cm.replaceSelection("\t", "end");},
+    defaultTab: function(cm) {
+      if (cm.somethingSelected()) cm.indentSelection("add");
+      else cm.replaceSelection("\t", "end");
+    },
+    transposeChars: function(cm) {
+      var cur = cm.getCursor(), line = cm.getLine(cur.line);
+      if (cur.ch > 0 && cur.ch < line.length - 1)
+        cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
+                        {line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1});
+    },
+    newlineAndIndent: function(cm) {
+      cm.replaceSelection("\n", "end");
+      cm.indentLine(cm.getCursor().line);
+    },
+    toggleOverwrite: function(cm) {cm.toggleOverwrite();}
+  };
+
+  var keyMap = CodeMirror.keyMap = {};
+  keyMap.basic = {
+    "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
+    "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
+    "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
+    "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
+  };
+  // Note that the save and find-related commands aren't defined by
+  // default. Unknown commands are simply ignored.
+  keyMap.pcDefault = {
+    "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
+    "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
+    "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
+    "Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
+    "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
+    "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
+    fallthrough: "basic"
+  };
+  keyMap.macDefault = {
+    "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
+    "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft",
+    "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
+    "Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
+    "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
+    "Cmd-[": "indentLess", "Cmd-]": "indentMore",
+    fallthrough: ["basic", "emacsy"]
+  };
+  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
+  keyMap.emacsy = {
+    "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+    "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
+    "Ctrl-V": "goPageUp", "Shift-Ctrl-V": "goPageDown", "Ctrl-D": "delCharRight", "Ctrl-H": "delCharLeft",
+    "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
+  };
+
+  function getKeyMap(val) {
+    if (typeof val == "string") return keyMap[val];
+    else return val;
+  }
+  function lookupKey(name, extraMap, map, handle, stop) {
+    function lookup(map) {
+      map = getKeyMap(map);
+      var found = map[name];
+      if (found != null && handle(found)) return true;
+      if (map.nofallthrough) {
+        if (stop) stop();
+        return true;
+      }
+      var fallthrough = map.fallthrough;
+      if (fallthrough == null) return false;
+      if (Object.prototype.toString.call(fallthrough) != "[object Array]")
+        return lookup(fallthrough);
+      for (var i = 0, e = fallthrough.length; i < e; ++i) {
+        if (lookup(fallthrough[i])) return true;
+      }
+      return false;
+    }
+    if (extraMap && lookup(extraMap)) return true;
+    return lookup(map);
+  }
+  function isModifierKey(event) {
+    var name = keyNames[e_prop(event, "keyCode")];
+    return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
+  }
+
   CodeMirror.fromTextArea = function(textarea, options) {
     if (!options) options = {};
     options.value = textarea.value;
     if (!options.tabindex && textarea.tabindex)
       options.tabindex = textarea.tabindex;
+    if (options.autofocus == null && textarea.getAttribute("autofocus") != null)
+      options.autofocus = true;
 
     function save() {textarea.value = instance.getValue();}
     if (textarea.form) {
@@ -1734,6 +2248,7 @@
       textarea.parentNode.insertBefore(node, textarea.nextSibling);
     }, options);
     instance.save = save;
+    instance.getTextArea = function() { return textarea; };
     instance.toTextArea = function() {
       save();
       textarea.parentNode.removeChild(instance.getWrapperElement());
@@ -1760,16 +2275,17 @@
     }
     return nstate;
   }
-  CodeMirror.startState = startState;
+  CodeMirror.copyState = copyState;
   function startState(mode, a1, a2) {
     return mode.startState ? mode.startState(a1, a2) : true;
   }
-  CodeMirror.copyState = copyState;
+  CodeMirror.startState = startState;
 
   // The character stream used by a mode's parser.
-  function StringStream(string) {
+  function StringStream(string, tabSize) {
     this.pos = this.start = 0;
     this.string = string;
+    this.tabSize = tabSize || 8;
   }
   StringStream.prototype = {
     eol: function() {return this.pos >= this.string.length;},
@@ -1801,8 +2317,8 @@
       if (found > -1) {this.pos = found; return true;}
     },
     backUp: function(n) {this.pos -= n;},
-    column: function() {return countColumn(this.string, this.start);},
-    indentation: function() {return countColumn(this.string);},
+    column: function() {return countColumn(this.string, this.start, this.tabSize);},
+    indentation: function() {return countColumn(this.string, null, this.tabSize);},
     match: function(pattern, consume, caseInsensitive) {
       if (typeof pattern == "string") {
         function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
@@ -1810,8 +2326,7 @@
           if (consume !== false) this.pos += pattern.length;
           return true;
         }
-      }
-      else {
+      } else {
         var match = this.string.slice(this.pos).match(pattern);
         if (match && consume !== false) this.pos += match[0].length;
         return match;
@@ -1821,22 +2336,86 @@
   };
   CodeMirror.StringStream = StringStream;
 
+  function MarkedText(from, to, className, marker) {
+    this.from = from; this.to = to; this.style = className; this.marker = marker;
+  }
+  MarkedText.prototype = {
+    attach: function(line) { this.marker.set.push(line); },
+    detach: function(line) {
+      var ix = indexOf(this.marker.set, line);
+      if (ix > -1) this.marker.set.splice(ix, 1);
+    },
+    split: function(pos, lenBefore) {
+      if (this.to <= pos && this.to != null) return null;
+      var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
+      var to = this.to == null ? null : this.to - pos + lenBefore;
+      return new MarkedText(from, to, this.style, this.marker);
+    },
+    dup: function() { return new MarkedText(null, null, this.style, this.marker); },
+    clipTo: function(fromOpen, from, toOpen, to, diff) {
+      if (fromOpen && to > this.from && (to < this.to || this.to == null))
+        this.from = null;
+      else if (this.from != null && this.from >= from)
+        this.from = Math.max(to, this.from) + diff;
+      if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
+        this.to = null;
+      else if (this.to != null && this.to > from)
+        this.to = to < this.to ? this.to + diff : from;
+    },
+    isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
+    sameSet: function(x) { return this.marker == x.marker; }
+  };
+
+  function Bookmark(pos) {
+    this.from = pos; this.to = pos; this.line = null;
+  }
+  Bookmark.prototype = {
+    attach: function(line) { this.line = line; },
+    detach: function(line) { if (this.line == line) this.line = null; },
+    split: function(pos, lenBefore) {
+      if (pos < this.from) {
+        this.from = this.to = (this.from - pos) + lenBefore;
+        return this;
+      }
+    },
+    isDead: function() { return this.from > this.to; },
+    clipTo: function(fromOpen, from, toOpen, to, diff) {
+      if ((fromOpen || from < this.from) && (toOpen || to > this.to)) {
+        this.from = 0; this.to = -1;
+      } else if (this.from > from) {
+        this.from = this.to = Math.max(to, this.from) + diff;
+      }
+    },
+    sameSet: function(x) { return false; },
+    find: function() {
+      if (!this.line || !this.line.parent) return null;
+      return {line: lineNo(this.line), ch: this.from};
+    },
+    clear: function() {
+      if (this.line) {
+        var found = indexOf(this.line.marked, this);
+        if (found != -1) this.line.marked.splice(found, 1);
+        this.line = null;
+      }
+    }
+  };
+
   // Line objects. These hold state related to a line, including
   // highlighting info (the styles array).
   function Line(text, styles) {
     this.styles = styles || [text, null];
-    this.stateAfter = null;
     this.text = text;
-    this.marked = this.gutterMarker = this.className = null;
+    this.height = 1;
+    this.marked = this.gutterMarker = this.className = this.bgClassName = this.handlers = null;
+    this.stateAfter = this.parent = this.hidden = null;
   }
   Line.inheritMarks = function(text, orig) {
-    var ln = new Line(text), mk = orig.marked;
+    var ln = new Line(text), mk = orig && orig.marked;
     if (mk) {
       for (var i = 0; i < mk.length; ++i) {
-        if (mk[i].to == null) {
+        if (mk[i].to == null && mk[i].style) {
           var newmk = ln.marked || (ln.marked = []), mark = mk[i];
-          newmk.push({from: null, to: null, style: mark.style, set: mark.set});
-          mark.set.push(ln);
+          var nmark = mark.dup(); newmk.push(nmark); nmark.attach(ln);
         }
       }
     }
@@ -1853,23 +2432,11 @@
       this.text = this.text.slice(0, from) + text + this.text.slice(to);
       this.stateAfter = null;
       if (mk) {
-        var diff = text.length - (to - from), end = this.text.length;
-        var changeStart = Math.min(from, from + diff);
+        var diff = text.length - (to - from);
         for (var i = 0; i < mk.length; ++i) {
-          var mark = mk[i], del = false;
-          if (mark.from != null && mark.from >= end) del = true;
-          else {
-            if (mark.from != null && mark.from >= from) {
-              mark.from += diff;
-              if (mark.from <= 0) mark.from = from == null ? null : 0;
-            }
-            else if (to_ == null) mark.to = null;
-            if (mark.to != null && mark.to > from) {
-              mark.to += diff;
-              if (mark.to < 0) del = true;
-            }
-          }
-          if (del || (mark.from != null && mark.to != null && mark.from >= mark.to)) mk.splice(i--, 1);
+          var mark = mk[i];
+          mark.clipTo(from == null, from || 0, to_ == null, to, diff);
+          if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);}
         }
       }
     },
@@ -1881,57 +2448,77 @@
       if (mk) {
         for (var i = 0; i < mk.length; ++i) {
           var mark = mk[i];
-          if (mark.to > pos || mark.to == null) {
+          var newmark = mark.split(pos, textBefore.length);
+          if (newmark) {
             if (!taken.marked) taken.marked = [];
-            taken.marked.push({
-              from: mark.from < pos || mark.from == null ? null : mark.from - pos + textBefore.length,
-              to: mark.to == null ? null : mark.to - pos + textBefore.length,
-              style: mark.style, set: mark.set
-            });
-            mark.set.push(taken);
+            taken.marked.push(newmark); newmark.attach(taken);
+            if (newmark == mark) mk.splice(i--, 1);
           }
         }
       }
       return taken;
     },
     append: function(line) {
-      if (!line.text.length) return;
-      var mylen = this.text.length, mk = line.marked;
+      var mylen = this.text.length, mk = line.marked, mymk = this.marked;
       this.text += line.text;
       copyStyles(0, line.text.length, line.styles, this.styles);
-      if (mk && mk.length) {
-        var mymk = this.marked || (this.marked = []);
+      if (mymk) {
         for (var i = 0; i < mymk.length; ++i)
           if (mymk[i].to == null) mymk[i].to = mylen;
+      }
+      if (mk && mk.length) {
+        if (!mymk) this.marked = mymk = [];
         outer: for (var i = 0; i < mk.length; ++i) {
           var mark = mk[i];
           if (!mark.from) {
             for (var j = 0; j < mymk.length; ++j) {
               var mymark = mymk[j];
-              if (mymark.to == mylen && mymark.set == mark.set) {
+              if (mymark.to == mylen && mymark.sameSet(mark)) {
                 mymark.to = mark.to == null ? null : mark.to + mylen;
+                if (mymark.isDead()) {
+                  mymark.detach(this);
+                  mk.splice(i--, 1);
+                }
                 continue outer;
               }
             }
           }
           mymk.push(mark);
-          mark.set.push(this);
+          mark.attach(this);
           mark.from += mylen;
           if (mark.to != null) mark.to += mylen;
         }
       }
     },
-    addMark: function(from, to, style, set) {
-      set.push(this);
+    fixMarkEnds: function(other) {
+      var mk = this.marked, omk = other.marked;
+      if (!mk) return;
+      for (var i = 0; i < mk.length; ++i) {
+        var mark = mk[i], close = mark.to == null;
+        if (close && omk) {
+          for (var j = 0; j < omk.length; ++j)
+            if (omk[j].sameSet(mark)) {close = false; break;}
+        }
+        if (close) mark.to = this.text.length;
+      }
+    },
+    fixMarkStarts: function() {
+      var mk = this.marked;
+      if (!mk) return;
+      for (var i = 0; i < mk.length; ++i)
+        if (mk[i].from == null) mk[i].from = 0;
+    },
+    addMark: function(mark) {
+      mark.attach(this);
       if (this.marked == null) this.marked = [];
-      this.marked.push({from: from, to: to, style: style, set: set});
+      this.marked.push(mark);
       this.marked.sort(function(a, b){return (a.from || 0) - (b.from || 0);});
     },
     // Run the given mode's parser over a line, update the styles
     // array, which contains alternating fragments of text and CSS
     // classes.
-    highlight: function(mode, state) {
-      var stream = new StringStream(this.text), st = this.styles, pos = 0;
+    highlight: function(mode, state, tabSize) {
+      var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0;
       var changed = false, curWord = st[0], prevWord;
       if (this.text == "" && mode.blankLine) mode.blankLine(state);
       while (!stream.eol()) {
@@ -1972,74 +2559,125 @@
               className: style || null,
               state: state};
     },
-    indentation: function() {return countColumn(this.text);},
+    indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
     // Produces an HTML fragment for the line, taking selection,
     // marking, and highlighting into account.
-    getHTML: function(sfrom, sto, includePre, endAt) {
-      var html = [];
-      if (includePre)
-        html.push(this.className ? '<pre class="' + this.className + '">': "<pre>");
-      function span(text, style) {
+    getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) {
+      var html = [], first = true, col = 0;
+      function span_(text, style) {
         if (!text) return;
-        if (style) html.push('<span class="', style, '">', htmlEscape(text), "</span>");
-        else html.push(htmlEscape(text));
+        // Work around a bug where, in some compat modes, IE ignores leading spaces
+        if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
+        first = false;
+        if (text.indexOf("\t") == -1) {
+          col += text.length;
+          var escaped = htmlEscape(text);
+        } else {
+          var escaped = "";
+          for (var pos = 0;;) {
+            var idx = text.indexOf("\t", pos);
+            if (idx == -1) {
+              escaped += htmlEscape(text.slice(pos));
+              col += text.length - pos;
+              break;
+            } else {
+              col += idx - pos;
+              var tab = makeTab(col);
+              escaped += htmlEscape(text.slice(pos, idx)) + tab.html;
+              col += tab.width;
+              pos = idx + 1;
+            }
+          }
+        }
+        if (style) html.push('<span class="', style, '">', escaped, "</span>");
+        else html.push(escaped);
       }
+      var span = span_;
+      if (wrapAt != null) {
+        var outPos = 0, open = "<span id=\"" + wrapId + "\">";
+        span = function(text, style) {
+          var l = text.length;
+          if (wrapAt >= outPos && wrapAt < outPos + l) {
+            if (wrapAt > outPos) {
+              span_(text.slice(0, wrapAt - outPos), style);
+              // See comment at the definition of spanAffectsWrapping
+              if (wrapWBR) html.push("<wbr>");
+            }
+            html.push(open);
+            var cut = wrapAt - outPos;
+            span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
+            html.push("</span>");
+            if (opera) span_(text.slice(cut + 1), style);
+            wrapAt--;
+            outPos += l;
+          } else {
+            outPos += l;
+            span_(text, style);
+            // Output empty wrapper when at end of line
+            if (outPos == wrapAt && outPos == len) html.push(open + " </span>");
+            // Stop outputting HTML when gone sufficiently far beyond measure
+            else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
+          }
+        }
+      }
+
       var st = this.styles, allText = this.text, marked = this.marked;
-      if (sfrom == sto) sfrom = null;
       var len = allText.length;
-      if (endAt != null) len = Math.min(endAt, len);
+      function styleToClass(style) {
+        if (!style) return null;
+        return "cm-" + style.replace(/ +/g, " cm-");
+      }
 
-      if (!allText && endAt == null)
-        span(" ", sfrom != null && sto == null ? "CodeMirror-selected" : null);
-      else if (!marked && sfrom == null)
+      if (!allText && wrapAt == null) {
+        span(" ");
+      } else if (!marked || !marked.length) {
         for (var i = 0, ch = 0; ch < len; i+=2) {
           var str = st[i], style = st[i+1], l = str.length;
           if (ch + l > len) str = str.slice(0, len - ch);
           ch += l;
-          span(str, style && "cm-" + style);
+          span(str, styleToClass(style));
         }
-      else {
+      } else {
         var pos = 0, i = 0, text = "", style, sg = 0;
-        var markpos = -1, mark = null;
-        function nextMark() {
-          if (marked) {
-            markpos += 1;
-            mark = (markpos < marked.length) ? marked[markpos] : null;
+        var nextChange = marked[0].from || 0, marks = [], markpos = 0;
+        function advanceMarks() {
+          var m;
+          while (markpos < marked.length &&
+                 ((m = marked[markpos]).from == pos || m.from == null)) {
+            if (m.style != null) marks.push(m);
+            ++markpos;
+          }
+          nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
+          for (var i = 0; i < marks.length; ++i) {
+            var to = marks[i].to || Infinity;
+            if (to == pos) marks.splice(i--, 1);
+            else nextChange = Math.min(to, nextChange);
           }
         }
-        nextMark();
+        var m = 0;
         while (pos < len) {
-          var upto = len;
-          var extraStyle = "";
-          if (sfrom != null) {
-            if (sfrom > pos) upto = sfrom;
-            else if (sto == null || sto > pos) {
-              extraStyle = " CodeMirror-selected";
-              if (sto != null) upto = Math.min(upto, sto);
+          if (nextChange == pos) advanceMarks();
+          var upto = Math.min(len, nextChange);
+          while (true) {
+            if (text) {
+              var end = pos + text.length;
+              var appliedStyle = style;
+              for (var j = 0; j < marks.length; ++j)
+                appliedStyle = (appliedStyle ? appliedStyle + " " : "") + marks[j].style;
+              span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
+              if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
+              pos = end;
             }
-          }
-          while (mark && mark.to != null && mark.to <= pos) nextMark();
-          if (mark) {
-            if (mark.from > pos) upto = Math.min(upto, mark.from);
-            else {
-              extraStyle += " " + mark.style;
-              if (mark.to != null) upto = Math.min(upto, mark.to);
-            }
-          }
-          for (;;) {
-            var end = pos + text.length;
-            var appliedStyle = style;
-            if (extraStyle) appliedStyle = style ? style + extraStyle : extraStyle;
-            span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
-            if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
-            pos = end;
-            text = st[i++]; style = "cm-" + st[i++];
+            text = st[i++]; style = styleToClass(st[i++]);
           }
         }
-        if (sfrom != null && sto == null) span(" ", "CodeMirror-selected");
       }
-      if (includePre) html.push("</pre>");
       return html.join("");
+    },
+    cleanUp: function() {
+      this.parent = null;
+      if (this.marked)
+        for (var i = 0, e = this.marked.length; i < e; ++i) this.marked[i].detach(this);
     }
   };
   // Utility used by replace and split above
@@ -2049,8 +2687,7 @@
       if (state == 0) {
         if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
         if (end >= from) state = 1;
-      }
-      else if (state == 1) {
+      } else if (state == 1) {
         if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
         else dest.push(part, source[i+1]);
       }
@@ -2058,36 +2695,229 @@
     }
   }
 
+  // Data structure that holds the sequence of lines.
+  function LeafChunk(lines) {
+    this.lines = lines;
+    this.parent = null;
+    for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
+      lines[i].parent = this;
+      height += lines[i].height;
+    }
+    this.height = height;
+  }
+  LeafChunk.prototype = {
+    chunkSize: function() { return this.lines.length; },
+    remove: function(at, n, callbacks) {
+      for (var i = at, e = at + n; i < e; ++i) {
+        var line = this.lines[i];
+        this.height -= line.height;
+        line.cleanUp();
+        if (line.handlers)
+          for (var j = 0; j < line.handlers.length; ++j) callbacks.push(line.handlers[j]);
+      }
+      this.lines.splice(at, n);
+    },
+    collapse: function(lines) {
+      lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
+    },
+    insertHeight: function(at, lines, height) {
+      this.height += height;
+      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
+      for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
+    },
+    iterN: function(at, n, op) {
+      for (var e = at + n; at < e; ++at)
+        if (op(this.lines[at])) return true;
+    }
+  };
+  function BranchChunk(children) {
+    this.children = children;
+    var size = 0, height = 0;
+    for (var i = 0, e = children.length; i < e; ++i) {
+      var ch = children[i];
+      size += ch.chunkSize(); height += ch.height;
+      ch.parent = this;
+    }
+    this.size = size;
+    this.height = height;
+    this.parent = null;
+  }
+  BranchChunk.prototype = {
+    chunkSize: function() { return this.size; },
+    remove: function(at, n, callbacks) {
+      this.size -= n;
+      for (var i = 0; i < this.children.length; ++i) {
+        var child = this.children[i], sz = child.chunkSize();
+        if (at < sz) {
+          var rm = Math.min(n, sz - at), oldHeight = child.height;
+          child.remove(at, rm, callbacks);
+          this.height -= oldHeight - child.height;
+          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
+          if ((n -= rm) == 0) break;
+          at = 0;
+        } else at -= sz;
+      }
+      if (this.size - n < 25) {
+        var lines = [];
+        this.collapse(lines);
+        this.children = [new LeafChunk(lines)];
+        this.children[0].parent = this;
+      }
+    },
+    collapse: function(lines) {
+      for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
+    },
+    insert: function(at, lines) {
+      var height = 0;
+      for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
+      this.insertHeight(at, lines, height);
+    },
+    insertHeight: function(at, lines, height) {
+      this.size += lines.length;
+      this.height += height;
+      for (var i = 0, e = this.children.length; i < e; ++i) {
+        var child = this.children[i], sz = child.chunkSize();
+        if (at <= sz) {
+          child.insertHeight(at, lines, height);
+          if (child.lines && child.lines.length > 50) {
+            while (child.lines.length > 50) {
+              var spilled = child.lines.splice(child.lines.length - 25, 25);
+              var newleaf = new LeafChunk(spilled);
+              child.height -= newleaf.height;
+              this.children.splice(i + 1, 0, newleaf);
+              newleaf.parent = this;
+            }
+            this.maybeSpill();
+          }
+          break;
+        }
+        at -= sz;
+      }
+    },
+    maybeSpill: function() {
+      if (this.children.length <= 10) return;
+      var me = this;
+      do {
+        var spilled = me.children.splice(me.children.length - 5, 5);
+        var sibling = new BranchChunk(spilled);
+        if (!me.parent) { // Become the parent node
+          var copy = new BranchChunk(me.children);
+          copy.parent = me;
+          me.children = [copy, sibling];
+          me = copy;
+        } else {
+          me.size -= sibling.size;
+          me.height -= sibling.height;
+          var myIndex = indexOf(me.parent.children, me);
+          me.parent.children.splice(myIndex + 1, 0, sibling);
+        }
+        sibling.parent = me.parent;
+      } while (me.children.length > 10);
+      me.parent.maybeSpill();
+    },
+    iter: function(from, to, op) { this.iterN(from, to - from, op); },
+    iterN: function(at, n, op) {
+      for (var i = 0, e = this.children.length; i < e; ++i) {
+        var child = this.children[i], sz = child.chunkSize();
+        if (at < sz) {
+          var used = Math.min(n, sz - at);
+          if (child.iterN(at, used, op)) return true;
+          if ((n -= used) == 0) break;
+          at = 0;
+        } else at -= sz;
+      }
+    }
+  };
+
+  function getLineAt(chunk, n) {
+    while (!chunk.lines) {
+      for (var i = 0;; ++i) {
+        var child = chunk.children[i], sz = child.chunkSize();
+        if (n < sz) { chunk = child; break; }
+        n -= sz;
+      }
+    }
+    return chunk.lines[n];
+  }
+  function lineNo(line) {
+    if (line.parent == null) return null;
+    var cur = line.parent, no = indexOf(cur.lines, line);
+    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
+      for (var i = 0, e = chunk.children.length; ; ++i) {
+        if (chunk.children[i] == cur) break;
+        no += chunk.children[i].chunkSize();
+      }
+    }
+    return no;
+  }
+  function lineAtHeight(chunk, h) {
+    var n = 0;
+    outer: do {
+      for (var i = 0, e = chunk.children.length; i < e; ++i) {
+        var child = chunk.children[i], ch = child.height;
+        if (h < ch) { chunk = child; continue outer; }
+        h -= ch;
+        n += child.chunkSize();
+      }
+      return n;
+    } while (!chunk.lines);
+    for (var i = 0, e = chunk.lines.length; i < e; ++i) {
+      var line = chunk.lines[i], lh = line.height;
+      if (h < lh) break;
+      h -= lh;
+    }
+    return n + i;
+  }
+  function heightAtLine(chunk, n) {
+    var h = 0;
+    outer: do {
+      for (var i = 0, e = chunk.children.length; i < e; ++i) {
+        var child = chunk.children[i], sz = child.chunkSize();
+        if (n < sz) { chunk = child; continue outer; }
+        n -= sz;
+        h += child.height;
+      }
+      return h;
+    } while (!chunk.lines);
+    for (var i = 0; i < n; ++i) h += chunk.lines[i].height;
+    return h;
+  }
+
   // The history object 'chunks' changes that are made close together
   // and at almost the same time into bigger undoable units.
   function History() {
     this.time = 0;
     this.done = []; this.undone = [];
+    this.compound = 0;
+    this.closed = false;
   }
   History.prototype = {
     addChange: function(start, added, old) {
       this.undone.length = 0;
-      var time = +new Date, last = this.done[this.done.length - 1];
-      if (time - this.time > 400 || !last ||
-          last.start > start + added || last.start + last.added < start - last.added + last.old.length)
-        this.done.push({start: start, added: added, old: old});
-      else {
-        var oldoff = 0;
-        if (start < last.start) {
-          for (var i = last.start - start - 1; i >= 0; --i)
-            last.old.unshift(old[i]);
-          last.added += last.start - start;
-          last.start = start;
-        }
-        else if (last.start < start) {
-          oldoff = start - last.start;
-          added += oldoff;
-        }
-        for (var i = last.added - oldoff, e = old.length; i < e; ++i)
-          last.old.push(old[i]);
-        if (last.added < added) last.added = added;
+      var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
+      var dtime = time - this.time;
+
+      if (this.compound && cur && !this.closed) {
+        cur.push({start: start, added: added, old: old});
+      } else if (dtime > 400 || !last || this.closed ||
+                 last.start > start + old.length || last.start + last.added < start) {
+        this.done.push([{start: start, added: added, old: old}]);
+        this.closed = false;
+      } else {
+        var startBefore = Math.max(0, last.start - start),
+            endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
+        for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
+        for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
+        if (startBefore) last.start = start;
+        last.added += added - (old.length - startBefore - endAfter);
       }
       this.time = time;
+    },
+    startCompound: function() {
+      if (!this.compound++) this.closed = true;
+    },
+    endCompound: function() {
+      if (!--this.compound) this.closed = true;
     }
   };
 
@@ -2107,6 +2937,10 @@
     else e.cancelBubble = true;
   }
   function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
+  CodeMirror.e_stop = e_stop;
+  CodeMirror.e_preventDefault = e_preventDefault;
+  CodeMirror.e_stopPropagation = e_stopPropagation;
+
   function e_target(e) {return e.target || e.srcElement;}
   function e_button(e) {
     if (e.which) return e.which;
@@ -2115,60 +2949,76 @@
     else if (e.button & 4) return 2;
   }
 
+  // Allow 3rd-party code to override event properties by adding an override
+  // object to an event object.
+  function e_prop(e, prop) {
+    var overridden = e.override && e.override.hasOwnProperty(prop);
+    return overridden ? e.override[prop] : e[prop];
+  }
+
   // Event handler registration. If disconnect is true, it'll return a
   // function that unregisters the handler.
   function connect(node, type, handler, disconnect) {
-    function wrapHandler(event) {handler(event || window.event);}
     if (typeof node.addEventListener == "function") {
-      node.addEventListener(type, wrapHandler, false);
-      if (disconnect) return function() {node.removeEventListener(type, wrapHandler, false);};
-    }
-    else {
+      node.addEventListener(type, handler, false);
+      if (disconnect) return function() {node.removeEventListener(type, handler, false);};
+    } else {
+      var wrapHandler = function(event) {handler(event || window.event);};
       node.attachEvent("on" + type, wrapHandler);
       if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
     }
   }
+  CodeMirror.connect = connect;
 
   function Delayed() {this.id = null;}
   Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
 
-  // Some IE versions don't preserve whitespace when setting the
-  // innerHTML of a PRE tag.
-  var badInnerHTML = (function() {
-    var pre = document.createElement("pre");
-    pre.innerHTML = " "; return !pre.innerHTML;
-  })();
-
-  // Detect drag-and-drop
-  var dragAndDrop = (function() {
-    // IE8 has ondragstart and ondrop properties, but doesn't seem to
-    // actually support ondragstart the way it's supposed to work.
-    if (/MSIE [1-8]\b/.test(navigator.userAgent)) return false;
-    var div = document.createElement('div');
-    return "ondragstart" in div && "ondrop" in div;
-  })();
+  var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
 
   var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
   var ie = /MSIE \d/.test(navigator.userAgent);
+  var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
+  var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
+  var quirksMode = ie && document.documentMode == 5;
+  var webkit = /WebKit\//.test(navigator.userAgent);
+  var chrome = /Chrome\//.test(navigator.userAgent);
+  var opera = /Opera\//.test(navigator.userAgent);
   var safari = /Apple Computer/.test(navigator.vendor);
+  var khtml = /KHTML\//.test(navigator.userAgent);
+  var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
 
-  var lineSep = "\n";
+  // Detect drag-and-drop
+  var dragAndDrop = function() {
+    // There is *some* kind of drag-and-drop support in IE6-8, but I
+    // couldn't get it to work yet.
+    if (ie_lt9) return false;
+    var div = document.createElement('div');
+    return "draggable" in div || "dragDrop" in div;
+  }();
+
   // Feature-detect whether newlines in textareas are converted to \r\n
-  (function () {
+  var lineSep = function () {
     var te = document.createElement("textarea");
     te.value = "foo\nbar";
-    if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
-  }());
+    if (te.value.indexOf("\r") > -1) return "\r\n";
+    return "\n";
+  }();
 
-  var tabSize = 8;
-  var mac = /Mac/.test(navigator.platform);
-  var movementKeys = {};
-  for (var i = 35; i <= 40; ++i)
-    movementKeys[i] = movementKeys["c" + i] = true;
+  // For a reason I have yet to figure out, some browsers disallow
+  // word wrapping between certain characters *only* if a new inline
+  // element is started between them. This makes it hard to reliably
+  // measure the position of things, since that requires inserting an
+  // extra span. This terribly fragile set of regexps matches the
+  // character combinations that suffer from this phenomenon on the
+  // various browsers.
+  var spanAffectsWrapping = /^$/; // Won't match any two-character string
+  if (gecko) spanAffectsWrapping = /$'/;
+  else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
+  else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
 
   // Counts the column offset in a string, taking tabs into account.
   // Used mostly to find indentation.
-  function countColumn(string, end) {
+  function countColumn(string, end, tabSize) {
     if (end == null) {
       end = string.search(/[^\s\u00a0]/);
       if (end == -1) end = string.length;
@@ -2184,25 +3034,54 @@
     if (elt.currentStyle) return elt.currentStyle;
     return window.getComputedStyle(elt, null);
   }
+
   // Find the position of an element by following the offsetParent chain.
   // If screen==true, it returns screen (rather than page) coordinates.
   function eltOffset(node, screen) {
-    var doc = node.ownerDocument.body;
-    var x = 0, y = 0, skipDoc = false;
+    var bod = node.ownerDocument.body;
+    var x = 0, y = 0, skipBody = false;
     for (var n = node; n; n = n.offsetParent) {
-      x += n.offsetLeft; y += n.offsetTop;
+      var ol = n.offsetLeft, ot = n.offsetTop;
+      // Firefox reports weird inverted offsets when the body has a border.
+      if (n == bod) { x += Math.abs(ol); y += Math.abs(ot); }
+      else { x += ol, y += ot; }
       if (screen && computedStyle(n).position == "fixed")
-        skipDoc = true;
+        skipBody = true;
     }
-    var e = screen && !skipDoc ? null : doc;
+    var e = screen && !skipBody ? null : bod;
     for (var n = node.parentNode; n != e; n = n.parentNode)
       if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
     return {left: x, top: y};
   }
+  // Use the faster and saner getBoundingClientRect method when possible.
+  if (document.documentElement.getBoundingClientRect != null) eltOffset = function(node, screen) {
+    // Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
+    // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
+    try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
+    catch(e) { box = {top: 0, left: 0}; }
+    if (!screen) {
+      // Get the toplevel scroll, working around browser differences.
+      if (window.pageYOffset == null) {
+        var t = document.documentElement || document.body.parentNode;
+        if (t.scrollTop == null) t = document.body;
+        box.top += t.scrollTop; box.left += t.scrollLeft;
+      } else {
+        box.top += window.pageYOffset; box.left += window.pageXOffset;
+      }
+    }
+    return box;
+  };
+
   // Get a node's text content.
   function eltText(node) {
     return node.textContent || node.innerText || node.nodeValue || "";
   }
+  function selectInput(node) {
+    if (ios) { // Mobile Safari apparently has a bug where select() is broken.
+      node.selectionStart = 0;
+      node.selectionEnd = node.value.length;
+    } else node.select();
+  }
 
   // Operations on {line, ch} objects.
   function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
@@ -2211,21 +3090,30 @@
 
   var escapeElement = document.createElement("pre");
   function htmlEscape(str) {
-    if (badTextContent) {
+    escapeElement.textContent = str;
+    return escapeElement.innerHTML;
+  }
+  // Recent (late 2011) Opera betas insert bogus newlines at the start
+  // of the textContent, so we strip those.
+  if (htmlEscape("a") == "\na") {
+    htmlEscape = function(str) {
+      escapeElement.textContent = str;
+      return escapeElement.innerHTML.slice(1);
+    };
+  // Some IEs don't preserve tabs through innerHTML
+  } else if (htmlEscape("\t") != "\t") {
+    htmlEscape = function(str) {
       escapeElement.innerHTML = "";
       escapeElement.appendChild(document.createTextNode(str));
-    } else {
-      escapeElement.textContent = str;
-    }
-    return escapeElement.innerHTML;
+      return escapeElement.innerHTML;
+    };
   }
-  var badTextContent = htmlEscape("\t") != "\t";
   CodeMirror.htmlEscape = htmlEscape;
 
   // Used to position the cursor after an undo/redo by finding the
   // last edited character.
   function editEnd(from, to) {
-    if (!to) return from ? from.length : 0;
+    if (!to) return 0;
     if (!from) return to.length;
     for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
       if (from.charAt(i) != to.charAt(j)) break;
@@ -2238,95 +3126,54 @@
       if (collection[i] == elt) return i;
     return -1;
   }
+  function isWordChar(ch) {
+    return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase();
+  }
 
   // See if "".split is the broken IE version, if so, provide an
   // alternative way to split lines.
-  var splitLines, selRange, setSelRange;
-  if ("\n\nb".split(/\n/).length != 3)
-    splitLines = function(string) {
-      var pos = 0, nl, result = [];
-      while ((nl = string.indexOf("\n", pos)) > -1) {
-        result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
-        pos = nl + 1;
-      }
-      result.push(string.slice(pos));
-      return result;
-    };
-  else
-    splitLines = function(string){return string.split(/\r?\n/);};
+  var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
+    var pos = 0, nl, result = [];
+    while ((nl = string.indexOf("\n", pos)) > -1) {
+      result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
+      pos = nl + 1;
+    }
+    result.push(string.slice(pos));
+    return result;
+  } : function(string){return string.split(/\r?\n/);};
   CodeMirror.splitLines = splitLines;
 
-  // Sane model of finding and setting the selection in a textarea
-  if (window.getSelection) {
-    selRange = function(te) {
-      try {return {start: te.selectionStart, end: te.selectionEnd};}
-      catch(e) {return null;}
-    };
-    if (safari)
-      // On Safari, selection set with setSelectionRange are in a sort
-      // of limbo wrt their anchor. If you press shift-left in them,
-      // the anchor is put at the end, and the selection expanded to
-      // the left. If you press shift-right, the anchor ends up at the
-      // front. This is not what CodeMirror wants, so it does a
-      // spurious modify() call to get out of limbo.
-      setSelRange = function(te, start, end) {
-        if (start == end)
-          te.setSelectionRange(start, end);
-        else {
-          te.setSelectionRange(start, end - 1);
-          window.getSelection().modify("extend", "forward", "character");
-        }
-      };
-    else
-      setSelRange = function(te, start, end) {
-        try {te.setSelectionRange(start, end);}
-        catch(e) {} // Fails on Firefox when textarea isn't part of the document
-      };
-  }
-  // IE model. Don't ask.
-  else {
-    selRange = function(te) {
-      try {var range = te.ownerDocument.selection.createRange();}
-      catch(e) {return null;}
-      if (!range || range.parentElement() != te) return null;
-      var val = te.value, len = val.length, localRange = te.createTextRange();
-      localRange.moveToBookmark(range.getBookmark());
-      var endRange = te.createTextRange();
-      endRange.collapse(false);
-
-      if (localRange.compareEndPoints("StartToEnd", endRange) > -1)
-        return {start: len, end: len};
-
-      var start = -localRange.moveStart("character", -len);
-      for (var i = val.indexOf("\r"); i > -1 && i < start; i = val.indexOf("\r", i+1), start++) {}
-
-      if (localRange.compareEndPoints("EndToEnd", endRange) > -1)
-        return {start: start, end: len};
-
-      var end = -localRange.moveEnd("character", -len);
-      for (var i = val.indexOf("\r"); i > -1 && i < end; i = val.indexOf("\r", i+1), end++) {}
-      return {start: start, end: end};
-    };
-    setSelRange = function(te, start, end) {
-      var range = te.createTextRange();
-      range.collapse(true);
-      var endrange = range.duplicate();
-      var newlines = 0, txt = te.value;
-      for (var pos = txt.indexOf("\n"); pos > -1 && pos < start; pos = txt.indexOf("\n", pos + 1))
-        ++newlines;
-      range.move("character", start - newlines);
-      for (; pos > -1 && pos < end; pos = txt.indexOf("\n", pos + 1))
-        ++newlines;
-      endrange.move("character", end - newlines);
-      range.setEndPoint("EndToEnd", endrange);
-      range.select();
-    };
-  }
+  var hasSelection = window.getSelection ? function(te) {
+    try { return te.selectionStart != te.selectionEnd; }
+    catch(e) { return false; }
+  } : function(te) {
+    try {var range = te.ownerDocument.selection.createRange();}
+    catch(e) {}
+    if (!range || range.parentElement() != te) return false;
+    return range.compareEndPoints("StartToEnd", range) != 0;
+  };
 
   CodeMirror.defineMode("null", function() {
     return {token: function(stream) {stream.skipToEnd();}};
   });
   CodeMirror.defineMIME("text/plain", "null");
 
+  var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
+                  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
+                  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
+                  46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
+                  186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+                  221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
+                  63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
+  CodeMirror.keyNames = keyNames;
+  (function() {
+    // Number keys
+    for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
+    // Alphabetic keys
+    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
+    // Function keys
+    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
+  })();
+
   return CodeMirror;
 })();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/public/js/native.history.js	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,1 @@
+(function(a,b){"use strict";var c=a.History=a.History||{};if(typeof c.Adapter!="undefined")throw new Error("History.js Adapter has already been loaded...");c.Adapter={handlers:{},_uid:1,uid:function(a){return a._uid||(a._uid=c.Adapter._uid++)},bind:function(a,b,d){var e=c.Adapter.uid(a);c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[],c.Adapter.handlers[e][b].push(d),a["on"+b]=function(a,b){return function(d){c.Adapter.trigger(a,b,d)}}(a,b)},trigger:function(a,b,d){d=d||{};var e=c.Adapter.uid(a),f,g;c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[];for(f=0,g=c.Adapter.handlers[e][b].length;f<g;++f)c.Adapter.handlers[e][b][f].apply(this,[d])},extractEventData:function(a,c){var d=c&&c[a]||b;return d},onDomLoad:function(b){var c=a.setTimeout(function(){b()},2e3);a.onload=function(){clearTimeout(c),b()}}},typeof c.init!="undefined"&&c.init()})(window),function(a,b){"use strict";var c=a.console||b,d=a.document,e=a.navigator,f=a.sessionStorage||!1,g=a.setTimeout,h=a.clearTimeout,i=a.setInterval,j=a.clearInterval,k=a.JSON,l=a.alert,m=a.History=a.History||{},n=a.history;k.stringify=k.stringify||k.encode,k.parse=k.parse||k.decode;if(typeof m.init!="undefined")throw new Error("History.js Core has already been loaded...");m.init=function(){return typeof m.Adapter=="undefined"?!1:(typeof m.initCore!="undefined"&&m.initCore(),typeof m.initHtml4!="undefined"&&m.initHtml4(),!0)},m.initCore=function(){if(typeof m.initCore.initialized!="undefined")return!1;m.initCore.initialized=!0,m.options=m.options||{},m.options.hashChangeInterval=m.options.hashChangeInterval||100,m.options.safariPollInterval=m.options.safariPollInterval||500,m.options.doubleCheckInterval=m.options.doubleCheckInterval||500,m.options.storeInterval=m.options.storeInterval||1e3,m.options.busyDelay=m.options.busyDelay||250,m.options.debug=m.options.debug||!1,m.options.initialTitle=m.options.initialTitle||d.title,m.intervalList=[],m.clearAllIntervals=function(){var a,b=m.intervalList;if(typeof b!="undefined"&&b!==null){for(a=0;a<b.length;a++)j(b[a]);m.intervalList=null}},m.debug=function(){(m.options.debug||!1)&&m.log.apply(m,arguments)},m.log=function(){var a=typeof c!="undefined"&&typeof c.log!="undefined"&&typeof c.log.apply!="undefined",b=d.getElementById("log"),e,f,g,h,i;a?(h=Array.prototype.slice.call(arguments),e=h.shift(),typeof c.debug!="undefined"?c.debug.apply(c,[e,h]):c.log.apply(c,[e,h])):e="\n"+arguments[0]+"\n";for(f=1,g=arguments.length;f<g;++f){i=arguments[f];if(typeof i=="object"&&typeof k!="undefined")try{i=k.stringify(i)}catch(j){}e+="\n"+i+"\n"}return b?(b.value+=e+"\n-----\n",b.scrollTop=b.scrollHeight-b.clientHeight):a||l(e),!0},m.getInternetExplorerMajorVersion=function(){var a=m.getInternetExplorerMajorVersion.cached=typeof m.getInternetExplorerMajorVersion.cached!="undefined"?m.getInternetExplorerMajorVersion.cached:function(){var a=3,b=d.createElement("div"),c=b.getElementsByTagName("i");while((b.innerHTML="<!--[if gt IE "+ ++a+"]><i></i><![endif]-->")&&c[0]);return a>4?a:!1}();return a},m.isInternetExplorer=function(){var a=m.isInternetExplorer.cached=typeof m.isInternetExplorer.cached!="undefined"?m.isInternetExplorer.cached:Boolean(m.getInternetExplorerMajorVersion());return a},m.emulated={pushState:!Boolean(a.history&&a.history.pushState&&a.history.replaceState&&!/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(e.userAgent)&&!/AppleWebKit\/5([0-2]|3[0-2])/i.test(e.userAgent)),hashChange:Boolean(!("onhashchange"in a||"onhashchange"in d)||m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<8)},m.enabled=!m.emulated.pushState,m.bugs={setHash:Boolean(!m.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),safariPoll:Boolean(!m.emulated.pushState&&e.vendor==="Apple Computer, Inc."&&/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),ieDoubleCheck:Boolean(m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<8),hashEscape:Boolean(m.isInternetExplorer()&&m.getInternetExplorerMajorVersion()<7)},m.isEmptyObject=function(a){for(var b in a)return!1;return!0},m.cloneObject=function(a){var b,c;return a?(b=k.stringify(a),c=k.parse(b)):c={},c},m.getRootUrl=function(){var a=d.location.protocol+"//"+(d.location.hostname||d.location.host);if(d.location.port||!1)a+=":"+d.location.port;return a+="/",a},m.getBaseHref=function(){var a=d.getElementsByTagName("base"),b=null,c="";return a.length===1&&(b=a[0],c=b.href.replace(/[^\/]+$/,"")),c=c.replace(/\/+$/,""),c&&(c+="/"),c},m.getBaseUrl=function(){var a=m.getBaseHref()||m.getBasePageUrl()||m.getRootUrl();return a},m.getPageUrl=function(){var a=m.getState(!1,!1),b=(a||{}).url||d.location.href,c;return c=b.replace(/\/+$/,"").replace(/[^\/]+$/,function(a,b,c){return/\./.test(a)?a:a+"/"}),c},m.getBasePageUrl=function(){var a=d.location.href.replace(/[#\?].*/,"").replace(/[^\/]+$/,function(a,b,c){return/[^\/]$/.test(a)?"":a}).replace(/\/+$/,"")+"/";return a},m.getFullUrl=function(a,b){var c=a,d=a.substring(0,1);return b=typeof b=="undefined"?!0:b,/[a-z]+\:\/\//.test(a)||(d==="/"?c=m.getRootUrl()+a.replace(/^\/+/,""):d==="#"?c=m.getPageUrl().replace(/#.*/,"")+a:d==="?"?c=m.getPageUrl().replace(/[\?#].*/,"")+a:b?c=m.getBaseUrl()+a.replace(/^(\.\/)+/,""):c=m.getBasePageUrl()+a.replace(/^(\.\/)+/,"")),c.replace(/\#$/,"")},m.getShortUrl=function(a){var b=a,c=m.getBaseUrl(),d=m.getRootUrl();return m.emulated.pushState&&(b=b.replace(c,"")),b=b.replace(d,"/"),m.isTraditionalAnchor(b)&&(b="./"+b),b=b.replace(/^(\.\/)+/g,"./").replace(/\#$/,""),b},m.store={},m.idToState=m.idToState||{},m.stateToId=m.stateToId||{},m.urlToId=m.urlToId||{},m.storedStates=m.storedStates||[],m.savedStates=m.savedStates||[],m.normalizeStore=function(){m.store.idToState=m.store.idToState||{},m.store.urlToId=m.store.urlToId||{},m.store.stateToId=m.store.stateToId||{}},m.getState=function(a,b){typeof a=="undefined"&&(a=!0),typeof b=="undefined"&&(b=!0);var c=m.getLastSavedState();return!c&&b&&(c=m.createStateObject()),a&&(c=m.cloneObject(c),c.url=c.cleanUrl||c.url),c},m.getIdByState=function(a){var b=m.extractId(a.url),c;if(!b){c=m.getStateString(a);if(typeof m.stateToId[c]!="undefined")b=m.stateToId[c];else if(typeof m.store.stateToId[c]!="undefined")b=m.store.stateToId[c];else{for(;;){b=(new Date).getTime()+String(Math.random()).replace(/\D/g,"");if(typeof m.idToState[b]=="undefined"&&typeof m.store.idToState[b]=="undefined")break}m.stateToId[c]=b,m.idToState[b]=a}}return b},m.normalizeState=function(a){var b,c;if(!a||typeof a!="object")a={};if(typeof a.normalized!="undefined")return a;if(!a.data||typeof a.data!="object")a.data={};b={},b.normalized=!0,b.title=a.title||"",b.url=m.getFullUrl(m.unescapeString(a.url||d.location.href)),b.hash=m.getShortUrl(b.url),b.data=m.cloneObject(a.data),b.id=m.getIdByState(b),b.cleanUrl=b.url.replace(/\??\&_suid.*/,""),b.url=b.cleanUrl,c=!m.isEmptyObject(b.data);if(b.title||c)b.hash=m.getShortUrl(b.url).replace(/\??\&_suid.*/,""),/\?/.test(b.hash)||(b.hash+="?"),b.hash+="&_suid="+b.id;return b.hashedUrl=m.getFullUrl(b.hash),(m.emulated.pushState||m.bugs.safariPoll)&&m.hasUrlDuplicate(b)&&(b.url=b.hashedUrl),b},m.createStateObject=function(a,b,c){var d={data:a,title:b,url:c};return d=m.normalizeState(d),d},m.getStateById=function(a){a=String(a);var c=m.idToState[a]||m.store.idToState[a]||b;return c},m.getStateString=function(a){var b,c,d;return b=m.normalizeState(a),c={data:b.data,title:a.title,url:a.url},d=k.stringify(c),d},m.getStateId=function(a){var b,c;return b=m.normalizeState(a),c=b.id,c},m.getHashByState=function(a){var b,c;return b=m.normalizeState(a),c=b.hash,c},m.extractId=function(a){var b,c,d;return c=/(.*)\&_suid=([0-9]+)$/.exec(a),d=c?c[1]||a:a,b=c?String(c[2]||""):"",b||!1},m.isTraditionalAnchor=function(a){var b=!/[\/\?\.]/.test(a);return b},m.extractState=function(a,b){var c=null,d,e;return b=b||!1,d=m.extractId(a),d&&(c=m.getStateById(d)),c||(e=m.getFullUrl(a),d=m.getIdByUrl(e)||!1,d&&(c=m.getStateById(d)),!c&&b&&!m.isTraditionalAnchor(a)&&(c=m.createStateObject(null,null,e))),c},m.getIdByUrl=function(a){var c=m.urlToId[a]||m.store.urlToId[a]||b;return c},m.getLastSavedState=function(){return m.savedStates[m.savedStates.length-1]||b},m.getLastStoredState=function(){return m.storedStates[m.storedStates.length-1]||b},m.hasUrlDuplicate=function(a){var b=!1,c;return c=m.extractState(a.url),b=c&&c.id!==a.id,b},m.storeState=function(a){return m.urlToId[a.url]=a.id,m.storedStates.push(m.cloneObject(a)),a},m.isLastSavedState=function(a){var b=!1,c,d,e;return m.savedStates.length&&(c=a.id,d=m.getLastSavedState(),e=d.id,b=c===e),b},m.saveState=function(a){return m.isLastSavedState(a)?!1:(m.savedStates.push(m.cloneObject(a)),!0)},m.getStateByIndex=function(a){var b=null;return typeof a=="undefined"?b=m.savedStates[m.savedStates.length-1]:a<0?b=m.savedStates[m.savedStates.length+a]:b=m.savedStates[a],b},m.getHash=function(){var a=m.unescapeHash(d.location.hash);return a},m.unescapeString=function(b){var c=b,d;for(;;){d=a.decodeURI(c);if(d===c)break;c=d}return c},m.unescapeHash=function(a){var b=m.normalizeHash(a);return b=m.unescapeString(b),b},m.normalizeHash=function(a){var b=a.replace(/[^#]*#/,"").replace(/#.*/,"");return b},m.setHash=function(a,b){var c,e,f;return b!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.setHash,args:arguments,queue:b}),!1):(c=m.escapeHash(a),m.busy(!0),e=m.extractState(a,!0),e&&!m.emulated.pushState?m.pushState(e.data,e.title,e.url,!1):d.location.hash!==c&&(m.bugs.setHash?(f=m.getPageUrl(),m.pushState(null,null,f+"#"+c,!1)):d.location.hash=c),m)},m.escapeHash=function(b){var c=m.normalizeHash(b);return c=a.escape(c),m.bugs.hashEscape||(c=c.replace(/\%21/g,"!").replace(/\%26/g,"&").replace(/\%3D/g,"=").replace(/\%3F/g,"?")),c},m.getHashByUrl=function(a){var b=String(a).replace(/([^#]*)#?([^#]*)#?(.*)/,"$2");return b=m.unescapeHash(b),b},m.setTitle=function(a){var b=a.title,c;b||(c=m.getStateByIndex(0),c&&c.url===a.url&&(b=c.title||m.options.initialTitle));try{d.getElementsByTagName("title")[0].innerHTML=b.replace("<","&lt;").replace(">","&gt;").replace(" & "," &amp; ")}catch(e){}return d.title=b,m},m.queues=[],m.busy=function(a){typeof a!="undefined"?m.busy.flag=a:typeof m.busy.flag=="undefined"&&(m.busy.flag=!1);if(!m.busy.flag){h(m.busy.timeout);var b=function(){var a,c,d;if(m.busy.flag)return;for(a=m.queues.length-1;a>=0;--a){c=m.queues[a];if(c.length===0)continue;d=c.shift(),m.fireQueueItem(d),m.busy.timeout=g(b,m.options.busyDelay)}};m.busy.timeout=g(b,m.options.busyDelay)}return m.busy.flag},m.busy.flag=!1,m.fireQueueItem=function(a){return a.callback.apply(a.scope||m,a.args||[])},m.pushQueue=function(a){return m.queues[a.queue||0]=m.queues[a.queue||0]||[],m.queues[a.queue||0].push(a),m},m.queue=function(a,b){return typeof a=="function"&&(a={callback:a}),typeof b!="undefined"&&(a.queue=b),m.busy()?m.pushQueue(a):m.fireQueueItem(a),m},m.clearQueue=function(){return m.busy.flag=!1,m.queues=[],m},m.stateChanged=!1,m.doubleChecker=!1,m.doubleCheckComplete=function(){return m.stateChanged=!0,m.doubleCheckClear(),m},m.doubleCheckClear=function(){return m.doubleChecker&&(h(m.doubleChecker),m.doubleChecker=!1),m},m.doubleCheck=function(a){return m.stateChanged=!1,m.doubleCheckClear(),m.bugs.ieDoubleCheck&&(m.doubleChecker=g(function(){return m.doubleCheckClear(),m.stateChanged||a(),!0},m.options.doubleCheckInterval)),m},m.safariStatePoll=function(){var b=m.extractState(d.location.href),c;if(!m.isLastSavedState(b))c=b;else return;return c||(c=m.createStateObject()),m.Adapter.trigger(a,"popstate"),m},m.back=function(a){return a!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.back,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(function(){m.back(!1)}),n.go(-1),!0)},m.forward=function(a){return a!==!1&&m.busy()?(m.pushQueue({scope:m,callback:m.forward,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(function(){m.forward(!1)}),n.go(1),!0)},m.go=function(a,b){var c;if(a>0)for(c=1;c<=a;++c)m.forward(b);else{if(!(a<0))throw new Error("History.go: History.go requires a positive or negative integer passed.");for(c=-1;c>=a;--c)m.back(b)}return m};if(m.emulated.pushState){var o=function(){};m.pushState=m.pushState||o,m.replaceState=m.replaceState||o}else m.onPopState=function(b,c){var e=!1,f=!1,g,h;return m.doubleCheckComplete(),g=m.getHash(),g?(h=m.extractState(g||d.location.href,!0),h?m.replaceState(h.data,h.title,h.url,!1):(m.Adapter.trigger(a,"anchorchange"),m.busy(!1)),m.expectedStateId=!1,!1):(e=m.Adapter.extractEventData("state",b,c)||!1,e?f=m.getStateById(e):m.expectedStateId?f=m.getStateById(m.expectedStateId):f=m.extractState(d.location.href),f||(f=m.createStateObject(null,null,d.location.href)),m.expectedStateId=!1,m.isLastSavedState(f)?(m.busy(!1),!1):(m.storeState(f),m.saveState(f),m.setTitle(f),m.Adapter.trigger(a,"statechange"),m.busy(!1),!0))},m.Adapter.bind(a,"popstate",m.onPopState),m.pushState=function(b,c,d,e){if(m.getHashByUrl(d)&&m.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&m.busy())return m.pushQueue({scope:m,callback:m.pushState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expectedStateId=f.id,n.pushState(f.id,f.title,f.url),m.Adapter.trigger(a,"popstate")),!0},m.replaceState=function(b,c,d,e){if(m.getHashByUrl(d)&&m.emulated.pushState)throw new Error("History.js does not support states with fragement-identifiers (hashes/anchors).");if(e!==!1&&m.busy())return m.pushQueue({scope:m,callback:m.replaceState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expectedStateId=f.id,n.replaceState(f.id,f.title,f.url),m.Adapter.trigger(a,"popstate")),!0};if(f){try{m.store=k.parse(f.getItem("History.store"))||{}}catch(p){m.store={}}m.normalizeStore()}else m.store={},m.normalizeStore();m.Adapter.bind(a,"beforeunload",m.clearAllIntervals),m.Adapter.bind(a,"unload",m.clearAllIntervals),m.saveState(m.storeState(m.extractState(d.location.href,!0))),f&&(m.onUnload=function(){var a,b;try{a=k.parse(f.getItem("History.store"))||{}}catch(c){a={}}a.idToState=a.idToState||{},a.urlToId=a.urlToId||{},a.stateToId=a.stateToId||{};for(b in m.idToState){if(!m.idToState.hasOwnProperty(b))continue;a.idToState[b]=m.idToState[b]}for(b in m.urlToId){if(!m.urlToId.hasOwnProperty(b))continue;a.urlToId[b]=m.urlToId[b]}for(b in m.stateToId){if(!m.stateToId.hasOwnProperty(b))continue;a.stateToId[b]=m.stateToId[b]}m.store=a,m.normalizeStore(),f.setItem("History.store",k.stringify(a))},m.intervalList.push(i(m.onUnload,m.options.storeInterval)),m.Adapter.bind(a,"beforeunload",m.onUnload),m.Adapter.bind(a,"unload",m.onUnload));if(!m.emulated.pushState){m.bugs.safariPoll&&m.intervalList.push(i(m.safariStatePoll,m.options.safariPollInterval));if(e.vendor==="Apple Computer, Inc."||(e.appCodeName||"")==="Mozilla")m.Adapter.bind(a,"hashchange",function(){m.Adapter.trigger(a,"popstate")}),m.getHash()&&m.Adapter.onDomLoad(function(){m.Adapter.trigger(a,"hashchange")})}},m.init()}(window)
\ No newline at end of file
--- a/rhodecode/public/js/rhodecode.js	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/public/js/rhodecode.js	Sun Sep 02 21:19:54 2012 +0200
@@ -44,6 +44,50 @@
 
 }();
 
+String.prototype.strip = function(char) {
+	if(char === undefined){
+	    char = '\\s';
+	}
+	return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
+}
+String.prototype.lstrip = function(char) {
+	if(char === undefined){
+	    char = '\\s';
+	}
+	return this.replace(new RegExp('^'+char+'+'),'');
+}
+String.prototype.rstrip = function(char) {
+	if(char === undefined){
+	    char = '\\s';
+	}
+	return this.replace(new RegExp(''+char+'+$'),'');
+}
+
+
+if(!Array.prototype.indexOf) {
+    Array.prototype.indexOf = function(needle) {
+        for(var i = 0; i < this.length; i++) {
+            if(this[i] === needle) {
+                return i;
+            }
+        }
+        return -1;
+    };
+}
+
+// IE(CRAP) doesn't support previousElementSibling
+var prevElementSibling = function( el ) {
+    if( el.previousElementSibling ) {
+        return el.previousElementSibling;
+    } else {
+        while( el = el.previousSibling ) {
+            if( el.nodeType === 1 ) return el;
+        }
+    }
+}
+
+
+
 
 /**
  * SmartColorGenerator
@@ -187,10 +231,10 @@
 		success:s_wrapper,
 		failure:function(o){
 			console.log(o);
-			YUD.get(container).innerHTML='ERROR';
+			YUD.get(container).innerHTML='<span class="error_red">ERROR: {0}</span>'.format(o.status);
 			YUD.setStyle(container,'opacity','1.0');
-			YUD.setStyle(container,'color','red');
-		}
+		},
+		cache:false
 	},args);
 	
 };
@@ -354,7 +398,7 @@
 	
 	// create event for hide button
 	form = new YAHOO.util.Element(form);
-	var form_hide_button = new YAHOO.util.Element(form.getElementsByClassName('hide-inline-form')[0]);
+	var form_hide_button = new YAHOO.util.Element(YUD.getElementsByClassName('hide-inline-form',null,form)[0]);
 	form_hide_button.on('click', function(e) {
 		var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
 		if(YUD.hasClass(newtr.nextElementSibling,'inline-comments-button')){
@@ -378,11 +422,12 @@
 		  return
 	  }
 	  var submit_url = AJAX_COMMENT_URL;
-	  if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context') || YUD.hasClass(tr,'no-comment')){
+	  var _td = YUD.getElementsByClassName('code',null,tr)[0];
+	  if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context') || YUD.hasClass(_td,'no-comment')){
 		  return
 	  }	
 	  YUD.addClass(tr,'form-open');
-	  var node = tr.parentNode.parentNode.parentNode.getElementsByClassName('full_f_path')[0];
+	  var node = YUD.getElementsByClassName('full_f_path',null,tr.parentNode.parentNode.parentNode)[0];
 	  var f_path = YUD.getAttribute(node,'path');
 	  var lineno = getLineNo(tr);
 	  var form = createInlineForm(tr, f_path, lineno, submit_url);
@@ -400,11 +445,10 @@
 	  }	  
 	  YUD.insertAfter(form,parent);
 	  
-	  YUD.get('text_'+lineno).focus();
 	  var f = YUD.get(form);
 	  
-	  var overlay = f.getElementsByClassName('overlay')[0];
-	  var _form = f.getElementsByClassName('inline-form')[0];
+	  var overlay = YUD.getElementsByClassName('overlay',null,f)[0];
+	  var _form = YUD.getElementsByClassName('inline-form',null,f)[0];
 	  
 	  form.on('submit',function(e){
 		  YUE.preventDefault(e);
@@ -448,7 +492,16 @@
 		  ajaxPOST(submit_url, postData, success);
 	  });
 	  
-	  tooltip_activate();
+	  setTimeout(function(){
+		  // callbacks
+		  tooltip_activate();
+		  MentionsAutoComplete('text_'+lineno, 'mentions_container_'+lineno, 
+	                         _USERS_AC_DATA, _GROUPS_AC_DATA);
+		  var _e = YUD.get('text_'+lineno);
+		  if(_e){
+			  _e.focus();
+		  }
+	  },10)
 };
 
 var deleteComment = function(comment_id){
@@ -456,7 +509,7 @@
     var postData = {'_method':'delete'};
     var success = function(o){
         var n = YUD.get('comment-tr-'+comment_id);
-        var root = n.previousElementSibling.previousElementSibling;
+        var root = prevElementSibling(prevElementSibling(n));
         n.parentNode.removeChild(n);
 
         // scann nodes, and attach add button to last one
@@ -465,6 +518,15 @@
     ajaxPOST(url,postData,success);
 }
 
+var updateReviewers = function(reviewers_ids){
+	var url = AJAX_UPDATE_PULLREQUEST;
+	var postData = {'_method':'put',
+			        'reviewers_ids': reviewers_ids};
+	var success = function(o){
+		window.location.reload();
+	}
+	ajaxPOST(url,postData,success);
+}
 
 var createInlineAddButton = function(tr){
 
@@ -506,8 +568,8 @@
 		  // next element are comments !
 		  if(YUD.hasClass(n,'inline-comments')){
 			  last_node = n;
-			  //also remove the comment button from previos
-			  var comment_add_buttons = last_node.getElementsByClassName('add-comment');
+			  //also remove the comment button from previous
+			  var comment_add_buttons = YUD.getElementsByClassName('add-comment',null,last_node);
 			  for(var i=0;i<comment_add_buttons.length;i++){
 				  var b = comment_add_buttons[i];
 				  b.parentNode.removeChild(b);
@@ -520,7 +582,7 @@
 	  
     var add = createInlineAddButton(target_tr);
     // get the comment div
-    var comment_block = last_node.getElementsByClassName('comment')[0];
+    var comment_block = YUD.getElementsByClassName('comment',null,last_node)[0];
     // attach add button
     YUD.insertAfter(add,comment_block);	
 }
@@ -592,9 +654,15 @@
     }	
 }
 
+var removeReviewer = function(reviewer_id){
+	var el = YUD.get('reviewer_{0}'.format(reviewer_id));
+	if (el.parentNode !== undefined){
+		el.parentNode.removeChild(el);
+	}
+}
 
-var fileBrowserListeners = function(current_url, node_list_url, url_base,
-									truncated_lbl, nomatch_lbl){
+var fileBrowserListeners = function(current_url, node_list_url, url_base){
+	
 	var current_url_branch = +"?branch=__BRANCH__";
 	var url = url_base;
 	var node_url = node_list_url;	
@@ -623,7 +691,7 @@
 	  YUC.initHeader('X-PARTIAL-XHR',true);
 	  YUC.asyncRequest('GET',url,{
 	      success:function(o){
-	        nodes = JSON.parse(o.responseText);
+	        nodes = JSON.parse(o.responseText).nodes;
 	        YUD.setStyle('node_filter_box_loading','display','none');
 	        YUD.setStyle('node_filter_box','display','');
 	        n_filter.focus();
@@ -663,13 +731,13 @@
 	                    var t = nodes[i].type;
 	                    var n_hl = n.substring(0,pos)
 	                      +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
-	                      +n.substring(pos+query.length)                    
-	                    match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,node_url.replace('__FPATH__',n),n_hl));
+	                      +n.substring(pos+query.length)
+	                    node_url = node_url.replace('__FPATH__',n);
+	                    match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,node_url,n_hl));
 	                }
 	                if(match.length >= matches_max){
-	                    match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(truncated_lbl));
+	                    match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['search truncated']));
 	                }
-	                
 	            }                       
 	        }
 	        if(query != ""){
@@ -677,7 +745,7 @@
 	            YUD.setStyle('tbody_filtered','display','');
 	            
 	            if (match.length==0){
-	              match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(nomatch_lbl));
+	              match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['no matching files']));
 	            }                           
 	            
 	            YUD.get('tbody_filtered').innerHTML = match.join("");   
@@ -816,10 +884,31 @@
     											  callback, postData);
 };	
 
+var readNotification = function(url, notification_id,callbacks){
+    var callback = { 
+		success:function(o){
+		    var obj = YUD.get(String("notification_"+notification_id));
+		    YUD.removeClass(obj, 'unread');
+		    var r_button = YUD.getElementsByClassName('read-notification',null,obj.children[0])[0];
+		    
+		    if(r_button.parentNode !== undefined){
+		    	r_button.parentNode.removeChild(r_button);
+			}		    
+			_run_callbacks(callbacks);
+		},
+	    failure:function(o){
+	        alert("error");
+	    },
+	};
+    var postData = '_method=put';
+    var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
+    var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, 
+    											  callback, postData);
+};	
 
 /** MEMBERS AUTOCOMPLETE WIDGET **/
 
-var MembersAutoComplete = function (users_list, groups_list, group_lbl, members_lbl) {
+var MembersAutoComplete = function (divid, cont, users_list, groups_list) {
     var myUsers = users_list;
     var myGroups = groups_list;
 
@@ -834,9 +923,11 @@
             // Match against each name of each contact
             for (; i < l; i++) {
                 contact = myUsers[i];
-                if ((contact.fname.toLowerCase().indexOf(query) > -1) || (contact.lname.toLowerCase().indexOf(query) > -1) || (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) {
-                    matches[matches.length] = contact;
-                }
+                if (((contact.fname+"").toLowerCase().indexOf(query) > -1) || 
+                   	 ((contact.lname+"").toLowerCase().indexOf(query) > -1) || 
+                   	 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
+                       matches[matches.length] = contact;
+                   }
             }
             return matches;
         };
@@ -879,15 +970,20 @@
     };
 
     // Instantiate AutoComplete for perms
-    var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
+    var membersAC = new YAHOO.widget.AutoComplete(divid, cont, memberDS);
     membersAC.useShadow = false;
     membersAC.resultTypeList = false;
+    membersAC.animVert = false;
+    membersAC.animHoriz = false;    
+    membersAC.animSpeed = 0.1;
 
     // Instantiate AutoComplete for owner
     var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
     ownerAC.useShadow = false;
     ownerAC.resultTypeList = false;
-
+    ownerAC.animVert = false;
+    ownerAC.animHoriz = false;
+    ownerAC.animSpeed = 0.1;
 
     // Helper highlight function for the formatter
     var highlightMatch = function (full, snippet, matchindex) {
@@ -912,21 +1008,22 @@
                 var grname = oResultData.grname;
                 var grmembers = oResultData.grmembers;
                 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
-                var grprefix = "{0}: ".format(group_lbl);
+                var grprefix = "{0}: ".format(_TM['Group']);
                 var grsuffix = " (" + grmembers + "  )";
-                var grsuffix = " ({0}  {1})".format(grmembers, members_lbl);
+                var grsuffix = " ({0}  {1})".format(grmembers, _TM['members']);
 
                 if (grnameMatchIndex > -1) {
                     return _gravatar(grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix,null,true);
                 }
 			    return _gravatar(grprefix + oResultData.grname + grsuffix, null,true);
             // Users
-            } else if (oResultData.fname != undefined) {
-                var fname = oResultData.fname,
-                    lname = oResultData.lname,
-                    nname = oResultData.nname || "",
-                    // Guard against null value
-                    fnameMatchIndex = fname.toLowerCase().indexOf(query),
+            } else if (oResultData.nname != undefined) {
+                var fname = oResultData.fname || "";
+                var lname = oResultData.lname || "";
+                var nname = oResultData.nname;
+                
+                // Guard against null value
+                var fnameMatchIndex = fname.toLowerCase().indexOf(query),
                     lnameMatchIndex = lname.toLowerCase().indexOf(query),
                     nnameMatchIndex = nname.toLowerCase().indexOf(query),
                     displayfname, displaylname, displaynname;
@@ -958,7 +1055,7 @@
     ownerAC.formatResult = custom_formatter;
 
     var myHandler = function (sType, aArgs) {
-
+    		var nextId = divid.split('perm_new_member_name_')[1];
             var myAC = aArgs[0]; // reference back to the AC instance
             var elLI = aArgs[1]; // reference to the selected LI element
             var oData = aArgs[2]; // object literal of selected item's result data
@@ -966,11 +1063,11 @@
             if (oData.nname != undefined) {
                 //users
                 myAC.getInputEl().value = oData.nname;
-                YUD.get('perm_new_member_type').value = 'user';
+                YUD.get('perm_new_member_type_'+nextId).value = 'user';
             } else {
                 //groups
                 myAC.getInputEl().value = oData.grname;
-                YUD.get('perm_new_member_type').value = 'users_group';
+                YUD.get('perm_new_member_type_'+nextId).value = 'users_group';
             }
         };
 
@@ -988,6 +1085,359 @@
 }
 
 
+var MentionsAutoComplete = function (divid, cont, users_list, groups_list) {
+    var myUsers = users_list;
+    var myGroups = groups_list;
+
+    // Define a custom search function for the DataSource of users
+    var matchUsers = function (sQuery) {
+    	    var org_sQuery = sQuery;
+    	    if(this.mentionQuery == null){
+    	    	return []    	    	
+    	    }
+    	    sQuery = this.mentionQuery;
+            // Case insensitive matching
+            var query = sQuery.toLowerCase();
+            var i = 0;
+            var l = myUsers.length;
+            var matches = [];
+
+            // Match against each name of each contact
+            for (; i < l; i++) {
+                contact = myUsers[i];
+                if (((contact.fname+"").toLowerCase().indexOf(query) > -1) || 
+                	 ((contact.lname+"").toLowerCase().indexOf(query) > -1) || 
+                	 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
+                    matches[matches.length] = contact;
+                }
+            }
+            return matches
+        };
+
+    //match all
+    var matchAll = function (sQuery) {
+            u = matchUsers(sQuery);
+            return u
+        };
+
+    // DataScheme for owner
+    var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
+
+    ownerDS.responseSchema = {
+        fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
+    };
+
+    // Instantiate AutoComplete for mentions
+    var ownerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
+    ownerAC.useShadow = false;
+    ownerAC.resultTypeList = false;
+    ownerAC.suppressInputUpdate = true;
+    ownerAC.animVert = false;
+    ownerAC.animHoriz = false;    
+    ownerAC.animSpeed = 0.1;
+    
+    // Helper highlight function for the formatter
+    var highlightMatch = function (full, snippet, matchindex) {
+            return full.substring(0, matchindex) 
+            + "<span class='match'>" 
+            + full.substr(matchindex, snippet.length) 
+            + "</span>" + full.substring(matchindex + snippet.length);
+        };
+
+    // Custom formatter to highlight the matching letters
+    ownerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
+		    var org_sQuery = sQuery;
+		    if(this.dataSource.mentionQuery != null){
+		    	sQuery = this.dataSource.mentionQuery;		    	
+		    }
+
+            var query = sQuery.toLowerCase();
+            var _gravatar = function(res, em, group){
+            	if (group !== undefined){
+            		em = '/images/icons/group.png'
+            	}
+            	tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
+            	return tmpl.format(em,res)
+            }
+            if (oResultData.nname != undefined) {
+                var fname = oResultData.fname || "";
+                var lname = oResultData.lname || "";
+                var nname = oResultData.nname;
+                
+                // Guard against null value
+                var fnameMatchIndex = fname.toLowerCase().indexOf(query),
+                    lnameMatchIndex = lname.toLowerCase().indexOf(query),
+                    nnameMatchIndex = nname.toLowerCase().indexOf(query),
+                    displayfname, displaylname, displaynname;
+
+                if (fnameMatchIndex > -1) {
+                    displayfname = highlightMatch(fname, query, fnameMatchIndex);
+                } else {
+                    displayfname = fname;
+                }
+
+                if (lnameMatchIndex > -1) {
+                    displaylname = highlightMatch(lname, query, lnameMatchIndex);
+                } else {
+                    displaylname = lname;
+                }
+
+                if (nnameMatchIndex > -1) {
+                    displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
+                } else {
+                    displaynname = nname ? "(" + nname + ")" : "";
+                }
+
+                return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
+            } else {
+                return '';
+            }
+        };
+
+    if(ownerAC.itemSelectEvent){
+    	ownerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
+
+            var myAC = aArgs[0]; // reference back to the AC instance
+            var elLI = aArgs[1]; // reference to the selected LI element
+            var oData = aArgs[2]; // object literal of selected item's result data
+            //fill the autocomplete with value
+            if (oData.nname != undefined) {
+                //users
+            	//Replace the mention name with replaced
+            	var re = new RegExp();
+            	var org = myAC.getInputEl().value;
+            	var chunks = myAC.dataSource.chunks
+            	// replace middle chunk(the search term) with actuall  match
+            	chunks[1] = chunks[1].replace('@'+myAC.dataSource.mentionQuery,
+            								  '@'+oData.nname+' ');
+                myAC.getInputEl().value = chunks.join('')
+                YUD.get(myAC.getInputEl()).focus(); // Y U NO WORK !?
+            } else {
+                //groups
+                myAC.getInputEl().value = oData.grname;
+                YUD.get('perm_new_member_type').value = 'users_group';
+            }
+        });
+    }
+
+    // in this keybuffer we will gather current value of search !
+    // since we need to get this just when someone does `@` then we do the
+    // search
+    ownerAC.dataSource.chunks = [];
+    ownerAC.dataSource.mentionQuery = null;
+
+    ownerAC.get_mention = function(msg, max_pos) {
+    	var org = msg;
+    	var re = new RegExp('(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)$')
+    	var chunks  = [];
+
+		
+    	// cut first chunk until curret pos
+		var to_max = msg.substr(0, max_pos);		
+		var at_pos = Math.max(0,to_max.lastIndexOf('@')-1);
+		var msg2 = to_max.substr(at_pos);
+
+		chunks.push(org.substr(0,at_pos))// prefix chunk
+		chunks.push(msg2)                // search chunk
+		chunks.push(org.substr(max_pos)) // postfix chunk
+
+		// clean up msg2 for filtering and regex match
+		var msg2 = msg2.lstrip(' ').lstrip('\n');
+
+		if(re.test(msg2)){
+			var unam = re.exec(msg2)[1];
+			return [unam, chunks];
+		}
+		return [null, null];
+    };
+    
+    if (ownerAC.textboxKeyUpEvent){
+		ownerAC.textboxKeyUpEvent.subscribe(function(type, args){
+			
+			var ac_obj = args[0];
+			var currentMessage = args[1];
+			var currentCaretPosition = args[0]._elTextbox.selectionStart;
+	
+			var unam = ownerAC.get_mention(currentMessage, currentCaretPosition); 
+			var curr_search = null;
+			if(unam[0]){
+				curr_search = unam[0];
+			}
+			
+			ownerAC.dataSource.chunks = unam[1];
+			ownerAC.dataSource.mentionQuery = curr_search;
+	
+		})
+	}	
+    return {
+        ownerDS: ownerDS,
+        ownerAC: ownerAC,
+    };
+}
+
+
+var PullRequestAutoComplete = function (divid, cont, users_list, groups_list) {
+    var myUsers = users_list;
+    var myGroups = groups_list;
+
+    // Define a custom search function for the DataSource of users
+    var matchUsers = function (sQuery) {
+            // Case insensitive matching
+            var query = sQuery.toLowerCase();
+            var i = 0;
+            var l = myUsers.length;
+            var matches = [];
+
+            // Match against each name of each contact
+            for (; i < l; i++) {
+                contact = myUsers[i];
+                if (((contact.fname+"").toLowerCase().indexOf(query) > -1) || 
+                   	 ((contact.lname+"").toLowerCase().indexOf(query) > -1) || 
+                   	 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
+                       matches[matches.length] = contact;
+                   }
+            }
+            return matches;
+        };
+
+    // Define a custom search function for the DataSource of usersGroups
+    var matchGroups = function (sQuery) {
+            // Case insensitive matching
+            var query = sQuery.toLowerCase();
+            var i = 0;
+            var l = myGroups.length;
+            var matches = [];
+
+            // Match against each name of each contact
+            for (; i < l; i++) {
+                matched_group = myGroups[i];
+                if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
+                    matches[matches.length] = matched_group;
+                }
+            }
+            return matches;
+        };
+
+    //match all
+    var matchAll = function (sQuery) {
+            u = matchUsers(sQuery);
+            return u
+        };
+
+    // DataScheme for owner
+    var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
+
+    ownerDS.responseSchema = {
+        fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
+    };
+
+    // Instantiate AutoComplete for mentions
+    var reviewerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
+    reviewerAC.useShadow = false;
+    reviewerAC.resultTypeList = false;
+    reviewerAC.suppressInputUpdate = true;
+    reviewerAC.animVert = false;
+    reviewerAC.animHoriz = false;    
+    reviewerAC.animSpeed = 0.1;
+    
+    // Helper highlight function for the formatter
+    var highlightMatch = function (full, snippet, matchindex) {
+            return full.substring(0, matchindex) 
+            + "<span class='match'>" 
+            + full.substr(matchindex, snippet.length) 
+            + "</span>" + full.substring(matchindex + snippet.length);
+        };
+
+    // Custom formatter to highlight the matching letters
+    reviewerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
+		    var org_sQuery = sQuery;
+		    if(this.dataSource.mentionQuery != null){
+		    	sQuery = this.dataSource.mentionQuery;		    	
+		    }
+
+            var query = sQuery.toLowerCase();
+            var _gravatar = function(res, em, group){
+            	if (group !== undefined){
+            		em = '/images/icons/group.png'
+            	}
+            	tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
+            	return tmpl.format(em,res)
+            }
+            if (oResultData.nname != undefined) {
+                var fname = oResultData.fname || "";
+                var lname = oResultData.lname || "";
+                var nname = oResultData.nname;
+                
+                // Guard against null value
+                var fnameMatchIndex = fname.toLowerCase().indexOf(query),
+                    lnameMatchIndex = lname.toLowerCase().indexOf(query),
+                    nnameMatchIndex = nname.toLowerCase().indexOf(query),
+                    displayfname, displaylname, displaynname;
+
+                if (fnameMatchIndex > -1) {
+                    displayfname = highlightMatch(fname, query, fnameMatchIndex);
+                } else {
+                    displayfname = fname;
+                }
+
+                if (lnameMatchIndex > -1) {
+                    displaylname = highlightMatch(lname, query, lnameMatchIndex);
+                } else {
+                    displaylname = lname;
+                }
+
+                if (nnameMatchIndex > -1) {
+                    displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
+                } else {
+                    displaynname = nname ? "(" + nname + ")" : "";
+                }
+
+                return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
+            } else {
+                return '';
+            }
+        };
+        
+    //members cache to catch duplicates
+    reviewerAC.dataSource.cache = [];
+    // hack into select event
+    if(reviewerAC.itemSelectEvent){
+    	reviewerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
+
+            var myAC = aArgs[0]; // reference back to the AC instance
+            var elLI = aArgs[1]; // reference to the selected LI element
+            var oData = aArgs[2]; // object literal of selected item's result data
+            var members  = YUD.get('review_members');
+            //fill the autocomplete with value
+
+            if (oData.nname != undefined) {
+            	if (myAC.dataSource.cache.indexOf(oData.id) != -1){
+            		return
+            	}
+
+            	var tmpl = '<li id="reviewer_{2}">'+
+		                      '<div class="reviewers_member">'+
+		                        '<div class="gravatar"><img alt="gravatar" src="{0}"/> </div>'+
+		                        '<div style="float:left">{1}</div>'+
+		                        '<input type="hidden" value="{2}" name="review_members" />'+
+		                        '<span class="delete_icon action_button" onclick="removeReviewer({2})"></span>'+
+		                      '</div>'+
+		                   '</li>'
+
+		        var displayname = "{0} {1} ({2})".format(oData.fname,oData.lname,oData.nname);
+            	var element = tmpl.format(oData.gravatar_lnk,displayname,oData.id);
+            	members.innerHTML += element;
+            	myAC.dataSource.cache.push(oData.id);
+            	YUD.get('user').value = '' 
+            }
+    	});        
+    }
+    return {
+        ownerDS: ownerDS,
+        reviewerAC: reviewerAC,
+    };
+}
+
 
 /**
  * QUICK REPO MENU
@@ -1041,10 +1491,18 @@
 	return name
 }
 var get_date = function(node){
-	var date_ = node.firstElementChild.innerHTML;
+	var date_ = YUD.getAttribute(node.firstElementChild,'date');
 	return date_
 }
 
+var get_age = function(node){
+	return node
+}
+
+var get_link = function(node){
+	return node.firstElementChild.text;
+}
+
 var revisionSort = function(a, b, desc, field) {
 	  
 	  var a_ = fromHTML(a.getData(field));
@@ -1059,8 +1517,21 @@
 	  return compState;
 };
 var ageSort = function(a, b, desc, field) {
-    var a_ = a.getData(field);
-    var b_ = b.getData(field);
+    var a_ = fromHTML(a.getData(field));
+    var b_ = fromHTML(b.getData(field));
+    
+    // extract name from table
+    a_ = get_date(a_)
+    b_ = get_date(b_)          
+    
+    var comp = YAHOO.util.Sort.compare;
+    var compState = comp(a_, b_, desc);
+    return compState;
+};
+
+var lastLoginSort = function(a, b, desc, field) {
+	var a_ = a.getData('last_login_raw') || 0;
+    var b_ = b.getData('last_login_raw') || 0;
     
     var comp = YAHOO.util.Sort.compare;
     var compState = comp(a_, b_, desc);
@@ -1070,7 +1541,7 @@
 var nameSort = function(a, b, desc, field) {
     var a_ = fromHTML(a.getData(field));
     var b_ = fromHTML(b.getData(field));
-    
+
     // extract name from table
     a_ = get_name(a_)
     b_ = get_name(b_)          
@@ -1116,4 +1587,173 @@
     var comp = YAHOO.util.Sort.compare;
     var compState = comp(a_, b_, desc);
     return compState;
-};
\ No newline at end of file
+};
+
+var linkSort = function(a, b, desc, field) {
+	  var a_ = fromHTML(a.getData(field));
+	  var b_ = fromHTML(a.getData(field));
+	  
+	  // extract url text from string nodes 
+	  a_ = get_link(a_)
+	  b_ = get_link(b_)
+
+	  var comp = YAHOO.util.Sort.compare;
+	  var compState = comp(a_, b_, desc);
+	  return compState;
+}
+
+var addPermAction = function(_html, users_list, groups_list){
+    var elmts = YUD.getElementsByClassName('last_new_member');
+    var last_node = elmts[elmts.length-1];
+    if (last_node){
+       var next_id = (YUD.getElementsByClassName('new_members')).length;
+       _html = _html.format(next_id);
+       last_node.innerHTML = _html;
+       YUD.setStyle(last_node, 'display', '');
+       YUD.removeClass(last_node, 'last_new_member');
+       MembersAutoComplete("perm_new_member_name_"+next_id, 
+               "perm_container_"+next_id, users_list, groups_list);          
+       //create new last NODE
+       var el = document.createElement('tr');
+       el.id = 'add_perm_input';
+       YUD.addClass(el,'last_new_member');
+       YUD.addClass(el,'new_members');
+       YUD.insertAfter(el, last_node);
+    }	
+}
+
+/* Multi selectors */
+
+var MultiSelectWidget = function(selected_id, available_id, form_id){
+
+
+	//definition of containers ID's
+	var selected_container = selected_id;
+	var available_container = available_id;
+	
+	//temp container for selected storage.
+	var cache = new Array();
+	var av_cache = new Array();
+	var c =  YUD.get(selected_container);
+	var ac = YUD.get(available_container);
+	
+	//get only selected options for further fullfilment
+	for(var i = 0;node =c.options[i];i++){
+	    if(node.selected){
+	        //push selected to my temp storage left overs :)
+	        cache.push(node);
+	    }
+	}
+	
+	//get all available options to cache
+	for(var i = 0;node =ac.options[i];i++){
+	        //push selected to my temp storage left overs :)
+	        av_cache.push(node);
+	}
+	
+	//fill available only with those not in choosen
+	ac.options.length=0;
+	tmp_cache = new Array();
+	
+	for(var i = 0;node = av_cache[i];i++){
+	    var add = true;
+	    for(var i2 = 0;node_2 = cache[i2];i2++){
+	        if(node.value == node_2.value){
+	            add=false;
+	            break;
+	        }
+	    }
+	    if(add){
+	        tmp_cache.push(new Option(node.text, node.value, false, false));
+	    }
+	}
+	
+	for(var i = 0;node = tmp_cache[i];i++){
+	    ac.options[i] = node;
+	}
+	
+	function prompts_action_callback(e){
+	
+	    var choosen = YUD.get(selected_container);
+	    var available = YUD.get(available_container);
+	
+	    //get checked and unchecked options from field
+	    function get_checked(from_field){
+	        //temp container for storage.
+	        var sel_cache = new Array();
+	        var oth_cache = new Array();
+	
+	        for(var i = 0;node = from_field.options[i];i++){
+	            if(node.selected){
+	                //push selected fields :)
+	                sel_cache.push(node);
+	            }
+	            else{
+	                oth_cache.push(node)
+	            }
+	        }
+	
+	        return [sel_cache,oth_cache]
+	    }
+	
+	    //fill the field with given options
+	    function fill_with(field,options){
+	        //clear firtst
+	        field.options.length=0;
+	        for(var i = 0;node = options[i];i++){
+	                field.options[i]=new Option(node.text, node.value,
+	                        false, false);
+	        }
+	
+	    }
+	    //adds to current field
+	    function add_to(field,options){
+	        for(var i = 0;node = options[i];i++){
+	                field.appendChild(new Option(node.text, node.value,
+	                        false, false));
+	        }
+	    }
+	
+	    // add action
+	    if (this.id=='add_element'){
+	        var c = get_checked(available);
+	        add_to(choosen,c[0]);
+	        fill_with(available,c[1]);
+	    }
+	    // remove action
+	    if (this.id=='remove_element'){
+	        var c = get_checked(choosen);
+	        add_to(available,c[0]);
+	        fill_with(choosen,c[1]);
+	    }
+	    // add all elements
+	    if(this.id=='add_all_elements'){
+	        for(var i=0; node = available.options[i];i++){
+	                choosen.appendChild(new Option(node.text,
+	                        node.value, false, false));
+	        }
+	        available.options.length = 0;
+	    }
+	    //remove all elements
+	    if(this.id=='remove_all_elements'){
+	        for(var i=0; node = choosen.options[i];i++){
+	            available.appendChild(new Option(node.text,
+	                    node.value, false, false));
+	        }
+	        choosen.options.length = 0;
+	    }
+	
+	}
+	
+	YUE.addListener(['add_element','remove_element',
+	               'add_all_elements','remove_all_elements'],'click',
+	               prompts_action_callback)
+	if (form_id !== undefined) {
+		YUE.addListener(form_id,'submit',function(){
+		    var choosen = YUD.get(selected_container);
+		    for (var i = 0; i < choosen.options.length; i++) {
+		        choosen.options[i].selected = 'selected';
+		    }
+		});
+	}
+}
--- a/rhodecode/public/js/yui.2.9.js	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/public/js/yui.2.9.js	Sun Sep 02 21:19:54 2012 +0200
@@ -1,150 +1,877 @@
+if("undefined"==typeof YAHOO||!YAHOO)var YAHOO={};YAHOO.namespace=function(){var a=arguments,c=null,b,d,f;for(b=0;b<a.length;b+=1){f=(""+a[b]).split(".");c=YAHOO;for(d="YAHOO"==f[0]?1:0;d<f.length;d+=1)c[f[d]]=c[f[d]]||{},c=c[f[d]]}return c};YAHOO.log=function(a,c,b){var d=YAHOO.widget.Logger;return d&&d.log?d.log(a,c,b):!1};
+YAHOO.register=function(a,c,b){var d=YAHOO.env.modules,f,g,j;d[a]||(d[a]={versions:[],builds:[]});d=d[a];f=b.version;b=b.build;g=YAHOO.env.listeners;d.name=a;d.version=f;d.build=b;d.versions.push(f);d.builds.push(b);d.mainClass=c;for(j=0;j<g.length;j+=1)g[j](d);c?(c.VERSION=f,c.BUILD=b):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.parseUA=function(a){var c=function(a){var b=0;return parseFloat(a.replace(/\./g,function(){return 1==b++?"":"."}))},b=navigator,b={ie:0,opera:0,gecko:0,webkit:0,chrome:0,mobile:null,air:0,ipad:0,iphone:0,ipod:0,ios:null,android:0,webos:0,caja:b&&b.cajaVersion,secure:!1,os:null},a=a||navigator&&navigator.userAgent,d=window&&window.location,d=d&&d.href;b.secure=d&&0===d.toLowerCase().indexOf("https");if(a){/windows|win32/i.test(a)?b.os="windows":/macintosh/i.test(a)?b.os="macintosh":/rhino/i.test(a)&&
+(b.os="rhino");/KHTML/.test(a)&&(b.webkit=1);if((d=a.match(/AppleWebKit\/([^\s]*)/))&&d[1]){b.webkit=c(d[1]);if(/ Mobile\//.test(a)){if(b.mobile="Apple",(d=a.match(/OS ([^\s]*)/))&&d[1]&&(d=c(d[1].replace("_","."))),b.ios=d,b.ipad=b.ipod=b.iphone=0,(d=a.match(/iPad|iPod|iPhone/))&&d[0])b[d[0].toLowerCase()]=b.ios}else{if(d=a.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/))b.mobile=d[0];if(/webOS/.test(a)&&(b.mobile="WebOS",(d=a.match(/webOS\/([^\s]*);/))&&d[1]))b.webos=c(d[1]);if(/ Android/.test(a)&&
+(b.mobile="Android",(d=a.match(/Android ([^\s]*);/))&&d[1]))b.android=c(d[1])}if((d=a.match(/Chrome\/([^\s]*)/))&&d[1])b.chrome=c(d[1]);else if(d=a.match(/AdobeAIR\/([^\s]*)/))b.air=d[0]}if(!b.webkit)if((d=a.match(/Opera[\s\/]([^\s]*)/))&&d[1]){b.opera=c(d[1]);if((d=a.match(/Version\/([^\s]*)/))&&d[1])b.opera=c(d[1]);if(d=a.match(/Opera Mini[^;]*/))b.mobile=d[0]}else if((d=a.match(/MSIE\s([^;]*)/))&&d[1])b.ie=c(d[1]);else if(d=a.match(/Gecko\/([^\s]*)/))if(b.gecko=1,(d=a.match(/rv:([^\s\)]*)/))&&
+d[1])b.gecko=c(d[1])}return b};YAHOO.env.ua=YAHOO.env.parseUA();(function(){YAHOO.namespace("util","widget","example");if("undefined"!==typeof YAHOO_config){var a=YAHOO_config.listener,c=YAHOO.env.listeners,b=!0,d;if(a){for(d=0;d<c.length;d++)if(c[d]==a){b=!1;break}b&&c.push(a)}}})();YAHOO.lang=YAHOO.lang||{};
+(function(){var a=YAHOO.lang,c=Object.prototype,b=[],d={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;","`":"&#x60;"},f=["toString","valueOf"],g={isArray:function(a){return"[object Array]"===c.toString.apply(a)},isBoolean:function(a){return"boolean"===typeof a},isFunction:function(a){return"function"===typeof a||"[object Function]"===c.toString.apply(a)},isNull:function(a){return null===a},isNumber:function(a){return"number"===typeof a&&isFinite(a)},isObject:function(b){return b&&
+("object"===typeof b||a.isFunction(b))||!1},isString:function(a){return"string"===typeof a},isUndefined:function(a){return"undefined"===typeof a},_IEEnumFix:YAHOO.env.ua.ie?function(b,d){var e,i,k;for(e=0;e<f.length;e+=1)i=f[e],k=d[i],a.isFunction(k)&&k!=c[i]&&(b[i]=k)}:function(){},escapeHTML:function(a){return a.replace(/[&<>"'\/`]/g,function(a){return d[a]})},extend:function(b,d,e){if(!d||!b)throw Error("extend failed, please check that all dependencies are included.");var i=function(){},k;i.prototype=
+d.prototype;b.prototype=new i;b.prototype.constructor=b;b.superclass=d.prototype;d.prototype.constructor==c.constructor&&(d.prototype.constructor=d);if(e){for(k in e)a.hasOwnProperty(e,k)&&(b.prototype[k]=e[k]);a._IEEnumFix(b.prototype,e)}},augmentObject:function(b,d){if(!d||!b)throw Error("Absorb failed, verify dependencies.");var e=arguments,i,k=e[2];if(k&&!0!==k)for(i=2;i<e.length;i+=1)b[e[i]]=d[e[i]];else{for(i in d)if(k||!(i in b))b[i]=d[i];a._IEEnumFix(b,d)}return b},augmentProto:function(b,
+d){if(!d||!b)throw Error("Augment failed, verify dependencies.");var e=[b.prototype,d.prototype],i;for(i=2;i<arguments.length;i+=1)e.push(arguments[i]);a.augmentObject.apply(this,e);return b},dump:function(b,d){var e,i,k=[];if(a.isObject(b)){if(b instanceof Date||"nodeType"in b&&"tagName"in b)return b;if(a.isFunction(b))return"f(){...}"}else return b+"";d=a.isNumber(d)?d:3;if(a.isArray(b)){k.push("[");e=0;for(i=b.length;e<i;e+=1)a.isObject(b[e])?k.push(0<d?a.dump(b[e],d-1):"{...}"):k.push(b[e]),k.push(", ");
+1<k.length&&k.pop();k.push("]")}else{k.push("{");for(e in b)a.hasOwnProperty(b,e)&&(k.push(e+" => "),a.isObject(b[e])?k.push(0<d?a.dump(b[e],d-1):"{...}"):k.push(b[e]),k.push(", "));1<k.length&&k.pop();k.push("}")}return k.join("")},substitute:function(b,d,e,i){for(var k,f,c,g,n,o=[],m,r=b.length;;){k=b.lastIndexOf("{",r);if(0>k)break;f=b.indexOf("}",k);if(k+1>f)break;g=m=b.substring(k+1,f);n=null;c=g.indexOf(" ");-1<c&&(n=g.substring(c+1),g=g.substring(0,c));c=d[g];e&&(c=e(g,c,n));a.isObject(c)?
+a.isArray(c)?c=a.dump(c,parseInt(n,10)):(n=n||"",g=n.indexOf("dump"),-1<g&&(n=n.substring(4)),m=c.toString(),c="[object Object]"===m||-1<g?a.dump(c,parseInt(n,10)):m):!a.isString(c)&&!a.isNumber(c)&&(c="~-"+o.length+"-~",o[o.length]=m);b=b.substring(0,k)+c+b.substring(f+1);!1===i&&(r=k-1)}for(k=o.length-1;0<=k;k-=1)b=b.replace(RegExp("~-"+k+"-~"),"{"+o[k]+"}","g");return b},trim:function(a){try{return a.replace(/^\s+|\s+$/g,"")}catch(b){return a}},merge:function(){var b={},d=arguments,e=d.length,
+i;for(i=0;i<e;i+=1)a.augmentObject(b,d[i],!0);return b},later:function(d,f,e,i,k){var d=d||0,f=f||{},c=e,g=i,p;a.isString(e)&&(c=f[e]);if(!c)throw new TypeError("method undefined");!a.isUndefined(i)&&!a.isArray(g)&&(g=[i]);e=function(){c.apply(f,g||b)};p=k?setInterval(e,d):setTimeout(e,d);return{interval:k,cancel:function(){this.interval?clearInterval(p):clearTimeout(p)}}},isValue:function(b){return a.isObject(b)||a.isString(b)||a.isNumber(b)||a.isBoolean(b)}};a.hasOwnProperty=c.hasOwnProperty?function(a,
+b){return a&&a.hasOwnProperty&&a.hasOwnProperty(b)}:function(b,d){return!a.isUndefined(b[d])&&b.constructor.prototype[d]!==b[d]};g.augmentObject(a,g,!0);YAHOO.util.Lang=a;a.augment=a.augmentProto;YAHOO.augment=a.augmentProto;YAHOO.extend=a.extend})();YAHOO.register("yahoo",YAHOO,{version:"2.9.0",build:"2800"});
+YAHOO.util.Get=function(){var a={},c=0,b=0,d=!1,f=YAHOO.env.ua,g=YAHOO.lang,j,h,e,i=function(e,a,i){var e=(i||window).document.createElement(e),b;for(b in a)a.hasOwnProperty(b)&&e.setAttribute(b,a[b]);return e},k=function(e,a,k){e={id:"yui__dyn_"+b++,type:"text/javascript",src:e};k&&g.augmentObject(e,k);return i("script",e,a)},l=function(e,a){return{tId:e.tId,win:e.win,data:e.data,nodes:e.nodes,msg:a,purge:function(){h(this.tId)}}},q=function(e,i){var b=a[i];(b=g.isString(e)?b.win.document.getElementById(e):
+e)||j(i,"target node not found: "+e);return b},p=function(e){YAHOO.log("Finishing transaction "+e);var i=a[e];i.finished=!0;i.aborted?j(e,"transaction "+e+" was aborted"):i.onSuccess&&(e=i.scope||i.win,i.onSuccess.call(e,l(i)))},n=function(e){YAHOO.log("Timeout "+e,"info","get");var e=a[e],i;e.onTimeout&&(i=e.scope||e,e.onTimeout.call(i,l(e)))},o=function(d,c){YAHOO.log("_next: "+d+", loaded: "+c,"info","Get");var l=a[d],h=l.win,m=h.document.getElementsByTagName("head")[0],x,v;l.timer&&l.timer.cancel();
+if(l.aborted)j(d,"transaction "+d+" was aborted");else if(c?(l.url.shift(),l.varName&&l.varName.shift()):(l.url=g.isString(l.url)?[l.url]:l.url,l.varName&&(l.varName=g.isString(l.varName)?[l.varName]:l.varName)),0===l.url.length)"script"===l.type&&f.webkit&&420>f.webkit&&!l.finalpass&&!l.varName?(v=k(null,l.win,l.attributes),v.innerHTML='YAHOO.util.Get._finalize("'+d+'");',l.nodes.push(v),m.appendChild(v)):p(d);else{v=l.url[0];if(!v)return l.url.shift(),YAHOO.log("skipping empty url"),o(d);YAHOO.log("attempting to load "+
+v,"info","Get");l.timeout&&(l.timer=g.later(l.timeout,l,n,d));if("script"===l.type)x=k(v,h,l.attributes);else{x=l.attributes;var y={id:"yui__dyn_"+b++,type:"text/css",rel:"stylesheet",href:v};x&&g.augmentObject(y,x);x=i("link",y,h)}e(l.type,x,d,v,h,l.url.length);l.nodes.push(x);l.insertBefore?(m=q(l.insertBefore,d))&&m.parentNode.insertBefore(x,m):m.appendChild(x);YAHOO.log("Appending node: "+v,"info","Get");(f.webkit||f.gecko)&&"css"===l.type&&o(d,v)}},m=function(e,i,b){var k="q"+c++,b=b||{};if(0===
+c%YAHOO.util.Get.PURGE_THRESH&&!d){d=!0;var f,l;for(f in a)a.hasOwnProperty(f)&&(l=a[f],l.autopurge&&l.finished&&(h(l.tId),delete a[f]));d=!1}a[k]=g.merge(b,{tId:k,type:e,url:i,finished:!1,aborted:!1,nodes:[]});i=a[k];i.win=i.win||window;i.scope=i.scope||i.win;i.autopurge="autopurge"in i?i.autopurge:"script"===e?!0:!1;i.attributes=i.attributes||{};i.attributes.charset=b.charset||i.attributes.charset||"utf-8";g.later(0,i,o,k);return{tId:k}};e=function(e,i,b,k,d,l,c){var h=c||o,q,p,m,n,C,z;f.ie?i.onreadystatechange=
+function(){q=this.readyState;if("loaded"===q||"complete"===q)YAHOO.log(b+" onload "+k,"info","Get"),i.onreadystatechange=null,h(b,k)}:f.webkit?"script"===e&&(420<=f.webkit?i.addEventListener("load",function(){YAHOO.log(b+" DOM2 onload "+k,"info","Get");h(b,k)}):(p=a[b],p.varName?(e=YAHOO.util.Get.POLL_FREQ,YAHOO.log("Polling for "+p.varName[0]),p.maxattempts=YAHOO.util.Get.TIMEOUT/e,p.attempts=0,p._cache=p.varName[0].split("."),p.timer=g.later(e,p,function(){m=this._cache;C=m.length;n=this.win;for(z=
+0;z<C;z+=1)if(n=n[m[z]],!n){this.attempts++;this.attempts++>this.maxattempts?(p.timer.cancel(),j(b,"Over retry limit, giving up")):YAHOO.log(m[z]+" failed, retrying");return}YAHOO.log("Safari poll complete");p.timer.cancel();h(b,k)},null,!0)):g.later(YAHOO.util.Get.POLL_FREQ,null,h,[b,k]))):i.onload=function(){YAHOO.log(b+" onload "+k,"info","Get");h(b,k)}};j=function(e,i){YAHOO.log("get failure: "+i,"warn","Get");var b=a[e],k;b.onFailure&&(k=b.scope||b.win,b.onFailure.call(k,l(b,i)))};h=function(e){if(a[e]){var i=
+a[e],b=i.nodes,k=b.length,d=i.win.document.getElementsByTagName("head")[0],f,l;if(i.insertBefore&&(e=q(i.insertBefore,e)))d=e.parentNode;for(e=0;e<k;e+=1){f=b[e];if(f.clearAttributes)f.clearAttributes();else for(l in f)f.hasOwnProperty(l)&&delete f[l];d.removeChild(f)}i.nodes=[]}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2E3,_finalize:function(e){YAHOO.log(e+" finalized ","info","Get");g.later(0,null,p,e)},abort:function(e){var e=g.isString(e)?e:e.tId,i=a[e];i&&(YAHOO.log("Aborting "+e,"info",
+"Get"),i.aborted=!0)},script:function(e,a){return m("script",e,a)},css:function(e,a){return m("css",e,a)}}}();YAHOO.register("get",YAHOO.util.Get,{version:"2.9.0",build:"2800"});
+(function(){var a,c,b,d,f,g=YAHOO,j=g.util,h=g.lang,e=g.env;f={yahoo:!0,get:!0};a={defaultSkin:"sam",base:"assets/skins/",path:"skin.css",after:["reset","fonts","grids","base"],rollup:3};c={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:!0},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:!0},calendar:{type:"js",path:"calendar/calendar-min.js",requires:["event","dom"],supersedes:["datemath"],skinnable:!0},carousel:{type:"js",path:"carousel/carousel-min.js",requires:["element"],optional:["animation"],skinnable:!0},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:!0},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:!0},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:!0},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:!0},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:!0},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:!0},logger:{type:"js",path:"logger/logger-min.js",requires:["event","dom"],optional:["dragdrop"],skinnable:!0},menu:{type:"js",path:"menu/menu-min.js",
+requires:["containercore"],skinnable:!0},paginator:{type:"js",path:"paginator/paginator-min.js",requires:["element"],skinnable:!0},profiler:{type:"js",path:"profiler/profiler-min.js",requires:["yahoo"]},profilerviewer:{type:"js",path:"profilerviewer/profilerviewer-min.js",requires:["profiler","yuiloader","element"],skinnable:!0},progressbar:{type:"js",path:"progressbar/progressbar-min.js",requires:["element"],optional:["animation"],skinnable:!0},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:!0},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:!0,pkg:"editor"},slider:{type:"js",path:"slider/slider-min.js",requires:["dragdrop"],optional:["animation"],skinnable:!0},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:!0},treeview:{type:"js",path:"treeview/treeview-min.js",requires:["event","dom"],optional:["json","animation","calendar"],skinnable:!0},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".split(" "),
+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".split(" "),rollup:5},yuitest:{type:"js",path:"yuitest/yuitest-min.js",requires:["logger"],optional:["event-simulate"],
+skinnable:!0}};b={appendArray:function(e,a){if(a)for(var b=0;b<a.length;b+=1)e[a[b]]=!0},keys:function(e){var a=[],b;for(b in e)h.hasOwnProperty(e,b)&&a.push(b);return a}};d={appendArray:function(e,a){Array.prototype.push.apply(e,a)},indexOf:function(e,a){for(var b=0;b<e.length;b+=1)if(e[b]===a)return b;return-1},toObject:function(e){for(var a={},b=0;b<e.length;b+=1)a[e[b]]=!0;return a},uniq:function(e){return b.keys(d.toObject(e))}};YAHOO.util.YUILoader=function(i){this._internalCallback=null;this._useYahooListener=
+!1;this.onSuccess=null;this.onFailure=g.log;this.onTimeout=this.onProgress=null;this.scope=this;this.varName=this.charset=this.insertBefore=this.data=null;this.base="http://yui.yahooapis.com/2.9.0/build/";this.comboBase="http://yui.yahooapis.com/combo?";this.combine=!1;this.root="2.9.0/build/";this.timeout=0;this.force=this.ignore=null;this.allowRollup=!0;this.filter=null;this.required={};this.moduleInfo=h.merge(c);this.rollups=null;this.loadOptional=!1;this.sorted=[];this.loaded={};this.dirty=!0;
+this.inserted={};var b=this;e.listeners.push(function(e){b._useYahooListener&&b.loadNext(e.name)});this.skin=h.merge(a);this._config(i)};g.util.YUILoader.prototype={FILTERS:{RAW:{searchExp:"-min\\.js",replaceStr:".js"},DEBUG:{searchExp:"-min\\.js",replaceStr:"-debug.js"}},SKIN_PREFIX:"skin-",_config:function(e){if(e)for(var a in e)h.hasOwnProperty(e,a)&&("require"==a?this.require(e[a]):this[a]=e[a]);e=this.filter;h.isString(e)&&(e=e.toUpperCase(),"DEBUG"===e&&this.require("logger"),g.widget.LogWriter||
+(g.widget.LogWriter=function(){return g}),this.filter=this.FILTERS[e])},addModule:function(e){if(!e||!e.name||!e.type||!e.path&&!e.fullpath)return!1;e.ext="ext"in e?e.ext:!0;e.requires=e.requires||[];this.moduleInfo[e.name]=e;return this.dirty=!0},require:function(e){var a="string"===typeof e?arguments:e;this.dirty=!0;b.appendArray(this.required,a)},_addSkin:function(e,a){var b=this.formatSkin(e),d=this.moduleInfo,f=this.skin,c=d[a]&&d[a].ext;d[b]||this.addModule({name:b,type:"css",path:f.base+e+
+"/"+f.path,after:f.after,rollup:f.rollup,ext:c});a&&(b=this.formatSkin(e,a),d[b]||this.addModule({name:b,type:"css",after:f.after,path:(d[a].pkg||a)+"/"+f.base+e+"/"+a+".css",ext:c}));return b},getRequires:function(e){if(!e)return[];if(!this.dirty&&e.expanded)return e.expanded;e.requires=e.requires||[];var a,b=[],f=e.requires,c=e.optional,g=this.moduleInfo,h;for(a=0;a<f.length;a+=1)b.push(f[a]),h=g[f[a]],d.appendArray(b,this.getRequires(h));if(c&&this.loadOptional)for(a=0;a<c.length;a+=1)b.push(c[a]),
+d.appendArray(b,this.getRequires(g[c[a]]));e.expanded=d.uniq(b);return e.expanded},getProvides:function(e,a){var b=!a?"_provides":"_supersedes",d=this.moduleInfo[e],f={};if(!d)return f;if(d[b])return d[b];var c=d.supersedes,g={};if(c)for(var j=0;j<c.length;j+=1){var r=c[j];g[r]||(g[r]=!0,h.augmentObject(f,this.getProvides(r)))}d._supersedes=f;d._provides=h.merge(f);d._provides[e]=!0;return d[b]},calculate:function(e){if(e||this.dirty)this._config(e),this._setup(),this._explode(),this.allowRollup&&
+this._rollup(),this._reduce(),this._sort(),this.dirty=!1},_setup:function(){var a=this.moduleInfo,k,f,c;for(k in a)if(h.hasOwnProperty(a,k)){var g=a[k];if(g&&g.skinnable){var j=this.skin.overrides,o;if(j&&j[k])for(f=0;f<j[k].length;f+=1)o=this._addSkin(j[k][f],k);else o=this._addSkin(this.skin.defaultSkin,k);-1==d.indexOf(g.requires,o)&&g.requires.push(o)}}a=h.merge(this.inserted);this._sandbox||(a=h.merge(a,e.modules));this.ignore&&b.appendArray(a,this.ignore);if(this.force)for(f=0;f<this.force.length;f+=
+1)this.force[f]in a&&delete a[this.force[f]];for(c in a)h.hasOwnProperty(a,c)&&h.augmentObject(a,this.getProvides(c));this.loaded=a},_explode:function(){var e=this.required,a,d;for(a in e)if(h.hasOwnProperty(e,a)&&(d=this.moduleInfo[a]))(d=this.getRequires(d))&&b.appendArray(e,d)},_skin:function(){},formatSkin:function(e,a){var b=this.SKIN_PREFIX+e;a&&(b=b+"-"+a);return b},parseSkin:function(e){return 0===e.indexOf(this.SKIN_PREFIX)?(e=e.split("-"),{skin:e[1],module:e[2]}):null},_rollup:function(){var e,
+a,b,d,c={},g=this.required,j,m=this.moduleInfo;if(this.dirty||!this.rollups){for(e in m)h.hasOwnProperty(m,e)&&(b=m[e])&&b.rollup&&(c[e]=b);this.rollups=c}for(;;){var r=!1;for(e in c)if(!g[e]&&!this.loaded[e]&&(b=m[e],d=b.supersedes,j=!1,b.rollup)){var s=0;if(b.ext?0:this.parseSkin(e))for(a in g){if(h.hasOwnProperty(g,a)&&(e!==a&&this.parseSkin(a))&&(s++,j=s>=b.rollup))break}else for(a=0;a<d.length;a+=1)if(this.loaded[d[a]]&&!f[d[a]]){j=!1;break}else if(g[d[a]]&&(s++,j=s>=b.rollup))break;j&&(r=g[e]=
+!0,this.getRequires(b))}if(!r)break}},_reduce:function(){var e,a,b,d=this.required;for(e in d)if(e in this.loaded)delete d[e];else if(b=this.parseSkin(e)){if(!b.module){var f=this.SKIN_PREFIX+b.skin;for(a in d)h.hasOwnProperty(d,a)&&(b=this.moduleInfo[a],(!b||!b.ext)&&(a!==e&&-1<a.indexOf(f))&&delete d[a])}}else if(b=(b=this.moduleInfo[e])&&b.supersedes)for(a=0;a<b.length;a+=1)b[a]in d&&delete d[b[a]]},_onFailure:function(e){YAHOO.log("Failure","info","loader");var a=this.onFailure;a&&a.call(this.scope,
+{msg:"failure: "+e,data:this.data,success:!1})},_onTimeout:function(){YAHOO.log("Timeout","info","loader");var e=this.onTimeout;e&&e.call(this.scope,{msg:"timeout",data:this.data,success:!1})},_sort:function(){var e=[],a=this.moduleInfo,b=this.loaded,f=!this.loadOptional,c=function(e,i){var g=a[e];if(b[i]||!g)return!1;var h;h=g.expanded;var j=g.after,o=a[i],m=g.optional;if(h&&-1<d.indexOf(h,i)||j&&-1<d.indexOf(j,i)||f&&m&&-1<d.indexOf(m,i))return!0;if(j=a[i]&&a[i].supersedes)for(h=0;h<j.length;h+=
+1)if(c(e,j[h]))return!0;return g.ext&&"css"==g.type&&!o.ext&&"css"==o.type?!0:!1},g;for(g in this.required)h.hasOwnProperty(this.required,g)&&e.push(g);for(g=0;;){var j=e.length,m,r,s,t=!1;for(r=g;r<j;r+=1){m=e[r];for(s=r+1;s<j;s+=1)if(c(m,e[s])){m=e.splice(s,1);e.splice(r,0,m[0]);t=!0;break}if(t)break;else g+=1}if(!t)break}this.sorted=e},toString:function(){h.dump({type:"YUILoader",base:this.base,filter:this.filter,required:this.required,loaded:this.loaded,inserted:this.inserted},1)},_combine:function(){this._combining=
+[];var e=this,a=this.sorted,b=a.length,d=this.comboBase,f=this.comboBase,c,g=d.length,h,j,s=this.loadType;YAHOO.log("type "+s);for(h=0;h<b;h+=1)if((j=this.moduleInfo[a[h]])&&!j.ext&&(!s||s===j.type))c=this.root+j.path,c+="&","js"==j.type?d+=c:f+=c,this._combining.push(a[h]);if(this._combining.length){YAHOO.log("Attempting to combine: "+this._combining,"info","loader");var t=function(e){var a=this._combining,i=a.length,b;for(b=0;b<i;b+=1)this.inserted[a[b]]=!0;this.loadNext(e.data)},a=function(){d.length>
+g?YAHOO.util.Get.script(e._filter(d),{data:e._loading,onSuccess:t,onFailure:e._onFailure,onTimeout:e._onTimeout,insertBefore:e.insertBefore,charset:e.charset,timeout:e.timeout,scope:e}):this.loadNext()};f.length>g?YAHOO.util.Get.css(this._filter(f),{data:this._loading,onSuccess:a,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,scope:e}):a()}else this.loadNext(this._loading)},insert:function(e,a){this.calculate(e);this._loading=
+!0;this.loadType=a;if(this.combine)return this._combine();if(a)this.loadNext();else{var b=this;this._internalCallback=function(){b._internalCallback=null;b.insert(null,"js")};this.insert(null,"css")}},sandbox:function(e,a){var b=this,d=function(e){var a=e.argument[2];b._scriptText[e.argument[0]]=e.responseText;b.onProgress&&b.onProgress.call(b.scope,{name:a,scriptText:e.responseText,xhrResponse:e,data:b.data});b._loadCount++;b._loadCount>=b._stopCount&&(e="\nreturn "+(b.varName||"YAHOO")+";\n})();",
+e=eval("(function() {\n"+b._scriptText.join("\n")+e),b._pushEvents(e),e?b.onSuccess.call(b.scope,{reference:e,data:b.data}):b._onFailure.call(b.varName+" reference failure"))},f=function(e){b.onFailure.call(b.scope,{msg:"XHR failure",xhrResponse:e,data:b.data})};b._config(e);if(!b.onSuccess)throw Error("You must supply an onSuccess handler for your sandbox");b._sandbox=!0;if(!a||"js"!==a)b._internalCallback=function(){b._internalCallback=null;b.sandbox(null,"js")},b.insert(null,"css");else if(j.Connect){b._scriptText=
+[];b._loadCount=0;b._stopCount=b.sorted.length;b._xhr=[];b.calculate();var c=b.sorted,g=c.length,h,r,s;for(h=0;h<g;h+=1){r=b.moduleInfo[c[h]];if(!r){b._onFailure("undefined module "+r);for(d=0;d<b._xhr.length;d+=1)b._xhr[d].abort();break}"js"!==r.type?b._loadCount++:(s=(s=r.fullpath)?b._filter(s):b._url(r.path),b._xhr.push(j.Connect.asyncRequest("GET",s,{success:d,failure:f,scope:b,argument:[h,s,c[h]]})))}}else(new YAHOO.util.YUILoader).insert({base:b.base,filter:b.filter,require:"connection",insertBefore:b.insertBefore,
+charset:b.charset,onSuccess:function(){b.sandbox(null,"js")},scope:b},"js")},loadNext:function(a){if(this._loading){var b=this,d=function(e){b.loadNext(e.data)},f=this.sorted,c=f.length,g,h;if(a){if(a!==this._loading)return;this.inserted[a]=!0;this.onProgress&&this.onProgress.call(this.scope,{name:a,data:this.data})}for(a=0;a<c;a+=1)if(!(f[a]in this.inserted)){if(f[a]===this._loading)return;g=this.moduleInfo[f[a]];if(!g){this.onFailure.call(this.scope,{msg:"undefined module "+g,data:this.data});return}if(!this.loadType||
+this.loadType===g.type){this._loading=f[a];c="css"===g.type?j.Get.css:j.Get.script;h=(h=g.fullpath)?this._filter(h):this._url(g.path);e.ua.webkit&&(420>e.ua.webkit&&"js"===g.type&&!g.varName)&&(d=null,this._useYahooListener=!0);c(h,{data:f[a],onSuccess:d,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,varName:g.varName,scope:b});return}}this._loading=null;this._internalCallback?(f=this._internalCallback,this._internalCallback=
+null,f.call(this)):this.onSuccess&&(this._pushEvents(),this.onSuccess.call(this.scope,{data:this.data}))}},_pushEvents:function(e){e=e||YAHOO;e.util&&e.util.Event&&e.util.Event._load()},_filter:function(e){var a=this.filter;return a?e.replace(RegExp(a.searchExp,"g"),a.replaceStr):e},_url:function(e){return this._filter((this.base||"")+e)}}})();YAHOO.register("yuiloader",YAHOO.util.YUILoader,{version:"2.9.0",build:"2800"});
+(function(){YAHOO.env._id_counter=YAHOO.env._id_counter||0;var a=YAHOO.util,c=YAHOO.lang,b=YAHOO.env.ua,d=YAHOO.lang.trim,f={},g={},j=/^t(?:able|d|h)$/i,h=/color$/i,e=window.document,i=e.documentElement,k=b.opera,l=b.webkit,q=b.gecko,p=b.ie;a.Dom={CUSTOM_ATTRIBUTES:!i.hasAttribute?{"for":"htmlFor","class":"className"}:{htmlFor:"for",className:"class"},DOT_ATTRIBUTES:{checked:!0},get:function(i){var b,d,f,k;b=null;if(i){if("string"==typeof i||"number"==typeof i){b=i+"";f=(i=e.getElementById(i))?i.attributes:
+null;if(i&&f&&f.id&&f.id.value===b)return i;if(i&&e.all&&(i=null,(d=e.all[b])&&d.length)){f=0;for(k=d.length;f<k;++f)if(d[f].id===b)return d[f]}}else if(a.Element&&i instanceof a.Element)i=i.get("element");else if(!i.nodeType&&"length"in i){b=[];f=0;for(k=i.length;f<k;++f)b[b.length]=a.Dom.get(i[f]);i=b}b=i}return b},getComputedStyle:function(e,i){if(window.getComputedStyle)return e.ownerDocument.defaultView.getComputedStyle(e,null)[i];if(e.currentStyle)return a.Dom.IE_ComputedStyle.get(e,i)},getStyle:function(e,
+i){return a.Dom.batch(e,a.Dom._getStyle,i)},_getStyle:function(){if(window.getComputedStyle)return function(e,i){var i="float"===i?i="cssFloat":a.Dom._toCamel(i),b=e.style[i],d;b||(d=e.ownerDocument.defaultView.getComputedStyle(e,null))&&(b=d[i]);return b};if(i.currentStyle)return function(e,i){var b;switch(i){case "opacity":b=100;try{b=e.filters["DXImageTransform.Microsoft.Alpha"].opacity}catch(d){try{b=e.filters("alpha").opacity}catch(f){}}return b/100;case "float":i="styleFloat";default:return i=
+a.Dom._toCamel(i),b=e.currentStyle?e.currentStyle[i]:null,e.style[i]||b}}}(),setStyle:function(e,i,b){a.Dom.batch(e,a.Dom._setStyle,{prop:i,val:b})},_setStyle:function(){return!window.getComputedStyle&&e.documentElement.currentStyle?function(e,i){var b=a.Dom._toCamel(i.prop),d=i.val;if(e)switch(b){case "opacity":if(""===d||null===d||1===d)e.style.removeAttribute("filter");else if(c.isString(e.style.filter)&&(e.style.filter="alpha(opacity="+100*d+")",!e.currentStyle||!e.currentStyle.hasLayout))e.style.zoom=
+1;break;case "float":b="styleFloat";default:e.style[b]=d}}:function(e,i){var b=a.Dom._toCamel(i.prop),d=i.val;e&&("float"==b&&(b="cssFloat"),e.style[b]=d)}}(),getXY:function(e){return a.Dom.batch(e,a.Dom._getXY)},_canPosition:function(e){return"none"!==a.Dom._getStyle(e,"display")&&a.Dom._inDoc(e)},_getXY:function(e){var i,b,d=Math.round;b=!1;if(a.Dom._canPosition(e)){b=e.getBoundingClientRect();i=e.ownerDocument;e=a.Dom.getDocumentScrollLeft(i);i=a.Dom.getDocumentScrollTop(i);b=[b.left,b.top];if(i||
+e)b[0]+=e,b[1]+=i;b[0]=d(b[0]);b[1]=d(b[1])}return b},getX:function(e){return a.Dom.batch(e,function(e){return a.Dom.getXY(e)[0]},a.Dom,!0)},getY:function(e){return a.Dom.batch(e,function(e){return a.Dom.getXY(e)[1]},a.Dom,!0)},setXY:function(e,i,b){a.Dom.batch(e,a.Dom._setXY,{pos:i,noRetry:b})},_setXY:function(e,i){var b=a.Dom._getStyle(e,"position"),d=a.Dom.setStyle,f=i.pos,k=i.noRetry,c=[parseInt(a.Dom.getComputedStyle(e,"left"),10),parseInt(a.Dom.getComputedStyle(e,"top"),10)],g;g=a.Dom._getXY(e);
+if(!f||!1===g)return!1;"static"==b&&(b="relative",d(e,"position",b));isNaN(c[0])&&(c[0]="relative"==b?0:e.offsetLeft);isNaN(c[1])&&(c[1]="relative"==b?0:e.offsetTop);null!==f[0]&&d(e,"left",f[0]-g[0]+c[0]+"px");null!==f[1]&&d(e,"top",f[1]-g[1]+c[1]+"px");k||(b=a.Dom._getXY(e),(null!==f[0]&&b[0]!=f[0]||null!==f[1]&&b[1]!=f[1])&&a.Dom._setXY(e,{pos:f,noRetry:!0}))},setX:function(e,i){a.Dom.setXY(e,[i,null])},setY:function(e,i){a.Dom.setXY(e,[null,i])},getRegion:function(e){return a.Dom.batch(e,function(e){var i=
+!1;a.Dom._canPosition(e)&&(i=a.Region.getRegion(e));return i},a.Dom,!0)},getClientWidth:function(){return a.Dom.getViewportWidth()},getClientHeight:function(){return a.Dom.getViewportHeight()},getElementsByClassName:function(i,b,d,f,k,c){b=b||"*";d=d?a.Dom.get(d):e;if(!d)return[];for(var g=[],b=d.getElementsByTagName(b),d=a.Dom.hasClass,l=0,h=b.length;l<h;++l)d(b[l],i)&&(g[g.length]=b[l]);f&&a.Dom.batch(g,f,k,c);return g},hasClass:function(e,i){return a.Dom.batch(e,a.Dom._hasClass,i)},_hasClass:function(e,
+i){var b=!1;e&&i&&((b=a.Dom._getAttribute(e,"className")||"")&&(b=b.replace(/\s+/g," ")),b=i.exec?i.test(b):i&&-1<(" "+b+" ").indexOf(" "+i+" "));return b},addClass:function(e,i){return a.Dom.batch(e,a.Dom._addClass,i)},_addClass:function(e,i){var b=!1,f;e&&i&&(f=a.Dom._getAttribute(e,"className")||"",a.Dom._hasClass(e,i)||(a.Dom.setAttribute(e,"className",d(f+" "+i)),b=!0));return b},removeClass:function(e,i){return a.Dom.batch(e,a.Dom._removeClass,i)},_removeClass:function(e,i){var b=!1,f,k;e&&
+i&&(f=a.Dom._getAttribute(e,"className")||"",a.Dom.setAttribute(e,"className",f.replace(a.Dom._getClassRegex(i),"")),k=a.Dom._getAttribute(e,"className"),f!==k&&(a.Dom.setAttribute(e,"className",d(k)),b=!0,""===a.Dom._getAttribute(e,"className")&&(f=e.hasAttribute&&e.hasAttribute("class")?"class":"className",e.removeAttribute(f))));return b},replaceClass:function(e,i,b){return a.Dom.batch(e,a.Dom._replaceClass,{from:i,to:b})},_replaceClass:function(e,i){var b,f,k=!1;e&&i&&(b=i.from,(f=i.to)?b?b!==
+f&&(k=a.Dom._getAttribute(e,"className")||"",b=(" "+k.replace(a.Dom._getClassRegex(b)," "+f).replace(/\s+/g," ")).split(a.Dom._getClassRegex(f)),b.splice(1,0," "+f),a.Dom.setAttribute(e,"className",d(b.join(""))),k=!0):k=a.Dom._addClass(e,i.to):k=!1);return k},generateId:function(e,i){var i=i||"yui-gen",b=function(e){if(e&&e.id)return e.id;var b=i+YAHOO.env._id_counter++;if(e){if(e.ownerDocument&&e.ownerDocument.getElementById(b))return a.Dom.generateId(e,b+i);e.id=b}return b};return a.Dom.batch(e,
+b,a.Dom,!0)||b.apply(a.Dom,arguments)},isAncestor:function(e,i){var e=a.Dom.get(e),i=a.Dom.get(i),b=!1;e&&i&&(e.nodeType&&i.nodeType)&&(e.contains&&e!==i?b=e.contains(i):e.compareDocumentPosition&&(b=!!(e.compareDocumentPosition(i)&16)));return b},inDocument:function(e,i){return a.Dom._inDoc(a.Dom.get(e),i)},_inDoc:function(e,i){var b=!1;e&&e.tagName&&(i=i||e.ownerDocument,b=a.Dom.isAncestor(i.documentElement,e));return b},getElementsBy:function(i,b,d,f,k,c,g){var b=b||"*",d=d?a.Dom.get(d):e,l=g?
+null:[];if(d){for(var b=d.getElementsByTagName(b),d=0,h=b.length;d<h;++d)if(i(b[d]))if(g){l=b[d];break}else l[l.length]=b[d];f&&a.Dom.batch(l,f,k,c)}return l},getElementBy:function(e,i,b){return a.Dom.getElementsBy(e,i,b,null,null,null,!0)},batch:function(e,i,b,d){var f=[],d=d?b:null;if((e=e&&(e.tagName||e.item)?e:a.Dom.get(e))&&i){if(e.tagName||void 0===e.length)return i.call(d,e,b);for(var k=0;k<e.length;++k)f[f.length]=i.call(d||e[k],e[k],b)}else return!1;return f},getDocumentHeight:function(){return Math.max("CSS1Compat"!=
+e.compatMode||l?e.body.scrollHeight:i.scrollHeight,a.Dom.getViewportHeight())},getDocumentWidth:function(){return Math.max("CSS1Compat"!=e.compatMode||l?e.body.scrollWidth:i.scrollWidth,a.Dom.getViewportWidth())},getViewportHeight:function(){var a=self.innerHeight,b=e.compatMode;if((b||p)&&!k)a="CSS1Compat"==b?i.clientHeight:e.body.clientHeight;return a},getViewportWidth:function(){var a=self.innerWidth,b=e.compatMode;if(b||p)a="CSS1Compat"==b?i.clientWidth:e.body.clientWidth;return a},getAncestorBy:function(e,
+i){for(;e=e.parentNode;)if(a.Dom._testElement(e,i))return e;return null},getAncestorByClassName:function(e,i){e=a.Dom.get(e);return!e?null:a.Dom.getAncestorBy(e,function(e){return a.Dom.hasClass(e,i)})},getAncestorByTagName:function(e,i){e=a.Dom.get(e);return!e?null:a.Dom.getAncestorBy(e,function(e){return e.tagName&&e.tagName.toUpperCase()==i.toUpperCase()})},getPreviousSiblingBy:function(e,i){for(;e;)if(e=e.previousSibling,a.Dom._testElement(e,i))return e;return null},getPreviousSibling:function(e){e=
+a.Dom.get(e);return!e?null:a.Dom.getPreviousSiblingBy(e)},getNextSiblingBy:function(e,i){for(;e;)if(e=e.nextSibling,a.Dom._testElement(e,i))return e;return null},getNextSibling:function(e){e=a.Dom.get(e);return!e?null:a.Dom.getNextSiblingBy(e)},getFirstChildBy:function(e,i){return(a.Dom._testElement(e.firstChild,i)?e.firstChild:null)||a.Dom.getNextSiblingBy(e.firstChild,i)},getFirstChild:function(e){e=a.Dom.get(e);return!e?null:a.Dom.getFirstChildBy(e)},getLastChildBy:function(e,i){return!e?null:
+(a.Dom._testElement(e.lastChild,i)?e.lastChild:null)||a.Dom.getPreviousSiblingBy(e.lastChild,i)},getLastChild:function(e){e=a.Dom.get(e);return a.Dom.getLastChildBy(e)},getChildrenBy:function(e,i){var b=a.Dom.getFirstChildBy(e,i),d=b?[b]:[];a.Dom.getNextSiblingBy(b,function(e){if(!i||i(e))d[d.length]=e;return!1});return d},getChildren:function(e){e=a.Dom.get(e);return a.Dom.getChildrenBy(e)},getDocumentScrollLeft:function(a){a=a||e;return Math.max(a.documentElement.scrollLeft,a.body.scrollLeft)},
+getDocumentScrollTop:function(a){a=a||e;return Math.max(a.documentElement.scrollTop,a.body.scrollTop)},insertBefore:function(e,i){e=a.Dom.get(e);i=a.Dom.get(i);return!e||!i||!i.parentNode?null:i.parentNode.insertBefore(e,i)},insertAfter:function(e,i){e=a.Dom.get(e);i=a.Dom.get(i);return!e||!i||!i.parentNode?null:i.nextSibling?i.parentNode.insertBefore(e,i.nextSibling):i.parentNode.appendChild(e)},getClientRegion:function(){var e=a.Dom.getDocumentScrollTop(),i=a.Dom.getDocumentScrollLeft(),b=a.Dom.getViewportWidth()+
+i,d=a.Dom.getViewportHeight()+e;return new a.Region(e,b,d,i)},setAttribute:function(e,i,b){a.Dom.batch(e,a.Dom._setAttribute,{attr:i,val:b})},_setAttribute:function(e,i){var b=a.Dom._toCamel(i.attr),d=i.val;e&&e.setAttribute&&(a.Dom.DOT_ATTRIBUTES[b]&&e.tagName&&"BUTTON"!=e.tagName?e[b]=d:(b=a.Dom.CUSTOM_ATTRIBUTES[b]||b,e.setAttribute(b,d)))},getAttribute:function(e,i){return a.Dom.batch(e,a.Dom._getAttribute,i)},_getAttribute:function(e,i){var b,i=a.Dom.CUSTOM_ATTRIBUTES[i]||i;a.Dom.DOT_ATTRIBUTES[i]?
+b=e[i]:e&&"getAttribute"in e&&(b=/^(?:href|src)$/.test(i)?e.getAttribute(i,2):e.getAttribute(i));return b},_toCamel:function(e){function a(e,i){return i.toUpperCase()}return f[e]||(f[e]=-1===e.indexOf("-")?e:e.replace(/-([a-z])/gi,a))},_getClassRegex:function(e){var i;void 0!==e&&(e.exec?i=e:(i=g[e],i||(e=e.replace(a.Dom._patterns.CLASS_RE_TOKENS,"\\$1"),e=e.replace(/\s+/g," "),i=g[e]=RegExp("(?:^|\\s)"+e+"(?= |$)","g"))));return i},_patterns:{ROOT_TAG:/^body|html$/i,CLASS_RE_TOKENS:/([\.\(\)\^\$\*\+\?\|\[\]\{\}\\])/g},
+_testElement:function(e,a){return e&&1==e.nodeType&&(!a||a(e))},_calcBorders:function(e,i){var b=parseInt(a.Dom.getComputedStyle(e,"borderTopWidth"),10)||0,d=parseInt(a.Dom.getComputedStyle(e,"borderLeftWidth"),10)||0;q&&j.test(e.tagName)&&(d=b=0);i[0]+=d;i[1]+=b;return i}};var n=a.Dom.getComputedStyle;b.opera&&(a.Dom.getComputedStyle=function(e,i){var b=n(e,i);h.test(i)&&(b=a.Dom.Color.toRGB(b));return b});b.webkit&&(a.Dom.getComputedStyle=function(e,a){var i=n(e,a);"rgba(0, 0, 0, 0)"===i&&(i="transparent");
+return i});b.ie&&8<=b.ie&&(a.Dom.DOT_ATTRIBUTES.type=!0)})();YAHOO.util.Region=function(a,c,b,d){this.y=this.top=a;this[1]=a;this.right=c;this.bottom=b;this.x=this.left=d;this[0]=d;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(a){var c=Math.max(this.top,a.top),b=Math.min(this.right,a.right),d=Math.min(this.bottom,a.bottom),a=Math.max(this.left,a.left);return d>=c&&b>=a?new YAHOO.util.Region(c,b,d,a):null};YAHOO.util.Region.prototype.union=function(a){var c=Math.min(this.top,a.top),b=Math.max(this.right,a.right),d=Math.max(this.bottom,a.bottom),a=Math.min(this.left,a.left);return new YAHOO.util.Region(c,b,d,a)};
+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(a){var c=YAHOO.util.Dom.getXY(a);return new YAHOO.util.Region(c[1],c[0]+a.offsetWidth,c[1]+a.offsetHeight,c[0])};YAHOO.util.Point=function(a,c){YAHOO.lang.isArray(a)&&(c=a[1],a=a[0]);YAHOO.util.Point.superclass.constructor.call(this,c,a,c,a)};
+YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);
+(function(){var a=YAHOO.util,c=/^width|height$/,b=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,d={get:function(d,f){var c="",c=d.currentStyle[f];return c="opacity"===f?a.Dom.getStyle(d,"opacity"):!c||c.indexOf&&-1<c.indexOf("px")?c:a.Dom.IE_COMPUTED[f]?a.Dom.IE_COMPUTED[f](d,f):b.test(c)?a.Dom.IE.ComputedStyle.getPixel(d,f):c},getOffset:function(a,b){var d=a.currentStyle[b],e=b.charAt(0).toUpperCase()+b.substr(1),i="offset"+e,f="pixel"+e,e="";"auto"==d?(e=
+d=a[i],c.test(b)&&(a.style[b]=d,a[i]>d&&(e=d-(a[i]-d)),a.style[b]="auto")):(!a.style[f]&&!a.style[b]&&(a.style[b]=d),e=a.style[f]);return e+"px"},getBorderWidth:function(a,b){var d=null;a.currentStyle.hasLayout||(a.style.zoom=1);switch(b){case "borderTopWidth":d=a.clientTop;break;case "borderBottomWidth":d=a.offsetHeight-a.clientHeight-a.clientTop;break;case "borderLeftWidth":d=a.clientLeft;break;case "borderRightWidth":d=a.offsetWidth-a.clientWidth-a.clientLeft}return d+"px"},getPixel:function(a,
+b){var d=null,e=a.currentStyle.right;a.style.right=a.currentStyle[b];d=a.style.pixelRight;a.style.right=e;return d+"px"},getMargin:function(b,d){return"auto"==b.currentStyle[d]?"0px":a.Dom.IE.ComputedStyle.getPixel(b,d)},getVisibility:function(a,b){for(var d;(d=a.currentStyle)&&"inherit"==d[b];)a=a.parentNode;return d?d[b]:"visible"},getColor:function(b,d){return a.Dom.Color.toRGB(b.currentStyle[d])||"transparent"},getBorderColor:function(b,d){var f=b.currentStyle;return a.Dom.Color.toRGB(a.Dom.Color.toHex(f[d]||
+f.color))}},f={};f.top=f.right=f.bottom=f.left=f.width=f.height=d.getOffset;f.color=d.getColor;f.borderTopWidth=f.borderRightWidth=f.borderBottomWidth=f.borderLeftWidth=d.getBorderWidth;f.marginTop=f.marginRight=f.marginBottom=f.marginLeft=d.getMargin;f.visibility=d.getVisibility;f.borderColor=f.borderTopColor=f.borderRightColor=f.borderBottomColor=f.borderLeftColor=d.getBorderColor;a.Dom.IE_COMPUTED=f;a.Dom.IE_ComputedStyle=d})();
+(function(){var a=parseInt,c=RegExp,b=YAHOO.util;b.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(d){b.Dom.Color.re_RGB.test(d)||(d=b.Dom.Color.toHex(d));b.Dom.Color.re_hex.exec(d)&&
+(d="rgb("+[a(c.$1,16),a(c.$2,16),a(c.$3,16)].join(", ")+")");return d},toHex:function(a){a=b.Dom.Color.KEYWORDS[a]||a;if(b.Dom.Color.re_RGB.exec(a)){for(var a=[Number(c.$1).toString(16),Number(c.$2).toString(16),Number(c.$3).toString(16)],f=0;f<a.length;f++)2>a[f].length&&(a[f]="0"+a[f]);a=a.join("")}6>a.length&&(a=a.replace(b.Dom.Color.re_hex3,"$1$1"));"transparent"!==a&&0>a.indexOf("#")&&(a="#"+a);return a.toUpperCase()}}})();YAHOO.register("dom",YAHOO.util.Dom,{version:"2.9.0",build:"2800"});
+YAHOO.util.CustomEvent=function(a,c,b,d,f){this.type=a;this.scope=c||window;this.silent=b;this.fireOnce=f;this.fired=!1;this.firedWith=null;this.signature=d||YAHOO.util.CustomEvent.LIST;this.subscribers=[];"_YUICEOnSubscribe"!==a&&(this.subscribeEvent=new YAHOO.util.CustomEvent("_YUICEOnSubscribe",this,!0));this.lastError=null};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;
+YAHOO.util.CustomEvent.prototype={subscribe:function(a,c,b){if(!a)throw Error("Invalid callback for subscriber to '"+this.type+"'");this.subscribeEvent&&this.subscribeEvent.fire(a,c,b);a=new YAHOO.util.Subscriber(a,c,b);this.fireOnce&&this.fired?this.notify(a,this.firedWith):this.subscribers.push(a)},unsubscribe:function(a,c){if(!a)return this.unsubscribeAll();for(var b=!1,d=0,f=this.subscribers.length;d<f;++d){var g=this.subscribers[d];g&&g.contains(a,c)&&(this._delete(d),b=!0)}return b},fire:function(){this.lastError=
+null;var a=this.subscribers.length,c=[].slice.call(arguments,0),b=!0,d;if(this.fireOnce){if(this.fired)return!0;this.firedWith=c}this.fired=!0;if(!a&&this.silent)return!0;var f=this.subscribers.slice();for(d=0;d<a;++d){var g=f[d];if(g&&g.fn&&(b=this.notify(g,c),!1===b))break}return!1!==b},notify:function(a,c){var b,d=null,f=a.getScope(this.scope),g=YAHOO.util.Event.throwErrors;if(this.signature==YAHOO.util.CustomEvent.FLAT){0<c.length&&(d=c[0]);try{b=a.fn.call(f,d,a.obj)}catch(j){if(this.lastError=
+j,g)throw j;}}else try{b=a.fn.call(f,this.type,c,a.obj)}catch(h){if(this.lastError=h,g)throw h;}return b},unsubscribeAll:function(){var a=this.subscribers.length,c;for(c=a-1;-1<c;c--)this._delete(c);this.subscribers=[];return a},_delete:function(a){var c=this.subscribers[a];c&&(delete c.fn,delete c.obj);this.subscribers.splice(a,1)},toString:function(){return"CustomEvent: '"+this.type+"', context: "+this.scope}};
+YAHOO.util.Subscriber=function(a,c,b){this.fn=a;this.obj=YAHOO.lang.isUndefined(c)?null:c;this.overrideContext=b};YAHOO.util.Subscriber.prototype.getScope=function(a){return this.overrideContext?!0===this.overrideContext?this.obj:this.overrideContext:a};YAHOO.util.Subscriber.prototype.contains=function(a,c){return c?this.fn==a&&this.obj==c:this.fn==a};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", overrideContext: "+(this.overrideContext||"no")+" }"};
+YAHOO.util.Event||(YAHOO.util.Event=function(){var a=!1,c=[],b=[],d=0,f=[],g=0,j={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9},h=YAHOO.env.ua.ie;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:h,_interval:null,_dri:null,_specialTypes:{focusin:h?"focusin":"focus",focusout:h?"focusout":"blur"},DOMReady:!1,throwErrors:!1,startInterval:function(){this._interval||
+(this._interval=YAHOO.lang.later(this.POLL_INTERVAL,this,this._tryPreloadAttach,null,!0))},onAvailable:function(e,a,b,c,g){for(var e=YAHOO.lang.isString(e)?[e]:e,h=0;h<e.length;h+=1)f.push({id:e[h],fn:a,obj:b,overrideContext:c,checkReady:g});d=this.POLL_RETRYS;this.startInterval()},onContentReady:function(e,a,b,d){this.onAvailable(e,a,b,d,!0)},onDOMReady:function(){this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent,arguments)},_addListener:function(e,a,d,f,g,h){if(!d||!d.call)return!1;if(this._isValidCollection(e)){for(var j=
+!0,o=0,m=e.length;o<m;++o)j=this.on(e[o],a,d,f,g)&&j;return j}if(YAHOO.lang.isString(e))if(j=this.getEl(e))e=j;else return this.onAvailable(e,function(){YAHOO.util.Event._addListener(e,a,d,f,g,h)}),!0;if(!e)return!1;if("unload"==a&&f!==this)return b[b.length]=[e,a,d,f,g],!0;var r=e;g&&(r=!0===g?f:g);j=function(a){return d.call(r,YAHOO.util.Event.getEvent(a,e),f)};c[c.length]=[e,a,d,j,r,f,g,h];try{this._simpleAdd(e,a,j,h)}catch(s){return this.lastError=s,this.removeListener(e,a,d),!1}return!0},_getType:function(e){return this._specialTypes[e]||
+e},addListener:function(e,a,b,d,f){var c=("focusin"==a||"focusout"==a)&&!YAHOO.env.ua.ie?!0:!1;return this._addListener(e,this._getType(a),b,d,f,c)},addFocusListener:function(e,a,b,d){return this.on(e,"focusin",a,b,d)},removeFocusListener:function(e,a){return this.removeListener(e,"focusin",a)},addBlurListener:function(e,a,b,d){return this.on(e,"focusout",a,b,d)},removeBlurListener:function(e,a){return this.removeListener(e,"focusout",a)},removeListener:function(e,a,d,f){var g,a=this._getType(a);
+if("string"==typeof e)e=this.getEl(e);else if(this._isValidCollection(e)){f=!0;for(g=e.length-1;-1<g;g--)f=this.removeListener(e[g],a,d)&&f;return f}if(!d||!d.call)return this.purgeElement(e,!1,a);if("unload"==a){for(g=b.length-1;-1<g;g--)if((f=b[g])&&f[0]==e&&f[1]==a&&f[2]==d)return b.splice(g,1),!0;return!1}g=null;"undefined"===typeof f&&(f=this._getCacheIndex(c,e,a,d));0<=f&&(g=c[f]);if(!e||!g)return!1;d=!0===g[this.CAPTURE]?!0:!1;try{this._simpleRemove(e,a,g[this.WFN],d)}catch(h){return this.lastError=
+h,!1}delete c[f][this.WFN];delete c[f][this.FN];c.splice(f,1);return!0},getTarget:function(e){return this.resolveTextNode(e.target||e.srcElement)},resolveTextNode:function(e){try{if(e&&3==e.nodeType)return e.parentNode}catch(a){return null}return e},getPageX:function(e){var a=e.pageX;!a&&0!==a&&(a=e.clientX||0,this.isIE&&(a+=this._getScrollLeft()));return a},getPageY:function(e){var a=e.pageY;!a&&0!==a&&(a=e.clientY||0,this.isIE&&(a+=this._getScrollTop()));return a},getXY:function(e){return[this.getPageX(e),
+this.getPageY(e)]},getRelatedTarget:function(e){var a=e.relatedTarget;a||("mouseout"==e.type?a=e.toElement:"mouseover"==e.type&&(a=e.fromElement));return this.resolveTextNode(a)},getTime:function(e){if(!e.time){var a=(new Date).getTime();try{e.time=a}catch(b){return this.lastError=b,a}}return e.time},stopEvent:function(e){this.stopPropagation(e);this.preventDefault(e)},stopPropagation:function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},preventDefault:function(e){e.preventDefault?
+e.preventDefault():e.returnValue=!1},getEvent:function(e){e=e||window.event;if(!e)for(var a=this.getEvent.caller;a&&!((e=a.arguments[0])&&Event==e.constructor);)a=a.caller;return e},getCharCode:function(e){e=e.keyCode||e.charCode||0;YAHOO.env.ua.webkit&&e in j&&(e=j[e]);return e},_getCacheIndex:function(e,a,b,d){for(var f=0,c=e.length;f<c;f+=1){var g=e[f];if(g&&g[this.FN]==d&&g[this.EL]==a&&g[this.TYPE]==b)return f}return-1},generateId:function(e){var a=e.id;a||(a="yuievtautoid-"+g,++g,e.id=a);return a},
+_isValidCollection:function(e){try{return e&&"string"!==typeof e&&e.length&&!e.tagName&&!e.alert&&"undefined"!==typeof e[0]}catch(a){return!1}},elCache:{},getEl:function(e){return"string"===typeof e?document.getElementById(e):e},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent("DOMReady",YAHOO,0,0,1),_load:function(){if(!a){a=!0;var e=YAHOO.util.Event;e._ready();e._tryPreloadAttach()}},_ready:function(){var e=YAHOO.util.Event;e.DOMReady||(e.DOMReady=!0,e.DOMReadyEvent.fire(),e._simpleRemove(document,
+"DOMContentLoaded",e._ready))},_tryPreloadAttach:function(){if(0===f.length)d=0,this._interval&&(this._interval.cancel(),this._interval=null);else if(!this.locked)if(this.isIE&&!this.DOMReady)this.startInterval();else{this.locked=!0;var e=!a;e||(e=0<d&&0<f.length);var i=[],b=function(e,a){var i=e;a.overrideContext&&(i=!0===a.overrideContext?a.obj:a.overrideContext);a.fn.call(i,a.obj)},c,g,h,j,o=[];c=0;for(g=f.length;c<g;c+=1)if(h=f[c])if(j=this.getEl(h.id))if(h.checkReady){if(a||j.nextSibling||!e)o.push(h),
+f[c]=null}else b(j,h),f[c]=null;else i.push(h);c=0;for(g=o.length;c<g;c+=1)h=o[c],b(this.getEl(h.id),h);d--;if(e){for(c=f.length-1;-1<c;c--)h=f[c],(!h||!h.id)&&f.splice(c,1);this.startInterval()}else this._interval&&(this._interval.cancel(),this._interval=null);this.locked=!1}},purgeElement:function(e,a,b){var e=YAHOO.lang.isString(e)?this.getEl(e):e,d=this.getListeners(e,b),f;if(d)for(f=d.length-1;-1<f;f--){var c=d[f];this.removeListener(e,c.type,c.fn)}if(a&&e&&e.childNodes){f=0;for(d=e.childNodes.length;f<
+d;++f)this.purgeElement(e.childNodes[f],a,b)}},getListeners:function(e,a){var d=[],f;a?"unload"===a?f=[b]:(a=this._getType(a),f=[c]):f=[c,b];for(var g=YAHOO.lang.isString(e)?this.getEl(e):e,h=0;h<f.length;h+=1){var j=f[h];if(j)for(var o=0,m=j.length;o<m;++o){var r=j[o];r&&(r[this.EL]===g&&(!a||a===r[this.TYPE]))&&d.push({type:r[this.TYPE],fn:r[this.FN],obj:r[this.OBJ],adjust:r[this.OVERRIDE],scope:r[this.ADJ_SCOPE],index:o})}}return d.length?d:null},_unload:function(e){var a=YAHOO.util.Event,d,f,
+g,h=b.slice(),j;d=0;for(g=b.length;d<g;++d)if(f=h[d]){try{j=window,f[a.ADJ_SCOPE]&&(j=!0===f[a.ADJ_SCOPE]?f[a.UNLOAD_OBJ]:f[a.ADJ_SCOPE]),f[a.FN].call(j,a.getEvent(e,f[a.EL]),f[a.UNLOAD_OBJ])}catch(o){}h[d]=null}b=null;if(c)for(e=c.length-1;-1<e;e--)if(f=c[e])try{a.removeListener(f[a.EL],f[a.TYPE],f[a.FN],e)}catch(m){}try{a._simpleRemove(window,"unload",a._unload),a._simpleRemove(window,"load",a._load)}catch(r){}},_getScrollLeft:function(){return this._getScroll()[1]},_getScrollTop:function(){return this._getScroll()[0]},
+_getScroll:function(){var e=document.documentElement,a=document.body;return e&&(e.scrollTop||e.scrollLeft)?[e.scrollTop,e.scrollLeft]:a?[a.scrollTop,a.scrollLeft]:[0,0]},regCE:function(){},_simpleAdd:function(){return window.addEventListener?function(e,a,b,d){e.addEventListener(a,b,d)}:window.attachEvent?function(e,a,b){e.attachEvent("on"+a,b)}:function(){}}(),_simpleRemove:function(){return window.removeEventListener?function(e,a,b,d){e.removeEventListener(a,b,d)}:window.detachEvent?function(e,a,
+b){e.detachEvent("on"+a,b)}:function(){}}()}}(),function(){var a=YAHOO.util.Event;a.on=a.addListener;a.onFocus=a.addFocusListener;a.onBlur=a.addBlurListener;if(a.isIE)if(self!==self.top)document.onreadystatechange=function(){"complete"==document.readyState&&(document.onreadystatechange=null,a._ready())};else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,!0);var c=document.createElement("p");a._dri=setInterval(function(){try{c.doScroll("left"),clearInterval(a._dri),
+a._dri=null,a._ready(),c=null}catch(b){}},a.POLL_INTERVAL)}else a.webkit&&525>a.webkit?a._dri=setInterval(function(){var b=document.readyState;if("loaded"==b||"complete"==b)clearInterval(a._dri),a._dri=null,a._ready()},a.POLL_INTERVAL):a._simpleAdd(document,"DOMContentLoaded",a._ready);a._simpleAdd(window,"load",a._load);a._simpleAdd(window,"unload",a._unload);a._tryPreloadAttach()}());YAHOO.util.EventProvider=function(){};
+YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(a,c,b,d){this.__yui_events=this.__yui_events||{};var f=this.__yui_events[a];if(f)f.subscribe(c,b,d);else{f=this.__yui_subscribers=this.__yui_subscribers||{};f[a]||(f[a]=[]);f[a].push({fn:c,obj:b,overrideContext:d})}},unsubscribe:function(a,c,b){var d=this.__yui_events=this.__yui_events||{};if(a){if(d=d[a])return d.unsubscribe(c,b)}else{var a=true,f;for(f in d)YAHOO.lang.hasOwnProperty(d,f)&&(a=a&&d[f].unsubscribe(c,
+b));return a}return false},unsubscribeAll:function(a){return this.unsubscribe(a)},createEvent:function(a,c){this.__yui_events=this.__yui_events||{};var b=c||{},d=this.__yui_events,f;if(!d[a]){f=new YAHOO.util.CustomEvent(a,b.scope||this,b.silent,YAHOO.util.CustomEvent.FLAT,b.fireOnce);d[a]=f;b.onSubscribeCallback&&f.subscribeEvent.subscribe(b.onSubscribeCallback);this.__yui_subscribers=this.__yui_subscribers||{};if(b=this.__yui_subscribers[a])for(var g=0;g<b.length;++g)f.subscribe(b[g].fn,b[g].obj,
+b[g].overrideContext)}return d[a]},fireEvent:function(a){this.__yui_events=this.__yui_events||{};var c=this.__yui_events[a];if(!c)return null;for(var b=[],d=1;d<arguments.length;++d)b.push(arguments[d]);return c.fire.apply(c,b)},hasEvent:function(a){return this.__yui_events&&this.__yui_events[a]?true:false}};
+(function(){var a=YAHOO.util.Event,c=YAHOO.lang;YAHOO.util.KeyListener=function(b,f,g,j){function h(b){if(!f.shift)f.shift=false;if(!f.alt)f.alt=false;if(!f.ctrl)f.ctrl=false;if(b.shiftKey==f.shift&&b.altKey==f.alt&&b.ctrlKey==f.ctrl){var d,c=f.keys,g;if(YAHOO.lang.isArray(c))for(var h=0;h<c.length;h++){d=c[h];g=a.getCharCode(b);if(d==g){e.fire(g,b);break}}else{g=a.getCharCode(b);c==g&&e.fire(g,b)}}}if(!j)j=YAHOO.util.KeyListener.KEYDOWN;var e=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=
+new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");c.isString(b)&&(b=document.getElementById(b));c.isFunction(g)?e.subscribe(g):e.subscribe(g.fn,g.scope,g.correctScope);this.enable=function(){if(!this.enabled){a.on(b,j,h);this.enabledEvent.fire(f)}this.enabled=true};this.disable=function(){if(this.enabled){a.removeListener(b,j,h);this.disabledEvent.fire(f)}this.enabled=false};this.toString=function(){return"KeyListener ["+f.keys+"] "+b.tagName+(b.id?"["+
+b.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.9.0",build:"2800"});
+YAHOO.util.Connect={_msxml_progid:["Microsoft.XMLHTTP","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP"],_http_headers:{},_has_http_headers:!1,_use_default_post_header:!0,_default_post_header:"application/x-www-form-urlencoded; charset=UTF-8",_default_form_header:"application/x-www-form-urlencoded",_use_default_xhr_header:!0,_default_xhr_header:"XMLHttpRequest",_has_default_headers:!0,_isFormSubmit:!1,_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;this._use_default_post_header=true}else if(typeof a=="boolean")this._use_default_post_header=a},setDefaultXhrHeader:function(a){typeof a=="string"?this._default_xhr_header=a:this._use_default_xhr_header=a},setPollingInterval:function(a){if(typeof a=="number"&&isFinite(a))this._polling_interval=a},createXhrObject:function(a){var c,b,d;try{b=new XMLHttpRequest;c={conn:b,tId:a,xhr:true}}catch(f){for(d=0;d<this._msxml_progid.length;++d)try{b=new ActiveXObject(this._msxml_progid[d]);
+c={conn:b,tId:a,xhr:true};break}catch(g){}}finally{return c}},getConnectionObject:function(a){var c,b=this._transaction_id;try{if(a){c={tId:b};if(a==="xdr"){c.conn=this._transport;c.xdr=true}else if(a==="upload")c.upload=true}else c=this.createXhrObject(b);c&&this._transaction_id++}catch(d){}return c},asyncRequest:function(a,c,b,d){var f=b&&b.argument?b.argument:null,g=this,j,h;this._isFileUpload?h="upload":b&&b.xdr&&(h="xdr");j=this.getConnectionObject(h);if(!j)return null;b&&b.customevents&&this.initCustomEvents(j,
+b);if(this._isFormSubmit){if(this._isFileUpload){window.setTimeout(function(){g.uploadFile(j,b,c,d)},10);return j}a.toUpperCase()=="GET"?this._sFormData.length!==0&&(c=c+((c.indexOf("?")==-1?"?":"&")+this._sFormData)):a.toUpperCase()=="POST"&&(d=d?this._sFormData+"&"+d:this._sFormData)}a.toUpperCase()=="GET"&&(b&&b.cache===false)&&(c=c+((c.indexOf("?")==-1?"?":"&")+"rnd="+(new Date).valueOf().toString()));this._use_default_xhr_header&&(this._default_headers["X-Requested-With"]||this.initHeader("X-Requested-With",
+this._default_xhr_header,true));a.toUpperCase()==="POST"&&this._use_default_post_header&&this._isFormSubmit===false&&this.initHeader("Content-Type",this._default_post_header);if(j.xdr){this.xdr(j,a,c,b,d);return j}j.conn.open(a,c,true);(this._has_default_headers||this._has_http_headers)&&this.setHeader(j);this.handleReadyState(j,b);j.conn.send(d||"");this._isFormSubmit===true&&this.resetFormState();this.startEvent.fire(j,f);j.startEvent&&j.startEvent.fire(j,f);return j},initCustomEvents:function(a,
+c){for(var 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(a,c){var b=this,d=c&&c.argument?c.argument:null;c&&c.timeout&&(this._timeOut[a.tId]=window.setTimeout(function(){b.abort(a,c,true)},c.timeout));this._poll[a.tId]=window.setInterval(function(){if(a.conn&&a.conn.readyState===4){window.clearInterval(b._poll[a.tId]);
+delete b._poll[a.tId];if(c&&c.timeout){window.clearTimeout(b._timeOut[a.tId]);delete b._timeOut[a.tId]}b.completeEvent.fire(a,d);a.completeEvent&&a.completeEvent.fire(a,d);b.handleTransactionResponse(a,c)}},this._polling_interval)},handleTransactionResponse:function(a,c,b){var d,f=c&&c.argument?c.argument:null,g=a.r&&a.r.statusText==="xdr:success"?true:false,j=a.r&&a.r.statusText==="xdr:failure"?true:false;try{d=a.conn.status!==void 0&&a.conn.status!==0||g?a.conn.status:j&&!b?0:13030}catch(h){d=13030}if(d>=
+200&&d<300||d===1223||g){b=a.xdr?a.r:this.createResponseObject(a,f);c&&c.success&&(c.scope?c.success.apply(c.scope,[b]):c.success(b));this.successEvent.fire(b);a.successEvent&&a.successEvent.fire(b)}else{switch(d){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:b=this.createExceptionObject(a.tId,f,b?b:false);c&&c.failure&&(c.scope?c.failure.apply(c.scope,[b]):c.failure(b));break;default:b=a.xdr?a.response:this.createResponseObject(a,f);c&&c.failure&&(c.scope?c.failure.apply(c.scope,
+[b]):c.failure(b))}this.failureEvent.fire(b);a.failureEvent&&a.failureEvent.fire(b)}this.releaseObject(a)},createResponseObject:function(a,c){var b={},d={},f,g,j,h;try{g=a.conn.getAllResponseHeaders();j=g.split("\n");for(f=0;f<j.length;f++){h=j[f].indexOf(":");h!=-1&&(d[j[f].substring(0,h)]=YAHOO.lang.trim(j[f].substring(h+2)))}}catch(e){}b.tId=a.tId;b.status=a.conn.status==1223?204:a.conn.status;b.statusText=a.conn.status==1223?"No Content":a.conn.statusText;b.getResponseHeader=d;b.getAllResponseHeaders=
+g;b.responseText=a.conn.responseText;b.responseXML=a.conn.responseXML;if(c)b.argument=c;return b},createExceptionObject:function(a,c,b){var d={};d.tId=a;if(b){d.status=-1;d.statusText="transaction aborted"}else{d.status=0;d.statusText="communication failure"}if(c)d.argument=c;return d},initHeader:function(a,c,b){(b?this._default_headers:this._http_headers)[a]=c;b?this._has_default_headers=true:this._has_http_headers=true},setHeader:function(a){var c;if(this._has_default_headers)for(c in this._default_headers)YAHOO.lang.hasOwnProperty(this._default_headers,
+c)&&a.conn.setRequestHeader(c,this._default_headers[c]);if(this._has_http_headers){for(c in this._http_headers)YAHOO.lang.hasOwnProperty(this._http_headers,c)&&a.conn.setRequestHeader(c,this._http_headers[c]);this._http_headers={};this._has_http_headers=false}},resetDefaultHeaders:function(){this._default_headers={};this._has_default_headers=false},abort:function(a,c,b){var d,f=c&&c.argument?c.argument:null,a=a||{};if(a.conn)if(a.xhr){if(this.isCallInProgress(a)){a.conn.abort();window.clearInterval(this._poll[a.tId]);
+delete this._poll[a.tId];if(b){window.clearTimeout(this._timeOut[a.tId]);delete this._timeOut[a.tId]}d=true}}else{if(a.xdr){a.conn.abort(a.tId);d=true}}else if(a.upload){var g=document.getElementById("yuiIO"+a.tId);if(g){YAHOO.util.Event.removeListener(g,"load");document.body.removeChild(g);if(b){window.clearTimeout(this._timeOut[a.tId]);delete this._timeOut[a.tId]}d=true}}else d=false;if(d===true){this.abortEvent.fire(a,f);a.abortEvent&&a.abortEvent.fire(a,f);this.handleTransactionResponse(a,c,true)}return d},
+isCallInProgress:function(a){a=a||{};return a.xhr&&a.conn?a.conn.readyState!==4&&a.conn.readyState!==0:a.xdr&&a.conn?a.conn.isCallInProgress(a.tId):a.upload===true?document.getElementById("yuiIO"+a.tId)?true:false:false},releaseObject:function(a){if(a&&a.conn)a.conn=null}};
+(function(){function a(a){var a='<object id="YUIConnectionSwf" type="application/x-shockwave-flash" data="'+a+'" width="0" height="0"><param name="movie" value="'+a+'"><param name="allowScriptAccess" value="always"></object>',b=document.createElement("div");document.body.appendChild(b);b.innerHTML=a}var c=YAHOO.util.Connect,b={};c.xdr=function(a,f,c,j,h){b[parseInt(a.tId)]={o:a,c:j};if(h){j.method=f;j.data=h}a.conn.send(c,j,a.tId)};c.swf=a;c.transport=function(b){a(b);c._transport=document.getElementById("YUIConnectionSwf")};
+c.xdrReadyEvent=new YAHOO.util.CustomEvent("xdrReady");c.xdrReady=function(){c.xdrReadyEvent.fire()};c.handleXdrResponse=function(a){var f=b[a.tId].o,g=b[a.tId].c;if(a.statusText==="xdr:start"){if(f){c.startEvent.fire(f,g.argument);f.startEvent&&f.startEvent.fire(f,g.argument)}}else{a.responseText=decodeURI(a.responseText);f.r=a;if(g.argument)f.r.argument=g.argument;this.handleTransactionResponse(f,g,a.statusText==="xdr:abort"?true:false);delete b[a.tId]}}})();
+(function(){var a=YAHOO.util.Connect,c=YAHOO.util.Event,b=document.documentMode?document.documentMode:false;a._isFileUpload=false;a._formNode=null;a._sFormData=null;a._submitElementValue=null;a.uploadEvent=new YAHOO.util.CustomEvent("upload");a._hasSubmitListener=function(){if(c){c.addListener(document,"click",function(b){var b=c.getTarget(b),f=b.nodeName.toLowerCase();if((f==="input"||f==="button")&&b.type&&b.type.toLowerCase()=="submit")a._submitElementValue=encodeURIComponent(b.name)+"="+encodeURIComponent(b.value)});
+return true}return false}();a.setForm=function(a,b,c){var j,h=false,e=[],i=0,k,l,q,p;this.resetFormState();if(typeof a=="string")a=document.getElementById(a)||document.forms[a];else if(typeof a!="object")return;if(b){this.createFrame(c?c:null);this._isFileUpload=this._isFormSubmit=true;this._formNode=a}else{k=0;for(l=a.elements.length;k<l;++k){b=a.elements[k];j=b.disabled;c=b.name;if(!j&&c){c=encodeURIComponent(c)+"=";j=encodeURIComponent(b.value);switch(b.type){case "select-one":if(b.selectedIndex>
+-1){p=b.options[b.selectedIndex];e[i++]=c+encodeURIComponent(p.attributes.value&&p.attributes.value.specified?p.value:p.text)}break;case "select-multiple":if(b.selectedIndex>-1){j=b.selectedIndex;for(q=b.options.length;j<q;++j){p=b.options[j];p.selected&&(e[i++]=c+encodeURIComponent(p.attributes.value&&p.attributes.value.specified?p.value:p.text))}}break;case "radio":case "checkbox":b.checked&&(e[i++]=c+j);break;case "file":case void 0:case "reset":case "button":break;case "submit":if(h===false){if(this._hasSubmitListener&&
+this._submitElementValue)e[i++]=this._submitElementValue;h=true}break;default:e[i++]=c+j}}}this._isFormSubmit=true;this._sFormData=e.join("&");this.initHeader("Content-Type",this._default_form_header);return this._sFormData}};a.resetFormState=function(){this._isFileUpload=this._isFormSubmit=false;this._formNode=null;this._sFormData=""};a.createFrame=function(a){var f="yuiIO"+this._transaction_id,c=b===9?true:false;if(YAHOO.env.ua.ie&&!c){c=document.createElement('<iframe id="'+f+'" name="'+f+'" />');
+if(typeof a=="boolean")c.src="javascript:false"}else{c=document.createElement("iframe");c.id=f;c.name=f}c.style.position="absolute";c.style.top="-1000px";c.style.left="-1000px";document.body.appendChild(c)};a.appendPostData=function(a){var b=[],a=a.split("&"),c,j;for(c=0;c<a.length;c++){j=a[c].indexOf("=");if(j!=-1){b[c]=document.createElement("input");b[c].type="hidden";b[c].name=decodeURIComponent(a[c].substring(0,j));b[c].value=decodeURIComponent(a[c].substring(j+1));this._formNode.appendChild(b[c])}}return b};
+a.uploadFile=function(a,f,g,j){var h="yuiIO"+a.tId,e=document.getElementById(h),i=b>=8?true:false,k=this,l=f&&f.argument?f.argument:null,q,p,n,o,m;o={action:this._formNode.getAttribute("action"),method:this._formNode.getAttribute("method"),target:this._formNode.getAttribute("target")};this._formNode.setAttribute("action",g);this._formNode.setAttribute("method","POST");this._formNode.setAttribute("target",h);YAHOO.env.ua.ie&&!i?this._formNode.setAttribute("encoding","multipart/form-data"):this._formNode.setAttribute("enctype",
+"multipart/form-data");j&&(q=this.appendPostData(j));this._formNode.submit();this.startEvent.fire(a,l);a.startEvent&&a.startEvent.fire(a,l);f&&f.timeout&&(this._timeOut[a.tId]=window.setTimeout(function(){k.abort(a,f,true)},f.timeout));if(q&&q.length>0)for(g=0;g<q.length;g++)this._formNode.removeChild(q[g]);for(p in o)YAHOO.lang.hasOwnProperty(o,p)&&(o[p]?this._formNode.setAttribute(p,o[p]):this._formNode.removeAttribute(p));this.resetFormState();m=function(){var b,i,g;if(f&&f.timeout){window.clearTimeout(k._timeOut[a.tId]);
+delete k._timeOut[a.tId]}k.completeEvent.fire(a,l);a.completeEvent&&a.completeEvent.fire(a,l);n={tId:a.tId,argument:l};try{b=e.contentWindow.document.getElementsByTagName("body")[0];i=e.contentWindow.document.getElementsByTagName("pre")[0];b&&(g=i?i.textContent?i.textContent:i.innerText:b.textContent?b.textContent:b.innerText);n.responseText=g;n.responseXML=e.contentWindow.document.XMLDocument?e.contentWindow.document.XMLDocument:e.contentWindow.document}catch(h){}f&&f.upload&&(f.scope?f.upload.apply(f.scope,
+[n]):f.upload(n));k.uploadEvent.fire(n);a.uploadEvent&&a.uploadEvent.fire(n);c.removeListener(e,"load",m);setTimeout(function(){document.body.removeChild(e);k.releaseObject(a)},100)};c.addListener(e,"load",m)}})();YAHOO.register("connection",YAHOO.util.Connect,{version:"2.9.0",build:"2800"});
+(function(){var a=YAHOO.util,c=function(a,d,f,c){this.init(a,d,f,c)};c.NAME="Anim";c.prototype={toString:function(){var a=this.getEl()||{};return this.constructor.NAME+": "+(a.id||a.tagName)},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(a,d,f){return this.method(this.currentFrame,d,f-d,this.totalFrames)},setAttribute:function(b,
+d,f){var c=this.getEl();this.patterns.noNegatives.test(b)&&(d=d>0?d:0);b in c&&!("style"in c&&b in c.style)?c[b]=d:a.Dom.setStyle(c,b,d+f)},getAttribute:function(b){var d=this.getEl(),f=a.Dom.getStyle(d,b);if(f!=="auto"&&!this.patterns.offsetUnit.test(f))return parseFloat(f);var c=this.patterns.offsetAttribute.exec(b)||[],j=!!c[3],h=!!c[2];"style"in d?f=h||a.Dom.getStyle(d,"position")=="absolute"&&j?d["offset"+c[0].charAt(0).toUpperCase()+c[0].substr(1)]:0:b in d&&(f=d[b]);return f},getDefaultUnit:function(a){return this.patterns.defaultUnit.test(a)?
+"px":""},setRuntimeAttribute:function(a){var d,f,c=this.attributes;this.runtimeAttributes[a]={};var j=function(e){return typeof e!=="undefined"};if(!j(c[a].to)&&!j(c[a].by))return false;d=j(c[a].from)?c[a].from:this.getAttribute(a);if(j(c[a].to))f=c[a].to;else if(j(c[a].by))if(d.constructor==Array){f=[];for(var h=0,e=d.length;h<e;++h)f[h]=d[h]+c[a].by[h]*1}else f=d+c[a].by*1;this.runtimeAttributes[a].start=d;this.runtimeAttributes[a].end=f;this.runtimeAttributes[a].unit=j(c[a].unit)?c[a].unit:this.getDefaultUnit(a);
+return true},init:function(b,d,f,c){var j=false,h=null,e=0,b=a.Dom.get(b);this.attributes=d||{};this.duration=!YAHOO.lang.isUndefined(f)?f:1;this.method=c||a.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=a.AnimMgr.fps;this.setEl=function(e){b=a.Dom.get(e)};this.getEl=function(){return b};this.isAnimated=function(){return j};this.getStartTime=function(){return h};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated())return false;this.currentFrame=0;this.totalFrames=
+this.useSeconds?Math.ceil(a.AnimMgr.fps*this.duration):this.duration;if(this.duration===0&&this.useSeconds)this.totalFrames=1;a.AnimMgr.registerElement(this);return true};this.stop=function(e){if(!this.isAnimated())return false;if(e){this.currentFrame=this.totalFrames;this._onTween.fire()}a.AnimMgr.stop(this)};this._handleStart=function(){this.onStart.fire();this.runtimeAttributes={};for(var a in this.attributes)this.attributes.hasOwnProperty(a)&&this.setRuntimeAttribute(a);j=true;e=0;h=new Date};
+this._handleTween=function(){var a={duration:new Date-this.getStartTime(),currentFrame:this.currentFrame,toString:function(){return"duration: "+a.duration+", currentFrame: "+a.currentFrame}};this.onTween.fire(a);var b=this.runtimeAttributes,d;for(d in b)b.hasOwnProperty(d)&&this.setAttribute(d,this.doMethod(d,b[d].start,b[d].end),b[d].unit);this.afterTween.fire(a);e=e+1};this._handleComplete=function(){var a=(new Date-h)/1E3,b={duration:a,frames:e,fps:e/a,toString:function(){return"duration: "+b.duration+
+", frames: "+b.frames+", fps: "+b.fps}};j=false;e=0;this.onComplete.fire(b)};this._onStart=new a.CustomEvent("_start",this,true);this.onStart=new a.CustomEvent("start",this);this.onTween=new a.CustomEvent("tween",this);this.afterTween=new a.CustomEvent("afterTween",this);this._onTween=new a.CustomEvent("_tween",this,true);this.onComplete=new a.CustomEvent("complete",this);this._onComplete=new a.CustomEvent("_complete",this,true);this._onStart.subscribe(this._handleStart);this._onTween.subscribe(this._handleTween);
+this._onComplete.subscribe(this._handleComplete)}};a.Anim=c})();
+YAHOO.util.AnimMgr=new function(){var a=null,c=[],b=0;this.fps=1E3;this.delay=20;this.registerElement=function(e){c[c.length]=e;b=b+1;e._onStart.fire();this.start()};var d=[],f=false,g=function(){var e=d.shift();j.apply(YAHOO.util.AnimMgr,e);d.length&&arguments.callee()},j=function(e,a){a=a||h(e);if(!e.isAnimated()||a===-1)return false;e._onComplete.fire();c.splice(a,1);b=b-1;b<=0&&this.stop();return true};this.unRegister=function(){d.push(arguments);if(!f){f=true;g();f=false}};this.start=function(){a===
+null&&(a=setInterval(this.run,this.delay))};this.stop=function(e){if(e)this.unRegister(e);else{clearInterval(a);for(var e=0,i=c.length;e<i;++e)this.unRegister(c[0],0);c=[];a=null;b=0}};this.run=function(){for(var e=0,a=c.length;e<a;++e){var b=c[e];if(b&&b.isAnimated())if(b.currentFrame<b.totalFrames||b.totalFrames===null){b.currentFrame=b.currentFrame+1;if(b.useSeconds){var d=b,f=d.totalFrames,g=d.currentFrame,h=d.currentFrame*d.duration*1E3/d.totalFrames,j=new Date-d.getStartTime(),m=0,m=j<d.duration*
+1E3?Math.round((j/h-1)*d.currentFrame):f-(g+1);if(m>0&&isFinite(m)){d.currentFrame+m>=f&&(m=f-(g+1));d.currentFrame=d.currentFrame+m}}b._onTween.fire()}else YAHOO.util.AnimMgr.stop(b,e)}};var h=function(e){for(var a=0,b=c.length;a<b;++a)if(c[a]===e)return a;return-1};this._queue=c;this._getIndex=h};
+YAHOO.util.Bezier=new function(){this.getPosition=function(a,c){for(var b=a.length,d=[],f=0;f<b;++f)d[f]=[a[f][0],a[f][1]];for(var g=1;g<b;++g)for(f=0;f<b-g;++f){d[f][0]=(1-c)*d[f][0]+c*d[parseInt(f+1,10)][0];d[f][1]=(1-c)*d[f][1]+c*d[parseInt(f+1,10)][1]}return[d[0][0],d[0][1]]}};
+(function(){var a=function(b,d,c,h){a.superclass.constructor.call(this,b,d,c,h)};a.NAME="ColorAnim";a.DEFAULT_BGCOLOR="#fff";var c=YAHOO.util;YAHOO.extend(a,c.Anim);var b=a.superclass,d=a.prototype;d.patterns.color=/color$/i;d.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;d.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;d.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;d.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;d.parseColor=function(a){if(a.length==
+3)return a;var b=this.patterns.hex.exec(a);if(b&&b.length==4)return[parseInt(b[1],16),parseInt(b[2],16),parseInt(b[3],16)];if((b=this.patterns.rgb.exec(a))&&b.length==4)return[parseInt(b[1],10),parseInt(b[2],10),parseInt(b[3],10)];return(b=this.patterns.hex3.exec(a))&&b.length==4?[parseInt(b[1]+b[1],16),parseInt(b[2]+b[2],16),parseInt(b[3]+b[3],16)]:null};d.getAttribute=function(d){var g=this.getEl();if(this.patterns.color.test(d)){var j=YAHOO.util.Dom.getStyle(g,d),h=this;if(this.patterns.transparent.test(j))j=
+(g=YAHOO.util.Dom.getAncestorBy(g,function(){return!h.patterns.transparent.test(j)}))?c.Dom.getStyle(g,d):a.DEFAULT_BGCOLOR}else j=b.getAttribute.call(this,d);return j};d.doMethod=function(a,d,c){var h;if(this.patterns.color.test(a)){h=[];for(var e=0,i=d.length;e<i;++e)h[e]=b.doMethod.call(this,a,d[e],c[e]);h="rgb("+Math.floor(h[0])+","+Math.floor(h[1])+","+Math.floor(h[2])+")"}else h=b.doMethod.call(this,a,d,c);return h};d.setRuntimeAttribute=function(a){b.setRuntimeAttribute.call(this,a);if(this.patterns.color.test(a)){var d=
+this.attributes,c=this.parseColor(this.runtimeAttributes[a].start),h=this.parseColor(this.runtimeAttributes[a].end);if(typeof d[a].to==="undefined"&&typeof d[a].by!=="undefined")for(var h=this.parseColor(d[a].by),d=0,e=c.length;d<e;++d)h[d]=c[d]+h[d];this.runtimeAttributes[a].start=c;this.runtimeAttributes[a].end=h}};c.ColorAnim=a})();
+YAHOO.util.Easing={easeNone:function(a,c,b,d){return b*a/d+c},easeIn:function(a,c,b,d){return b*(a=a/d)*a+c},easeOut:function(a,c,b,d){return-b*(a=a/d)*(a-2)+c},easeBoth:function(a,c,b,d){return(a=a/(d/2))<1?b/2*a*a+c:-b/2*(--a*(a-2)-1)+c},easeInStrong:function(a,c,b,d){return b*(a=a/d)*a*a*a+c},easeOutStrong:function(a,c,b,d){return-b*((a=a/d-1)*a*a*a-1)+c},easeBothStrong:function(a,c,b,d){return(a=a/(d/2))<1?b/2*a*a*a*a+c:-b/2*((a=a-2)*a*a*a-2)+c},elasticIn:function(a,c,b,d,f,g){if(a==0)return c;
+if((a=a/d)==1)return c+b;g||(g=d*0.3);if(!f||f<Math.abs(b)){f=b;b=g/4}else b=g/(2*Math.PI)*Math.asin(b/f);return-(f*Math.pow(2,10*(a=a-1))*Math.sin((a*d-b)*2*Math.PI/g))+c},elasticOut:function(a,c,b,d,f,g){if(a==0)return c;if((a=a/d)==1)return c+b;g||(g=d*0.3);if(!f||f<Math.abs(b))var f=b,j=g/4;else j=g/(2*Math.PI)*Math.asin(b/f);return f*Math.pow(2,-10*a)*Math.sin((a*d-j)*2*Math.PI/g)+b+c},elasticBoth:function(a,c,b,d,f,g){if(a==0)return c;if((a=a/(d/2))==2)return c+b;g||(g=d*0.3*1.5);if(!f||f<Math.abs(b))var f=
+b,j=g/4;else j=g/(2*Math.PI)*Math.asin(b/f);return a<1?-0.5*f*Math.pow(2,10*(a=a-1))*Math.sin((a*d-j)*2*Math.PI/g)+c:f*Math.pow(2,-10*(a=a-1))*Math.sin((a*d-j)*2*Math.PI/g)*0.5+b+c},backIn:function(a,c,b,d,f){typeof f=="undefined"&&(f=1.70158);return b*(a=a/d)*a*((f+1)*a-f)+c},backOut:function(a,c,b,d,f){typeof f=="undefined"&&(f=1.70158);return b*((a=a/d-1)*a*((f+1)*a+f)+1)+c},backBoth:function(a,c,b,d,f){typeof f=="undefined"&&(f=1.70158);return(a=a/(d/2))<1?b/2*a*a*(((f=f*1.525)+1)*a-f)+c:b/2*
+((a=a-2)*a*(((f=f*1.525)+1)*a+f)+2)+c},bounceIn:function(a,c,b,d){return b-YAHOO.util.Easing.bounceOut(d-a,0,b,d)+c},bounceOut:function(a,c,b,d){return(a=a/d)<1/2.75?b*7.5625*a*a+c:a<2/2.75?b*(7.5625*(a=a-1.5/2.75)*a+0.75)+c:a<2.5/2.75?b*(7.5625*(a=a-2.25/2.75)*a+0.9375)+c:b*(7.5625*(a=a-2.625/2.75)*a+0.984375)+c},bounceBoth:function(a,c,b,d){return a<d/2?YAHOO.util.Easing.bounceIn(a*2,0,b,d)*0.5+c:YAHOO.util.Easing.bounceOut(a*2-d,0,b,d)*0.5+b*0.5+c}};
+(function(){var a=function(b,d,e,i){b&&a.superclass.constructor.call(this,b,d,e,i)};a.NAME="Motion";var c=YAHOO.util;YAHOO.extend(a,c.ColorAnim);var b=a.superclass,d=a.prototype;d.patterns.points=/^points$/i;d.setAttribute=function(a,d,e){if(this.patterns.points.test(a)){e=e||"px";b.setAttribute.call(this,"left",d[0],e);b.setAttribute.call(this,"top",d[1],e)}else b.setAttribute.call(this,a,d,e)};d.getAttribute=function(a){return this.patterns.points.test(a)?[b.getAttribute.call(this,"left"),b.getAttribute.call(this,
+"top")]:b.getAttribute.call(this,a)};d.doMethod=function(a,d,e){var i=null;if(this.patterns.points.test(a)){d=this.method(this.currentFrame,0,100,this.totalFrames)/100;i=c.Bezier.getPosition(this.runtimeAttributes[a],d)}else i=b.doMethod.call(this,a,d,e);return i};d.setRuntimeAttribute=function(a){if(this.patterns.points.test(a)){var d=this.getEl(),e=this.attributes,i=e.points.control||[],k,l,q;if(i.length>0&&!(i[0]instanceof Array))i=[i];else{var p=[];l=0;for(q=i.length;l<q;++l)p[l]=i[l];i=p}c.Dom.getStyle(d,
+"position")=="static"&&c.Dom.setStyle(d,"position","relative");g(e.points.from)?c.Dom.setXY(d,e.points.from):c.Dom.setXY(d,c.Dom.getXY(d));d=this.getAttribute("points");if(g(e.points.to)){k=f.call(this,e.points.to,d);c.Dom.getXY(this.getEl());l=0;for(q=i.length;l<q;++l)i[l]=f.call(this,i[l],d)}else if(g(e.points.by)){k=[d[0]+e.points.by[0],d[1]+e.points.by[1]];l=0;for(q=i.length;l<q;++l)i[l]=[d[0]+i[l][0],d[1]+i[l][1]]}this.runtimeAttributes[a]=[d];i.length>0&&(this.runtimeAttributes[a]=this.runtimeAttributes[a].concat(i));
+this.runtimeAttributes[a][this.runtimeAttributes[a].length]=k}else b.setRuntimeAttribute.call(this,a)};var f=function(a,b){var e=c.Dom.getXY(this.getEl());return a=[a[0]-e[0]+b[0],a[1]-e[1]+b[1]]},g=function(a){return typeof a!=="undefined"};c.Motion=a})();
+(function(){var a=function(b,d,c,h){b&&a.superclass.constructor.call(this,b,d,c,h)};a.NAME="Scroll";var c=YAHOO.util;YAHOO.extend(a,c.ColorAnim);var b=a.superclass,d=a.prototype;d.doMethod=function(a,d,c){var h=null;return h=a=="scroll"?[this.method(this.currentFrame,d[0],c[0]-d[0],this.totalFrames),this.method(this.currentFrame,d[1],c[1]-d[1],this.totalFrames)]:b.doMethod.call(this,a,d,c)};d.getAttribute=function(a){var d=null,d=this.getEl();return d=a=="scroll"?[d.scrollLeft,d.scrollTop]:b.getAttribute.call(this,
+a)};d.setAttribute=function(a,d,c){var h=this.getEl();if(a=="scroll"){h.scrollLeft=d[0];h.scrollTop=d[1]}else b.setAttribute.call(this,a,d,c)};c.Scroll=a})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.9.0",build:"2800"});
+YAHOO.util.DragDropMgr||(YAHOO.util.DragDropMgr=function(){var a=YAHOO.util.Event,c=YAHOO.util.Dom;return{useShim:false,_shimActive:false,_shimState:false,_debugShim:false,_createShim:function(){var b=document.createElement("div");b.id="yui-ddm-shim";document.body.firstChild?document.body.insertBefore(b,document.body.firstChild):document.body.appendChild(b);b.style.display="none";b.style.backgroundColor="red";b.style.position="absolute";b.style.zIndex="99999";c.setStyle(b,"opacity","0");this._shim=
+b;a.on(b,"mouseup",this.handleMouseUp,this,true);a.on(b,"mousemove",this.handleMouseMove,this,true);a.on(window,"scroll",this._sizeShim,this,true)},_sizeShim:function(){if(this._shimActive){var a=this._shim;a.style.height=c.getDocumentHeight()+"px";a.style.width=c.getDocumentWidth()+"px";a.style.top="0";a.style.left="0"}},_activateShim:function(){if(this.useShim){this._shim||this._createShim();this._shimActive=true;var a=this._shim,d="0";this._debugShim&&(d=".5");c.setStyle(a,"opacity",d);this._sizeShim();
+a.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(a,d){for(var f in this.ids)for(var c in this.ids[f]){var j=this.ids[f][c];this.isTypeOfDD(j)&&j[a].apply(j,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(){this._execOnAll("resetConstraints",[])},lock:function(){this.locked=true},unlock:function(){this.locked=false},isLocked:function(){return this.locked},locationCache:{},useCache:true,clickPixelThresh:3,clickTimeThresh:1E3,dragThreshMet:false,clickTimeout:null,startX:0,startY:0,
+fromTimeout:false,regDragDrop:function(a,d){this.initialized||this.init();this.ids[d]||(this.ids[d]={});this.ids[d][a.id]=a},removeDDFromGroup:function(a,d){this.ids[d]||(this.ids[d]={});var f=this.ids[d];f&&f[a.id]&&delete f[a.id]},_remove:function(a){for(var d in a.groups)if(d){var f=this.ids[d];f&&f[a.id]&&delete f[a.id]}delete this.handleIds[a.id]},regHandle:function(a,d){this.handleIds[a]||(this.handleIds[a]={});this.handleIds[a][d]=d},isDragDrop:function(a){return this.getDDById(a)?true:false},
+getRelated:function(a,d){var f=[],c;for(c in a.groups)for(var j in this.ids[c]){var h=this.ids[c][j];if(this.isTypeOfDD(h)&&(!d||h.isTarget))f[f.length]=h}return f},isLegalTarget:function(a,d){for(var f=this.getRelated(a,true),c=0,j=f.length;c<j;++c)if(f[c].id==d.id)return true;return false},isTypeOfDD:function(a){return a&&a.__ygDragDrop},isHandle:function(a,d){return this.handleIds[a]&&this.handleIds[a][d]},getDDById:function(a){for(var d in this.ids)if(this.ids[d][a])return this.ids[d][a];return null},
+handleMouseDown:function(a,d){this.currentTarget=YAHOO.util.Event.getTarget(a);this.dragCurrent=d;var f=d.getEl();this.startX=YAHOO.util.Event.getPageX(a);this.startY=YAHOO.util.Event.getPageY(a);this.deltaX=this.startX-f.offsetLeft;this.deltaY=this.startY-f.offsetTop;this.dragThreshMet=false;this.clickTimeout=setTimeout(function(){var a=YAHOO.util.DDM;a.startDrag(a.startX,a.startY);a.fromTimeout=true},this.clickTimeThresh)},startDrag:function(a,d){if(this.dragCurrent&&this.dragCurrent.useShim){this._shimState=
+this.useShim;this.useShim=true}this._activateShim();clearTimeout(this.clickTimeout);var f=this.dragCurrent;if(f&&f.events.b4StartDrag){f.b4StartDrag(a,d);f.fireEvent("b4StartDragEvent",{x:a,y:d})}if(f&&f.events.startDrag){f.startDrag(a,d);f.fireEvent("startDragEvent",{x:a,y:d})}this.dragThreshMet=true},handleMouseUp:function(a){if(this.dragCurrent){clearTimeout(this.clickTimeout);if(this.dragThreshMet){if(this.fromTimeout){this.fromTimeout=false;this.handleMouseMove(a)}this.fromTimeout=false;this.fireEvents(a,
+true)}this.stopDrag(a);this.stopEvent(a)}},stopEvent:function(a){this.stopPropagation&&YAHOO.util.Event.stopPropagation(a);this.preventDefault&&YAHOO.util.Event.preventDefault(a)},stopDrag:function(a,d){var f=this.dragCurrent;if(f&&!d){if(this.dragThreshMet){if(f.events.b4EndDrag){f.b4EndDrag(a);f.fireEvent("b4EndDragEvent",{e:a})}if(f.events.endDrag){f.endDrag(a);f.fireEvent("endDragEvent",{e:a})}}if(f.events.mouseUp){f.onMouseUp(a);f.fireEvent("mouseUpEvent",{e:a})}}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(a){var d=this.dragCurrent;if(d){if(YAHOO.env.ua.ie&&YAHOO.env.ua.ie<9&&!a.button){this.stopEvent(a);return this.handleMouseUp(a)}if(!this.dragThreshMet){var f=Math.abs(this.startX-YAHOO.util.Event.getPageX(a)),c=Math.abs(this.startY-YAHOO.util.Event.getPageY(a));(f>this.clickPixelThresh||c>this.clickPixelThresh)&&this.startDrag(this.startX,
+this.startY)}if(this.dragThreshMet){if(d&&d.events.b4Drag){d.b4Drag(a);d.fireEvent("b4DragEvent",{e:a})}if(d&&d.events.drag){d.onDrag(a);d.fireEvent("dragEvent",{e:a})}d&&this.fireEvents(a,false)}this.stopEvent(a)}},fireEvents:function(a,d){var f=this.dragCurrent;if(f&&!f.isLocked()&&!f.dragOnly){var c=YAHOO.util.Event.getPageX(a),j=YAHOO.util.Event.getPageY(a),h=new YAHOO.util.Point(c,j),j=f.getTargetCoord(h.x,h.y),e=f.getDragEl(),c=["out","over","drop","enter"],i=new YAHOO.util.Region(j.y,j.x+e.offsetWidth,
+j.y+e.offsetHeight,j.x),k=[],l={},j={},e=[],q={outEvts:[],overEvts:[],dropEvts:[],enterEvts:[]},p;for(p in this.dragOvers){var n=this.dragOvers[p];if(this.isTypeOfDD(n)){this.isOverTarget(h,n,this.mode,i)||q.outEvts.push(n);k[p]=true;delete this.dragOvers[p]}}for(var o in f.groups)if("string"==typeof o)for(p in this.ids[o]){n=this.ids[o][p];if(this.isTypeOfDD(n)&&n.isTarget&&(!n.isLocked()&&n!=f)&&this.isOverTarget(h,n,this.mode,i)){l[o]=true;if(d)q.dropEvts.push(n);else{k[n.id]?q.overEvts.push(n):
+q.enterEvts.push(n);this.dragOvers[n.id]=n}}}this.interactionInfo={out:q.outEvts,enter:q.enterEvts,over:q.overEvts,drop:q.dropEvts,point:h,draggedRegion:i,sourceRegion:this.locationCache[f.id],validDrop:d};for(var m in l)e.push(m);if(d&&!q.dropEvts.length){this.interactionInfo.validDrop=false;if(f.events.invalidDrop){f.onInvalidDrop(a);f.fireEvent("invalidDropEvent",{e:a})}}for(p=0;p<c.length;p++){o=null;q[c[p]+"Evts"]&&(o=q[c[p]+"Evts"]);if(o&&o.length){k=c[p].charAt(0).toUpperCase()+c[p].substr(1);
+m="onDrag"+k;h="b4Drag"+k;i="drag"+k+"Event";k="drag"+k;if(this.mode){if(f.events[h]){f[h](a,o,e);j[m]=f.fireEvent(h+"Event",{event:a,info:o,group:e})}if(f.events[k]&&j[m]!==false){f[m](a,o,e);f.fireEvent(i,{event:a,info:o,group:e})}}else{l=0;for(n=o.length;l<n;++l){if(f.events[h]){f[h](a,o[l].id,e[0]);j[m]=f.fireEvent(h+"Event",{event:a,info:o[l].id,group:e[0]})}if(f.events[k]&&j[m]!==false){f[m](a,o[l].id,e[0]);f.fireEvent(i,{event:a,info:o[l].id,group:e[0]})}}}}}}},getBestMatch:function(a){var d=
+null,f=a.length;if(f==1)d=a[0];else for(var c=0;c<f;++c){var j=a[c];if(this.mode==this.INTERSECT&&j.cursorIsOver){d=j;break}else if(!d||!d.overlap||j.overlap&&d.overlap.getArea()<j.overlap.getArea())d=j}return d},refreshCache:function(a){var a=a||this.ids,d;for(d in a)if("string"==typeof d)for(var f in this.ids[d]){var c=this.ids[d][f];if(this.isTypeOfDD(c)){var j=this.getLocation(c);j?this.locationCache[c.id]=j:delete this.locationCache[c.id]}}},verifyEl:function(a){try{if(a&&a.offsetParent)return true}catch(d){}return false},
+getLocation:function(a){if(!this.isTypeOfDD(a))return null;var d=a.getEl(),f,c,j;try{f=YAHOO.util.Dom.getXY(d)}catch(h){}if(!f)return null;c=f[0];j=c+d.offsetWidth;f=f[1];return new YAHOO.util.Region(f-a.padding[0],j+a.padding[1],f+d.offsetHeight+a.padding[2],c-a.padding[3])},isOverTarget:function(a,d,f,c){var j=this.locationCache[d.id];if(!j||!this.useCache){j=this.getLocation(d);this.locationCache[d.id]=j}if(!j)return false;d.cursorIsOver=j.contains(a);var h=this.dragCurrent;if(!h||!f&&!h.constrainX&&
+!h.constrainY)return d.cursorIsOver;d.overlap=null;if(!c){a=h.getTargetCoord(a.x,a.y);h=h.getDragEl();c=new YAHOO.util.Region(a.y,a.x+h.offsetWidth,a.y+h.offsetHeight,a.x)}if(j=c.intersect(j)){d.overlap=j;return f?true:d.cursorIsOver}return false},_onUnload:function(){this.unregAll()},unregAll:function(){if(this.dragCurrent){this.stopDrag();this.dragCurrent=null}this._execOnAll("unreg",[]);this.ids={}},elementCache:{},getElWrapper:function(a){var d=this.elementCache[a];if(!d||!d.el)d=this.elementCache[a]=
+new this.ElementWrapper(YAHOO.util.Dom.get(a));return d},getElement:function(a){return YAHOO.util.Dom.get(a)},getCss:function(a){return(a=YAHOO.util.Dom.get(a))?a.style:null},ElementWrapper:function(a){this.id=(this.el=a||null)&&a.id;this.css=this.el&&a.style},getPosX:function(a){return YAHOO.util.Dom.getX(a)},getPosY:function(a){return YAHOO.util.Dom.getY(a)},swapNode:function(a,d){if(a.swapNode)a.swapNode(d);else{var f=d.parentNode,c=d.nextSibling;if(c==a)f.insertBefore(a,d);else if(d==a.nextSibling)f.insertBefore(d,
+a);else{a.parentNode.replaceChild(d,a);f.insertBefore(a,c)}}},getScroll:function(){var a,d,f=document.documentElement,c=document.body;if(f&&(f.scrollTop||f.scrollLeft)){a=f.scrollTop;d=f.scrollLeft}else if(c){a=c.scrollTop;d=c.scrollLeft}return{top:a,left:d}},getStyle:function(a,d){return YAHOO.util.Dom.getStyle(a,d)},getScrollTop:function(){return this.getScroll().top},getScrollLeft:function(){return this.getScroll().left},moveToEl:function(a,d){var f=YAHOO.util.Dom.getXY(d);YAHOO.util.Dom.setXY(a,
+f)},getClientHeight:function(){return YAHOO.util.Dom.getViewportHeight()},getClientWidth:function(){return YAHOO.util.Dom.getViewportWidth()},numericSort:function(a,d){return a-d},_timeoutCount:0,_addListeners:function(){var a=YAHOO.util.DDM;if(YAHOO.util.Event&&document)a._onLoad();else if(!(a._timeoutCount>2E3)){setTimeout(a._addListeners,10);if(document&&document.body)a._timeoutCount=a._timeoutCount+1}},handleWasClicked:function(a,d){if(this.isHandle(d,a.id))return true;for(var f=a.parentNode;f;){if(this.isHandle(d,
+f.id))return true;f=f.parentNode}return false}}}(),YAHOO.util.DDM=YAHOO.util.DragDropMgr,YAHOO.util.DDM._addListeners());
+(function(){var a=YAHOO.util.Event,c=YAHOO.util.Dom;YAHOO.util.DragDrop=function(a,d,f){a&&this.init(a,d,f)};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(){},startDrag:function(){},b4Drag:function(){},onDrag:function(){},onDragEnter:function(){},b4DragOver:function(){},onDragOver:function(){},b4DragOut:function(){},onDragOut:function(){},b4DragDrop:function(){},onDragDrop:function(){},
+onInvalidDrop:function(){},b4EndDrag:function(){},endDrag:function(){},b4MouseDown:function(){},onMouseDown:function(){},onMouseUp:function(){},onAvailable:function(){},getEl:function(){if(!this._domRef)this._domRef=c.get(this.id);return this._domRef},getDragEl:function(){return c.get(this.dragElId)},init:function(b,d,f){this.initTarget(b,d,f);a.on(this._domRef||this.id,"mousedown",this.handleMouseDown,this,true);for(var c in this.events)this.createEvent(c+"Event")},initTarget:function(b,d,f){this.config=
+f||{};this.events={};this.DDM=YAHOO.util.DDM;this.groups={};if(typeof b!=="string"){this._domRef=b;b=c.generateId(b)}this.id=b;this.addToGroup(d?d:"default");this.handleElId=b;a.onAvailable(b,this.handleOnAvailable,this,true);this.setDragElId(b);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 a in this.config.events)this.config.events[a]===false&&(this.events[a]=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(a,d,f,c){this.padding=!d&&0!==d?[a,a,a,a]:!f&&0!==f?[a,d,a,d]:[a,d,f,c]},setInitPosition:function(a,d){var f=this.getEl();if(this.DDM.verifyEl(f)){var g=a||0,j=d||0,f=c.getXY(f);this.initPageX=f[0]-g;this.initPageY=f[1]-j;this.lastPageX=f[0];this.lastPageY=f[1];this.setStartPosition(f)}},setStartPosition:function(a){a=a||c.getXY(this.getEl());this.deltaSetXY=
+null;this.startPageX=a[0];this.startPageY=a[1]},addToGroup:function(a){this.groups[a]=true;this.DDM.regDragDrop(this,a)},removeFromGroup:function(a){this.groups[a]&&delete this.groups[a];this.DDM.removeDDFromGroup(this,a)},setDragElId:function(a){this.dragElId=a},setHandleElId:function(a){typeof a!=="string"&&(a=c.generateId(a));this.handleElId=a;this.DDM.regHandle(this.id,a)},setOuterHandleElId:function(b){typeof b!=="string"&&(b=c.generateId(b));a.on(b,"mousedown",this.handleMouseDown,this,true);
+this.setHandleElId(b);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(b){var d=b.which||b.button;if(!(this.primaryButtonOnly&&d>1)&&!this.isLocked()){var d=this.b4MouseDown(b),f=true;this.events.b4MouseDown&&(f=this.fireEvent("b4MouseDownEvent",b));var c=this.onMouseDown(b),j=true;this.events.mouseDown&&(j=c===false?
+false:this.fireEvent("mouseDownEvent",b));if(!(d===false||c===false||f===false||j===false)){this.DDM.refreshCache(this.groups);d=new YAHOO.util.Point(a.getPageX(b),a.getPageY(b));if((this.hasOuterHandles||this.DDM.isOverTarget(d,this))&&this.clickValidator(b)){this.setStartPosition();this.DDM.handleMouseDown(b,this);this.DDM.stopEvent(b)}}}},clickValidator:function(a){a=YAHOO.util.Event.getTarget(a);return this.isValidHandleChild(a)&&(this.id==this.handleElId||this.DDM.handleWasClicked(a,this.id))},
+getTargetCoord:function(a,d){var f=a-this.deltaX,c=d-this.deltaY;if(this.constrainX){if(f<this.minX)f=this.minX;if(f>this.maxX)f=this.maxX}if(this.constrainY){if(c<this.minY)c=this.minY;if(c>this.maxY)c=this.maxY}f=this.getTick(f,this.xTicks);c=this.getTick(c,this.yTicks);return{x:f,y:c}},addInvalidHandleType:function(a){a=a.toUpperCase();this.invalidHandleTypes[a]=a},addInvalidHandleId:function(a){typeof a!=="string"&&(a=c.generateId(a));this.invalidHandleIds[a]=a},addInvalidHandleClass:function(a){this.invalidHandleClasses.push(a)},
+removeInvalidHandleType:function(a){delete this.invalidHandleTypes[a.toUpperCase()]},removeInvalidHandleId:function(a){typeof a!=="string"&&(a=c.generateId(a));delete this.invalidHandleIds[a]},removeInvalidHandleClass:function(a){for(var d=0,f=this.invalidHandleClasses.length;d<f;++d)this.invalidHandleClasses[d]==a&&delete this.invalidHandleClasses[d]},isValidHandleChild:function(a){var d=true,f;try{f=a.nodeName.toUpperCase()}catch(g){f=a.nodeName}d=(d=d&&!this.invalidHandleTypes[f])&&!this.invalidHandleIds[a.id];
+f=0;for(var j=this.invalidHandleClasses.length;d&&f<j;++f)d=!c.hasClass(a,this.invalidHandleClasses[f]);return d},setXTicks:function(a,d){this.xTicks=[];this.xTickSize=d;for(var f={},c=this.initPageX;c>=this.minX;c=c-d)if(!f[c]){this.xTicks[this.xTicks.length]=c;f[c]=true}for(c=this.initPageX;c<=this.maxX;c=c+d)if(!f[c]){this.xTicks[this.xTicks.length]=c;f[c]=true}this.xTicks.sort(this.DDM.numericSort)},setYTicks:function(a,d){this.yTicks=[];this.yTickSize=d;for(var f={},c=this.initPageY;c>=this.minY;c=
+c-d)if(!f[c]){this.yTicks[this.yTicks.length]=c;f[c]=true}for(c=this.initPageY;c<=this.maxY;c=c+d)if(!f[c]){this.yTicks[this.yTicks.length]=c;f[c]=true}this.yTicks.sort(this.DDM.numericSort)},setXConstraint:function(a,d,f){this.leftConstraint=parseInt(a,10);this.rightConstraint=parseInt(d,10);this.minX=this.initPageX-this.leftConstraint;this.maxX=this.initPageX+this.rightConstraint;f&&this.setXTicks(this.initPageX,f);this.constrainX=true},clearConstraints:function(){this.constrainY=this.constrainX=
+false;this.clearTicks()},clearTicks:function(){this.yTicks=this.xTicks=null;this.yTickSize=this.xTickSize=0},setYConstraint:function(a,d,f){this.topConstraint=parseInt(a,10);this.bottomConstraint=parseInt(d,10);this.minY=this.initPageY-this.topConstraint;this.maxY=this.initPageY+this.bottomConstraint;f&&this.setYTicks(this.initPageY,f);this.constrainY=true},resetConstraints:function(){this.initPageX||this.initPageX===0?this.setInitPosition(this.maintainOffset?this.lastPageX-this.initPageX:0,this.maintainOffset?
+this.lastPageY-this.initPageY:0):this.setInitPosition();this.constrainX&&this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);this.constrainY&&this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize)},getTick:function(a,d){if(d){if(d[0]>=a)return d[0];for(var f=0,c=d.length;f<c;++f){var j=f+1;if(d[j]&&d[j]>=a)return d[j]-a>a-d[f]?d[f]:d[j]}return d[d.length-1]}return a},toString:function(){return"DragDrop "+this.id}};YAHOO.augment(YAHOO.util.DragDrop,YAHOO.util.EventProvider)})();
+YAHOO.util.DD=function(a,c,b){a&&this.init(a,c,b)};
+YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop,{scroll:!0,autoOffset:function(a,c){this.setDelta(a-this.startPageX,c-this.startPageY)},setDelta:function(a,c){this.deltaX=a;this.deltaY=c},setDragElPos:function(a,c){this.alignElWithMouse(this.getDragEl(),a,c)},alignElWithMouse:function(a,c,b){var d=this.getTargetCoord(c,b);if(this.deltaSetXY){YAHOO.util.Dom.setStyle(a,"left",d.x+this.deltaSetXY[0]+"px");YAHOO.util.Dom.setStyle(a,"top",d.y+this.deltaSetXY[1]+"px")}else{YAHOO.util.Dom.setXY(a,[d.x,d.y]);
+c=parseInt(YAHOO.util.Dom.getStyle(a,"left"),10);b=parseInt(YAHOO.util.Dom.getStyle(a,"top"),10);this.deltaSetXY=[c-d.x,b-d.y]}this.cachePosition(d.x,d.y);var f=this;setTimeout(function(){f.autoScroll.call(f,d.x,d.y,a.offsetHeight,a.offsetWidth)},0)},cachePosition:function(a,c){if(a){this.lastPageX=a;this.lastPageY=c}else{var b=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=b[0];this.lastPageY=b[1]}},autoScroll:function(a,c,b,d){if(this.scroll){var f=this.DDM.getClientHeight(),g=this.DDM.getClientWidth(),
+j=this.DDM.getScrollTop(),h=this.DDM.getScrollLeft(),d=d+a,e=f+j-c-this.deltaY,i=g+h-a-this.deltaX,k=document.all?80:30;b+c>f&&e<40&&window.scrollTo(h,j+k);c<j&&(j>0&&c-j<40)&&window.scrollTo(h,j-k);d>g&&i<40&&window.scrollTo(h+k,j);a<h&&(h>0&&a-h<40)&&window.scrollTo(h-k,j)}},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(a,c,b){if(a){this.init(a,c,b);this.initFrame()}};YAHOO.util.DDProxy.dragElId="ygddfdiv";
+YAHOO.extend(YAHOO.util.DDProxy,YAHOO.util.DD,{resizeFrame:!0,centerFrame:!1,createFrame:function(){var a=this,c=document.body;if(!c||!c.firstChild)setTimeout(function(){a.createFrame()},50);else{var b=this.getDragEl(),d=YAHOO.util.Dom;if(!b){b=document.createElement("div");b.id=this.dragElId;var f=b.style;f.position="absolute";f.visibility="hidden";f.cursor="move";f.border="2px solid #aaa";f.zIndex=999;f.height="25px";f.width="25px";f=document.createElement("div");d.setStyle(f,"height","100%");d.setStyle(f,
+"width","100%");d.setStyle(f,"background-color","#ccc");d.setStyle(f,"opacity","0");b.appendChild(f);c.insertBefore(b,c.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(a,c){this.getEl();var b=this.getDragEl(),d=b.style;this._resizeProxy();
+this.centerFrame&&this.setDelta(Math.round(parseInt(d.width,10)/2),Math.round(parseInt(d.height,10)/2));this.setDragElPos(a,c);YAHOO.util.Dom.setStyle(b,"visibility","visible")},_resizeProxy:function(){if(this.resizeFrame){var a=YAHOO.util.Dom,c=this.getEl(),b=this.getDragEl(),d=parseInt(a.getStyle(b,"borderTopWidth"),10),f=parseInt(a.getStyle(b,"borderRightWidth"),10),g=parseInt(a.getStyle(b,"borderBottomWidth"),10),j=parseInt(a.getStyle(b,"borderLeftWidth"),10);isNaN(d)&&(d=0);isNaN(f)&&(f=0);isNaN(g)&&
+(g=0);isNaN(j)&&(j=0);f=Math.max(0,c.offsetWidth-f-j);c=Math.max(0,c.offsetHeight-d-g);a.setStyle(b,"width",f+"px");a.setStyle(b,"height",c+"px")}},b4MouseDown:function(a){this.setStartPosition();var c=YAHOO.util.Event.getPageX(a),a=YAHOO.util.Event.getPageY(a);this.autoOffset(c,a)},b4StartDrag:function(a,c){this.showFrame(a,c)},b4EndDrag:function(){YAHOO.util.Dom.setStyle(this.getDragEl(),"visibility","hidden")},endDrag:function(){var a=YAHOO.util.Dom,c=this.getEl(),b=this.getDragEl();a.setStyle(b,
+"visibility","");a.setStyle(c,"visibility","hidden");YAHOO.util.DDM.moveToEl(c,b);a.setStyle(b,"visibility","hidden");a.setStyle(c,"visibility","")},toString:function(){return"DDProxy "+this.id}});YAHOO.util.DDTarget=function(a,c,b){a&&this.initTarget(a,c,b)};YAHOO.extend(YAHOO.util.DDTarget,YAHOO.util.DragDrop,{toString:function(){return"DDTarget "+this.id}});YAHOO.register("dragdrop",YAHOO.util.DragDropMgr,{version:"2.9.0",build:"2800"});
+YAHOO.util.Attribute=function(a,c){if(c){this.owner=c;this.configure(a,true)}};YAHOO.util.Attribute.INVALID_VALUE={};
+YAHOO.util.Attribute.prototype={name:void 0,value:null,owner:null,readOnly:!1,writeOnce:!1,_initialConfig:null,_written:!1,method:null,setter:null,getter:null,validator:null,getValue:function(){var a=this.value;this.getter&&(a=this.getter.call(this.owner,this.name,a));return a},setValue:function(a,c){var b,d=this.owner,f=this.name,g=YAHOO.util.Attribute.INVALID_VALUE,j={type:f,prevValue:this.getValue(),newValue:a};if(this.readOnly||this.writeOnce&&this._written||this.validator&&!this.validator.call(d,
+a))return false;if(!c){b=d.fireBeforeChangeEvent(j);if(b===false)return false}if(this.setter){a=this.setter.call(d,a,this.name);if(a===g)return false}if(this.method&&this.method.call(d,a,this.name)===g)return false;this.value=a;this._written=true;j.type=f;c||this.owner.fireChangeEvent(j);return true},configure:function(a,c){a=a||{};if(c)this._written=false;this._initialConfig=this._initialConfig||{};for(var b in a)if(a.hasOwnProperty(b)){this[b]=a[b];c&&(this._initialConfig[b]=a[b])}},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(a){this._configs=this._configs||{};var b=this._configs[a];return!b||!this._configs.hasOwnProperty(a)?null:b.getValue()},set:function(a,b,d){this._configs=this._configs||{};a=this._configs[a];return!a?false:a.setValue(b,d)},getAttributeKeys:function(){this._configs=this._configs;var c=[],b;for(b in this._configs)a.hasOwnProperty(this._configs,b)&&!a.isUndefined(this._configs[b])&&
+(c[c.length]=b);return c},setAttributes:function(c,b){for(var d in c)a.hasOwnProperty(c,d)&&this.set(d,c[d],b)},resetValue:function(a,b){this._configs=this._configs||{};if(this._configs[a]){this.set(a,this._configs[a]._initialConfig.value,b);return true}return false},refresh:function(c,b){for(var d=this._configs=this._configs||{},c=(a.isString(c)?[c]:c)||this.getAttributeKeys(),f=0,g=c.length;f<g;++f)d.hasOwnProperty(c[f])&&this._configs[c[f]].refresh(b)},register:function(a,b){this.setAttributeConfig(a,
+b)},getAttributeConfig:function(c){this._configs=this._configs||{};var b=this._configs[c]||{},d={};for(c in b)a.hasOwnProperty(b,c)&&(d[c]=b[c]);return d},setAttributeConfig:function(a,b,d){this._configs=this._configs||{};b=b||{};if(this._configs[a])this._configs[a].configure(b,d);else{b.name=a;this._configs[a]=this.createAttribute(b)}},configureAttribute:function(a,b,d){this.setAttributeConfig(a,b,d)},resetAttributeConfig:function(a){this._configs=this._configs||{};this._configs[a].resetConfig()},
+subscribe:function(a,b){this._events=this._events||{};a in this._events||(this._events[a]=this.createEvent(a));YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments)},on:function(){this.subscribe.apply(this,arguments)},addListener:function(){this.subscribe.apply(this,arguments)},fireBeforeChangeEvent:function(a){var b;b="before"+(a.type.charAt(0).toUpperCase()+a.type.substr(1)+"Change");a.type=b;return this.fireEvent(a.type,a)},fireChangeEvent:function(a){a.type=a.type+"Change";return this.fireEvent(a.type,
+a)},createAttribute:function(a){return new YAHOO.util.Attribute(a,this)}};YAHOO.augment(YAHOO.util.AttributeProvider,YAHOO.util.EventProvider)})();
+(function(){var a=YAHOO.util.Dom,c=YAHOO.util.AttributeProvider,b={mouseenter:true,mouseleave:true},d=function(a,b){this.init.apply(this,arguments)};d.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};d.prototype={DOM_EVENTS:null,DEFAULT_HTML_SETTER:function(a,b){var d=this.get("element");d&&(d[b]=a);return a},DEFAULT_HTML_GETTER:function(a){var b=
+this.get("element"),d;b&&(d=b[a]);return d},appendChild:function(a){a=a.get?a.get("element"):a;return this.get("element").appendChild(a)},getElementsByTagName:function(a){return this.get("element").getElementsByTagName(a)},hasChildNodes:function(){return this.get("element").hasChildNodes()},insertBefore:function(a,b){a=a.get?a.get("element"):a;b=b&&b.get?b.get("element"):b;return this.get("element").insertBefore(a,b)},removeChild:function(a){a=a.get?a.get("element"):a;return this.get("element").removeChild(a)},
+replaceChild:function(a,b){a=a.get?a.get("element"):a;b=b.get?b.get("element"):b;return this.get("element").replaceChild(a,b)},initAttributes:function(){},addListener:function(a,d,c,h){var h=h||this,e=YAHOO.util.Event,i=this.get("element")||this.get("id"),k=this;if(b[a]&&!e._createMouseDelegate)return false;if(!this._events[a]){if(i&&this.DOM_EVENTS[a])e.on(i,a,function(b,d){if(b.srcElement&&!b.target)b.target=b.srcElement;if(b.toElement&&!b.relatedTarget||b.fromElement&&!b.relatedTarget)b.relatedTarget=
+e.getRelatedTarget(b);if(!b.currentTarget)b.currentTarget=i;k.fireEvent(a,b,d)},c,h);this.createEvent(a,{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(a,b){return this.unsubscribe.apply(this,arguments)},addClass:function(b){a.addClass(this.get("element"),b)},getElementsByClassName:function(b,d){return a.getElementsByClassName(b,
+d,this.get("element"))},hasClass:function(b){return a.hasClass(this.get("element"),b)},removeClass:function(b){return a.removeClass(this.get("element"),b)},replaceClass:function(b,d){return a.replaceClass(this.get("element"),b,d)},setStyle:function(b,d){return a.setStyle(this.get("element"),b,d)},getStyle:function(b){return a.getStyle(this.get("element"),b)},fireQueue:function(){for(var a=this._queue,b=0,d=a.length;b<d;++b)this[a[b][0]].apply(this,a[b][1])},appendTo:function(b,d){b=b.get?b.get("element"):
+a.get(b);this.fireEvent("beforeAppendTo",{type:"beforeAppendTo",target:b});var d=d&&d.get?d.get("element"):a.get(d),c=this.get("element");if(!c||!b)return false;c.parent!=b&&(d?b.insertBefore(c,d):b.appendChild(c));this.fireEvent("appendTo",{type:"appendTo",target:b});return c},get:function(a){var b=this._configs||{},d=b.element;d&&(!b[a]&&!YAHOO.lang.isUndefined(d.value[a]))&&this._setHTMLAttrConfig(a);return c.prototype.get.call(this,a)},setAttributes:function(a,b){for(var d={},c=this._configOrder,
+e=0,i=c.length;e<i;++e)if(a[c[e]]!==void 0){d[c[e]]=true;this.set(c[e],a[c[e]],b)}for(var k in a)a.hasOwnProperty(k)&&!d[k]&&this.set(k,a[k],b)},set:function(a,b,d){var h=this.get("element");if(h){!this._configs[a]&&!YAHOO.lang.isUndefined(h[a])&&this._setHTMLAttrConfig(a);return c.prototype.set.apply(this,arguments)}this._queue[this._queue.length]=["set",arguments];if(this._configs[a])this._configs[a].value=b},setAttributeConfig:function(a,b,d){this._configOrder.push(a);c.prototype.setAttributeConfig.apply(this,
+arguments)},createEvent:function(a,b){this._events[a]=true;return c.prototype.createEvent.apply(this,arguments)},init:function(a,b){this._initElement(a,b)},destroy:function(){var a=this.get("element");YAHOO.util.Event.purgeElement(a,true);this.unsubscribeAll();a&&a.parentNode&&a.parentNode.removeChild(a);this._queue=[];this._events={};this._configs={};this._configOrder=[]},_initElement:function(b,c){this._queue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};this._configOrder=
+[];c=c||{};c.element=c.element||b||null;var j=false,h=d.DOM_EVENTS;this.DOM_EVENTS=this.DOM_EVENTS||{};for(var e in h)h.hasOwnProperty(e)&&(this.DOM_EVENTS[e]=h[e]);typeof c.element==="string"&&this._setHTMLAttrConfig("id",{value:c.element});if(a.get(c.element)){j=true;this._initHTMLElement(c);this._initContent(c)}YAHOO.util.Event.onAvailable(c.element,function(){j||this._initHTMLElement(c);this.fireEvent("available",{type:"available",target:a.get(c.element)})},this,true);YAHOO.util.Event.onContentReady(c.element,
+function(){j||this._initContent(c);this.fireEvent("contentReady",{type:"contentReady",target:a.get(c.element)})},this,true)},_initHTMLElement:function(b){this.setAttributeConfig("element",{value:a.get(b.element),readOnly:true})},_initContent:function(a){this.initAttributes(a);this.setAttributes(a,true);this.fireQueue()},_setHTMLAttrConfig:function(a,b){var d=this.get("element"),b=b||{};b.name=a;b.setter=b.setter||this.DEFAULT_HTML_SETTER;b.getter=b.getter||this.DEFAULT_HTML_GETTER;b.value=b.value||
+d[a];this._configs[a]=new YAHOO.util.Attribute(b,this)}};YAHOO.augment(d,c);YAHOO.util.Element=d})();YAHOO.register("element",YAHOO.util.Element,{version:"2.9.0",build:"2800"});YAHOO.register("utilities",YAHOO,{version:"2.9.0",build:"2800"});
+(function(){var a=YAHOO.lang,c=YAHOO.util;c.DataSourceBase=function(b,f){if(!(b===null||b===void 0)){this.liveData=b;this._oQueue={interval:null,conn:null,requests:[]};this.responseSchema={};if(f&&f.constructor==Object)for(var g in f)g&&(this[g]=f[g]);a.isNumber(this.maxCacheEntries);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");g=c.DataSourceBase;this._sName="DataSource instance"+g._nIndex;g._nIndex++}};var b=c.DataSourceBase;a.augmentObject(b,{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,_cloneObject:function(d){if(!a.isValue(d))return d;var c={};if(Object.prototype.toString.apply(d)===
+"[object RegExp]")c=d;else if(a.isFunction(d))c=d;else if(a.isArray(d))for(var c=[],g=0,j=d.length;g<j;g++)c[g]=b._cloneObject(d[g]);else if(a.isObject(d))for(g in d)a.hasOwnProperty(d,g)&&(c[g]=a.isValue(d[g])&&a.isObject(d[g])||a.isArray(d[g])?b._cloneObject(d[g]):d[g]);else c=d;return c},_getLocationValue:function(b,c){var g=b.locator||b.key||b,j=c.ownerDocument||c,h,e,i=null;try{if(a.isUndefined(j.evaluate)){j.setProperty("SelectionLanguage","XPath");h=c.selectNodes(g)[0];i=h.value||h.text||null}else for(h=
+j.evaluate(g,c,j.createNSResolver(!c.ownerDocument?c.documentElement:c.ownerDocument.documentElement),0,null);e=h.iterateNext();)i=e.textContent;return i}catch(k){}},issueCallback:function(b,c,g,j){if(a.isFunction(b))b.apply(j,c);else if(a.isObject(b)){var j=b.scope||j||window,h=b.success;if(g)h=b.failure;h&&h.apply(j,c.concat([b.argument]))}},parseString:function(b){if(!a.isValue(b))return null;b=b+"";return a.isString(b)?b:null},parseNumber:function(b){if(!a.isValue(b)||b==="")return null;b=b*1;
+return a.isNumber(b)?b:null},convertNumber:function(a){return b.parseNumber(a)},parseDate:function(b){var c=null;if(a.isValue(b)&&!(b instanceof Date))c=new Date(b);else return b;return c instanceof Date?c:null},convertDate:function(a){return b.parseDate(a)}});b.Parser={string:b.parseString,number:b.parseNumber,date:b.parseDate};b.prototype={_sName:null,_aCache:null,_oQueue:null,_aIntervals:null,maxCacheEntries:0,liveData:null,dataType:b.TYPE_UNKNOWN,responseType:b.TYPE_UNKNOWN,responseSchema:null,
+useXPath:false,cloneBeforeCaching:false,toString:function(){return this._sName},getCachedResponse:function(a,b,c){var j=this._aCache;if(this.maxCacheEntries>0)if(j){var h=j.length;if(h>0){var e=null;this.fireEvent("cacheRequestEvent",{request:a,callback:b,caller:c});for(var i=h-1;i>=0;i--){var k=j[i];if(this.isCacheHit(a,k.request)){e=k.response;this.fireEvent("cacheResponseEvent",{request:a,response:e,callback:b,caller:c});if(i<h-1){j.splice(i,1);this.addToCache(a,e)}e.cached=true;break}}return e}}else this._aCache=
+[];else if(j)this._aCache=null;return null},isCacheHit:function(a,b){return a===b},addToCache:function(a,c){var g=this._aCache;if(g){for(;g.length>=this.maxCacheEntries;)g.shift();c=this.cloneBeforeCaching?b._cloneObject(c):c;g[g.length]={request:a,response:c};this.fireEvent("responseCacheEvent",{request:a,response:c})}},flushCache:function(){if(this._aCache){this._aCache=[];this.fireEvent("cacheFlushEvent")}},setInterval:function(b,c,g,j){if(a.isNumber(b)&&b>=0){var h=this,b=setInterval(function(){h.makeConnection(c,
+g,j)},b);this._aIntervals.push(b);return b}},clearInterval:function(a){for(var b=this._aIntervals||[],c=b.length-1;c>-1;c--)if(b[c]===a){b.splice(c,1);clearInterval(a)}},clearAllIntervals:function(){for(var a=this._aIntervals||[],b=a.length-1;b>-1;b--)clearInterval(a[b])},sendRequest:function(a,c,g){var j=this.getCachedResponse(a,c,g);if(j){b.issueCallback(c,[a,j],false,g);return null}return this.makeConnection(a,c,g)},makeConnection:function(a,c,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",
+{tId:j,request:a,callback:c,caller:g});this.handleResponse(a,this.liveData,c,g,j);return j},handleResponse:function(d,c,g,j,h){this.fireEvent("responseEvent",{tId:h,request:d,response:c,callback:g,caller:j});var e=this.dataType==b.TYPE_XHR?true:false,i=null,k=c;if(this.responseType===b.TYPE_UNKNOWN)if(i=c&&c.getResponseHeader?c.getResponseHeader["Content-Type"]:null)if(i.indexOf("text/xml")>-1)this.responseType=b.TYPE_XML;else if(i.indexOf("application/json")>-1)this.responseType=b.TYPE_JSON;else{if(i.indexOf("text/plain")>
+-1)this.responseType=b.TYPE_TEXT}else if(YAHOO.lang.isArray(c))this.responseType=b.TYPE_JSARRAY;else if(c&&c.nodeType&&(c.nodeType===9||c.nodeType===1||c.nodeType===11))this.responseType=b.TYPE_XML;else if(c&&c.nodeName&&c.nodeName.toLowerCase()=="table")this.responseType=b.TYPE_HTMLTABLE;else if(YAHOO.lang.isObject(c))this.responseType=b.TYPE_JSON;else if(YAHOO.lang.isString(c))this.responseType=b.TYPE_TEXT;switch(this.responseType){case b.TYPE_JSARRAY:if(e&&c&&c.responseText)k=c.responseText;try{if(a.isString(k)){var l=
+[k].concat(this.parseJSONArgs);if(a.JSON)k=a.JSON.parse.apply(a.JSON,l);else if(window.JSON&&JSON.parse)k=JSON.parse.apply(JSON,l);else if(k.parseJSON)k=k.parseJSON.apply(k,l.slice(1));else{for(;k.length>0&&k.charAt(0)!="{"&&k.charAt(0)!="[";)k=k.substring(1,k.length);if(k.length>0)var q=Math.max(k.lastIndexOf("]"),k.lastIndexOf("}")),k=k.substring(0,q+1),k=eval("("+k+")")}}}catch(p){}k=this.doBeforeParseData(d,k,g);i=this.parseArrayData(d,k);break;case b.TYPE_JSON:if(e&&c&&c.responseText)k=c.responseText;
+try{if(a.isString(k)){l=[k].concat(this.parseJSONArgs);if(a.JSON)k=a.JSON.parse.apply(a.JSON,l);else if(window.JSON&&JSON.parse)k=JSON.parse.apply(JSON,l);else if(k.parseJSON)k=k.parseJSON.apply(k,l.slice(1));else{for(;k.length>0&&k.charAt(0)!="{"&&k.charAt(0)!="[";)k=k.substring(1,k.length);if(k.length>0)var n=Math.max(k.lastIndexOf("]"),k.lastIndexOf("}")),k=k.substring(0,n+1),k=eval("("+k+")")}}}catch(o){}k=this.doBeforeParseData(d,k,g);i=this.parseJSONData(d,k);break;case b.TYPE_HTMLTABLE:if(e&&
+c.responseText){e=document.createElement("div");e.innerHTML=c.responseText;k=e.getElementsByTagName("table")[0]}k=this.doBeforeParseData(d,k,g);i=this.parseHTMLTableData(d,k);break;case b.TYPE_XML:if(e&&c.responseXML)k=c.responseXML;k=this.doBeforeParseData(d,k,g);i=this.parseXMLData(d,k);break;case b.TYPE_TEXT:if(e&&a.isString(c.responseText))k=c.responseText;k=this.doBeforeParseData(d,k,g);i=this.parseTextData(d,k);break;default:k=this.doBeforeParseData(d,k,g);i=this.parseData(d,k)}i=i||{};if(!i.results)i.results=
+[];if(!i.meta)i.meta={};if(i.error){i.error=true;this.fireEvent("dataErrorEvent",{request:d,response:c,callback:g,caller:j,message:b.ERROR_DATANULL})}else{i=this.doBeforeCallback(d,k,i,g);this.fireEvent("responseParseEvent",{request:d,response:i,callback:g,caller:j});this.addToCache(d,i)}i.tId=h;b.issueCallback(g,[d,i],i.error,j)},doBeforeParseData:function(a,b){return b},doBeforeCallback:function(a,b,c){return c},parseData:function(b,c){return a.isValue(c)?{results:c,meta:{}}:null},parseArrayData:function(d,
+c){if(a.isArray(c)){var g=[],j,h,e,i,k;if(a.isArray(this.responseSchema.fields)){var l=this.responseSchema.fields;for(j=l.length-1;j>=0;--j)typeof l[j]!=="object"&&(l[j]={key:l[j]});var q={};for(j=l.length-1;j>=0;--j)(h=(typeof l[j].parser==="function"?l[j].parser:b.Parser[l[j].parser+""])||l[j].converter)&&(q[l[j].key]=h);var p=a.isArray(c[0]);for(j=c.length-1;j>-1;j--){var n={};e=c[j];if(typeof e==="object")for(h=l.length-1;h>-1;h--){i=l[h];k=p?e[h]:e[i.key];q[i.key]&&(k=q[i.key].call(this,k));
+k===void 0&&(k=null);n[i.key]=k}else if(a.isString(e))for(h=l.length-1;h>-1;h--){i=l[h];k=e;q[i.key]&&(k=q[i.key].call(this,k));k===void 0&&(k=null);n[i.key]=k}g[j]=n}}else g=c;return{results:g}}return null},parseTextData:function(d,c){if(a.isString(c)&&a.isString(this.responseSchema.recordDelim)&&a.isString(this.responseSchema.fieldDelim)){var g={results:[]},j=this.responseSchema.recordDelim,h=this.responseSchema.fieldDelim;if(c.length>0){var e=c.length-j.length;c.substr(e)==j&&(c=c.substr(0,e));
+if(c.length>0)for(var j=c.split(j),e=0,i=j.length,k=0;e<i;++e){var l=false,q=j[e];if(a.isString(q)&&q.length>0){var q=j[e].split(h),p={};if(a.isArray(this.responseSchema.fields))for(var n=this.responseSchema.fields,o=n.length-1;o>-1;o--)try{var m=q[o];if(a.isString(m)){m.charAt(0)=='"'&&(m=m.substr(1));m.charAt(m.length-1)=='"'&&(m=m.substr(0,m.length-1));var r=n[o],s=a.isValue(r.key)?r.key:r;if(!r.parser&&r.converter)r.parser=r.converter;var t=typeof r.parser==="function"?r.parser:b.Parser[r.parser+
+""];t&&(m=t.call(this,m));m===void 0&&(m=null);p[s]=m}else l=true}catch(u){l=true}else p=q;l||(g.results[k++]=p)}}}return g}return null},parseXMLResult:function(d){var c={},g=this.responseSchema;try{for(var j=g.fields.length-1;j>=0;j--){var h=g.fields[j],e=a.isValue(h.key)?h.key:h,i=null;if(this.useXPath)i=YAHOO.util.DataSource._getLocationValue(h,d);else{var k=d.attributes.getNamedItem(e);if(k)i=k.value;else{var l=d.getElementsByTagName(e);if(l&&l.item(0)){var q=l.item(0),i=q?q.text?q.text:q.textContent?
+q.textContent:null:null;if(!i){for(var p=[],n=0,o=q.childNodes.length;n<o;n++)if(q.childNodes[n].nodeValue)p[p.length]=q.childNodes[n].nodeValue;p.length>0&&(i=p.join(""))}}}}i===null&&(i="");if(!h.parser&&h.converter)h.parser=h.converter;var m=typeof h.parser==="function"?h.parser:b.Parser[h.parser+""];m&&(i=m.call(this,i));i===void 0&&(i=null);c[e]=i}}catch(r){}return c},parseXMLData:function(b,c){var g=false,j=this.responseSchema,h={meta:{}},e=null,i=j.metaNode,k=j.metaFields||{},l,q,p;try{if(this.useXPath)for(l in k)h.meta[l]=
+YAHOO.util.DataSource._getLocationValue(k[l],c);else if(i=i?c.getElementsByTagName(i)[0]:c)for(l in k)if(a.hasOwnProperty(k,l)){q=k[l];if(p=i.getElementsByTagName(q)[0])p=p.firstChild.nodeValue;else if(p=i.attributes.getNamedItem(q))p=p.value;a.isValue(p)&&(h.meta[l]=p)}e=j.resultNode?c.getElementsByTagName(j.resultNode):null}catch(n){}if(!e||!a.isArray(j.fields))g=true;else{h.results=[];for(j=e.length-1;j>=0;--j){i=this.parseXMLResult(e.item(j));h.results[j]=i}}if(g)h.error=true;return h},parseJSONData:function(d,
+c){var g={results:[],meta:{}};if(a.isObject(c)&&this.responseSchema.resultsList){var j=this.responseSchema,h=j.fields,e=c,i=[],k=j.metaFields||{},l=[],q=[],p=[],n=false,o,m,r,s=function(e){var a=null,b=[],i=0;if(e){e=e.replace(/\[(['"])(.*?)\1\]/g,function(e,a,d){b[i]=d;return".@"+i++}).replace(/\[(\d+)\]/g,function(e,a){b[i]=parseInt(a,10)|0;return".@"+i++}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(e)){a=e.split(".");for(i=a.length-1;i>=0;--i)a[i].charAt(0)==="@"&&(a[i]=b[parseInt(a[i].substr(1),
+10)])}}return a},t=function(e,a){for(var b=a,i=0,d=e.length;i<d&&b;++i)b=b[e[i]];return b};if(r=s(j.resultsList)){e=t(r,c);e===void 0&&(n=true)}else n=true;e||(e=[]);a.isArray(e)||(e=[e]);if(n)g.error=true;else{if(j.fields){j=0;for(n=h.length;j<n;j++){r=h[j];o=r.key||r;m=(typeof r.parser==="function"?r.parser:b.Parser[r.parser+""])||r.converter;r=s(o);m&&(l[l.length]={key:o,parser:m});r&&(r.length>1?q[q.length]={key:o,path:r}:p[p.length]={key:o,path:r[0]})}for(j=e.length-1;j>=0;--j){n=e[j];r={};if(n){for(h=
+p.length-1;h>=0;--h)r[p[h].key]=n[p[h].path]!==void 0?n[p[h].path]:n[h];for(h=q.length-1;h>=0;--h)r[q[h].key]=t(q[h].path,n);for(h=l.length-1;h>=0;--h){n=l[h].key;r[n]=l[h].parser.call(this,r[n]);r[n]===void 0&&(r[n]=null)}}i[j]=r}}else i=e;for(o in k)if(a.hasOwnProperty(k,o))if(r=s(k[o])){e=t(r,c);g.meta[o]=e}}g.results=i}else g.error=true;return g},parseHTMLTableData:function(d,c){var g=false,j=this.responseSchema.fields,h={results:[]};if(a.isArray(j))for(var e=0;e<c.tBodies.length;e++)for(var i=
+c.tBodies[e],k=i.rows.length-1;k>-1;k--){for(var l=i.rows[k],q={},p=j.length-1;p>-1;p--){var n=j[p],o=a.isValue(n.key)?n.key:n,m=l.cells[p].innerHTML;if(!n.parser&&n.converter)n.parser=n.converter;(n=typeof n.parser==="function"?n.parser:b.Parser[n.parser+""])&&(m=n.call(this,m));m===void 0&&(m=null);q[o]=m}h.results[k]=q}else g=true;if(g)h.error=true;return h}};a.augmentProto(b,c.EventProvider);c.LocalDataSource=function(a,f){this.dataType=b.TYPE_LOCAL;if(a)if(YAHOO.lang.isArray(a))this.responseType=
+b.TYPE_JSARRAY;else if(a.nodeType&&a.nodeType==9)this.responseType=b.TYPE_XML;else if(a.nodeName&&a.nodeName.toLowerCase()=="table"){this.responseType=b.TYPE_HTMLTABLE;a=a.cloneNode(true)}else if(YAHOO.lang.isString(a))this.responseType=b.TYPE_TEXT;else{if(YAHOO.lang.isObject(a))this.responseType=b.TYPE_JSON}else{a=[];this.responseType=b.TYPE_JSARRAY}c.LocalDataSource.superclass.constructor.call(this,a,f)};a.extend(c.LocalDataSource,b);a.augmentObject(c.LocalDataSource,b);c.FunctionDataSource=function(a,
+f){this.dataType=b.TYPE_JSFUNCTION;c.FunctionDataSource.superclass.constructor.call(this,a||function(){},f)};a.extend(c.FunctionDataSource,b,{scope:null,makeConnection:function(a,c,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",{tId:j,request:a,callback:c,caller:g});var h=this.scope?this.liveData.call(this.scope,a,this,c):this.liveData(a,c);if(this.responseType===b.TYPE_UNKNOWN)if(YAHOO.lang.isArray(h))this.responseType=b.TYPE_JSARRAY;else if(h&&h.nodeType&&h.nodeType==9)this.responseType=
+b.TYPE_XML;else if(h&&h.nodeName&&h.nodeName.toLowerCase()=="table")this.responseType=b.TYPE_HTMLTABLE;else if(YAHOO.lang.isObject(h))this.responseType=b.TYPE_JSON;else if(YAHOO.lang.isString(h))this.responseType=b.TYPE_TEXT;this.handleResponse(a,h,c,g,j);return j}});a.augmentObject(c.FunctionDataSource,b);c.ScriptNodeDataSource=function(a,f){this.dataType=b.TYPE_SCRIPTNODE;c.ScriptNodeDataSource.superclass.constructor.call(this,a||"",f)};a.extend(c.ScriptNodeDataSource,b,{getUtility:c.Get,asyncMode:"allowAll",
+scriptCallbackParam:"callback",generateRequestCallback:function(a){return"&"+this.scriptCallbackParam+"=YAHOO.util.ScriptNodeDataSource.callbacks["+a+"]"},doBeforeGetScriptNode:function(a){return a},makeConnection:function(a,f,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",{tId:j,request:a,callback:f,caller:g});if(c.ScriptNodeDataSource._nPending===0){c.ScriptNodeDataSource.callbacks=[];c.ScriptNodeDataSource._nId=0}var h=c.ScriptNodeDataSource._nId;c.ScriptNodeDataSource._nId++;var e=
+this;c.ScriptNodeDataSource.callbacks[h]=function(i){if(e.asyncMode!=="ignoreStaleResponses"||h===c.ScriptNodeDataSource.callbacks.length-1){if(e.responseType===b.TYPE_UNKNOWN)if(YAHOO.lang.isArray(i))e.responseType=b.TYPE_JSARRAY;else if(i.nodeType&&i.nodeType==9)e.responseType=b.TYPE_XML;else if(i.nodeName&&i.nodeName.toLowerCase()=="table")e.responseType=b.TYPE_HTMLTABLE;else if(YAHOO.lang.isObject(i))e.responseType=b.TYPE_JSON;else if(YAHOO.lang.isString(i))e.responseType=b.TYPE_TEXT;e.handleResponse(a,
+i,f,g,j)}delete c.ScriptNodeDataSource.callbacks[h]};c.ScriptNodeDataSource._nPending++;var i=this.liveData+a+this.generateRequestCallback(h),i=this.doBeforeGetScriptNode(i);this.getUtility.script(i,{autopurge:true,onsuccess:c.ScriptNodeDataSource._bumpPendingDown,onfail:c.ScriptNodeDataSource._bumpPendingDown});return j}});a.augmentObject(c.ScriptNodeDataSource,b);a.augmentObject(c.ScriptNodeDataSource,{_nId:0,_nPending:0,callbacks:[]});c.XHRDataSource=function(a,f){this.dataType=b.TYPE_XHR;this.connMgr=
+this.connMgr||c.Connect;c.XHRDataSource.superclass.constructor.call(this,a||"",f)};a.extend(c.XHRDataSource,b,{connMgr:null,connXhrMode:"allowAll",connMethodPost:false,connTimeout:0,makeConnection:function(d,c,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",{tId:j,request:d,callback:c,caller:g});var h=this.connMgr,e=this._oQueue,i={success:function(a){if(a&&this.connXhrMode=="ignoreStaleResponses"&&a.tId!=e.conn.tId)return null;if(a){if(this.responseType===b.TYPE_UNKNOWN){var i=a.getResponseHeader?
+a.getResponseHeader["Content-Type"]:null;if(i)if(i.indexOf("text/xml")>-1)this.responseType=b.TYPE_XML;else if(i.indexOf("application/json")>-1)this.responseType=b.TYPE_JSON;else if(i.indexOf("text/plain")>-1)this.responseType=b.TYPE_TEXT}this.handleResponse(d,a,c,g,j)}else{this.fireEvent("dataErrorEvent",{request:d,response:null,callback:c,caller:g,message:b.ERROR_DATANULL});b.issueCallback(c,[d,{error:true}],true,g);return null}},failure:function(e){this.fireEvent("dataErrorEvent",{request:d,response:e,
+callback:c,caller:g,message:b.ERROR_DATAINVALID});a.isString(this.liveData)&&a.isString(d)&&this.liveData.lastIndexOf("?")!==this.liveData.length-1&&d.indexOf("?");e=e||{};e.error=true;b.issueCallback(c,[d,e],true,g);return null},scope:this};if(a.isNumber(this.connTimeout))i.timeout=this.connTimeout;if(this.connXhrMode=="cancelStaleRequests"&&e.conn&&h.abort){h.abort(e.conn);e.conn=null}if(h&&h.asyncRequest){var k=this.liveData,l=this.connMethodPost,q=l?"POST":"GET",p=l||!a.isValue(d)?k:k+d,n=l?d:
+null;if(this.connXhrMode!="queueRequests")e.conn=h.asyncRequest(q,p,i,n);else if(e.conn){var o=e.requests;o.push({request:d,callback:i});if(!e.interval)e.interval=setInterval(function(){if(!h.isCallInProgress(e.conn))if(o.length>0){p=l||!a.isValue(o[0].request)?k:k+o[0].request;n=l?o[0].request:null;e.conn=h.asyncRequest(q,p,o[0].callback,n);o.shift()}else{clearInterval(e.interval);e.interval=null}},50)}else e.conn=h.asyncRequest(q,p,i,n)}else b.issueCallback(c,[d,{error:true}],true,g);return j}});
+a.augmentObject(c.XHRDataSource,b);c.DataSource=function(a,f){var f=f||{},g=f.dataType;if(g){if(g==b.TYPE_LOCAL)return new c.LocalDataSource(a,f);if(g==b.TYPE_XHR)return new c.XHRDataSource(a,f);if(g==b.TYPE_SCRIPTNODE)return new c.ScriptNodeDataSource(a,f);if(g==b.TYPE_JSFUNCTION)return new c.FunctionDataSource(a,f)}return YAHOO.lang.isString(a)?new c.XHRDataSource(a,f):YAHOO.lang.isFunction(a)?new c.FunctionDataSource(a,f):new c.LocalDataSource(a,f)};a.augmentObject(c.DataSource,b)})();
+YAHOO.util.Number={format:function(a,c){if(a===""||a===null||!isFinite(a))return"";var a=+a,c=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,c||{}),b=Math.abs(a),d=c.decimalPlaces||0,f=c.thousandsSeparator,g=c.negativeFormat||"-"+c.format,j;g.indexOf("#")>-1&&(g=g.replace(/#/,c.format));if(d<0){j=b-b%1+"";d=j.length+d;j=d>0?Number("."+j).toFixed(d).slice(2)+Array(j.length-d+1).join("0"):"0"}else if(d>0||(b+"").indexOf(".")>0){j=Math.pow(10,d);j=Math.round(b*j)/j+"";var h=j.indexOf(".");if(h<0){h=
+(Math.pow(10,d)+"").substring(1);d>0&&(j=j+"."+h)}else{d=d-(j.length-h-1);h=(Math.pow(10,d)+"").substring(1);j=j+h}}else j=b.toFixed(d)+"";j=j.split(/\D/);if(b>=1E3){d=j[0].length%3||3;j[0]=j[0].slice(0,d)+j[0].slice(d).replace(/(\d{3})/g,f+"$1")}return YAHOO.util.Number.format._applyFormat(a<0?g:c.format,j.join(c.decimalSeparator),c)}};YAHOO.util.Number.format.defaults={format:"{prefix}{number}{suffix}",negativeFormat:null,decimalSeparator:".",decimalPlaces:null,thousandsSeparator:""};
+YAHOO.util.Number.format._applyFormat=function(a,c,b){return a.replace(/\{(\w+)\}/g,function(a,f){return f==="number"?c:f in b?b[f]:""})};
+(function(){var a=function(a,d,c){for(typeof c==="undefined"&&(c=10);parseInt(a,10)<c&&c>1;c=c/10)a=d.toString()+a;return a.toString()},c={formats:{a:function(a,d){return d.a[a.getDay()]},A:function(a,d){return d.A[a.getDay()]},b:function(a,d){return d.b[a.getMonth()]},B:function(a,d){return d.B[a.getMonth()]},C:function(b){return a(parseInt(b.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(b){return a(parseInt(c.formats.G(b)%100,10),0)},G:function(a){var d=a.getFullYear(),
+f=parseInt(c.formats.V(a),10),a=parseInt(c.formats.W(a),10);a>f?d++:a===0&&f>=52&&d--;return d},H:["getHours","0"],I:function(b){b=b.getHours()%12;return a(b===0?12:b,0)},j:function(b){var d=new Date(""+b.getFullYear()+"/1/1 GMT"),b=new Date(""+b.getFullYear()+"/"+(b.getMonth()+1)+"/"+b.getDate()+" GMT")-d,b=parseInt(b/6E4/60/24,10)+1;return a(b,0,100)},k:["getHours"," "],l:function(b){b=b.getHours()%12;return a(b===0?12:b," ")},m:function(b){return a(b.getMonth()+1,0)},M:["getMinutes","0"],p:function(a,
+d){return d.p[a.getHours()>=12?1:0]},P:function(a,d){return d.P[a.getHours()>=12?1:0]},s:function(a){return parseInt(a.getTime()/1E3,10)},S:["getSeconds","0"],u:function(a){a=a.getDay();return a===0?7:a},U:function(b){var d=parseInt(c.formats.j(b),10),b=6-b.getDay(),d=parseInt((d+b)/7,10);return a(d,0)},V:function(b){var d=parseInt(c.formats.W(b),10),f=(new Date(""+b.getFullYear()+"/1/1")).getDay(),d=d+(f>4||f<=1?0:1);d===53&&(new Date(""+b.getFullYear()+"/12/31")).getDay()<4?d=1:d===0&&(d=c.formats.V(new Date(""+
+(b.getFullYear()-1)+"/12/31")));return a(d,0)},w:"getDay",W:function(b){var d=parseInt(c.formats.j(b),10),b=7-c.formats.u(b),d=parseInt((d+b)/7,10);return a(d,0,10)},y:function(b){return a(b.getFullYear()%100,0)},Y:"getFullYear",z:function(b){var b=b.getTimezoneOffset(),d=a(parseInt(Math.abs(b/60),10),0),c=a(Math.abs(b%60),0);return(b>0?"-":"+")+d+c},Z:function(a){var d=a.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");d.length>4&&(d=c.formats.z(a));
+return d},"%":function(){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(b,d,f){d=d||{};if(!(b instanceof Date))return YAHOO.lang.isValue(b)?b:"";d=d.format||"%m/%d/%Y";d==="YYYY/MM/DD"?d="%Y/%m/%d":d==="DD/MM/YYYY"?d="%d/%m/%Y":d==="MM/DD/YYYY"&&(d="%m/%d/%Y");f=f||"en";f in YAHOO.util.DateLocale||(f=f.replace(/-[a-zA-Z]+$/,"")in YAHOO.util.DateLocale?f.replace(/-[a-zA-Z]+$/,""):"en");for(var g=
+YAHOO.util.DateLocale[f],f=function(a,e){var b=c.aggregates[e];return b==="locale"?g[e]:b},j=function(d,e){var i=c.formats[e];return typeof i==="string"?b[i]():typeof i==="function"?i.call(b,b,g):typeof i==="object"&&typeof i[0]==="string"?a(b[i[0]](),i[1]):e};d.match(/%[cDFhnrRtTxX]/);)d=d.replace(/%([cDFhnrRtTxX])/g,f);d=d.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,j);f=j=void 0;return d}};YAHOO.namespace("YAHOO.util");YAHOO.util.Date=c;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.9.0",build:"2800"});YAHOO.widget.DS_JSArray=YAHOO.util.LocalDataSource;YAHOO.widget.DS_JSFunction=YAHOO.util.FunctionDataSource;
+YAHOO.widget.DS_XHR=function(a,c,b){a=new YAHOO.util.XHRDataSource(a,b);a._aDeprecatedSchema=c;return a};YAHOO.widget.DS_ScriptNode=function(a,c,b){a=new YAHOO.util.ScriptNodeDataSource(a,b);a._aDeprecatedSchema=c;return a};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(a,c,b,d){if(a&&c&&b&&b&&YAHOO.lang.isFunction(b.sendRequest)){this.dataSource=b;this.key=0;var f=b.responseSchema;if(b._aDeprecatedSchema){var g=b._aDeprecatedSchema;if(YAHOO.lang.isArray(g)){if(b.responseType===YAHOO.util.DataSourceBase.TYPE_JSON||b.responseType===YAHOO.util.DataSourceBase.TYPE_UNKNOWN){f.resultsList=g[0];this.key=g[1];f.fields=g.length<3?null:g.slice(1)}else if(b.responseType===YAHOO.util.DataSourceBase.TYPE_XML){f.resultNode=g[0];this.key=g[1];
+f.fields=g.slice(1)}else if(b.responseType===YAHOO.util.DataSourceBase.TYPE_TEXT){f.recordDelim=g[0];f.fieldDelim=g[1]}b.responseSchema=f}}if(YAHOO.util.Dom.inDocument(a)){if(YAHOO.lang.isString(a)){this._sName="instance"+YAHOO.widget.AutoComplete._nIndex+" "+a;this._elTextbox=document.getElementById(a)}else{this._sName=a.id?"instance"+YAHOO.widget.AutoComplete._nIndex+" "+a.id:"instance"+YAHOO.widget.AutoComplete._nIndex;this._elTextbox=a}YAHOO.util.Dom.addClass(this._elTextbox,"yui-ac-input");if(YAHOO.util.Dom.inDocument(c)){this._elContainer=
+YAHOO.lang.isString(c)?document.getElementById(c):c;a=this._elContainer.parentNode;a.tagName.toLowerCase()=="div"&&YAHOO.util.Dom.addClass(a,"yui-ac");if(this.dataSource.dataType===YAHOO.util.DataSourceBase.TYPE_LOCAL)this.applyLocalFilter=true;if(d&&d.constructor==Object)for(var j in d)j&&(this[j]=d[j]);this._initContainerEl();this._initProps();this._initListEl();this._initContainerHelperEls();d=this._elTextbox;YAHOO.util.Event.addListener(d,"keyup",this._onTextboxKeyUp,this);YAHOO.util.Event.addListener(d,
+"keydown",this._onTextboxKeyDown,this);YAHOO.util.Event.addListener(d,"focus",this._onTextboxFocus,this);YAHOO.util.Event.addListener(d,"blur",this._onTextboxBlur,this);YAHOO.util.Event.addListener(c,"mouseover",this._onContainerMouseover,this);YAHOO.util.Event.addListener(c,"mouseout",this._onContainerMouseout,this);YAHOO.util.Event.addListener(c,"click",this._onContainerClick,this);YAHOO.util.Event.addListener(c,"scroll",this._onContainerScroll,this);YAHOO.util.Event.addListener(c,"resize",this._onContainerResize,
+this);YAHOO.util.Event.addListener(d,"keypress",this._onTextboxKeyPress,this);YAHOO.util.Event.addListener(window,"unload",this._onWindowUnload,this);this.textboxFocusEvent=new YAHOO.util.CustomEvent("textboxFocus",this);this.textboxKeyEvent=new YAHOO.util.CustomEvent("textboxKey",this);this.textboxKeyUpEvent=new YAHOO.util.CustomEvent("textboxKeyUp",this);this.dataRequestEvent=new YAHOO.util.CustomEvent("dataRequest",this);this.dataRequestCancelEvent=new YAHOO.util.CustomEvent("dataRequestCancel",
+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);d.setAttribute("autocomplete","off");YAHOO.widget.AutoComplete._nIndex++}}}};YAHOO.widget.AutoComplete.prototype.dataSource=null;YAHOO.widget.AutoComplete.prototype.applyLocalFilter=null;YAHOO.widget.AutoComplete.prototype.queryMatchCase=!1;YAHOO.widget.AutoComplete.prototype.queryMatchContains=!1;YAHOO.widget.AutoComplete.prototype.queryMatchSubset=!1;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=!0;
+YAHOO.widget.AutoComplete.prototype.typeAhead=!1;YAHOO.widget.AutoComplete.prototype.animHoriz=!1;YAHOO.widget.AutoComplete.prototype.animVert=!0;YAHOO.widget.AutoComplete.prototype.animSpeed=0.3;YAHOO.widget.AutoComplete.prototype.forceSelection=!1;YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete=!0;YAHOO.widget.AutoComplete.prototype.alwaysShowContainer=!1;YAHOO.widget.AutoComplete.prototype.useIFrame=!1;YAHOO.widget.AutoComplete.prototype.useShadow=!1;
+YAHOO.widget.AutoComplete.prototype.suppressInputUpdate=!1;YAHOO.widget.AutoComplete.prototype.resultTypeList=!0;YAHOO.widget.AutoComplete.prototype.queryQuestionMark=!0;YAHOO.widget.AutoComplete.prototype.autoSnapContainer=!0;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){return a._sResultMatch?a._sResultMatch:null};YAHOO.widget.AutoComplete.prototype.getListItemData=function(a){return a._oResultData?a._oResultData:null};
+YAHOO.widget.AutoComplete.prototype.getListItemIndex=function(a){return YAHOO.lang.isNumber(a._nItemIndex)?a._nItemIndex:null};YAHOO.widget.AutoComplete.prototype.setHeader=function(a){if(this._elHeader){var c=this._elHeader;if(a){c.innerHTML=a;c.style.display=""}else{c.innerHTML="";c.style.display="none"}}};YAHOO.widget.AutoComplete.prototype.setFooter=function(a){if(this._elFooter){var c=this._elFooter;if(a){c.innerHTML=a;c.style.display=""}else{c.innerHTML="";c.style.display="none"}}};
+YAHOO.widget.AutoComplete.prototype.setBody=function(a){if(this._elBody){var c=this._elBody;YAHOO.util.Event.purgeElement(c,true);if(a){c.innerHTML=a;c.style.display=""}else{c.innerHTML="";c.style.display="none"}this._elList=null}};
+YAHOO.widget.AutoComplete.prototype.generateRequest=function(a){var c=this.dataSource.dataType;c===YAHOO.util.DataSourceBase.TYPE_XHR?a=this.dataSource.connMethodPost?(this.dataSource.scriptQueryParam||"query")+"="+a+(this.dataSource.scriptQueryAppend?"&"+this.dataSource.scriptQueryAppend:""):(this.queryQuestionMark?"?":"")+(this.dataSource.scriptQueryParam||"query")+"="+a+(this.dataSource.scriptQueryAppend?"&"+this.dataSource.scriptQueryAppend:""):c===YAHOO.util.DataSourceBase.TYPE_SCRIPTNODE&&(a=
+"&"+(this.dataSource.scriptQueryParam||"query")+"="+a+(this.dataSource.scriptQueryAppend?"&"+this.dataSource.scriptQueryAppend:""));return a};YAHOO.widget.AutoComplete.prototype.sendQuery=function(a){this._bFocused=true;this._sendQuery(this.delimChar?this._elTextbox.value+a:a)};YAHOO.widget.AutoComplete.prototype.snapContainer=function(){var a=this._elTextbox,c=YAHOO.util.Dom.getXY(a);c[1]=c[1]+(YAHOO.util.Dom.get(a).offsetHeight+2);YAHOO.util.Dom.setXY(this._elContainer,c)};
+YAHOO.widget.AutoComplete.prototype.expandContainer=function(){this._toggleContainer(true)};YAHOO.widget.AutoComplete.prototype.collapseContainer=function(){this._toggleContainer(false)};YAHOO.widget.AutoComplete.prototype.clearList=function(){for(var a=this._elList.childNodes,c=a.length-1;c>-1;c--)a[c].style.display="none"};
+YAHOO.widget.AutoComplete.prototype.getSubsetMatches=function(a){for(var c,b=a.length;b>=this.minQueryLength;b--){c=this.generateRequest(a.substr(0,b));this.dataRequestEvent.fire(this,void 0,c);if(c=this.dataSource.getCachedResponse(c))return this.filterResults.apply(this.dataSource,[a,c,c,{scope:this}])}return null};
+YAHOO.widget.AutoComplete.prototype.preparseRawResponse=function(a,c){var b=this.responseStripAfter!==""&&c.indexOf?c.indexOf(this.responseStripAfter):-1;b!=-1&&(c=c.substring(0,b));return c};
+YAHOO.widget.AutoComplete.prototype.filterResults=function(a,c,b,d){if(d&&d.argument&&YAHOO.lang.isValue(d.argument.query))a=d.argument.query;if(a&&a!==""){for(var b=YAHOO.widget.AutoComplete._cloneObject(b),f=d.scope,c=b.results,d=[],g=f.maxResultsDisplayed,j=this.queryMatchCase||f.queryMatchCase,f=this.queryMatchContains||f.queryMatchContains,h=0,e=c.length;h<e;h++){var i=c[h],k=null;YAHOO.lang.isString(i)?k=i:YAHOO.lang.isArray(i)?k=i[0]:this.responseSchema.fields?k=i[this.responseSchema.fields[0].key||
+this.responseSchema.fields[0]]:this.key&&(k=i[this.key]);if(YAHOO.lang.isString(k)){k=j?k.indexOf(decodeURIComponent(a)):k.toLowerCase().indexOf(decodeURIComponent(a).toLowerCase());(!f&&k===0||f&&k>-1)&&d.push(i)}if(e>g&&d.length===g)break}b.results=d}return b};YAHOO.widget.AutoComplete.prototype.handleResponse=function(a,c,b){this instanceof YAHOO.widget.AutoComplete&&this._sName&&this._populateList(a,c,b)};YAHOO.widget.AutoComplete.prototype.doBeforeLoadData=function(){return true};
+YAHOO.widget.AutoComplete.prototype.formatResult=function(a,c,b){return b?b:""};YAHOO.widget.AutoComplete.prototype.formatEscapedResult=function(a,c,b){return YAHOO.lang.escapeHTML(b?b:"")};YAHOO.widget.AutoComplete.prototype.doBeforeExpandContainer=function(){return true};
+YAHOO.widget.AutoComplete.prototype.destroy=function(){var a=this._elTextbox,c=this._elContainer;this.textboxFocusEvent.unsubscribeAll();this.textboxKeyEvent.unsubscribeAll();this.textboxKeyUpEvent.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(c,true);c.innerHTML="";for(var b in this)YAHOO.lang.hasOwnProperty(this,b)&&(this[b]=null)};
+YAHOO.widget.AutoComplete.prototype.textboxFocusEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyUpEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestCancelEvent=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=!1;YAHOO.widget.AutoComplete.prototype._oAnim=null;YAHOO.widget.AutoComplete.prototype._bContainerOpen=!1;YAHOO.widget.AutoComplete.prototype._bOverContainer=!1;
+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=!1;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(){if(!YAHOO.lang.isNumber(this.minQueryLength))this.minQueryLength=1;var a=this.maxResultsDisplayed;if(!YAHOO.lang.isNumber(a)||a<1)this.maxResultsDisplayed=10;a=this.queryDelay;if(!YAHOO.lang.isNumber(a)||a<0)this.queryDelay=0.2;a=this.typeAheadDelay;if(!YAHOO.lang.isNumber(a)||a<0)this.typeAheadDelay=0.2;a=this.delimChar;if(YAHOO.lang.isString(a)&&a.length>0)this.delimChar=[a];else if(!YAHOO.lang.isArray(a))this.delimChar=null;a=this.animSpeed;
+if((this.animHoriz||this.animVert)&&YAHOO.util.Anim){if(!YAHOO.lang.isNumber(a)||a<0)this.animSpeed=0.3;this._oAnim?this._oAnim.duration=this.animSpeed:this._oAnim=new YAHOO.util.Anim(this._elContent,{},this.animSpeed)}};
+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){a=document.createElement("iframe");a.src=this._iFrameSrc;a.frameBorder=0;a.scrolling="no";a.style.position="absolute";a.style.width=0;a.style.height=0;a.style.padding=0;a.tabIndex=-1;a.role="presentation";a.title=
+"Presentational iframe shim";this._elIFrame=this._elContainer.appendChild(a)}};
+YAHOO.widget.AutoComplete.prototype._initContainerEl=function(){YAHOO.util.Dom.addClass(this._elContainer,"yui-ac-container");if(!this._elContent){var a=document.createElement("div");a.className="yui-ac-content";a.style.display="none";this._elContent=this._elContainer.appendChild(a);a=document.createElement("div");a.className="yui-ac-hd";a.style.display="none";this._elHeader=this._elContent.appendChild(a);a=document.createElement("div");a.className="yui-ac-bd";this._elBody=this._elContent.appendChild(a);
+a=document.createElement("div");a.className="yui-ac-ft";a.style.display="none";this._elFooter=this._elContent.appendChild(a)}};
+YAHOO.widget.AutoComplete.prototype._initListEl=function(){for(var a=this.maxResultsDisplayed,c=this._elList||document.createElement("ul"),b;c.childNodes.length<a;){b=document.createElement("li");b.style.display="none";b._nItemIndex=c.childNodes.length;c.appendChild(b)}if(!this._elList){a=this._elBody;YAHOO.util.Event.purgeElement(a,true);a.innerHTML="";this._elList=a.appendChild(c)}this._elBody.style.display=""};
+YAHOO.widget.AutoComplete.prototype._focus=function(){var a=this;setTimeout(function(){try{a._elTextbox.focus()}catch(c){}},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;if(a!=this._sLastTextboxValue){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){return 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?true:false};
+YAHOO.widget.AutoComplete.prototype._sendQuery=function(a){if(this.minQueryLength<0)this._toggleContainer(false);else{if(this.delimChar){var c=this._extractQuery(a),a=c.query;this._sPastSelections=c.previous}if(a&&a.length<this.minQueryLength||!a&&this.minQueryLength>0){this._nDelayID!=-1&&clearTimeout(this._nDelayID);this._toggleContainer(false)}else{a=encodeURIComponent(a);this._nDelayID=-1;if(this.dataSource.queryMatchSubset||this.queryMatchSubset)if(c=this.getSubsetMatches(a)){this.handleResponse(a,
+c,{query:a});return}if(this.dataSource.responseStripAfter)this.dataSource.doBeforeParseData=this.preparseRawResponse;if(this.applyLocalFilter)this.dataSource.doBeforeCallback=this.filterResults;c=this.generateRequest(a);if(c!==void 0){this.dataRequestEvent.fire(this,a,c);this.dataSource.sendRequest(c,{success:this.handleResponse,failure:this.handleResponse,scope:this,argument:{query:a}})}else this.dataRequestCancelEvent.fire(this,a)}}};
+YAHOO.widget.AutoComplete.prototype._populateListItem=function(a,c,b){a.innerHTML=this.formatResult(c,b,a._sResultMatch)};
+YAHOO.widget.AutoComplete.prototype._populateList=function(a,c,b){this._nTypeAheadDelayID!=-1&&clearTimeout(this._nTypeAheadDelayID);a=b&&b.query?b.query:a;if((b=this.doBeforeLoadData(a,c,b))&&!c.error){this.dataReturnEvent.fire(this,a,c.results);if(this._bFocused){var d=decodeURIComponent(a);this._sCurQuery=d;this._bItemSelected=false;var c=c.results,b=Math.min(c.length,this.maxResultsDisplayed),f=this.dataSource.responseSchema.fields?this.dataSource.responseSchema.fields[0].key||this.dataSource.responseSchema.fields[0]:
+0;if(b>0){(!this._elList||this._elList.childNodes.length<b)&&this._initListEl();this._initContainerHelperEls();for(var g=this._elList.childNodes,j=b-1;j>=0;j--){var h=g[j],e=c[j];if(this.resultTypeList){var i=[];i[0]=YAHOO.lang.isString(e)?e:e[f]||e[this.key];var k=this.dataSource.responseSchema.fields;if(YAHOO.lang.isArray(k)&&k.length>1)for(var l=1,q=k.length;l<q;l++)i[i.length]=e[k[l].key||k[l]];else YAHOO.lang.isArray(e)?i=e:YAHOO.lang.isString(e)?i=[e]:i[1]=e;e=i}h._sResultMatch=YAHOO.lang.isString(e)?
+e:YAHOO.lang.isArray(e)?e[0]:e[f]||"";h._oResultData=e;this._populateListItem(h,e,d);h.style.display=""}if(b<g.length)for(f=g.length-1;f>=b;f--){d=g[f];d.style.display="none"}this._nDisplayedItems=b;this.containerPopulateEvent.fire(this,a,c);if(this.autoHighlight){b=this._elList.firstChild;this._toggleHighlight(b,"to");this.itemArrowToEvent.fire(this,b);this._typeAhead(b,a)}else this._toggleHighlight(this._elCurListItem,"from");b=this._doBeforeExpandContainer(this._elTextbox,this._elContainer,a,c);
+this._toggleContainer(b)}else this._toggleContainer(false)}}else this.dataErrorEvent.fire(this,a,c)};YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer=function(a,c,b,d){this.autoSnapContainer&&this.snapContainer();return this.doBeforeExpandContainer(a,c,b,d)};
+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(){for(var a=null,c=0;c<this._nDisplayedItems;c++){var b=this._elList.childNodes[c];if((""+b._sResultMatch).toLowerCase()==this._sCurQuery.toLowerCase()){a=b;break}}return a};
+YAHOO.widget.AutoComplete.prototype._typeAhead=function(a,c){if(this.typeAhead&&this._nKeyCode!=8){var b=this,d=this._elTextbox;if(d.setSelectionRange||d.createTextRange)this._nTypeAheadDelayID=setTimeout(function(){var f=d.value.length;b._updateValue(a);var g=d.value.length;b._selectText(d,f,g);f=d.value.substr(f,g);b._sCurQuery=a._sResultMatch;b.typeAheadEvent.fire(b,c,f)},this.typeAheadDelay*1E3)}};
+YAHOO.widget.AutoComplete.prototype._selectText=function(a,c,b){if(a.setSelectionRange)a.setSelectionRange(c,b);else if(a.createTextRange){var d=a.createTextRange();d.moveStart("character",c);d.moveEnd("character",b-a.value.length);d.select()}else a.select()};
+YAHOO.widget.AutoComplete.prototype._extractQuery=function(a){for(var c=this.delimChar,b=-1,d,f=c.length-1;f>=0;f--){d=a.lastIndexOf(c[f]);d>b&&(b=d)}if(c[f]==" ")for(d=c.length-1;d>=0;d--)if(a[b-1]==c[d]){b--;break}if(b>-1){for(c=b+1;a.charAt(c)==" ";)c=c+1;b=a.substring(0,c);a=a.substr(c)}else b="";return{previous:b,query:a}};
+YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers=function(a){var c=this._elContent.offsetWidth+"px",b=this._elContent.offsetHeight+"px";if(this.useIFrame&&this._elIFrame){var d=this._elIFrame;if(a){d.style.width=c;d.style.height=b;d.style.padding=""}else{d.style.width=0;d.style.height=0;d.style.padding=0}}if(this.useShadow&&this._elShadow){d=this._elShadow;if(a){d.style.width=c;d.style.height=b}else{d.style.width=0;d.style.height=0}}};
+YAHOO.widget.AutoComplete.prototype._toggleContainer=function(a){var c=this._elContainer;if(!this.alwaysShowContainer||!this._bContainerOpen){if(!a){this._toggleHighlight(this._elCurListItem,"from");this._nDisplayedItems=0;this._sCurQuery=null;if(this._elContent.style.display=="none")return}var b=this._oAnim;if(b&&b.getEl()&&(this.animHoriz||this.animVert)){b.isAnimated()&&b.stop(true);var d=this._elContent.cloneNode(true);c.appendChild(d);d.style.top="-9000px";d.style.width="";d.style.height="";
+d.style.display="";var f=d.offsetWidth,g=d.offsetHeight,j=this.animHoriz?0:f,h=this.animVert?0:g;b.attributes=a?{width:{to:f},height:{to:g}}:{width:{to:j},height:{to:h}};if(a&&!this._bContainerOpen){this._elContent.style.width=j+"px";this._elContent.style.height=h+"px"}else{this._elContent.style.width=f+"px";this._elContent.style.height=g+"px"}c.removeChild(d);var d=null,e=this;this._toggleContainerHelpers(false);this._elContent.style.display="";b.onComplete.subscribe(function(){b.onComplete.unsubscribeAll();
+if(a){e._toggleContainerHelpers(true);e._bContainerOpen=a;e.containerExpandEvent.fire(e)}else{e._elContent.style.display="none";e._bContainerOpen=a;e.containerCollapseEvent.fire(e)}});b.animate()}else if(a){this._elContent.style.display="";this._toggleContainerHelpers(true);this._bContainerOpen=a;this.containerExpandEvent.fire(this)}else{this._toggleContainerHelpers(false);this._elContent.style.display="none";this._bContainerOpen=a;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(a,c){var b=this.prehighlightClassName;this._elCurPrehighlightItem&&YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem,b);if(a!=this._elCurListItem)if(c=="mouseover"&&b){YAHOO.util.Dom.addClass(a,b);this._elCurPrehighlightItem=a}else YAHOO.util.Dom.removeClass(a,b)};
+YAHOO.widget.AutoComplete.prototype._updateValue=function(a){if(!this.suppressInputUpdate){var c=this._elTextbox,b=this.delimChar?this.delimChar[0]||this.delimChar:null,d=a._sResultMatch,f="";if(b){f=this._sPastSelections;f=f+(d+b);b!=" "&&(f=f+" ")}else f=d;c.value=f;if(c.type=="textarea")c.scrollTop=c.scrollHeight;b=c.value.length;this._selectText(c,b,b);this._elCurListItem=a}};
+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(){this._elCurListItem?this._selectItem(this._elCurListItem):this._toggleContainer(false)};
+YAHOO.widget.AutoComplete.prototype._moveSelection=function(a){if(this._bContainerOpen){var c=this._elCurListItem,b=-1;if(c)b=c._nItemIndex;b=a==40?b+1:b-1;if(!(b<-2||b>=this._nDisplayedItems)){if(c){this._toggleHighlight(c,"from");this.itemArrowFromEvent.fire(this,c)}if(b==-1)this._elTextbox.value=this.delimChar?this._sPastSelections+this._sCurQuery:this._sCurQuery;else if(b==-2)this._toggleContainer(false);else{var c=this._elList.childNodes[b],d=this._elContent,f=YAHOO.util.Dom.getStyle(d,"overflow"),
+g=YAHOO.util.Dom.getStyle(d,"overflowY");if((f=="auto"||f=="scroll"||g=="auto"||g=="scroll")&&b>-1&&b<this._nDisplayedItems)if(a==40)if(c.offsetTop+c.offsetHeight>d.scrollTop+d.offsetHeight)d.scrollTop=c.offsetTop+c.offsetHeight-d.offsetHeight;else{if(c.offsetTop+c.offsetHeight<d.scrollTop)d.scrollTop=c.offsetTop}else if(c.offsetTop<d.scrollTop)this._elContent.scrollTop=c.offsetTop;else if(c.offsetTop>d.scrollTop+d.offsetHeight)this._elContent.scrollTop=c.offsetTop+c.offsetHeight-d.offsetHeight;this._toggleHighlight(c,
+"to");this.itemArrowToEvent.fire(this,c);if(this.typeAhead){this._updateValue(c);this._sCurQuery=c._sResultMatch}}}}};
+YAHOO.widget.AutoComplete.prototype._onContainerMouseover=function(a,c){for(var b=YAHOO.util.Event.getTarget(a),d=b.nodeName.toLowerCase();b&&d!="table";){switch(d){case "body":return;case "li":c.prehighlightClassName?c._togglePrehighlight(b,"mouseover"):c._toggleHighlight(b,"to");c.itemMouseOverEvent.fire(c,b);break;case "div":if(YAHOO.util.Dom.hasClass(b,"yui-ac-container")){c._bOverContainer=true;return}}(b=b.parentNode)&&(d=b.nodeName.toLowerCase())}};
+YAHOO.widget.AutoComplete.prototype._onContainerMouseout=function(a,c){for(var b=YAHOO.util.Event.getTarget(a),d=b.nodeName.toLowerCase();b&&d!="table";){switch(d){case "body":return;case "li":c.prehighlightClassName?c._togglePrehighlight(b,"mouseout"):c._toggleHighlight(b,"from");c.itemMouseOutEvent.fire(c,b);break;case "ul":c._toggleHighlight(c._elCurListItem,"to");break;case "div":if(YAHOO.util.Dom.hasClass(b,"yui-ac-container")){c._bOverContainer=false;return}}(b=b.parentNode)&&(d=b.nodeName.toLowerCase())}};
+YAHOO.widget.AutoComplete.prototype._onContainerClick=function(a,c){for(var b=YAHOO.util.Event.getTarget(a),d=b.nodeName.toLowerCase();b&&d!="table";){switch(d){case "body":return;case "li":c._toggleHighlight(b,"to");c._selectItem(b);return}(b=b.parentNode)&&(d=b.nodeName.toLowerCase())}};YAHOO.widget.AutoComplete.prototype._onContainerScroll=function(a,c){c._focus()};YAHOO.widget.AutoComplete.prototype._onContainerResize=function(a,c){c._toggleContainerHelpers(c._bContainerOpen)};
+YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown=function(a,c){var b=a.keyCode;c._nTypeAheadDelayID!=-1&&clearTimeout(c._nTypeAheadDelayID);switch(b){case 9:if(!YAHOO.env.ua.opera&&navigator.userAgent.toLowerCase().indexOf("mac")==-1||YAHOO.env.ua.webkit>420)if(c._elCurListItem){c.delimChar&&c._nKeyCode!=b&&c._bContainerOpen&&YAHOO.util.Event.stopEvent(a);c._selectItem(c._elCurListItem)}else c._toggleContainer(false);break;case 13:if(!YAHOO.env.ua.opera&&navigator.userAgent.toLowerCase().indexOf("mac")==
+-1||YAHOO.env.ua.webkit>420)if(c._elCurListItem){c._nKeyCode!=b&&c._bContainerOpen&&YAHOO.util.Event.stopEvent(a);c._selectItem(c._elCurListItem)}else c._toggleContainer(false);break;case 27:c._toggleContainer(false);return;case 39:c._jumpSelection();break;case 38:if(c._bContainerOpen){YAHOO.util.Event.stopEvent(a);c._moveSelection(b)}break;case 40:if(c._bContainerOpen){YAHOO.util.Event.stopEvent(a);c._moveSelection(b)}break;default:c._bItemSelected=false;c._toggleHighlight(c._elCurListItem,"from");
+c.textboxKeyEvent.fire(c,b)}b===18&&c._enableIntervalDetection();c._nKeyCode=b};
+YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress=function(a,c){var b=a.keyCode;if(YAHOO.env.ua.opera||navigator.userAgent.toLowerCase().indexOf("mac")!=-1&&YAHOO.env.ua.webkit<420)switch(b){case 9:if(c._bContainerOpen){c.delimChar&&YAHOO.util.Event.stopEvent(a);c._elCurListItem?c._selectItem(c._elCurListItem):c._toggleContainer(false)}break;case 13:if(c._bContainerOpen){YAHOO.util.Event.stopEvent(a);c._elCurListItem?c._selectItem(c._elCurListItem):c._toggleContainer(false)}}else b==229&&c._enableIntervalDetection()};
+YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp=function(a,c){var b=this.value;c._initProps();if(!c._isIgnoreKey(a.keyCode)){c._nDelayID!=-1&&clearTimeout(c._nDelayID);c._nDelayID=setTimeout(function(){c._sendQuery(b)},c.queryDelay*1E3);c.textboxKeyUpEvent.fire(c,b)}};YAHOO.widget.AutoComplete.prototype._onTextboxFocus=function(a,c){if(!c._bFocused){c._elTextbox.setAttribute("autocomplete","off");c._bFocused=true;c._sInitInputValue=c._elTextbox.value;c.textboxFocusEvent.fire(c)}};
+YAHOO.widget.AutoComplete.prototype._onTextboxBlur=function(a,c){if(!c._bOverContainer||c._nKeyCode==9){if(!c._bItemSelected){var b=c._textMatchesOption();!c._bContainerOpen||c._bContainerOpen&&b===null?c.forceSelection?c._clearSelection():c.unmatchedItemSelectEvent.fire(c,c._sCurQuery):c.forceSelection&&c._selectItem(b)}c._clearInterval();c._bFocused=false;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,c){c&&(c._elTextbox&&c.allowBrowserAutocomplete)&&c._elTextbox.setAttribute("autocomplete","on")};YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery=function(a){return this.generateRequest(a)};YAHOO.widget.AutoComplete.prototype.getListItems=function(){for(var a=[],c=this._elList.childNodes,b=c.length-1;b>=0;b--)a[b]=c[b];return a};
+YAHOO.widget.AutoComplete._cloneObject=function(a){if(!YAHOO.lang.isValue(a))return a;var c={};if(YAHOO.lang.isFunction(a))c=a;else if(YAHOO.lang.isArray(a))for(var c=[],b=0,d=a.length;b<d;b++)c[b]=YAHOO.widget.AutoComplete._cloneObject(a[b]);else if(YAHOO.lang.isObject(a))for(b in a)YAHOO.lang.hasOwnProperty(a,b)&&(c[b]=YAHOO.lang.isValue(a[b])&&YAHOO.lang.isObject(a[b])||YAHOO.lang.isArray(a[b])?YAHOO.widget.AutoComplete._cloneObject(a[b]):a[b]);else c=a;return c};
+YAHOO.register("autocomplete",YAHOO.widget.AutoComplete,{version:"2.9.0",build:"2800"});
+(function(){YAHOO.util.Config=function(a){a&&this.init(a)};var a=YAHOO.lang,c=YAHOO.util.CustomEvent,b=YAHOO.util.Config;b.CONFIG_CHANGED_EVENT="configChanged";b.BOOLEAN_TYPE="boolean";b.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(a){this.owner=a;this.configChangedEvent=this.createEvent(b.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=c.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};
+this.eventQueue=[]},checkBoolean:function(a){return typeof a==b.BOOLEAN_TYPE},checkNumber:function(a){return!isNaN(a)},fireEvent:function(a,b){var c=this.config[a];c&&c.event&&c.event.fire(b)},addProperty:function(a,b){a=a.toLowerCase();this.config[a]=b;b.event=this.createEvent(a,{scope:this.owner});b.event.signature=c.LIST;b.key=a;b.handler&&b.event.subscribe(b.handler,this.owner);this.setProperty(a,b.value,true);b.suppressEvent||this.queueProperty(a,b.value)},getConfig:function(){var b={},c=this.config,
+g,j;for(g in c)if(a.hasOwnProperty(c,g))if((j=c[g])&&j.event)b[g]=j.value;return b},getProperty:function(a){if((a=this.config[a.toLowerCase()])&&a.event)return a.value},resetProperty:function(a){var a=a.toLowerCase(),b=this.config[a];if(b&&b.event){if(a in this.initialConfig){this.setProperty(a,this.initialConfig[a]);return true}}else return false},setProperty:function(a,b,c){var j,a=a.toLowerCase();if(this.queueInProgress&&!c){this.queueProperty(a,b);return true}if((j=this.config[a])&&j.event){if(j.validator&&
+!j.validator(b))return false;j.value=b;if(!c){this.fireEvent(a,b);this.configChangedEvent.fire([a,b])}return true}return false},queueProperty:function(b,c){var b=b.toLowerCase(),g=this.config[b],j=false,h,e,i,k,l,q;if(g&&g.event){if(!a.isUndefined(c)&&g.validator&&!g.validator(c))return false;a.isUndefined(c)?c=g.value:g.value=c;j=false;h=this.eventQueue.length;for(l=0;l<h;l++)if(e=this.eventQueue[l]){i=e[0];e=e[1];if(i==b){this.eventQueue[l]=null;this.eventQueue.push([b,!a.isUndefined(c)?c:e]);j=
+true;break}}!j&&!a.isUndefined(c)&&this.eventQueue.push([b,c]);if(g.supercedes){j=g.supercedes.length;for(e=0;e<j;e++){h=g.supercedes[e];i=this.eventQueue.length;for(q=0;q<i;q++)if(k=this.eventQueue[q]){l=k[0];k=k[1];if(l==h.toLowerCase()){this.eventQueue.push([l,k]);this.eventQueue[q]=null;break}}}}return true}return false},refireEvent:function(b){var b=b.toLowerCase(),c=this.config[b];c&&(c.event&&!a.isUndefined(c.value))&&(this.queueInProgress?this.queueProperty(b):this.fireEvent(b,c.value))},
+applyConfig:function(b,c){var g,j;if(c){j={};for(g in b)a.hasOwnProperty(b,g)&&(j[g.toLowerCase()]=b[g]);this.initialConfig=j}for(g in b)a.hasOwnProperty(b,g)&&this.queueProperty(g,b[g])},refresh:function(){for(var b in this.config)a.hasOwnProperty(this.config,b)&&this.refireEvent(b)},fireQueue:function(){var a,b,c,j;this.queueInProgress=true;for(a=0;a<this.eventQueue.length;a++)if(b=this.eventQueue[a]){c=b[0];b=b[1];j=this.config[c];j.value=b;this.eventQueue[a]=null;this.fireEvent(c,b)}this.queueInProgress=
+false;this.eventQueue=[]},subscribeToConfigEvent:function(a,c,g,j){if((a=this.config[a.toLowerCase()])&&a.event){b.alreadySubscribed(a.event,c,g)||a.event.subscribe(c,g,j);return true}return false},unsubscribeFromConfigEvent:function(a,b,c){return(a=this.config[a.toLowerCase()])&&a.event?a.event.unsubscribe(b,c):false},toString:function(){var a="Config";this.owner&&(a=a+(" ["+this.owner.toString()+"]"));return a},outputEventQueue:function(){var a="",b,c,j=this.eventQueue.length;for(c=0;c<j;c++)(b=
+this.eventQueue[c])&&(a=a+(b[0]+"="+b[1]+", "));return a},destroy:function(){var b=this.config,c,g;for(c in b)if(a.hasOwnProperty(b,c)){g=b[c];g.event.unsubscribeAll();g.event=null}this.configChangedEvent.unsubscribeAll();this.eventQueue=this.initialConfig=this.config=this.owner=this.configChangedEvent=null}};b.alreadySubscribed=function(a,b,c){var j=a.subscribers.length,h;if(j>0){h=j-1;do if((j=a.subscribers[h])&&j.obj==c&&j.fn==b)return true;while(h--)}return false};YAHOO.lang.augmentProto(b,YAHOO.util.EventProvider)})();
+(function(){function a(){if(!k){k=document.createElement("div");k.innerHTML='<div class="'+e.CSS_HEADER+'"></div><div class="'+e.CSS_BODY+'"></div><div class="'+e.CSS_FOOTER+'"></div>';l=k.firstChild;q=l.nextSibling;p=q.nextSibling}return k}function c(){l||a();return l.cloneNode(false)}function b(){q||a();return q.cloneNode(false)}function d(){p||a();return p.cloneNode(false)}YAHOO.widget.Module=function(a,e){a&&this.init(a,e)};var f=YAHOO.util.Dom,g=YAHOO.util.Config,j=YAHOO.util.Event,h=YAHOO.util.CustomEvent,
+e=YAHOO.widget.Module,i=YAHOO.env.ua,k,l,q,p,n=YAHOO.lang.isBoolean,o=["visible"];e.IMG_ROOT=null;e.IMG_ROOT_SSL=null;e.CSS_MODULE="yui-module";e.CSS_HEADER="hd";e.CSS_BODY="bd";e.CSS_FOOTER="ft";e.RESIZE_MONITOR_SECURE_URL="javascript:false;";e.RESIZE_MONITOR_BUFFER=1;e.textResizeEvent=new h("textResize");e.forceDocumentRedraw=function(){var a=document.documentElement;if(a){a.className=a.className+" ";a.className=YAHOO.lang.trim(a.className)}};var m=e,r=e,s=e.IMG_ROOT,t=function(){var a=navigator.userAgent.toLowerCase();
+return a.indexOf("windows")!=-1||a.indexOf("win32")!=-1?"windows":a.indexOf("macintosh")!=-1?"mac":false}(),u=function(){var a=navigator.userAgent.toLowerCase();return a.indexOf("opera")!=-1?"opera":a.indexOf("msie 7")!=-1?"ie7":a.indexOf("msie")!=-1?"ie":a.indexOf("safari")!=-1?"safari":a.indexOf("gecko")!=-1?"gecko":false}(),w;w=window.location.href.toLowerCase().indexOf("https")===0?true:false;m.prototype={constructor:r,element:null,header:null,body:null,footer:null,id:null,imageRoot:s,initEvents:function(){var a=
+h.LIST;this.beforeInitEvent=this.createEvent("beforeInit");this.beforeInitEvent.signature=a;this.initEvent=this.createEvent("init");this.initEvent.signature=a;this.appendEvent=this.createEvent("append");this.appendEvent.signature=a;this.beforeRenderEvent=this.createEvent("beforeRender");this.beforeRenderEvent.signature=a;this.renderEvent=this.createEvent("render");this.renderEvent.signature=a;this.changeHeaderEvent=this.createEvent("changeHeader");this.changeHeaderEvent.signature=a;this.changeBodyEvent=
+this.createEvent("changeBody");this.changeBodyEvent.signature=a;this.changeFooterEvent=this.createEvent("changeFooter");this.changeFooterEvent.signature=a;this.changeContentEvent=this.createEvent("changeContent");this.changeContentEvent.signature=a;this.destroyEvent=this.createEvent("destroy");this.destroyEvent.signature=a;this.beforeShowEvent=this.createEvent("beforeShow");this.beforeShowEvent.signature=a;this.showEvent=this.createEvent("show");this.showEvent.signature=a;this.beforeHideEvent=this.createEvent("beforeHide");
+this.beforeHideEvent.signature=a;this.hideEvent=this.createEvent("hide");this.hideEvent.signature=a},platform:t,browser:u,isSecure:w,initDefaultConfig:function(){this.cfg.addProperty("visible",{handler:this.configVisible,value:true,validator:n});this.cfg.addProperty("effect",{handler:this.configEffect,suppressEvent:true,supercedes:o});this.cfg.addProperty("monitorresize",{handler:this.configMonitorResize,value:true});this.cfg.addProperty("appendtodocumentbody",{value:false})},init:function(b,i){var c;
+this.initEvents();this.beforeInitEvent.fire(e);this.cfg=new g(this);if(this.isSecure)this.imageRoot=e.IMG_ROOT_SSL;if(typeof b=="string"){c=b;b=document.getElementById(b);if(!b){b=a().cloneNode(false);b.id=c}}this.id=f.generateId(b);this.element=b;if(c=this.element.firstChild){var d=false,k=false,l=false;do if(1==c.nodeType)if(!d&&f.hasClass(c,e.CSS_HEADER)){this.header=c;d=true}else if(!k&&f.hasClass(c,e.CSS_BODY)){this.body=c;k=true}else if(!l&&f.hasClass(c,e.CSS_FOOTER)){this.footer=c;l=true}while(c=
+c.nextSibling)}this.initDefaultConfig();f.addClass(this.element,e.CSS_MODULE);i&&this.cfg.applyConfig(i,true);g.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)||this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);this.initEvent.fire(e)},initResizeMonitor:function(){if(i.gecko&&this.platform=="windows"){var a=this;setTimeout(function(){a._initResizeMonitor()},0)}else this._initResizeMonitor()},_initResizeMonitor:function(){function a(){e.textResizeEvent.fire()}var b,c;if(!i.opera){c=
+f.get("_yuiResizeMonitor");var d=this._supportsCWResize();if(!c){c=document.createElement("iframe");if(this.isSecure&&e.RESIZE_MONITOR_SECURE_URL&&i.ie)c.src=e.RESIZE_MONITOR_SECURE_URL;if(!d)c.src="data:text/html;charset=utf-8,"+encodeURIComponent('<html><head><script type="text/javascript">window.onresize=function(){window.parent.YAHOO.widget.Module.textResizeEvent.fire();};<\/script></head><body></body></html>');c.id="_yuiResizeMonitor";c.title="Text Resize Monitor";c.tabIndex=-1;c.setAttribute("role",
+"presentation");c.style.position="absolute";c.style.visibility="hidden";b=document.body;var k=b.firstChild;k?b.insertBefore(c,k):b.appendChild(c);c.style.backgroundColor="transparent";c.style.borderWidth="0";c.style.width="2em";c.style.height="2em";c.style.left="0";c.style.top=-1*(c.offsetHeight+e.RESIZE_MONITOR_BUFFER)+"px";c.style.visibility="visible";if(i.webkit){b=c.contentWindow.document;b.open();b.close()}}if(c&&c.contentWindow){e.textResizeEvent.subscribe(this.onDomResize,this,true);if(!e.textResizeInitialized){if(d&&
+!j.on(c.contentWindow,"resize",a))j.on(c,"resize",a);e.textResizeInitialized=true}this.resizeMonitor=c}}},_supportsCWResize:function(){var a=true;i.gecko&&i.gecko<=1.8&&(a=false);return a},onDomResize:function(){this.resizeMonitor.style.top=-1*(this.resizeMonitor.offsetHeight+e.RESIZE_MONITOR_BUFFER)+"px";this.resizeMonitor.style.left="0"},setHeader:function(a){var e=this.header||(this.header=c());if(a.nodeName){e.innerHTML="";e.appendChild(a)}else e.innerHTML=a;this._rendered&&this._renderHeader();
+this.changeHeaderEvent.fire(a);this.changeContentEvent.fire()},appendToHeader:function(a){(this.header||(this.header=c())).appendChild(a);this.changeHeaderEvent.fire(a);this.changeContentEvent.fire()},setBody:function(a){var e=this.body||(this.body=b());if(a.nodeName){e.innerHTML="";e.appendChild(a)}else e.innerHTML=a;this._rendered&&this._renderBody();this.changeBodyEvent.fire(a);this.changeContentEvent.fire()},appendToBody:function(a){(this.body||(this.body=b())).appendChild(a);this.changeBodyEvent.fire(a);
+this.changeContentEvent.fire()},setFooter:function(a){var e=this.footer||(this.footer=d());if(a.nodeName){e.innerHTML="";e.appendChild(a)}else e.innerHTML=a;this._rendered&&this._renderFooter();this.changeFooterEvent.fire(a);this.changeContentEvent.fire()},appendToFooter:function(a){(this.footer||(this.footer=d())).appendChild(a);this.changeFooterEvent.fire(a);this.changeContentEvent.fire()},render:function(a,e){this.beforeRenderEvent.fire();if(!e)e=this.element;if(a){var b=a;typeof b=="string"&&
+(b=document.getElementById(b));if(b){this._addToParent(b,this.element);this.appendEvent.fire()}}else if(!f.inDocument(this.element))return false;this._renderHeader(e);this._renderBody(e);this._renderFooter(e);this._rendered=true;this.renderEvent.fire();return true},_renderHeader:function(a){a=a||this.element;if(this.header&&!f.inDocument(this.header)){var e=a.firstChild;e?a.insertBefore(this.header,e):a.appendChild(this.header)}},_renderBody:function(a){a=a||this.element;this.body&&!f.inDocument(this.body)&&
+(this.footer&&f.isAncestor(a,this.footer)?a.insertBefore(this.body,this.footer):a.appendChild(this.body))},_renderFooter:function(a){a=a||this.element;this.footer&&!f.inDocument(this.footer)&&a.appendChild(this.footer)},destroy:function(a){var b,a=!a;if(this.element){j.purgeElement(this.element,a);b=this.element.parentNode}b&&b.removeChild(this.element);this.footer=this.body=this.header=this.element=null;e.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(a,e){if(e[0]){if(this.beforeShowEvent.fire()){f.setStyle(this.element,"display","block");this.showEvent.fire()}}else if(this.beforeHideEvent.fire()){f.setStyle(this.element,"display","none");this.hideEvent.fire()}},configEffect:function(a,e){this._cachedEffects=this.cacheEffects?this._createEffects(e[0]):null},cacheEffects:true,_createEffects:function(a){var e=null,b,
+i,c;if(a)if(a instanceof Array){e=[];b=a.length;for(i=0;i<b;i++){c=a[i];c.effect&&(e[e.length]=c.effect(this,c.duration))}}else a.effect&&(e=[a.effect(this,a.duration)]);return e},configMonitorResize:function(a,b){if(b[0])this.initResizeMonitor();else{e.textResizeEvent.unsubscribe(this.onDomResize,this,true);this.resizeMonitor=null}},_addToParent:function(a,e){!this.cfg.getProperty("appendtodocumentbody")&&a===document.body&&a.firstChild?a.insertBefore(e,a.firstChild):a.appendChild(e)},toString:function(){return"Module "+
+this.id}};YAHOO.lang.augmentProto(e,YAHOO.util.EventProvider)})();
+(function(){YAHOO.widget.Overlay=function(a,e){YAHOO.widget.Overlay.superclass.constructor.call(this,a,e)};var a=YAHOO.lang,c=YAHOO.util.CustomEvent,b=YAHOO.widget.Module,d=YAHOO.util.Event,f=YAHOO.util.Dom,g=YAHOO.util.Config,j=YAHOO.env.ua,h=YAHOO.widget.Overlay,e,i=a.isNumber,k=["iframe"],l=a.isNumber,q=["iframe"],p=["iframe"],n=["iframe"],o=["iframe","visible"],m=["context","fixedcenter","iframe"],r=["context","fixedcenter","iframe"],s=["height"],t=a.isBoolean,u=["iframe","x","y","xy"],w=j.ie==
+6?true:false,x=a.isBoolean,v=["zindex"],y=a.isBoolean,B=["constraintoviewport"];h.IFRAME_SRC="javascript:false;";h.IFRAME_OFFSET=3;h.VIEWPORT_OFFSET=10;h.TOP_LEFT="tl";h.TOP_RIGHT="tr";h.BOTTOM_LEFT="bl";h.BOTTOM_RIGHT="br";h.PREVENT_OVERLAP_X={tltr:true,blbr:true,brbl:true,trtl:true};h.PREVENT_OVERLAP_Y={trbr:true,tlbl:true,bltl:true,brtr:true};h.CSS_OVERLAY="yui-overlay";h.CSS_HIDDEN="yui-overlay-hidden";h.CSS_IFRAME="yui-overlay-iframe";h.STD_MOD_RE=/^\s*?(body|footer|header)\s*?$/i;h.windowScrollEvent=
+new c("windowScroll");h.windowResizeEvent=new c("windowResize");h.windowScrollHandler=function(a){a=d.getTarget(a);if(!a||a===window||a===window.document)if(j.ie){if(!window.scrollEnd)window.scrollEnd=-1;clearTimeout(window.scrollEnd);window.scrollEnd=setTimeout(function(){h.windowScrollEvent.fire()},1)}else h.windowScrollEvent.fire()};h.windowResizeHandler=function(){if(j.ie){if(!window.resizeEnd)window.resizeEnd=-1;clearTimeout(window.resizeEnd);window.resizeEnd=setTimeout(function(){h.windowResizeEvent.fire()},
+100)}else h.windowResizeEvent.fire()};h._initialized=null;if(h._initialized===null){d.on(window,"scroll",h.windowScrollHandler);d.on(window,"resize",h.windowResizeHandler);h._initialized=true}h._TRIGGER_MAP={windowScroll:h.windowScrollEvent,windowResize:h.windowResizeEvent,textResize:b.textResizeEvent};YAHOO.extend(h,b,{CONTEXT_TRIGGERS:[],init:function(a,e){h.superclass.init.call(this,a);this.beforeInitEvent.fire(h);f.addClass(this.element,h.CSS_OVERLAY);e&&this.cfg.applyConfig(e,true);if(this.platform==
+"mac"&&j.gecko){g.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)||this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);g.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)||this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true)}this.initEvent.fire(h)},initEvents:function(){h.superclass.initEvents.call(this);var a=c.LIST;this.beforeMoveEvent=this.createEvent("beforeMove");this.beforeMoveEvent.signature=a;this.moveEvent=this.createEvent("move");
+this.moveEvent.signature=a},initDefaultConfig:function(){h.superclass.initDefaultConfig.call(this);var a=this.cfg;a.addProperty("x",{handler:this.configX,validator:i,suppressEvent:true,supercedes:k});a.addProperty("y",{handler:this.configY,validator:l,suppressEvent:true,supercedes:q});a.addProperty("xy",{handler:this.configXY,suppressEvent:true,supercedes:p});a.addProperty("context",{handler:this.configContext,suppressEvent:true,supercedes:n});a.addProperty("fixedcenter",{handler:this.configFixedCenter,
+value:false,validator:void 0,supercedes:o});a.addProperty("width",{handler:this.configWidth,suppressEvent:true,supercedes:m});a.addProperty("height",{handler:this.configHeight,suppressEvent:true,supercedes:r});a.addProperty("autofillheight",{handler:this.configAutoFillHeight,value:"body",validator:this._validateAutoFill,supercedes:s});a.addProperty("zindex",{handler:this.configzIndex,value:null});a.addProperty("constraintoviewport",{handler:this.configConstrainToViewport,value:false,validator:t,supercedes:u});
+a.addProperty("iframe",{handler:this.configIframe,value:w,validator:x,supercedes:v});a.addProperty("preventcontextoverlap",{value:false,validator:y,supercedes:B})},moveTo:function(a,e){this.cfg.setProperty("xy",[a,e])},hideMacGeckoScrollbars:function(){f.replaceClass(this.element,"show-scrollbars","hide-scrollbars")},showMacGeckoScrollbars:function(){f.replaceClass(this.element,"hide-scrollbars","show-scrollbars")},_setDomVisibility:function(a){f.setStyle(this.element,"visibility",a?"visible":"hidden");
+var e=h.CSS_HIDDEN;a?f.removeClass(this.element,e):f.addClass(this.element,e)},configVisible:function(a,e){var b=e[0],i=f.getStyle(this.element,"visibility"),c=this._cachedEffects||this._createEffects(this.cfg.getProperty("effect")),d=this.platform=="mac"&&j.gecko,k=g.alreadySubscribed,l;if(i=="inherit"){for(l=this.element.parentNode;l.nodeType!=9&&l.nodeType!=11;){i=f.getStyle(l,"visibility");if(i!="inherit")break;l=l.parentNode}i=="inherit"&&(i="visible")}if(b){d&&this.showMacGeckoScrollbars();
+if(c){if(b&&(i!="visible"||i===""||this._fadingOut)&&this.beforeShowEvent.fire()){b=c.length;for(d=0;d<b;d++){i=c[d];d===0&&!k(i.animateInCompleteEvent,this.showEvent.fire,this.showEvent)&&i.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true);i.animateIn()}}}else if(i!="visible"||i===""){if(this.beforeShowEvent.fire()){this._setDomVisibility(true);this.cfg.refireEvent("iframe");this.showEvent.fire()}}else this._setDomVisibility(true)}else{d&&this.hideMacGeckoScrollbars();if(c)if(i==
+"visible"||this._fadingIn){if(this.beforeHideEvent.fire()){b=c.length;for(i=0;i<b;i++){d=c[i];i===0&&!k(d.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)&&d.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true);d.animateOut()}}}else i===""&&this._setDomVisibility(false);else if(i=="visible"||i===""){if(this.beforeHideEvent.fire()){this._setDomVisibility(false);this.hideEvent.fire()}}else this._setDomVisibility(false)}},doCenterOnDOMEvent:function(){var a=this.cfg,
+e=a.getProperty("fixedcenter");a.getProperty("visible")&&e&&(e!=="contained"||this.fitsInViewport())&&this.center()},fitsInViewport:function(){var a=h.VIEWPORT_OFFSET,e=this.element,b=e.offsetWidth,e=e.offsetHeight,i=f.getViewportWidth(),c=f.getViewportHeight();return b+a<i&&e+a<c},configFixedCenter:function(a,e){var b=g.alreadySubscribed,i=h.windowResizeEvent,c=h.windowScrollEvent;if(e[0]){this.center();b(this.beforeShowEvent,this.center)||this.beforeShowEvent.subscribe(this.center);b(i,this.doCenterOnDOMEvent,
+this)||i.subscribe(this.doCenterOnDOMEvent,this,true);b(c,this.doCenterOnDOMEvent,this)||c.subscribe(this.doCenterOnDOMEvent,this,true)}else{this.beforeShowEvent.unsubscribe(this.center);i.unsubscribe(this.doCenterOnDOMEvent,this);c.unsubscribe(this.doCenterOnDOMEvent,this)}},configHeight:function(a,e){f.setStyle(this.element,"height",e[0]);this.cfg.refireEvent("iframe")},configAutoFillHeight:function(e,i){var c=i[0],d=this.cfg,k=d.getProperty("autofillheight"),l=this._autoFillOnHeightChange;d.unsubscribeFromConfigEvent("height",
+l);b.textResizeEvent.unsubscribe(l);this.changeContentEvent.unsubscribe(l);k&&(c!==k&&this[k])&&f.setStyle(this[k],"height","");if(c){c=a.trim(c.toLowerCase());d.subscribeToConfigEvent("height",l,this[c],this);b.textResizeEvent.subscribe(l,this[c],this);this.changeContentEvent.subscribe(l,this[c],this);d.setProperty("autofillheight",c,true)}},configWidth:function(a,e){f.setStyle(this.element,"width",e[0]);this.cfg.refireEvent("iframe")},configzIndex:function(a,e){var b=e[0],i=this.element;if(!b){b=
+f.getStyle(i,"zIndex");if(!b||isNaN(b))b=0}if(this.iframe||this.cfg.getProperty("iframe")===true)b<=0&&(b=1);f.setStyle(i,"zIndex",b);this.cfg.setProperty("zIndex",b,true);this.iframe&&this.stackIframe()},configXY:function(a,e){var b=e[0],i=b[0],b=b[1];this.cfg.setProperty("x",i);this.cfg.setProperty("y",b);this.beforeMoveEvent.fire([i,b]);i=this.cfg.getProperty("x");b=this.cfg.getProperty("y");this.cfg.refireEvent("iframe");this.moveEvent.fire([i,b])},configX:function(a,e){var b=e[0],i=this.cfg.getProperty("y");
+this.cfg.setProperty("x",b,true);this.cfg.setProperty("y",i,true);this.beforeMoveEvent.fire([b,i]);b=this.cfg.getProperty("x");i=this.cfg.getProperty("y");f.setX(this.element,b,true);this.cfg.setProperty("xy",[b,i],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([b,i])},configY:function(a,e){var b=this.cfg.getProperty("x"),i=e[0];this.cfg.setProperty("x",b,true);this.cfg.setProperty("y",i,true);this.beforeMoveEvent.fire([b,i]);b=this.cfg.getProperty("x");i=this.cfg.getProperty("y");f.setY(this.element,
+i,true);this.cfg.setProperty("xy",[b,i],true);this.cfg.refireEvent("iframe");this.moveEvent.fire([b,i])},showIframe:function(){var a=this.iframe,e;if(a){e=this.element.parentNode;e!=a.parentNode&&this._addToParent(e,a);a.style.display="block"}},hideIframe:function(){if(this.iframe)this.iframe.style.display="none"},syncIframe:function(){var e=this.iframe,b=this.element,i=h.IFRAME_OFFSET,c=i*2;if(e){e.style.width=b.offsetWidth+c+"px";e.style.height=b.offsetHeight+c+"px";b=this.cfg.getProperty("xy");
+if(!a.isArray(b)||isNaN(b[0])||isNaN(b[1])){this.syncPosition();b=this.cfg.getProperty("xy")}f.setXY(e,[b[0]-i,b[1]-i])}},stackIframe:function(){if(this.iframe){var a=f.getStyle(this.element,"zIndex");!YAHOO.lang.isUndefined(a)&&!isNaN(a)&&f.setStyle(this.iframe,"zIndex",a-1)}},configIframe:function(a,b){function i(){var a=this.iframe,b=this.element;if(!a){if(!e){e=document.createElement("iframe");if(this.isSecure)e.src=h.IFRAME_SRC;if(j.ie){e.style.filter="alpha(opacity=0)";e.frameBorder=0}else e.style.opacity=
+"0";e.style.position="absolute";e.style.border="none";e.style.margin="0";e.style.padding="0";e.style.display="none";e.tabIndex=-1;e.className=h.CSS_IFRAME}a=e.cloneNode(false);a.id=this.id+"_f";b=b.parentNode;this._addToParent(b||document.body,a);this.iframe=a}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 c(){i.call(this);this.beforeShowEvent.unsubscribe(c);this._iframeDeferred=false}if(b[0])if(this.cfg.getProperty("visible"))i.call(this);else{if(!this._iframeDeferred){this.beforeShowEvent.subscribe(c);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(a,e){if(e[0]){g.alreadySubscribed(this.beforeMoveEvent,this.enforceConstraints,this)||this.beforeMoveEvent.subscribe(this.enforceConstraints,this,true);g.alreadySubscribed(this.beforeShowEvent,this._primeXYFromDOM)||this.beforeShowEvent.subscribe(this._primeXYFromDOM)}else{this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);this.beforeMoveEvent.unsubscribe(this.enforceConstraints,
+this)}},configContext:function(a,e){var b=e[0],i,c,d,k,f=this.CONTEXT_TRIGGERS;if(b){i=b[0];c=b[1];d=b[2];k=b[3];b=b[4];f&&f.length>0&&(k=(k||[]).concat(f));if(i){typeof i=="string"&&this.cfg.setProperty("context",[document.getElementById(i),c,d,k,b],true);c&&d&&this.align(c,d,b);this._contextTriggers&&this._processTriggers(this._contextTriggers,"unsubscribe",this._alignOnTrigger);if(k){this._processTriggers(k,"subscribe",this._alignOnTrigger);this._contextTriggers=k}}}},_alignOnTrigger:function(){this.align()},
+_findTriggerCE:function(a){var e=null;a instanceof c?e=a:h._TRIGGER_MAP[a]&&(e=h._TRIGGER_MAP[a]);return e},_processTriggers:function(a,e,b){for(var i,c,d=0,k=a.length;d<k;++d){i=a[d];if(c=this._findTriggerCE(i))c[e](b,this,true);else this[e](i,b)}},align:function(a,e,b){function i(e,c){var k=null,f=null;switch(a){case h.TOP_LEFT:k=c;f=e;break;case h.TOP_RIGHT:k=c-l.offsetWidth;f=e;break;case h.BOTTOM_LEFT:k=c;f=e-l.offsetHeight;break;case h.BOTTOM_RIGHT:k=c-l.offsetWidth;f=e-l.offsetHeight}if(k!==
+null&&f!==null){if(b){k=k+b[0];f=f+b[1]}d.moveTo(k,f)}}var c=this.cfg.getProperty("context"),d=this,k,l;if(c){k=c[0];l=this.element;d=this;a||(a=c[1]);e||(e=c[2]);!b&&c[4]&&(b=c[4]);if(l&&k){c=f.getRegion(k);switch(e){case h.TOP_LEFT:i(c.top,c.left);break;case h.TOP_RIGHT:i(c.top,c.right);break;case h.BOTTOM_LEFT:i(c.bottom,c.left);break;case h.BOTTOM_RIGHT:i(c.bottom,c.right)}}}},enforceConstraints:function(a,e){var b=e[0],b=this.getConstrainedXY(b[0],b[1]);this.cfg.setProperty("x",b[0],true);this.cfg.setProperty("y",
+b[1],true);this.cfg.setProperty("xy",b,true)},_getConstrainedPos:function(a,e){var b=this.element,i=h.VIEWPORT_OFFSET,c=a=="x",b=c?b.offsetWidth:b.offsetHeight,d=c?f.getViewportWidth():f.getViewportHeight(),k=c?f.getDocumentScrollLeft():f.getDocumentScrollTop(),l=c?h.PREVENT_OVERLAP_X:h.PREVENT_OVERLAP_Y,c=this.cfg.getProperty("context"),g=b+i<d,l=this.cfg.getProperty("preventcontextoverlap")&&c&&l[c[1]+c[2]],j=k+i,i=k+d-b-i,q=e;if(e<j||e>i)l?q=this._preventOverlap(a,c[0],b,d,k):g?e<j?q=j:e>i&&(q=
+i):q=j;return q},_preventOverlap:function(a,e,b,i,c){var d=a=="x",k=h.VIEWPORT_OFFSET,l=this,g=(d?f.getX(e):f.getY(e))-c,j=d?e.offsetWidth:e.offsetHeight,q=g-k,p=i-(g+j)-k,n=false,o=function(){var e;e=l.cfg.getProperty(a)-c>g?g-b:g+j;l.cfg.setProperty(a,e+c,true);return e},m=function(){var e=l.cfg.getProperty(a)-c>g?p:q,i;if(b>e)if(n)o();else{o();n=true;i=m()}return i};m();return this.cfg.getProperty(a)},getConstrainedX:function(a){return this._getConstrainedPos("x",a)},getConstrainedY:function(a){return this._getConstrainedPos("y",
+a)},getConstrainedXY:function(a,e){return[this.getConstrainedX(a),this.getConstrainedY(e)]},center:function(){var a=h.VIEWPORT_OFFSET,e=this.element.offsetWidth,b=this.element.offsetHeight,i=f.getViewportWidth(),c=f.getViewportHeight(),e=e<i?i/2-e/2+f.getDocumentScrollLeft():a+f.getDocumentScrollLeft(),a=b<c?c/2-b/2+f.getDocumentScrollTop():a+f.getDocumentScrollTop();this.cfg.setProperty("xy",[parseInt(e,10),parseInt(a,10)]);this.cfg.refireEvent("iframe");j.webkit&&this.forceContainerRedraw()},syncPosition:function(){var a=
+f.getXY(this.element);this.cfg.setProperty("x",a[0],true);this.cfg.setProperty("y",a[1],true);this.cfg.setProperty("xy",a,true)},onDomResize:function(a,e){var b=this;h.superclass.onDomResize.call(this,a,e);setTimeout(function(){b.syncPosition();b.cfg.refireEvent("iframe");b.cfg.refireEvent("context")},0)},_getComputedHeight:function(){return document.defaultView&&document.defaultView.getComputedStyle?function(e){var b=null;if(e.ownerDocument&&e.ownerDocument.defaultView)(e=e.ownerDocument.defaultView.getComputedStyle(e,
+""))&&(b=parseInt(e.height,10));return a.isNumber(b)?b:null}:function(e){var b=null;if(e.style.pixelHeight)b=e.style.pixelHeight;return a.isNumber(b)?b:null}}(),_validateAutoFillHeight:function(e){return!e||a.isString(e)&&h.STD_MOD_RE.test(e)},_autoFillOnHeightChange:function(a,e,b){((a=this.cfg.getProperty("height"))&&a!=="auto"||a===0)&&this.fillHeight(b)},_getPreciseHeight:function(a){var e=a.offsetHeight;if(a.getBoundingClientRect){a=a.getBoundingClientRect();e=a.bottom-a.top}return e},fillHeight:function(a){if(a){var e=
+this.innerElement||this.element,b=[this.header,this.body,this.footer],i,c=i=0;i=0;for(var d=false,k=0,l=b.length;k<l;k++)(i=b[k])&&(a!==i?c=c+this._getPreciseHeight(i):d=true);if(d){(j.ie||j.opera)&&f.setStyle(a,"height","0px");i=this._getComputedHeight(e);if(i===null){f.addClass(e,"yui-override-padding");i=e.clientHeight;f.removeClass(e,"yui-override-padding")}i=Math.max(i-c,0);f.setStyle(a,"height",i+"px");a.offsetHeight!=i&&(i=Math.max(i-(a.offsetHeight-i),0));f.setStyle(a,"height",i+"px")}}},
+bringToTop:function(){var a=[],e=this.element;f.getElementsBy(function(b){var i=f.hasClass(b,h.CSS_OVERLAY),c=YAHOO.widget.Panel;i&&!f.isAncestor(e,b)&&(a[a.length]=c&&f.hasClass(b,c.CSS_PANEL)?b.parentNode:b)},"div",document.body);a.sort(function(a,e){var b=f.getStyle(a,"zIndex"),i=f.getStyle(e,"zIndex"),b=!b||isNaN(b)?0:parseInt(b,10),i=!i||isNaN(i)?0:parseInt(i,10);return b>i?-1:b<i?1:0});var b=a[0],i;if(b){i=f.getStyle(b,"zIndex");if(!isNaN(i)){var c=false;if(b!=e)c=true;else if(a.length>1){b=
+f.getStyle(a[1],"zIndex");!isNaN(b)&&i==b&&(c=true)}c&&this.cfg.setProperty("zindex",parseInt(i,10)+2)}}},destroy:function(a){this.iframe&&this.iframe.parentNode.removeChild(this.iframe);this.iframe=null;h.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent,this);h.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent,this);b.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);this._contextTriggers&&this._processTriggers(this._contextTriggers,"unsubscribe",this._alignOnTrigger);h.superclass.destroy.call(this,
+a)},forceContainerRedraw:function(){var a=this;f.addClass(a.element,"yui-force-redraw");setTimeout(function(){f.removeClass(a.element,"yui-force-redraw")},0)},toString:function(){return"Overlay "+this.id}})})();
+(function(){YAHOO.widget.OverlayManager=function(a){this.init(a)};var a=YAHOO.widget.Overlay,c=YAHOO.util.Event,b=YAHOO.util.Dom,d=YAHOO.util.Config,f=YAHOO.util.CustomEvent,g=YAHOO.widget.OverlayManager;g.CSS_FOCUSED="focused";g.prototype={constructor:g,overlays:null,initDefaultConfig:function(){this.cfg.addProperty("overlays",{suppressEvent:true});this.cfg.addProperty("focusevent",{value:"mousedown"})},init:function(a){this.cfg=new d(this);this.initDefaultConfig();a&&this.cfg.applyConfig(a,true);
+this.cfg.fireQueue();var f=null;this.getActive=function(){return f};this.focus=function(a){(a=this.find(a))&&a.focus()};this.remove=function(a){var a=this.find(a),i;if(a){f==a&&(f=null);var d=a.element===null&&a.cfg===null?true:false;if(!d){i=b.getStyle(a.element,"zIndex");a.cfg.setProperty("zIndex",-1E3,true)}this.overlays.sort(this.compareZIndexDesc);this.overlays=this.overlays.slice(0,this.overlays.length-1);a.hideEvent.unsubscribe(a.blur);a.destroyEvent.unsubscribe(this._onOverlayDestroy,a);a.focusEvent.unsubscribe(this._onOverlayFocusHandler,
+a);a.blurEvent.unsubscribe(this._onOverlayBlurHandler,a);if(!d){c.removeListener(a.element,this.cfg.getProperty("focusevent"),this._onOverlayElementFocus);a.cfg.setProperty("zIndex",i,true);a.cfg.setProperty("manager",null)}if(a.focusEvent._managed)a.focusEvent=null;if(a.blurEvent._managed)a.blurEvent=null;if(a.focus._managed)a.focus=null;if(a.blur._managed)a.blur=null}};this.blurAll=function(){var a=this.overlays.length;if(a>0){a=a-1;do this.overlays[a].blur();while(a--)}};this._manageBlur=function(a){var i=
+false;if(f==a){b.removeClass(f.element,g.CSS_FOCUSED);f=null;i=true}return i};this._manageFocus=function(a){var i=false;if(f!=a){f&&f.blur();f=a;this.bringToTop(f);b.addClass(f.element,g.CSS_FOCUSED);i=true}return i};a=this.cfg.getProperty("overlays");if(!this.overlays)this.overlays=[];if(a){this.register(a);this.overlays.sort(this.compareZIndexDesc)}},_onOverlayElementFocus:function(a){var a=c.getTarget(a),d=this.close;d&&(a==d||b.isAncestor(d,a))?this.blur():this.focus()},_onOverlayDestroy:function(a,
+b,e){this.remove(e)},_onOverlayFocusHandler:function(a,b,e){this._manageFocus(e)},_onOverlayBlurHandler:function(a,b,e){this._manageBlur(e)},_bindFocus:function(a){var b=this;if(a.focusEvent)a.focusEvent.subscribe(b._onOverlayFocusHandler,a,b);else{a.focusEvent=a.createEvent("focus");a.focusEvent.signature=f.LIST;a.focusEvent._managed=true}if(!a.focus){c.on(a.element,b.cfg.getProperty("focusevent"),b._onOverlayElementFocus,null,a);a.focus=function(){if(b._manageFocus(this)){this.cfg.getProperty("visible")&&
+this.focusFirst&&this.focusFirst();this.focusEvent.fire()}};a.focus._managed=true}},_bindBlur:function(a){var b=this;if(a.blurEvent)a.blurEvent.subscribe(b._onOverlayBlurHandler,a,b);else{a.blurEvent=a.createEvent("blur");a.blurEvent.signature=f.LIST;a.focusEvent._managed=true}if(!a.blur){a.blur=function(){b._manageBlur(this)&&this.blurEvent.fire()};a.blur._managed=true}a.hideEvent.subscribe(a.blur)},_bindDestroy:function(a){a.destroyEvent.subscribe(this._onOverlayDestroy,a,this)},_syncZIndex:function(a){var c=
+b.getStyle(a.element,"zIndex");isNaN(c)?a.cfg.setProperty("zIndex",0):a.cfg.setProperty("zIndex",parseInt(c,10))},register:function(b){var c=false,e,i;if(b instanceof a){b.cfg.addProperty("manager",{value:this});this._bindFocus(b);this._bindBlur(b);this._bindDestroy(b);this._syncZIndex(b);this.overlays.push(b);this.bringToTop(b);c=true}else if(b instanceof Array){e=0;for(i=b.length;e<i;e++)c=this.register(b[e])||c}return c},bringToTop:function(a){var a=this.find(a),c,e,i;if(a){i=this.overlays;i.sort(this.compareZIndexDesc);
+if(e=i[0]){c=b.getStyle(e.element,"zIndex");if(!isNaN(c)){var d=false;if(e!==a)d=true;else if(i.length>1){e=b.getStyle(i[1].element,"zIndex");!isNaN(e)&&c==e&&(d=true)}d&&a.cfg.setProperty("zindex",parseInt(c,10)+2)}i.sort(this.compareZIndexDesc)}}},find:function(b){var c=b instanceof a,e=this.overlays,i=e.length,d=null,f;if(c||typeof b=="string")for(f=i-1;f>=0;f--){i=e[f];if(c&&i===b||i.id==b){d=i;break}}return d},compareZIndexDesc:function(a,b){var e=a.cfg?a.cfg.getProperty("zIndex"):null,i=b.cfg?
+b.cfg.getProperty("zIndex"):null;return e===null&&i===null?0:e===null?1:i===null?-1:e>i?-1:e<i?1:0},showAll:function(){var a=this.overlays,b;for(b=a.length-1;b>=0;b--)a[b].show()},hideAll:function(){var a=this.overlays,b;for(b=a.length-1;b>=0;b--)a[b].hide()},toString:function(){return"OverlayManager"}}})();
+(function(){function a(){if("_originalWidth"in this){var a=this._originalWidth,e=this._forcedWidth,b=this.cfg;b.getProperty("width")==e&&b.setProperty("width",a)}var a=document.body,e=this.cfg,b=e.getProperty("width"),i,c;if((!b||b=="auto")&&(e.getProperty("container")!=a||e.getProperty("x")>=j.getViewportWidth()||e.getProperty("y")>=j.getViewportHeight())){c=this.element.cloneNode(true);c.style.visibility="hidden";c.style.top="0px";c.style.left="0px";a.appendChild(c);i=c.offsetWidth+"px";a.removeChild(c);
+e.setProperty("width",i);e.refireEvent("xy");this._originalWidth=b||"";this._forcedWidth=i}}function c(a,e,b){this.render(b)}function b(){f.onDOMReady(c,this.cfg.getProperty("container"),this)}YAHOO.widget.Tooltip=function(a,e){YAHOO.widget.Tooltip.superclass.constructor.call(this,a,e)};var d=YAHOO.lang,f=YAHOO.util.Event,g=YAHOO.util.CustomEvent,j=YAHOO.util.Dom,h=YAHOO.widget.Tooltip,e=YAHOO.env.ua,i=e.ie&&(e.ie<=6||document.compatMode=="BackCompat"),k,l=d.isBoolean,q=["x","y","xy"],p=d.isNumber,
+n=d.isNumber,o=d.isNumber,m=[0,25];h.CSS_TOOLTIP="yui-tt";YAHOO.extend(h,YAHOO.widget.Overlay,{init:function(e,i){h.superclass.init.call(this,e);this.beforeInitEvent.fire(h);j.addClass(this.element,h.CSS_TOOLTIP);i&&this.cfg.applyConfig(i,true);this.cfg.queueProperty("visible",false);this.cfg.queueProperty("constraintoviewport",true);this.setBody("");this.subscribe("changeContent",a);this.subscribe("init",b);this.subscribe("render",this.onRender);this.initEvent.fire(h)},initEvents:function(){h.superclass.initEvents.call(this);
+var a=g.LIST;this.contextMouseOverEvent=this.createEvent("contextMouseOver");this.contextMouseOverEvent.signature=a;this.contextMouseOutEvent=this.createEvent("contextMouseOut");this.contextMouseOutEvent.signature=a;this.contextTriggerEvent=this.createEvent("contextTrigger");this.contextTriggerEvent.signature=a},initDefaultConfig:function(){h.superclass.initDefaultConfig.call(this);this.cfg.addProperty("preventoverlap",{value:true,validator:l,supercedes:q});this.cfg.addProperty("showdelay",{handler:this.configShowDelay,
+value:200,validator:p});this.cfg.addProperty("autodismissdelay",{handler:this.configAutoDismissDelay,value:5E3,validator:n});this.cfg.addProperty("hidedelay",{handler:this.configHideDelay,value:250,validator:o});this.cfg.addProperty("text",{handler:this.configText,suppressEvent:true});this.cfg.addProperty("container",{handler:this.configContainer,value:document.body});this.cfg.addProperty("disabled",{handler:this.configContainer,value:false,supressEvent:true});this.cfg.addProperty("xyoffset",{value:m.concat(),
+supressEvent:true})},configText:function(a,e){var b=e[0];b&&this.setBody(b)},configContainer:function(a,e){var b=e[0];typeof b=="string"&&this.cfg.setProperty("container",document.getElementById(b),true)},_removeEventListeners:function(){var a=this._context,e,b;if(a){e=a.length;if(e>0){b=e-1;do{e=a[b];f.removeListener(e,"mouseover",this.onContextMouseOver);f.removeListener(e,"mousemove",this.onContextMouseMove);f.removeListener(e,"mouseout",this.onContextMouseOut)}while(b--)}}},configContext:function(a,
+e){var b=e[0],i,c;if(b){if(!(b instanceof Array)){typeof b=="string"?this.cfg.setProperty("context",[document.getElementById(b)],true):this.cfg.setProperty("context",[b],true);b=this.cfg.getProperty("context")}this._removeEventListeners();if(b=this._context=b){i=b.length;if(i>0){c=i-1;do{i=b[c];f.on(i,"mouseover",this.onContextMouseOver,this);f.on(i,"mousemove",this.onContextMouseMove,this);f.on(i,"mouseout",this.onContextMouseOut,this)}while(c--)}}}},onContextMouseMove:function(a,e){e.pageX=f.getPageX(a);
+e.pageY=f.getPageY(a)},onContextMouseOver:function(a,e){if(this.title){e._tempTitle=this.title;this.title=""}if(e.fireEvent("contextMouseOver",this,a)!==false&&!e.cfg.getProperty("disabled")){if(e.hideProcId){clearTimeout(e.hideProcId);e.hideProcId=null}f.on(this,"mousemove",e.onContextMouseMove,e);e.showProcId=e.doShow(a,this)}},onContextMouseOut:function(a,e){if(e._tempTitle){this.title=e._tempTitle;e._tempTitle=null}if(e.showProcId){clearTimeout(e.showProcId);e.showProcId=null}if(e.hideProcId){clearTimeout(e.hideProcId);
+e.hideProcId=null}e.fireEvent("contextMouseOut",this,a);e.hideProcId=setTimeout(function(){e.hide()},e.cfg.getProperty("hidedelay"))},doShow:function(a,b){var i=this.cfg.getProperty("xyoffset"),c=i[0],d=i[1],k=this;e.opera&&(b.tagName&&b.tagName.toUpperCase()=="A")&&(d=d+12);return setTimeout(function(){var a=k.cfg.getProperty("text");k._tempTitle&&(a===""||YAHOO.lang.isUndefined(a)||YAHOO.lang.isNull(a))?k.setBody(k._tempTitle):k.cfg.refireEvent("text");k.moveTo(k.pageX+c,k.pageY+d);k.cfg.getProperty("preventoverlap")&&
+k.preventOverlap(k.pageX,k.pageY);f.removeListener(b,"mousemove",k.onContextMouseMove);k.contextTriggerEvent.fire(b);k.show();k.hideProcId=k.doHide()},this.cfg.getProperty("showdelay"))},doHide:function(){var a=this;return setTimeout(function(){a.hide()},this.cfg.getProperty("autodismissdelay"))},preventOverlap:function(a,e){var b=this.element.offsetHeight,i=new YAHOO.util.Point(a,e),c=j.getRegion(this.element);c.top=c.top-5;c.left=c.left-5;c.right=c.right+5;c.bottom=c.bottom+5;c.contains(i)&&this.cfg.setProperty("y",
+e-b-5)},onRender:function(){function a(){var e=this.element,b=this.underlay;if(b){b.style.width=e.offsetWidth+6+"px";b.style.height=e.offsetHeight+1+"px"}}function b(){j.addClass(this.underlay,"yui-tt-shadow-visible");e.ie&&this.forceUnderlayRedraw()}function c(){j.removeClass(this.underlay,"yui-tt-shadow-visible")}function d(){var e=this.underlay,f,l,h;if(!e){f=this.element;l=YAHOO.widget.Module;h=this;if(!k){k=document.createElement("div");k.className="yui-tt-shadow"}e=k.cloneNode(false);f.appendChild(e);
+this._shadow=this.underlay=e;b.call(this);this.subscribe("beforeShow",b);this.subscribe("hide",c);if(i){window.setTimeout(function(){a.call(h)},0);this.cfg.subscribeToConfigEvent("width",a);this.cfg.subscribeToConfigEvent("height",a);this.subscribe("changeContent",a);l.textResizeEvent.subscribe(a,this,true);this.subscribe("destroy",function(){l.textResizeEvent.unsubscribe(a,this)})}}}function f(){d.call(this);this.unsubscribe("beforeShow",f)}this.cfg.getProperty("visible")?d.call(this):this.subscribe("beforeShow",
+f)},forceUnderlayRedraw:function(){var a=this;j.addClass(a.underlay,"yui-force-redraw");setTimeout(function(){j.removeClass(a.underlay,"yui-force-redraw")},0)},destroy:function(){this._removeEventListeners();h.superclass.destroy.call(this)},toString:function(){return"Tooltip "+this.id}})})();
+(function(){function a(){!this.header&&this.cfg.getProperty("draggable")&&this.setHeader("&#160;")}function c(a,e,b){var a=b[0],e=b[1],i=this.cfg;i.getProperty("width")==e&&i.setProperty("width",a);this.unsubscribe("hide",c,b)}function b(){var a,e,b;if(n){a=this.cfg;e=a.getProperty("width");if(!e||e=="auto"){b=this.element.offsetWidth+"px";a.setProperty("width",b);this.subscribe("hide",c,[e||"",b])}}}YAHOO.widget.Panel=function(a,e){YAHOO.widget.Panel.superclass.constructor.call(this,a,e)};var d=
+null,f=YAHOO.lang,g=YAHOO.util,j=g.Dom,h=g.Event,e=g.CustomEvent,i=YAHOO.util.KeyListener,k=g.Config,l=YAHOO.widget.Overlay,q=YAHOO.widget.Panel,p=YAHOO.env.ua,n=p.ie&&(p.ie<=6||document.compatMode=="BackCompat"),o,m,r,s=f.isBoolean,t=["visible"],u=f.isBoolean,w=["visible"],x=f.isBoolean,v=["draggable"],y=["visible"],B=f.isBoolean,A=["visible","zindex"],D=["visible"],E=["close"],C=f.isObject,z={close:"Close"};q.CSS_PANEL="yui-panel";q.CSS_PANEL_CONTAINER="yui-panel-container";q.FOCUSABLE=["a","button",
+"select","textarea","input","iframe"];YAHOO.extend(q,l,{init:function(e,b){q.superclass.init.call(this,e);this.beforeInitEvent.fire(q);j.addClass(this.element,q.CSS_PANEL);this.buildWrapper();b&&this.cfg.applyConfig(b,true);this.subscribe("showMask",this._addFocusHandlers);this.subscribe("hideMask",this._removeFocusHandlers);this.subscribe("beforeRender",a);this.subscribe("render",function(){this.setFirstLastFocusable();this.subscribe("changeContent",this.setFirstLastFocusable)});this.subscribe("show",
+this._focusOnShow);this.initEvent.fire(q)},_onElementFocus:function(a){if(d===this){var a=h.getTarget(a),e=a!==document.documentElement&&a!==window;if(e&&a!==this.element&&a!==this.mask&&!j.isAncestor(this.element,a))try{this._focusFirstModal()}catch(b){try{e&&a!==document.body&&a.blur()}catch(i){}}}},_focusFirstModal:function(){var a=this.firstElement;a?a.focus():this._modalFocus?this._modalFocus.focus():this.innerElement.focus()},_addFocusHandlers:function(){if(!this.firstElement)p.webkit||p.opera?
+this._modalFocus||this._createHiddenFocusElement():this.innerElement.tabIndex=0;this._setTabLoop(this.firstElement,this.lastElement);h.onFocus(document.documentElement,this._onElementFocus,this,true);d=this},_createHiddenFocusElement:function(){var a=document.createElement("button");a.style.height="1px";a.style.width="1px";a.style.position="absolute";a.style.left="-10000em";a.style.opacity=0;a.tabIndex=-1;this.innerElement.appendChild(a);this._modalFocus=a},_removeFocusHandlers:function(){h.removeFocusListener(document.documentElement,
+this._onElementFocus,this);d==this&&(d=null)},_focusOnShow:function(a,e,b){e&&e[1]&&h.stopEvent(e[1]);this.focusFirst(a,e,b)||this.cfg.getProperty("modal")&&this._focusFirstModal()},focusFirst:function(a,e){var b=this.firstElement,i=false;e&&e[1]&&h.stopEvent(e[1]);if(b)try{b.focus();i=true}catch(c){}return i},focusLast:function(a,e){var b=this.lastElement,i=false;e&&e[1]&&h.stopEvent(e[1]);if(b)try{b.focus();i=true}catch(c){}return i},_setTabLoop:function(a,e){this.setTabLoop(a,e)},setTabLoop:function(a,
+e){var b=this.preventBackTab,c=this.preventTabOut,d=this.showEvent,k=this.hideEvent;if(b){b.disable();d.unsubscribe(b.enable,b);k.unsubscribe(b.disable,b);this.preventBackTab=null}if(c){c.disable();d.unsubscribe(c.enable,c);k.unsubscribe(c.disable,c);this.preventTabOut=null}if(a){b=this.preventBackTab=new i(a,{shift:true,keys:9},{fn:this.focusLast,scope:this,correctScope:true});d.subscribe(b.enable,b,true);k.subscribe(b.disable,b,true)}if(e){c=this.preventTabOut=new i(e,{shift:false,keys:9},{fn:this.focusFirst,
+scope:this,correctScope:true});d.subscribe(c.enable,c,true);k.subscribe(c.disable,c,true)}},getFocusableElements:function(a){for(var a=a||this.innerElement,e={},b=this,i=0;i<q.FOCUSABLE.length;i++)e[q.FOCUSABLE[i]]=true;return j.getElementsBy(function(a){return b._testIfFocusable(a,e)},null,a)},_testIfFocusable:function(a,e){return a.focus&&a.type!=="hidden"&&!a.disabled&&e[a.tagName.toLowerCase()]?true:false},setFirstLastFocusable:function(){this.lastElement=this.firstElement=null;var a=this.getFocusableElements();
+this.focusableElements=a;if(a.length>0){this.firstElement=a[0];this.lastElement=a[a.length-1]}this.cfg.getProperty("modal")&&this._setTabLoop(this.firstElement,this.lastElement)},initEvents:function(){q.superclass.initEvents.call(this);var a=e.LIST;this.showMaskEvent=this.createEvent("showMask");this.showMaskEvent.signature=a;this.beforeShowMaskEvent=this.createEvent("beforeShowMask");this.beforeShowMaskEvent.signature=a;this.hideMaskEvent=this.createEvent("hideMask");this.hideMaskEvent.signature=
+a;this.beforeHideMaskEvent=this.createEvent("beforeHideMask");this.beforeHideMaskEvent.signature=a;this.dragEvent=this.createEvent("drag");this.dragEvent.signature=a},initDefaultConfig:function(){q.superclass.initDefaultConfig.call(this);this.cfg.addProperty("close",{handler:this.configClose,value:true,validator:s,supercedes:t});this.cfg.addProperty("draggable",{handler:this.configDraggable,value:g.DD?true:false,validator:u,supercedes:w});this.cfg.addProperty("dragonly",{value:false,validator:x,supercedes:v});
+this.cfg.addProperty("underlay",{handler:this.configUnderlay,value:"shadow",supercedes:y});this.cfg.addProperty("modal",{handler:this.configModal,value:false,validator:B,supercedes:A});this.cfg.addProperty("keylisteners",{handler:this.configKeyListeners,suppressEvent:true,supercedes:D});this.cfg.addProperty("strings",{value:z,handler:this.configStrings,validator:C,supercedes:E})},configClose:function(a,e){var b=e[0],i=this.close,c=this.cfg.getProperty("strings");if(b)if(i)i.style.display="block";
+else{if(!r){r=document.createElement("a");r.className="container-close";r.href="#"}i=r.cloneNode(true);(b=this.innerElement.firstChild)?this.innerElement.insertBefore(i,b):this.innerElement.appendChild(i);i.innerHTML=c&&c.close?c.close:"&#160;";h.on(i,"click",this._doClose,this,true);this.close=i}else if(i)i.style.display="none"},_doClose:function(a){h.preventDefault(a);this.hide()},configDraggable:function(a,e){if(e[0])if(g.DD){if(this.header){j.setStyle(this.header,"cursor","move");this.registerDragDrop()}this.subscribe("beforeShow",
+b)}else this.cfg.setProperty("draggable",false);else{this.dd&&this.dd.unreg();this.header&&j.setStyle(this.header,"cursor","auto");this.unsubscribe("beforeShow",b)}},configUnderlay:function(a,e){function b(){if(!f){if(!m){m=document.createElement("div");m.className="underlay"}f=m.cloneNode(false);this.element.appendChild(f);this.underlay=f;if(n){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)}p.webkit&&p.webkit<420&&this.changeContentEvent.subscribe(this.forceUnderlayRedraw)}}function i(){!b.call(this)&&n&&this.sizeUnderlay();this._underlayDeferred=false;this.beforeShowEvent.unsubscribe(i)}function c(){if(this._underlayDeferred){this.beforeShowEvent.unsubscribe(i);this._underlayDeferred=false}if(f){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(f);this.underlay=null}}var d=this.platform=="mac"&&p.gecko,k=e[0].toLowerCase(),f=this.underlay,l=this.element;switch(k){case "shadow":j.removeClass(l,"matte");j.addClass(l,"shadow");break;case "matte":d||c.call(this);j.removeClass(l,"shadow");j.addClass(l,"matte");break;default:d||
+c.call(this);j.removeClass(l,"shadow");j.removeClass(l,"matte")}if(k=="shadow"||d&&!f)if(this.cfg.getProperty("visible"))!b.call(this)&&n&&this.sizeUnderlay();else if(!this._underlayDeferred){this.beforeShowEvent.subscribe(i);this._underlayDeferred=true}},configModal:function(a,e){if(e[0]){if(!this._hasModalityEventListeners){this.subscribe("beforeShow",this.buildMask);this.subscribe("beforeShow",this.bringToTop);this.subscribe("beforeShow",this.showMask);this.subscribe("hide",this.hideMask);l.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);l.windowResizeEvent.unsubscribe(this.sizeMask,this);this._hasModalityEventListeners=false}},removeMask:function(){var a=this.mask,e;if(a){this.hideMask();(e=a.parentNode)&&
+e.removeChild(a);this.mask=null}},configKeyListeners:function(a,e){var b=e[0],i,c,d;if(b)if(b instanceof Array){c=b.length;for(d=0;d<c;d++){i=b[d];k.alreadySubscribed(this.showEvent,i.enable,i)||this.showEvent.subscribe(i.enable,i,true);if(!k.alreadySubscribed(this.hideEvent,i.disable,i)){this.hideEvent.subscribe(i.disable,i,true);this.destroyEvent.subscribe(i.disable,i,true)}}}else{k.alreadySubscribed(this.showEvent,b.enable,b)||this.showEvent.subscribe(b.enable,b,true);if(!k.alreadySubscribed(this.hideEvent,
+b.disable,b)){this.hideEvent.subscribe(b.disable,b,true);this.destroyEvent.subscribe(b.disable,b,true)}}},configStrings:function(a,e){this.cfg.setProperty("strings",f.merge(z,e[0]),true)},configHeight:function(a,e){j.setStyle(this.innerElement,"height",e[0]);this.cfg.refireEvent("iframe")},_autoFillOnHeightChange:function(a,e,b){q.superclass._autoFillOnHeightChange.apply(this,arguments);if(n){var i=this;setTimeout(function(){i.sizeUnderlay()},0)}},configWidth:function(a,e){j.setStyle(this.innerElement,
+"width",e[0]);this.cfg.refireEvent("iframe")},configzIndex:function(a,e,b){q.superclass.configzIndex.call(this,a,e,b);if(this.mask||this.cfg.getProperty("modal")===true){a=j.getStyle(this.element,"zIndex");if(!a||isNaN(a))a=0;a===0?this.cfg.setProperty("zIndex",1):this.stackMask()}},buildWrapper:function(){var a=this.element.parentNode,e=this.element,b=document.createElement("div");b.className=q.CSS_PANEL_CONTAINER;b.id=e.id+"_c";a&&a.insertBefore(b,e);b.appendChild(e);this.element=b;this.innerElement=
+e;j.setStyle(this.innerElement,"visibility","inherit")},sizeUnderlay:function(){var a=this.underlay,e;if(a){e=this.element;a.style.width=e.offsetWidth+"px";a.style.height=e.offsetHeight+"px"}},registerDragDrop:function(){var a=this;if(this.header&&g.DD){var e=this.cfg.getProperty("dragonly")===true;this.dd=new g.DD(this.element.id,this.id,{dragOnly:e});if(!this.header.id)this.header.id=this.id+"_h";this.dd.startDrag=function(){var e,b,i,c,d,k;YAHOO.env.ua.ie==6&&j.addClass(a.element,"drag");if(a.cfg.getProperty("constraintoviewport")){var f=
+l.VIEWPORT_OFFSET;e=a.element.offsetHeight;b=a.element.offsetWidth;i=j.getViewportWidth();c=j.getViewportHeight();d=j.getDocumentScrollLeft();k=j.getDocumentScrollTop();if(e+f<c){this.minY=k+f;this.maxY=k+c-e-f}else{this.minY=k+f;this.maxY=k+f}if(b+f<i){this.minX=d+f;this.maxX=d+i-b-f}else{this.minX=d+f;this.maxX=d+f}this.constrainY=this.constrainX=true}else this.constrainY=this.constrainX=false;a.dragEvent.fire("startDrag",arguments)};this.dd.onDrag=function(){a.syncPosition();a.cfg.refireEvent("iframe");
+this.platform=="mac"&&YAHOO.env.ua.gecko&&this.showMacGeckoScrollbars();a.dragEvent.fire("onDrag",arguments)};this.dd.endDrag=function(){YAHOO.env.ua.ie==6&&j.removeClass(a.element,"drag");a.dragEvent.fire("endDrag",arguments);a.moveEvent.fire(a.cfg.getProperty("xy"))};this.dd.setHandleElId(this.header.id);this.dd.addInvalidHandleType("INPUT");this.dd.addInvalidHandleType("SELECT");this.dd.addInvalidHandleType("TEXTAREA")}},buildMask:function(){var a=this.mask;if(!a){if(!o){o=document.createElement("div");
+o.className="mask";o.innerHTML="&#160;"}a=o.cloneNode(true);a.id=this.id+"_mask";document.body.insertBefore(a,document.body.firstChild);this.mask=a;YAHOO.env.ua.gecko&&this.platform=="mac"&&j.addClass(this.mask,"block-scrollbars");this.stackMask()}},hideMask:function(){if(this.cfg.getProperty("modal")&&this.mask&&this.beforeHideMaskEvent.fire()){this.mask.style.display="none";j.removeClass(document.body,"masked");this.hideMaskEvent.fire()}},showMask:function(){if(this.cfg.getProperty("modal")&&this.mask&&
+this.beforeShowMaskEvent.fire()){j.addClass(document.body,"masked");this.sizeMask();this.mask.style.display="block";this.showMaskEvent.fire()}},sizeMask:function(){if(this.mask){var a=this.mask,e=j.getViewportWidth(),b=j.getViewportHeight();if(a.offsetHeight>b)a.style.height=b+"px";if(a.offsetWidth>e)a.style.width=e+"px";a.style.height=j.getDocumentHeight()+"px";a.style.width=j.getDocumentWidth()+"px"}},stackMask:function(){if(this.mask){var a=j.getStyle(this.element,"zIndex");!YAHOO.lang.isUndefined(a)&&
+!isNaN(a)&&j.setStyle(this.mask,"zIndex",a-1)}},render:function(a){return q.superclass.render.call(this,a,this.innerElement)},_renderHeader:function(a){a=a||this.innerElement;q.superclass._renderHeader.call(this,a)},_renderBody:function(a){a=a||this.innerElement;q.superclass._renderBody.call(this,a)},_renderFooter:function(a){a=a||this.innerElement;q.superclass._renderFooter.call(this,a)},destroy:function(a){l.windowResizeEvent.unsubscribe(this.sizeMask,this);this.removeMask();this.close&&h.purgeElement(this.close);
+q.superclass.destroy.call(this,a)},forceUnderlayRedraw:function(){var a=this.underlay;j.addClass(a,"yui-force-redraw");setTimeout(function(){j.removeClass(a,"yui-force-redraw")},0)},toString:function(){return"Panel "+this.id}})})();
+(function(){function a(){var a=this._aButtons,e,b;if(g.isArray(a)){e=a.length;if(e>0){b=e-1;do{e=a[b];if(YAHOO.widget.Button&&e instanceof YAHOO.widget.Button)e.destroy();else if(e.tagName.toUpperCase()=="BUTTON"){c.purgeElement(e);c.purgeElement(e,false)}}while(b--)}}}YAHOO.widget.Dialog=function(a,e){YAHOO.widget.Dialog.superclass.constructor.call(this,a,e)};var c=YAHOO.util.Event,b=YAHOO.util.CustomEvent,d=YAHOO.util.Dom,f=YAHOO.widget.Dialog,g=YAHOO.lang,j=["visible"];f.CSS_DIALOG="yui-dialog";
+YAHOO.extend(f,YAHOO.widget.Panel,{form:null,initDefaultConfig:function(){f.superclass.initDefaultConfig.call(this);this.callback={success:null,failure:null,argument:null};this.cfg.addProperty("postmethod",{handler:this.configPostMethod,value:"async",validator:function(a){return a!="form"&&a!="async"&&a!="none"&&a!="manual"?false:true}});this.cfg.addProperty("postdata",{value:null});this.cfg.addProperty("hideaftersubmit",{value:true});this.cfg.addProperty("buttons",{handler:this.configButtons,value:"none",
+supercedes:j})},initEvents:function(){f.superclass.initEvents.call(this);var a=b.LIST;this.beforeSubmitEvent=this.createEvent("beforeSubmit");this.beforeSubmitEvent.signature=a;this.submitEvent=this.createEvent("submit");this.submitEvent.signature=a;this.manualSubmitEvent=this.createEvent("manualSubmit");this.manualSubmitEvent.signature=a;this.asyncSubmitEvent=this.createEvent("asyncSubmit");this.asyncSubmitEvent.signature=a;this.formSubmitEvent=this.createEvent("formSubmit");this.formSubmitEvent.signature=
+a;this.cancelEvent=this.createEvent("cancel");this.cancelEvent.signature=a},init:function(a,e){f.superclass.init.call(this,a);this.beforeInitEvent.fire(f);d.addClass(this.element,f.CSS_DIALOG);this.cfg.setProperty("visible",false);e&&this.cfg.applyConfig(e,true);this.beforeHideEvent.subscribe(this.blurButtons,this,true);this.subscribe("changeBody",this.registerForm);this.initEvent.fire(f)},doSubmit:function(){var a=YAHOO.util.Connect,e=this.form,b=false,c=false,d,f;switch(this.cfg.getProperty("postmethod")){case "async":d=
+e.elements;f=d.length;if(f>0){f=f-1;do if(d[f].type=="file"){b=true;break}while(f--)}b&&(YAHOO.env.ua.ie&&this.isSecure)&&(c=true);d=this._getFormAttributes(e);a.setForm(e,b,c);e=this.cfg.getProperty("postdata");this.asyncSubmitEvent.fire(a.asyncRequest(d.method,d.action,this.callback,e));break;case "form":e.submit();this.formSubmitEvent.fire();break;case "none":case "manual":this.manualSubmitEvent.fire()}},_getFormAttributes:function(a){var e={method:null,action:null};if(a)if(a.getAttributeNode){var b=
+a.getAttributeNode("action"),a=a.getAttributeNode("method");if(b)e.action=b.value;if(a)e.method=a.value}else{e.action=a.getAttribute("action");e.method=a.getAttribute("method")}e.method=(g.isString(e.method)?e.method:"POST").toUpperCase();e.action=g.isString(e.action)?e.action:"";return e},registerForm:function(){var a=this.element.getElementsByTagName("form")[0];if(this.form){if(this.form==a&&d.isAncestor(this.element,this.form))return;c.purgeElement(this.form);this.form=null}if(!a){a=document.createElement("form");
+a.name="frm_"+this.id;this.body.appendChild(a)}if(a){this.form=a;c.on(a,"submit",this._submitHandler,this,true)}},_submitHandler:function(a){c.stopEvent(a);this.submit();this.form.blur()},setTabLoop:function(a,e){a=a||this.firstButton;e=e||this.lastButton;f.superclass.setTabLoop.call(this,a,e)},_setTabLoop:function(a,e){a=a||this.firstButton;e=this.lastButton||e;this.setTabLoop(a,e)},setFirstLastFocusable:function(){f.superclass.setFirstLastFocusable.call(this);var a,e,b,c=this.focusableElements;
+this.lastFormElement=this.firstFormElement=null;if(this.form&&c&&c.length>0){e=c.length;for(a=0;a<e;++a){b=c[a];if(this.form===b.form){this.firstFormElement=b;break}}for(a=e-1;a>=0;--a){b=c[a];if(this.form===b.form){this.lastFormElement=b;break}}}},configClose:function(a,e,b){f.superclass.configClose.apply(this,arguments)},_doClose:function(a){c.preventDefault(a);this.cancel()},configButtons:function(b,e){var i=YAHOO.widget.Button,k=e[0],f=this.innerElement,j,p,n,o,m,r;a.call(this);this._aButtons=
+null;if(g.isArray(k)){m=document.createElement("span");m.className="button-group";o=k.length;this._aButtons=[];this.defaultHtmlButton=null;for(r=0;r<o;r++){j=k[r];if(i){n=new i({label:j.text,type:j.type});n.appendTo(m);p=n.get("element");if(j.isDefault){n.addClass("default");this.defaultHtmlButton=p}g.isFunction(j.handler)?n.set("onclick",{fn:j.handler,obj:this,scope:this}):g.isObject(j.handler)&&g.isFunction(j.handler.fn)&&n.set("onclick",{fn:j.handler.fn,obj:!g.isUndefined(j.handler.obj)?j.handler.obj:
+this,scope:j.handler.scope||this});this._aButtons[this._aButtons.length]=n}else{p=document.createElement("button");p.setAttribute("type","button");if(j.isDefault){p.className="default";this.defaultHtmlButton=p}p.innerHTML=j.text;if(g.isFunction(j.handler))c.on(p,"click",j.handler,this,true);else if(g.isObject(j.handler)&&g.isFunction(j.handler.fn))c.on(p,"click",j.handler.fn,!g.isUndefined(j.handler.obj)?j.handler.obj:this,j.handler.scope||this);m.appendChild(p);this._aButtons[this._aButtons.length]=
+p}j.htmlButton=p;if(r===0)this.firstButton=p;if(r==o-1)this.lastButton=p}this.setFooter(m);i=this.footer;d.inDocument(this.element)&&!d.isAncestor(f,i)&&f.appendChild(i);this.buttonSpan=m}else{m=this.buttonSpan;i=this.footer;if(m&&i){i.removeChild(m);this.defaultHtmlButton=this.lastButton=this.firstButton=this.buttonSpan=null}}this.changeContentEvent.fire()},getButtons:function(){return this._aButtons||null},focusFirst:function(a,e){var b=this.firstFormElement,d=false;if(e&&e[1]){c.stopEvent(e[1]);
+if(e[0]===9&&this.firstElement)b=this.firstElement}if(b)try{b.focus();d=true}catch(f){}else d=this.defaultHtmlButton?this.focusDefaultButton():this.focusFirstButton();return d},focusLast:function(a,e){var b=this.cfg.getProperty("buttons"),d=this.lastFormElement,f=false;if(e&&e[1]){c.stopEvent(e[1]);if(e[0]===9&&this.lastElement)d=this.lastElement}if(b&&g.isArray(b))f=this.focusLastButton();else if(d)try{d.focus();f=true}catch(j){}return f},_getButton:function(a){var e=YAHOO.widget.Button;e&&(a&&a.nodeName&&
+a.id)&&(a=e.getButton(a.id)||a);return a},focusDefaultButton:function(){var a=this._getButton(this.defaultHtmlButton),e=false;if(a)try{a.focus();e=true}catch(b){}return e},blurButtons:function(){var a=this.cfg.getProperty("buttons"),e,b;if(a&&g.isArray(a)){e=a.length;if(e>0){e=e-1;do if(b=a[e])if(b=this._getButton(b.htmlButton))try{b.blur()}catch(c){}while(e--)}}},focusFirstButton:function(){var a=this.cfg.getProperty("buttons"),e=false;if(a&&g.isArray(a))if(a=a[0])if(a=this._getButton(a.htmlButton))try{a.focus();
+e=true}catch(b){}return e},focusLastButton:function(){var a=this.cfg.getProperty("buttons"),e,b=false;if(a&&g.isArray(a)){e=a.length;if(e>0)if(a=a[e-1])if(a=this._getButton(a.htmlButton))try{a.focus();b=true}catch(c){}}return b},configPostMethod:function(){this.registerForm()},validate:function(){return true},submit:function(){if(this.validate()&&this.beforeSubmitEvent.fire()){this.doSubmit();this.submitEvent.fire();this.cfg.getProperty("hideaftersubmit")&&this.hide();return true}return false},cancel:function(){this.cancelEvent.fire();
+this.hide()},getData:function(){function a(e){var b=e.tagName.toUpperCase();return(b=="INPUT"||b=="TEXTAREA"||b=="SELECT")&&e.name==g}var e=this.form,b,c,f,g,j,n,o,m,r,s,t;if(e){b=e.elements;c=b.length;f={};for(t=0;t<c;t++){g=b[t].name;j=d.getElementsBy(a,"*",e);n=j.length;if(n>0)if(n==1){j=j[0];o=j.type;m=j.tagName.toUpperCase();switch(m){case "INPUT":if(o=="checkbox")f[g]=j.checked;else if(o!="radio")f[g]=j.value;break;case "TEXTAREA":f[g]=j.value;break;case "SELECT":j=j.options;n=j.length;m=[];
+for(o=0;o<n;o++){r=j[o];if(r.selected){s=r.attributes.value;m[m.length]=s&&s.specified?r.value:r.text}}f[g]=m}}else{o=j[0].type;switch(o){case "radio":for(o=0;o<n;o++){m=j[o];if(m.checked){f[g]=m.value;break}}break;case "checkbox":m=[];for(o=0;o<n;o++){r=j[o];if(r.checked)m[m.length]=r.value}f[g]=m}}}}return f},destroy:function(b){a.call(this);this._aButtons=null;var e=this.element.getElementsByTagName("form");if(e.length>0)if(e=e[0]){c.purgeElement(e);e.parentNode&&e.parentNode.removeChild(e);this.form=
+null}f.superclass.destroy.call(this,b)},toString:function(){return"Dialog "+this.id}})})();
+(function(){YAHOO.widget.SimpleDialog=function(a,b){YAHOO.widget.SimpleDialog.superclass.constructor.call(this,a,b)};var a=YAHOO.util.Dom,c=YAHOO.widget.SimpleDialog,b=["icon"];c.ICON_BLOCK="blckicon";c.ICON_ALARM="alrticon";c.ICON_HELP="hlpicon";c.ICON_INFO="infoicon";c.ICON_WARN="warnicon";c.ICON_TIP="tipicon";c.ICON_CSS_CLASSNAME="yui-icon";c.CSS_SIMPLEDIALOG="yui-simple-dialog";YAHOO.extend(c,YAHOO.widget.Dialog,{initDefaultConfig:function(){c.superclass.initDefaultConfig.call(this);this.cfg.addProperty("icon",
+{handler:this.configIcon,value:"none",suppressEvent:true});this.cfg.addProperty("text",{handler:this.configText,value:"",suppressEvent:true,supercedes:b})},init:function(b,f){c.superclass.init.call(this,b);this.beforeInitEvent.fire(c);a.addClass(this.element,c.CSS_SIMPLEDIALOG);this.cfg.queueProperty("postmethod","manual");f&&this.cfg.applyConfig(f,true);this.beforeRenderEvent.subscribe(function(){this.body||this.setBody("")},this,true);this.initEvent.fire(c)},registerForm:function(){c.superclass.registerForm.call(this);
+var a=this.form.ownerDocument.createElement("input");a.type="hidden";a.name=this.id;a.value="";this.form.appendChild(a)},configIcon:function(b,f){var g=f[0],j=this.body,h=c.ICON_CSS_CLASSNAME,e,i;if(g&&g!="none"){e=a.getElementsByClassName(h,"*",j);if(e.length===1){e=e[0];(i=e.parentNode)&&i.removeChild(e)}if(g.indexOf(".")==-1){e=document.createElement("span");e.className=h+" "+g;e.innerHTML="&#160;"}else{e=document.createElement("img");e.src=this.imageRoot+g;e.className=h}e&&j.insertBefore(e,j.firstChild)}},
+configText:function(a,b){var c=b[0];if(c){this.setBody(c);this.cfg.refireEvent("icon")}},toString:function(){return"SimpleDialog "+this.id}})})();
+(function(){YAHOO.widget.ContainerEffect=function(a,b,c,j,h){if(!h)h=YAHOO.util.Anim;this.overlay=a;this.attrIn=b;this.attrOut=c;this.targetElement=j||a.element;this.animClass=h};var a=YAHOO.util.Dom,c=YAHOO.util.CustomEvent,b=YAHOO.widget.ContainerEffect;b.FADE=function(c,f){var g=YAHOO.util.Easing,g=new b(c,{attributes:{opacity:{from:0,to:1}},duration:f,method:g.easeIn},{attributes:{opacity:{to:0}},duration:f,method:g.easeOut},c.element);g.handleUnderlayStart=function(){var b=this.overlay.underlay;
+b&&YAHOO.env.ua.ie&&b.filters&&b.filters.length>0&&a.addClass(c.element,"yui-effect-fade")};g.handleUnderlayComplete=function(){this.overlay.underlay&&YAHOO.env.ua.ie&&a.removeClass(c.element,"yui-effect-fade")};g.handleStartAnimateIn=function(b,c,e){e.overlay._fadingIn=true;a.addClass(e.overlay.element,"hide-select");e.overlay.underlay||e.overlay.cfg.refireEvent("underlay");e.handleUnderlayStart();e.overlay._setDomVisibility(true);a.setStyle(e.overlay.element,"opacity",0)};g.handleCompleteAnimateIn=
+function(b,c,e){e.overlay._fadingIn=false;a.removeClass(e.overlay.element,"hide-select");if(e.overlay.element.style.filter)e.overlay.element.style.filter=null;e.handleUnderlayComplete();e.overlay.cfg.refireEvent("iframe");e.animateInCompleteEvent.fire()};g.handleStartAnimateOut=function(b,c,e){e.overlay._fadingOut=true;a.addClass(e.overlay.element,"hide-select");e.handleUnderlayStart()};g.handleCompleteAnimateOut=function(b,c,e){e.overlay._fadingOut=false;a.removeClass(e.overlay.element,"hide-select");
+if(e.overlay.element.style.filter)e.overlay.element.style.filter=null;e.overlay._setDomVisibility(false);a.setStyle(e.overlay.element,"opacity",1);e.handleUnderlayComplete();e.overlay.cfg.refireEvent("iframe");e.animateOutCompleteEvent.fire()};g.init();return g};b.SLIDE=function(c,f){var g=YAHOO.util.Easing,j=c.cfg.getProperty("x")||a.getX(c.element),h=c.cfg.getProperty("y")||a.getY(c.element),e=a.getClientWidth(),i=c.element.offsetWidth,g=new b(c,{attributes:{points:{to:[j,h]}},duration:f,method:g.easeIn},
+{attributes:{points:{to:[e+25,h]}},duration:f,method:g.easeOut},c.element,YAHOO.util.Motion);g.handleStartAnimateIn=function(a,e,b){b.overlay.element.style.left=-25-i+"px";b.overlay.element.style.top=h+"px"};g.handleTweenAnimateIn=function(e,b,i){b=a.getXY(i.overlay.element);e=b[0];b=b[1];a.getStyle(i.overlay.element,"visibility")=="hidden"&&e<j&&i.overlay._setDomVisibility(true);i.overlay.cfg.setProperty("xy",[e,b],true);i.overlay.cfg.refireEvent("iframe")};g.handleCompleteAnimateIn=function(a,e,
+b){b.overlay.cfg.setProperty("xy",[j,h],true);b.startX=j;b.startY=h;b.overlay.cfg.refireEvent("iframe");b.animateInCompleteEvent.fire()};g.handleStartAnimateOut=function(e,b,i){e=a.getViewportWidth();b=a.getXY(i.overlay.element)[1];i.animOut.attributes.points.to=[e+25,b]};g.handleTweenAnimateOut=function(e,b,i){e=a.getXY(i.overlay.element);i.overlay.cfg.setProperty("xy",[e[0],e[1]],true);i.overlay.cfg.refireEvent("iframe")};g.handleCompleteAnimateOut=function(a,e,b){b.overlay._setDomVisibility(false);
+b.overlay.cfg.setProperty("xy",[j,h]);b.animateOutCompleteEvent.fire()};g.init();return g};b.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._stopAnims(this.lastFrameOnStop);this.beforeAnimateInEvent.fire();this.animIn.animate()},animateOut:function(){this._stopAnims(this.lastFrameOnStop);this.beforeAnimateOutEvent.fire();this.animOut.animate()},lastFrameOnStop:true,_stopAnims:function(a){this.animOut&&this.animOut.isAnimated()&&this.animOut.stop(a);this.animIn&&this.animIn.isAnimated()&&
+this.animIn.stop(a)},handleStartAnimateIn:function(){},handleTweenAnimateIn:function(){},handleCompleteAnimateIn:function(){},handleStartAnimateOut:function(){},handleTweenAnimateOut:function(){},handleCompleteAnimateOut:function(){},toString:function(){var a="ContainerEffect";this.overlay&&(a=a+(" ["+this.overlay.toString()+"]"));return a}};YAHOO.lang.augmentProto(b,YAHOO.util.EventProvider)})();YAHOO.register("container",YAHOO.widget.Module,{version:"2.9.0",build:"2800"});
+var Y=YAHOO,Y_DOM=YAHOO.util.Dom,EMPTY_ARRAY=[],Y_UA=Y.env.ua,Y_Lang=Y.lang,Y_DOC=document,Y_DOCUMENT_ELEMENT=Y_DOC.documentElement,Y_DOM_inDoc=Y_DOM.inDocument,Y_mix=Y_Lang.augmentObject,Y_guid=Y_DOM.generateId,Y_getDoc=function(a){var c=Y_DOC;a&&(c=a.nodeType===9?a:a.ownerDocument||a.document||Y_DOC);return c},Y_Array=function(a,c){var b,d,f=c||0;try{return Array.prototype.slice.call(a,f)}catch(g){d=[];for(b=a.length;f<b;f++)d.push(a[f]);return d}},Y_DOM_allById=function(a,c){var c=c||Y_DOC,b=[],
+d=[],f,g;if(c.querySelectorAll)d=c.querySelectorAll('[id="'+a+'"]');else if(c.all){if(b=c.all(a)){if(b.nodeName)if(b.id===a){d.push(b);b=EMPTY_ARRAY}else b=[b];if(b.length)for(f=0;g=b[f++];)(g.id===a||g.attributes&&g.attributes.id&&g.attributes.id.value===a)&&d.push(g)}}else d=[Y_getDoc(c).getElementById(a)];return d},COMPARE_DOCUMENT_POSITION="compareDocumentPosition",OWNER_DOCUMENT="ownerDocument",Selector={_foundCache:[],useNative:!0,_compare:"sourceIndex"in Y_DOCUMENT_ELEMENT?function(a,c){var b=
+a.sourceIndex,d=c.sourceIndex;return b===d?0:b>d?1:-1}:Y_DOCUMENT_ELEMENT[COMPARE_DOCUMENT_POSITION]?function(a,c){return a[COMPARE_DOCUMENT_POSITION](c)&4?-1:1}:function(a,c){var b,d;if(a&&c){b=a[OWNER_DOCUMENT].createRange();b.setStart(a,0);d=c[OWNER_DOCUMENT].createRange();d.setStart(c,0);b=b.compareBoundaryPoints(1,d)}return b},_sort:function(a){if(a){a=Y_Array(a,0,true);a.sort&&a.sort(Selector._compare)}return a},_deDupe:function(a){var c=[],b,d;for(b=0;d=a[b++];)if(!d._found){c[c.length]=d;
+d._found=true}for(b=0;d=c[b++];){d._found=null;d.removeAttribute("_found")}return c},query:function(a,c,b,d){if(c&&typeof c=="string"){c=Y_DOM.get(c);if(!c)return b?null:[]}else c=c||Y_DOC;var f=[],g=Selector.useNative&&Y_DOC.querySelector&&!d,j=[[a,c]],h=g?Selector._nativeQuery:Selector._bruteQuery;if(a&&h){if(!d&&(!g||c.tagName))j=Selector._splitQueries(a,c);for(a=0;c=j[a++];){c=h(c[0],c[1],b);b||(c=Y_Array(c,0,true));c&&(f=f.concat(c))}j.length>1&&(f=Selector._sort(Selector._deDupe(f)))}return b?
+f[0]||null:f},_splitQueries:function(a,c){var b=a.split(","),d=[],f="",g,j;if(c){if(c.tagName){c.id=c.id||Y_guid();f='[id="'+c.id+'"] '}g=0;for(j=b.length;g<j;++g){a=f+b[g];d.push([a,c])}}return d},_nativeQuery:function(a,c,b){if(Y_UA.webkit&&a.indexOf(":checked")>-1&&Selector.pseudos&&Selector.pseudos.checked)return Selector.query(a,c,b,true);try{return c["querySelector"+(b?"":"All")](a)}catch(d){return Selector.query(a,c,b,true)}},filter:function(a,c){var b=[],d,f;if(a&&c)for(d=0;f=a[d++];)Selector.test(f,
+c)&&(b[b.length]=f);return b},test:function(a,c,b){var d=false,c=c.split(","),f=false,g,j,h,e,i;if(a&&a.tagName){if(!b&&!Y_DOM_inDoc(a)){b=a.parentNode;if(!b){h=a[OWNER_DOCUMENT].createDocumentFragment();h.appendChild(a);b=h;f=true}}b=b||a[OWNER_DOCUMENT];if(!a.id)a.id=Y_guid();for(e=0;g=c[e++];){g=g+('[id="'+a.id+'"]');j=Selector.query(g,b);for(i=0;g=j[i++];)if(g===a){d=true;break}if(d)break}f&&h.removeChild(a)}return d}};YAHOO.util.Selector=Selector;
+var PARENT_NODE="parentNode",TAG_NAME="tagName",ATTRIBUTES="attributes",COMBINATOR="combinator",PSEUDOS="pseudos",SelectorCSS2={_reRegExpTokens:/([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,SORT_RESULTS:!0,_children:function(a,c){var b=a.children,d,f,g;if(a.children&&c&&a.children.tags)a.children.tags(c);else if(!b&&a[TAG_NAME]||b&&c){f=b||a.childNodes;b=[];for(d=0;g=f[d++];)g.tagName&&(!c||c===g.tagName)&&b.push(g)}return b||[]},_re:{attr:/(\[[^\]]*\])/g,esc:/\\[:\[\]\(\)#\.\'\>+~"]/gi,pseudos:/(\([^\)]*\))/g},
+shorthand:{"\\#(-?[_a-z]+[-\\w\\uE000]*)":"[id=$1]","\\.(-?[_a-z]+[-\\w\\uE000]*)":"[className~=$1]"},operators:{"":function(a,c){return!!a.getAttribute(c)},"~=":"(?:^|\\s+){val}(?:\\s+|$)","|=":"^{val}(?:-|$)"},pseudos:{"first-child":function(a){return Selector._children(a[PARENT_NODE])[0]===a}},_bruteQuery:function(a,c,b){var d=[],f=[],a=Selector._tokenize(a),g=a[a.length-1];Y_getDoc(c);var j,h;if(g){j=g.id;h=g.className;g=g.tagName||"*";if(c.getElementsByTagName)f=j&&(c.all||c.nodeType===9||Y_DOM_inDoc(c))?
+Y_DOM_allById(j,c):h?c.getElementsByClassName(h):c.getElementsByTagName(g);else for(c=c.firstChild;c;){c.tagName&&f.push(c);c=c.nextSilbing||c.firstChild}f.length&&(d=Selector._filterNodes(f,a,b))}return d},_filterNodes:function(a,c,b){for(var d=0,f,g=c.length,j=g-1,h=[],e=a[0],i=e,k=Selector.getters,l,q,p,n,o,m,d=0;i=e=a[d++];){j=g-1;p=null;a:for(;i&&i.tagName;){q=c[j];o=q.tests;if(f=o.length)for(;m=o[--f];){l=m[1];if(k[m[0]])n=k[m[0]](i,m[0]);else{n=i[m[0]];n===void 0&&i.getAttribute&&(n=i.getAttribute(m[0]))}if(l===
+"="&&n!==m[2]||typeof l!=="string"&&l.test&&!l.test(n)||!l.test&&typeof l==="function"&&!l(i,m[0],m[2])){if(i=i[p])for(;i&&(!i.tagName||q.tagName&&q.tagName!==i.tagName);)i=i[p];continue a}}j--;if(f=q.combinator){p=f.axis;for(i=i[p];i&&!i.tagName;)i=i[p];f.direct&&(p=null)}else{h.push(e);if(b)return h;break}}}return h},combinators:{" ":{axis:"parentNode"},">":{axis:"parentNode",direct:!0},"+":{axis:"previousSibling",direct:!0}},_parsers:[{name:ATTRIBUTES,re:/^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,
+fn:function(a,c){var b=a[2]||"",d=Selector.operators,f=a[3]?a[3].replace(/\\/g,""):"";if(a[1]==="id"&&b==="="||a[1]==="className"&&Y_DOCUMENT_ELEMENT.getElementsByClassName&&(b==="~="||b==="=")){c.prefilter=a[1];a[3]=f;c[a[1]]=a[1]==="id"?a[3]:f}if(b in d){b=d[b];if(typeof b==="string"){a[3]=f.replace(Selector._reRegExpTokens,"\\$1");b=RegExp(b.replace("{val}",a[3]))}a[2]=b}if(!c.last||c.prefilter!==a[1])return a.slice(1)}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(a,c){var b=a[1].toUpperCase();
+c.tagName=b;if(b!=="*"&&(!c.last||c.prefilter))return[TAG_NAME,"=",b];if(!c.prefilter)c.prefilter="tagName"}},{name:COMBINATOR,re:/^\s*([>+~]|\s)\s*/,fn:function(){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,fn:function(a){var c=Selector[PSEUDOS][a[1]];if(c){a[2]&&(a[2]=a[2].replace(/\\/g,""));return[a[2],c]}return false}}],_getToken:function(){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]}},_tokenize:function(a){var a=Selector._replaceShorthand(Y_Lang.trim(a||
+"")),c=Selector._getToken(),b=[],d=false,f,g,j;a:do{d=false;for(g=0;j=Selector._parsers[g++];)if(f=j.re.exec(a)){if(j.name!==COMBINATOR)c.selector=a;a=a.replace(f[0],"");if(!a.length)c.last=true;Selector._attrFilters[f[1]]&&(f[1]=Selector._attrFilters[f[1]]);d=j.fn(f,c);if(d===false){d=false;break a}else d&&c.tests.push(d);if(!a.length||j.name===COMBINATOR){b.push(c);c=Selector._getToken(c);if(j.name===COMBINATOR)c.combinator=Selector.combinators[f[1]]}d=true}}while(d&&a.length);if(!d||a.length)b=
+[];return b},_replaceShorthand:function(a){var c=Selector.shorthand,b=a.match(Selector._re.esc),d,f,g;b&&(a=a.replace(Selector._re.esc,"\ue000"));d=a.match(Selector._re.attr);f=a.match(Selector._re.pseudos);d&&(a=a.replace(Selector._re.attr,"\ue001"));f&&(a=a.replace(Selector._re.pseudos,"\ue002"));for(g in c)c.hasOwnProperty(g)&&(a=a.replace(RegExp(g,"gi"),c[g]));if(d){c=0;for(g=d.length;c<g;++c)a=a.replace(/\uE001/,d[c])}if(f){c=0;for(g=f.length;c<g;++c)a=a.replace(/\uE002/,f[c])}a=a.replace(/\[/g,
+"\ue003");a=a.replace(/\]/g,"\ue004");a=a.replace(/\(/g,"\ue005");a=a.replace(/\)/g,"\ue006");if(b){c=0;for(g=b.length;c<g;++c)a=a.replace("\ue000",b[c])}return a},_attrFilters:{"class":"className","for":"htmlFor"},getters:{href:function(a,c){return Y_DOM.getAttribute(a,c)}}};Y_mix(Selector,SelectorCSS2,!0);Selector.getters.src=Selector.getters.rel=Selector.getters.href;Selector.useNative&&Y_DOC.querySelector&&(Selector.shorthand["\\.([^\\s\\\\(\\[:]*)"]="[class~=$1]");Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
+Selector._getNth=function(a,c,b,d){Selector._reNth.test(c);var c=parseInt(RegExp.$1,10),f=RegExp.$2,g=RegExp.$3,j=parseInt(RegExp.$4,10)||0,b=Selector._children(a.parentNode,b);if(g){c=2;j=g==="odd"?1:0}else isNaN(c)&&(c=f?1:0);if(c===0){d&&(j=b.length-j+1);return b[j-1]===a?true:false}if(c<0){d=!!d;c=Math.abs(c)}if(d){d=b.length-j;for(f=b.length;d>=0;d=d-c)if(d<f&&b[d]===a)return true}else{d=j-1;for(f=b.length;d<f;d=d+c)if(d>=0&&b[d]===a)return true}return false};
+Y_mix(Selector.pseudos,{root:function(a){return a===a.ownerDocument.documentElement},"nth-child":function(a,c){return Selector._getNth(a,c)},"nth-last-child":function(a,c){return Selector._getNth(a,c,null,true)},"nth-of-type":function(a,c){return Selector._getNth(a,c,a.tagName)},"nth-last-of-type":function(a,c){return Selector._getNth(a,c,a.tagName,true)},"last-child":function(a){var c=Selector._children(a.parentNode);return c[c.length-1]===a},"first-of-type":function(a){return Selector._children(a.parentNode,
+a.tagName)[0]===a},"last-of-type":function(a){var c=Selector._children(a.parentNode,a.tagName);return c[c.length-1]===a},"only-child":function(a){var c=Selector._children(a.parentNode);return c.length===1&&c[0]===a},"only-of-type":function(a){var c=Selector._children(a.parentNode,a.tagName);return c.length===1&&c[0]===a},empty:function(a){return a.childNodes.length===0},not:function(a,c){return!Selector.test(a,c)},contains:function(a,c){return(a.innerText||a.textContent||"").indexOf(c)>-1},checked:function(a){return a.checked===
+true||a.selected===true},enabled:function(a){return a.disabled!==void 0&&!a.disabled},disabled:function(a){return a.disabled}});Y_mix(Selector.operators,{"^=":"^{val}","!=":function(a,c,b){return a[c]!==b},"$=":"{val}$","*=":"{val}"});Selector.combinators["~"]={axis:"previousSibling"};YAHOO.register("selector",YAHOO.util.Selector,{version:"2.9.0",build:"2800"});
+(function(){var a=YAHOO.util.Event,c=YAHOO.lang,b=[],d=function(a,b,c){return!a||a===c?false:YAHOO.util.Selector.test(a,b)?a:d(a.parentNode,b,c)};c.augmentObject(a,{_createDelegate:function(b,g,j,h){return function(e){var i=a.getTarget(e),k=g,l=this.nodeType===9,q;if(c.isFunction(g))q=g(i);else if(c.isString(g)){if(!l){(k=this.id)||(k=a.generateId(this));k="#"+k+" ";k=(k+g).replace(/,/gi,","+k)}YAHOO.util.Selector.test(i,k)?q=i:YAHOO.util.Selector.test(i,k.replace(/,/gi," *,")+" *")&&(q=d(i,k,this))}if(q){i=
+q;h&&(i=h===true?j:h);return b.call(i,e,q,this,j)}}},delegate:function(d,g,j,h,e,i){var k=g,l;if(c.isString(h)&&!YAHOO.util.Selector)return false;if(g=="mouseenter"||g=="mouseleave"){if(!a._createMouseDelegate)return false;k=a._getType(g);l=a._createMouseDelegate(j,e,i);g=a._createDelegate(function(a,e,b){return l.call(e,a,b)},h,e,i)}else g=a._createDelegate(j,h,e,i);b.push([d,k,j,g]);return a.on(d,k,g)},removeDelegate:function(c,d,j){var h=d,e=false,i;if(d=="mouseenter"||d=="mouseleave")h=a._getType(d);
+d=a._getCacheIndex(b,c,h,j);d>=0&&(i=b[d]);if(c&&i)if(e=a.removeListener(i[0],i[1],i[3])){delete b[d][2];delete b[d][3];b.splice(d,1)}return e}})})();YAHOO.register("event-delegate",YAHOO.util.Event,{version:"2.9.0",build:"2800"});
+(function(){function a(a){s[a]||(s[a]="\\u"+("0000"+(+a.charCodeAt(0)).toString(16)).slice(-4));return s[a]}function c(a,e){var b=function(a,i){var c,d,k=a[i];if(k&&typeof k==="object")for(c in k)if(j.hasOwnProperty(k,c)){d=b(k,c);d===void 0?delete k[c]:k[c]=d}return e.call(a,i,k)};return typeof e==="function"?b({"":a},""):a}function b(a){return j.isString(a)&&!m.test(a.replace(p,"@").replace(n,"]").replace(o,""))}function d(e,i){e=e.replace(q,a);if(b(e))return c(eval("("+e+")"),i);throw new SyntaxError("JSON.parse");
+}function f(a){var e=typeof a;return A[e]||A[k.call(a)]||(e===u?a?u:w:t)}function g(b,c,d){function l(b,k){var q=b[k],o=f(q),m=[],s=d?N:H,t,I,A,M;e(q)&&h(q.toJSON)?q=q.toJSON(k):o===B&&(q=p(q));h(g)&&(q=g.call(b,k,q));q!==b[k]&&(o=f(q));switch(o){case B:case u:break;case x:return G+q.replace(r,a)+G;case v:return isFinite(q)?q+D:w;case y:return q+D;case w:return w;default:return}for(t=n.length-1;t>=0;--t)if(n[t]===q)throw Error("JSON.stringify. Cyclical reference");o=i(q);n.push(q);if(o)for(t=q.length-
+1;t>=0;--t)m[t]=l(q,t)||w;else{I=c||q;t=0;for(A in I)if(j.hasOwnProperty(I,A))(M=l(q,A))&&(m[t++]=G+A.replace(r,a)+G+s+M)}n.pop();if(d&&m.length){if(o){q=z+F;m=m.join(L).replace(/^/gm,d);m=q+m+F+J}else{q=E+F;m=m.join(L).replace(/^/gm,d);m=q+m+F+C}return m}return o?z+m.join(K)+J:E+m.join(K)+C}if(b!==void 0){var g=h(c)?c:null,q=k.call(d).match(/String|Number/)||[],p=YAHOO.lang.JSON.dateToString,n=[],o,m,s;if(g||!i(c))c=void 0;if(c){o={};m=0;for(s=c.length;m<s;++m)o[c[m]]=true;c=o}d=q[0]==="Number"?
+Array(Math.min(Math.max(0,d),10)+1).join(" "):(d||D).slice(0,10);return l({"":b},"")}}var j=YAHOO.lang,h=j.isFunction,e=j.isObject,i=j.isArray,k=Object.prototype.toString,l=(YAHOO.env.ua.caja?window:this).JSON,q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,n=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,o=/(?:^|:|,)(?:\s*\[)+/g,m=/[^\],:{}\s]/,r=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+s={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},t="undefined",u="object",w="null",x="string",v="number",y="boolean",B="date",A={undefined:t,string:x,"[object String]":x,number:v,"[object Number]":v,"boolean":y,"[object Boolean]":y,"[object Date]":B,"[object RegExp]":u},D="",E="{",C="}",z="[",J="]",K=",",L=",\n",F="\n",H=":",N=": ",G='"',l=k.call(l)==="[object JSON]"&&l;YAHOO.lang.JSON={useNativeParse:!!l,useNativeStringify:!!l,isSafe:function(e){return b(e.replace(q,
+a))},parse:function(a,e){typeof a!=="string"&&(a=a+"");return l&&YAHOO.lang.JSON.useNativeParse?l.parse(a,e):d(a,e)},stringify:function(a,e,b){return l&&YAHOO.lang.JSON.useNativeStringify?l.stringify(a,e,b):g(a,e,b)},dateToString:function(a){function e(a){return a<10?"0"+a:a}return a.getUTCFullYear()+"-"+e(a.getUTCMonth()+1)+"-"+e(a.getUTCDate())+"T"+e(a.getUTCHours())+H+e(a.getUTCMinutes())+H+e(a.getUTCSeconds())+"Z"},stringToDate:function(a){var e=a.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3}))?Z$/);
+if(e){a=new Date;a.setUTCFullYear(e[1],e[2]-1,e[3]);a.setUTCHours(e[4],e[5],e[6],e[7]||0)}return a}};YAHOO.lang.JSON.isValid=YAHOO.lang.JSON.isSafe})();YAHOO.register("json",YAHOO.lang.JSON,{version:"2.9.0",build:"2800"});
+(function(){var a=YAHOO.util.Event,c=YAHOO.lang,b=a.addListener,d=a.removeListener,f=a.getListeners,g=[],j={mouseenter:"mouseover",mouseleave:"mouseout"},h=function(e,b,c){var c=a._getCacheIndex(g,e,b,c),f,h;c>=0&&(f=g[c]);if(e&&f)if(h=d.call(a,f[0],b,f[3])){delete g[c][2];delete g[c][3];g.splice(c,1)}return h};c.augmentObject(a._specialTypes,j);c.augmentObject(a,{_createMouseDelegate:function(e,b,c){return function(d,f){var g=a.getRelatedTarget(d),h;if(this!=g&&!YAHOO.util.Dom.isAncestor(this,g)){g=
+this;c&&(g=c===true?b:c);h=[d,b];f&&h.splice(1,0,this,f);return e.apply(g,h)}}},addListener:function(e,i,c,d,f){var h;if(j[i]){h=a._createMouseDelegate(c,d,f);h.mouseDelegate=true;g.push([e,i,c,h]);h=b.call(a,e,i,h)}else h=b.apply(a,arguments);return h},removeListener:function(e,b,c){return j[b]?h.apply(a,arguments):d.apply(a,arguments)},getListeners:function(e,b){var c=[],d,g=b==="mouseover"||b==="mouseout",h,n,o;if(b&&(g||j[b])){if(d=f.call(a,e,this._getType(b)))for(n=d.length-1;n>-1;n--){o=d[n];
+h=o.fn.mouseDelegate;(j[b]&&h||g&&!h)&&c.push(o)}}else c=f.apply(a,arguments);return c&&c.length?c:null}},true);a.on=a.addListener})();YAHOO.register("event-mouseenter",YAHOO.util.Event,{version:"2.9.0",build:"2800"});
+(function(){var a=YAHOO.lang,c=YAHOO.util;c.DataSourceBase=function(b,f){if(!(b===null||b===void 0)){this.liveData=b;this._oQueue={interval:null,conn:null,requests:[]};this.responseSchema={};if(f&&f.constructor==Object)for(var g in f)g&&(this[g]=f[g]);a.isNumber(this.maxCacheEntries);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");g=c.DataSourceBase;this._sName="DataSource instance"+g._nIndex;g._nIndex++}};var b=c.DataSourceBase;a.augmentObject(b,{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,_cloneObject:function(c){if(!a.isValue(c))return c;var f={};if(Object.prototype.toString.apply(c)===
+"[object RegExp]")f=c;else if(a.isFunction(c))f=c;else if(a.isArray(c))for(var f=[],g=0,j=c.length;g<j;g++)f[g]=b._cloneObject(c[g]);else if(a.isObject(c))for(g in c)a.hasOwnProperty(c,g)&&(f[g]=a.isValue(c[g])&&a.isObject(c[g])||a.isArray(c[g])?b._cloneObject(c[g]):c[g]);else f=c;return f},_getLocationValue:function(b,c){var g=b.locator||b.key||b,j=c.ownerDocument||c,h,e,i=null;try{if(a.isUndefined(j.evaluate)){j.setProperty("SelectionLanguage","XPath");h=c.selectNodes(g)[0];i=h.value||h.text||null}else for(h=
+j.evaluate(g,c,j.createNSResolver(!c.ownerDocument?c.documentElement:c.ownerDocument.documentElement),0,null);e=h.iterateNext();)i=e.textContent;return i}catch(k){}},issueCallback:function(b,c,g,j){if(a.isFunction(b))b.apply(j,c);else if(a.isObject(b)){var j=b.scope||j||window,h=b.success;if(g)h=b.failure;h&&h.apply(j,c.concat([b.argument]))}},parseString:function(b){if(!a.isValue(b))return null;b=b+"";return a.isString(b)?b:null},parseNumber:function(b){if(!a.isValue(b)||b==="")return null;b=b*1;
+return a.isNumber(b)?b:null},convertNumber:function(a){return b.parseNumber(a)},parseDate:function(b){var c=null;if(a.isValue(b)&&!(b instanceof Date))c=new Date(b);else return b;return c instanceof Date?c:null},convertDate:function(a){return b.parseDate(a)}});b.Parser={string:b.parseString,number:b.parseNumber,date:b.parseDate};b.prototype={_sName:null,_aCache:null,_oQueue:null,_aIntervals:null,maxCacheEntries:0,liveData:null,dataType:b.TYPE_UNKNOWN,responseType:b.TYPE_UNKNOWN,responseSchema:null,
+useXPath:false,cloneBeforeCaching:false,toString:function(){return this._sName},getCachedResponse:function(a,b,c){var j=this._aCache;if(this.maxCacheEntries>0)if(j){var h=j.length;if(h>0){var e=null;this.fireEvent("cacheRequestEvent",{request:a,callback:b,caller:c});for(var i=h-1;i>=0;i--){var k=j[i];if(this.isCacheHit(a,k.request)){e=k.response;this.fireEvent("cacheResponseEvent",{request:a,response:e,callback:b,caller:c});if(i<h-1){j.splice(i,1);this.addToCache(a,e)}e.cached=true;break}}return e}}else this._aCache=
+[];else if(j)this._aCache=null;return null},isCacheHit:function(a,b){return a===b},addToCache:function(a,c){var g=this._aCache;if(g){for(;g.length>=this.maxCacheEntries;)g.shift();c=this.cloneBeforeCaching?b._cloneObject(c):c;g[g.length]={request:a,response:c};this.fireEvent("responseCacheEvent",{request:a,response:c})}},flushCache:function(){if(this._aCache){this._aCache=[];this.fireEvent("cacheFlushEvent")}},setInterval:function(b,c,g,j){if(a.isNumber(b)&&b>=0){var h=this,b=setInterval(function(){h.makeConnection(c,
+g,j)},b);this._aIntervals.push(b);return b}},clearInterval:function(a){for(var b=this._aIntervals||[],c=b.length-1;c>-1;c--)if(b[c]===a){b.splice(c,1);clearInterval(a)}},clearAllIntervals:function(){for(var a=this._aIntervals||[],b=a.length-1;b>-1;b--)clearInterval(a[b])},sendRequest:function(a,c,g){var j=this.getCachedResponse(a,c,g);if(j){b.issueCallback(c,[a,j],false,g);return null}return this.makeConnection(a,c,g)},makeConnection:function(a,c,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",
+{tId:j,request:a,callback:c,caller:g});this.handleResponse(a,this.liveData,c,g,j);return j},handleResponse:function(c,f,g,j,h){this.fireEvent("responseEvent",{tId:h,request:c,response:f,callback:g,caller:j});var e=this.dataType==b.TYPE_XHR?true:false,i=null,k=f;if(this.responseType===b.TYPE_UNKNOWN)if(i=f&&f.getResponseHeader?f.getResponseHeader["Content-Type"]:null)if(i.indexOf("text/xml")>-1)this.responseType=b.TYPE_XML;else if(i.indexOf("application/json")>-1)this.responseType=b.TYPE_JSON;else{if(i.indexOf("text/plain")>
+-1)this.responseType=b.TYPE_TEXT}else if(YAHOO.lang.isArray(f))this.responseType=b.TYPE_JSARRAY;else if(f&&f.nodeType&&(f.nodeType===9||f.nodeType===1||f.nodeType===11))this.responseType=b.TYPE_XML;else if(f&&f.nodeName&&f.nodeName.toLowerCase()=="table")this.responseType=b.TYPE_HTMLTABLE;else if(YAHOO.lang.isObject(f))this.responseType=b.TYPE_JSON;else if(YAHOO.lang.isString(f))this.responseType=b.TYPE_TEXT;switch(this.responseType){case b.TYPE_JSARRAY:if(e&&f&&f.responseText)k=f.responseText;try{if(a.isString(k)){var l=
+[k].concat(this.parseJSONArgs);if(a.JSON)k=a.JSON.parse.apply(a.JSON,l);else if(window.JSON&&JSON.parse)k=JSON.parse.apply(JSON,l);else if(k.parseJSON)k=k.parseJSON.apply(k,l.slice(1));else{for(;k.length>0&&k.charAt(0)!="{"&&k.charAt(0)!="[";)k=k.substring(1,k.length);if(k.length>0)var q=Math.max(k.lastIndexOf("]"),k.lastIndexOf("}")),k=k.substring(0,q+1),k=eval("("+k+")")}}}catch(p){}k=this.doBeforeParseData(c,k,g);i=this.parseArrayData(c,k);break;case b.TYPE_JSON:if(e&&f&&f.responseText)k=f.responseText;
+try{if(a.isString(k)){l=[k].concat(this.parseJSONArgs);if(a.JSON)k=a.JSON.parse.apply(a.JSON,l);else if(window.JSON&&JSON.parse)k=JSON.parse.apply(JSON,l);else if(k.parseJSON)k=k.parseJSON.apply(k,l.slice(1));else{for(;k.length>0&&k.charAt(0)!="{"&&k.charAt(0)!="[";)k=k.substring(1,k.length);if(k.length>0)var n=Math.max(k.lastIndexOf("]"),k.lastIndexOf("}")),k=k.substring(0,n+1),k=eval("("+k+")")}}}catch(o){}k=this.doBeforeParseData(c,k,g);i=this.parseJSONData(c,k);break;case b.TYPE_HTMLTABLE:if(e&&
+f.responseText){e=document.createElement("div");e.innerHTML=f.responseText;k=e.getElementsByTagName("table")[0]}k=this.doBeforeParseData(c,k,g);i=this.parseHTMLTableData(c,k);break;case b.TYPE_XML:if(e&&f.responseXML)k=f.responseXML;k=this.doBeforeParseData(c,k,g);i=this.parseXMLData(c,k);break;case b.TYPE_TEXT:if(e&&a.isString(f.responseText))k=f.responseText;k=this.doBeforeParseData(c,k,g);i=this.parseTextData(c,k);break;default:k=this.doBeforeParseData(c,k,g);i=this.parseData(c,k)}i=i||{};if(!i.results)i.results=
+[];if(!i.meta)i.meta={};if(i.error){i.error=true;this.fireEvent("dataErrorEvent",{request:c,response:f,callback:g,caller:j,message:b.ERROR_DATANULL})}else{i=this.doBeforeCallback(c,k,i,g);this.fireEvent("responseParseEvent",{request:c,response:i,callback:g,caller:j});this.addToCache(c,i)}i.tId=h;b.issueCallback(g,[c,i],i.error,j)},doBeforeParseData:function(a,b){return b},doBeforeCallback:function(a,b,c){return c},parseData:function(b,c){return a.isValue(c)?{results:c,meta:{}}:null},parseArrayData:function(c,
+f){if(a.isArray(f)){var g=[],j,h,e,i,k;if(a.isArray(this.responseSchema.fields)){var l=this.responseSchema.fields;for(j=l.length-1;j>=0;--j)typeof l[j]!=="object"&&(l[j]={key:l[j]});var q={};for(j=l.length-1;j>=0;--j)(h=(typeof l[j].parser==="function"?l[j].parser:b.Parser[l[j].parser+""])||l[j].converter)&&(q[l[j].key]=h);var p=a.isArray(f[0]);for(j=f.length-1;j>-1;j--){var n={};e=f[j];if(typeof e==="object")for(h=l.length-1;h>-1;h--){i=l[h];k=p?e[h]:e[i.key];q[i.key]&&(k=q[i.key].call(this,k));
+k===void 0&&(k=null);n[i.key]=k}else if(a.isString(e))for(h=l.length-1;h>-1;h--){i=l[h];k=e;q[i.key]&&(k=q[i.key].call(this,k));k===void 0&&(k=null);n[i.key]=k}g[j]=n}}else g=f;return{results:g}}return null},parseTextData:function(c,f){if(a.isString(f)&&a.isString(this.responseSchema.recordDelim)&&a.isString(this.responseSchema.fieldDelim)){var g={results:[]},j=this.responseSchema.recordDelim,h=this.responseSchema.fieldDelim;if(f.length>0){var e=f.length-j.length;f.substr(e)==j&&(f=f.substr(0,e));
+if(f.length>0)for(var j=f.split(j),e=0,i=j.length,k=0;e<i;++e){var l=false,q=j[e];if(a.isString(q)&&q.length>0){var q=j[e].split(h),p={};if(a.isArray(this.responseSchema.fields))for(var n=this.responseSchema.fields,o=n.length-1;o>-1;o--)try{var m=q[o];if(a.isString(m)){m.charAt(0)=='"'&&(m=m.substr(1));m.charAt(m.length-1)=='"'&&(m=m.substr(0,m.length-1));var r=n[o],s=a.isValue(r.key)?r.key:r;if(!r.parser&&r.converter)r.parser=r.converter;var t=typeof r.parser==="function"?r.parser:b.Parser[r.parser+
+""];t&&(m=t.call(this,m));m===void 0&&(m=null);p[s]=m}else l=true}catch(u){l=true}else p=q;l||(g.results[k++]=p)}}}return g}return null},parseXMLResult:function(c){var f={},g=this.responseSchema;try{for(var j=g.fields.length-1;j>=0;j--){var h=g.fields[j],e=a.isValue(h.key)?h.key:h,i=null;if(this.useXPath)i=YAHOO.util.DataSource._getLocationValue(h,c);else{var k=c.attributes.getNamedItem(e);if(k)i=k.value;else{var l=c.getElementsByTagName(e);if(l&&l.item(0)){var q=l.item(0),i=q?q.text?q.text:q.textContent?
+q.textContent:null:null;if(!i){for(var p=[],n=0,o=q.childNodes.length;n<o;n++)if(q.childNodes[n].nodeValue)p[p.length]=q.childNodes[n].nodeValue;p.length>0&&(i=p.join(""))}}}}i===null&&(i="");if(!h.parser&&h.converter)h.parser=h.converter;var m=typeof h.parser==="function"?h.parser:b.Parser[h.parser+""];m&&(i=m.call(this,i));i===void 0&&(i=null);f[e]=i}}catch(r){}return f},parseXMLData:function(b,c){var g=false,j=this.responseSchema,h={meta:{}},e=null,i=j.metaNode,k=j.metaFields||{},l,q,p;try{if(this.useXPath)for(l in k)h.meta[l]=
+YAHOO.util.DataSource._getLocationValue(k[l],c);else if(i=i?c.getElementsByTagName(i)[0]:c)for(l in k)if(a.hasOwnProperty(k,l)){q=k[l];if(p=i.getElementsByTagName(q)[0])p=p.firstChild.nodeValue;else if(p=i.attributes.getNamedItem(q))p=p.value;a.isValue(p)&&(h.meta[l]=p)}e=j.resultNode?c.getElementsByTagName(j.resultNode):null}catch(n){}if(!e||!a.isArray(j.fields))g=true;else{h.results=[];for(j=e.length-1;j>=0;--j){i=this.parseXMLResult(e.item(j));h.results[j]=i}}if(g)h.error=true;return h},parseJSONData:function(c,
+f){var g={results:[],meta:{}};if(a.isObject(f)&&this.responseSchema.resultsList){var j=this.responseSchema,h=j.fields,e=f,i=[],k=j.metaFields||{},l=[],q=[],p=[],n=false,o,m,r,s=function(a){var e=null,b=[],i=0;if(a){a=a.replace(/\[(['"])(.*?)\1\]/g,function(a,e,c){b[i]=c;return".@"+i++}).replace(/\[(\d+)\]/g,function(a,e){b[i]=parseInt(e,10)|0;return".@"+i++}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(a)){e=a.split(".");for(i=e.length-1;i>=0;--i)e[i].charAt(0)==="@"&&(e[i]=b[parseInt(e[i].substr(1),
+10)])}}return e},t=function(a,e){for(var b=e,i=0,c=a.length;i<c&&b;++i)b=b[a[i]];return b};if(r=s(j.resultsList)){e=t(r,f);e===void 0&&(n=true)}else n=true;e||(e=[]);a.isArray(e)||(e=[e]);if(n)g.error=true;else{if(j.fields){j=0;for(n=h.length;j<n;j++){r=h[j];o=r.key||r;m=(typeof r.parser==="function"?r.parser:b.Parser[r.parser+""])||r.converter;r=s(o);m&&(l[l.length]={key:o,parser:m});r&&(r.length>1?q[q.length]={key:o,path:r}:p[p.length]={key:o,path:r[0]})}for(j=e.length-1;j>=0;--j){n=e[j];r={};if(n){for(h=
+p.length-1;h>=0;--h)r[p[h].key]=n[p[h].path]!==void 0?n[p[h].path]:n[h];for(h=q.length-1;h>=0;--h)r[q[h].key]=t(q[h].path,n);for(h=l.length-1;h>=0;--h){n=l[h].key;r[n]=l[h].parser.call(this,r[n]);r[n]===void 0&&(r[n]=null)}}i[j]=r}}else i=e;for(o in k)if(a.hasOwnProperty(k,o))if(r=s(k[o])){e=t(r,f);g.meta[o]=e}}g.results=i}else g.error=true;return g},parseHTMLTableData:function(c,f){var g=false,j=this.responseSchema.fields,h={results:[]};if(a.isArray(j))for(var e=0;e<f.tBodies.length;e++)for(var i=
+f.tBodies[e],k=i.rows.length-1;k>-1;k--){for(var l=i.rows[k],q={},p=j.length-1;p>-1;p--){var n=j[p],o=a.isValue(n.key)?n.key:n,m=l.cells[p].innerHTML;if(!n.parser&&n.converter)n.parser=n.converter;(n=typeof n.parser==="function"?n.parser:b.Parser[n.parser+""])&&(m=n.call(this,m));m===void 0&&(m=null);q[o]=m}h.results[k]=q}else g=true;if(g)h.error=true;return h}};a.augmentProto(b,c.EventProvider);c.LocalDataSource=function(a,f){this.dataType=b.TYPE_LOCAL;if(a)if(YAHOO.lang.isArray(a))this.responseType=
+b.TYPE_JSARRAY;else if(a.nodeType&&a.nodeType==9)this.responseType=b.TYPE_XML;else if(a.nodeName&&a.nodeName.toLowerCase()=="table"){this.responseType=b.TYPE_HTMLTABLE;a=a.cloneNode(true)}else if(YAHOO.lang.isString(a))this.responseType=b.TYPE_TEXT;else{if(YAHOO.lang.isObject(a))this.responseType=b.TYPE_JSON}else{a=[];this.responseType=b.TYPE_JSARRAY}c.LocalDataSource.superclass.constructor.call(this,a,f)};a.extend(c.LocalDataSource,b);a.augmentObject(c.LocalDataSource,b);c.FunctionDataSource=function(a,
+f){this.dataType=b.TYPE_JSFUNCTION;c.FunctionDataSource.superclass.constructor.call(this,a||function(){},f)};a.extend(c.FunctionDataSource,b,{scope:null,makeConnection:function(a,c,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",{tId:j,request:a,callback:c,caller:g});var h=this.scope?this.liveData.call(this.scope,a,this,c):this.liveData(a,c);if(this.responseType===b.TYPE_UNKNOWN)if(YAHOO.lang.isArray(h))this.responseType=b.TYPE_JSARRAY;else if(h&&h.nodeType&&h.nodeType==9)this.responseType=
+b.TYPE_XML;else if(h&&h.nodeName&&h.nodeName.toLowerCase()=="table")this.responseType=b.TYPE_HTMLTABLE;else if(YAHOO.lang.isObject(h))this.responseType=b.TYPE_JSON;else if(YAHOO.lang.isString(h))this.responseType=b.TYPE_TEXT;this.handleResponse(a,h,c,g,j);return j}});a.augmentObject(c.FunctionDataSource,b);c.ScriptNodeDataSource=function(a,f){this.dataType=b.TYPE_SCRIPTNODE;c.ScriptNodeDataSource.superclass.constructor.call(this,a||"",f)};a.extend(c.ScriptNodeDataSource,b,{getUtility:c.Get,asyncMode:"allowAll",
+scriptCallbackParam:"callback",generateRequestCallback:function(a){return"&"+this.scriptCallbackParam+"=YAHOO.util.ScriptNodeDataSource.callbacks["+a+"]"},doBeforeGetScriptNode:function(a){return a},makeConnection:function(a,f,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",{tId:j,request:a,callback:f,caller:g});if(c.ScriptNodeDataSource._nPending===0){c.ScriptNodeDataSource.callbacks=[];c.ScriptNodeDataSource._nId=0}var h=c.ScriptNodeDataSource._nId;c.ScriptNodeDataSource._nId++;var e=
+this;c.ScriptNodeDataSource.callbacks[h]=function(i){if(e.asyncMode!=="ignoreStaleResponses"||h===c.ScriptNodeDataSource.callbacks.length-1){if(e.responseType===b.TYPE_UNKNOWN)if(YAHOO.lang.isArray(i))e.responseType=b.TYPE_JSARRAY;else if(i.nodeType&&i.nodeType==9)e.responseType=b.TYPE_XML;else if(i.nodeName&&i.nodeName.toLowerCase()=="table")e.responseType=b.TYPE_HTMLTABLE;else if(YAHOO.lang.isObject(i))e.responseType=b.TYPE_JSON;else if(YAHOO.lang.isString(i))e.responseType=b.TYPE_TEXT;e.handleResponse(a,
+i,f,g,j)}delete c.ScriptNodeDataSource.callbacks[h]};c.ScriptNodeDataSource._nPending++;var i=this.liveData+a+this.generateRequestCallback(h),i=this.doBeforeGetScriptNode(i);this.getUtility.script(i,{autopurge:true,onsuccess:c.ScriptNodeDataSource._bumpPendingDown,onfail:c.ScriptNodeDataSource._bumpPendingDown});return j}});a.augmentObject(c.ScriptNodeDataSource,b);a.augmentObject(c.ScriptNodeDataSource,{_nId:0,_nPending:0,callbacks:[]});c.XHRDataSource=function(a,f){this.dataType=b.TYPE_XHR;this.connMgr=
+this.connMgr||c.Connect;c.XHRDataSource.superclass.constructor.call(this,a||"",f)};a.extend(c.XHRDataSource,b,{connMgr:null,connXhrMode:"allowAll",connMethodPost:false,connTimeout:0,makeConnection:function(c,f,g){var j=b._nTransactionId++;this.fireEvent("requestEvent",{tId:j,request:c,callback:f,caller:g});var h=this.connMgr,e=this._oQueue,i={success:function(a){if(a&&this.connXhrMode=="ignoreStaleResponses"&&a.tId!=e.conn.tId)return null;if(a){if(this.responseType===b.TYPE_UNKNOWN){var i=a.getResponseHeader?
+a.getResponseHeader["Content-Type"]:null;if(i)if(i.indexOf("text/xml")>-1)this.responseType=b.TYPE_XML;else if(i.indexOf("application/json")>-1)this.responseType=b.TYPE_JSON;else if(i.indexOf("text/plain")>-1)this.responseType=b.TYPE_TEXT}this.handleResponse(c,a,f,g,j)}else{this.fireEvent("dataErrorEvent",{request:c,response:null,callback:f,caller:g,message:b.ERROR_DATANULL});b.issueCallback(f,[c,{error:true}],true,g);return null}},failure:function(e){this.fireEvent("dataErrorEvent",{request:c,response:e,
+callback:f,caller:g,message:b.ERROR_DATAINVALID});a.isString(this.liveData)&&a.isString(c)&&this.liveData.lastIndexOf("?")!==this.liveData.length-1&&c.indexOf("?");e=e||{};e.error=true;b.issueCallback(f,[c,e],true,g);return null},scope:this};if(a.isNumber(this.connTimeout))i.timeout=this.connTimeout;if(this.connXhrMode=="cancelStaleRequests"&&e.conn&&h.abort){h.abort(e.conn);e.conn=null}if(h&&h.asyncRequest){var k=this.liveData,l=this.connMethodPost,q=l?"POST":"GET",p=l||!a.isValue(c)?k:k+c,n=l?c:
+null;if(this.connXhrMode!="queueRequests")e.conn=h.asyncRequest(q,p,i,n);else if(e.conn){var o=e.requests;o.push({request:c,callback:i});if(!e.interval)e.interval=setInterval(function(){if(!h.isCallInProgress(e.conn))if(o.length>0){p=l||!a.isValue(o[0].request)?k:k+o[0].request;n=l?o[0].request:null;e.conn=h.asyncRequest(q,p,o[0].callback,n);o.shift()}else{clearInterval(e.interval);e.interval=null}},50)}else e.conn=h.asyncRequest(q,p,i,n)}else b.issueCallback(f,[c,{error:true}],true,g);return j}});
+a.augmentObject(c.XHRDataSource,b);c.DataSource=function(a,f){var f=f||{},g=f.dataType;if(g){if(g==b.TYPE_LOCAL)return new c.LocalDataSource(a,f);if(g==b.TYPE_XHR)return new c.XHRDataSource(a,f);if(g==b.TYPE_SCRIPTNODE)return new c.ScriptNodeDataSource(a,f);if(g==b.TYPE_JSFUNCTION)return new c.FunctionDataSource(a,f)}return YAHOO.lang.isString(a)?new c.XHRDataSource(a,f):YAHOO.lang.isFunction(a)?new c.FunctionDataSource(a,f):new c.LocalDataSource(a,f)};a.augmentObject(c.DataSource,b)})();
+YAHOO.util.Number={format:function(a,c){if(a===""||a===null||!isFinite(a))return"";var a=+a,c=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,c||{}),b=Math.abs(a),d=c.decimalPlaces||0,f=c.thousandsSeparator,g=c.negativeFormat||"-"+c.format,j;g.indexOf("#")>-1&&(g=g.replace(/#/,c.format));if(d<0){j=b-b%1+"";d=j.length+d;j=d>0?Number("."+j).toFixed(d).slice(2)+Array(j.length-d+1).join("0"):"0"}else if(d>0||(b+"").indexOf(".")>0){j=Math.pow(10,d);j=Math.round(b*j)/j+"";var h=j.indexOf(".");if(h<0){h=
+(Math.pow(10,d)+"").substring(1);d>0&&(j=j+"."+h)}else{d=d-(j.length-h-1);h=(Math.pow(10,d)+"").substring(1);j=j+h}}else j=b.toFixed(d)+"";j=j.split(/\D/);if(b>=1E3){d=j[0].length%3||3;j[0]=j[0].slice(0,d)+j[0].slice(d).replace(/(\d{3})/g,f+"$1")}return YAHOO.util.Number.format._applyFormat(a<0?g:c.format,j.join(c.decimalSeparator),c)}};YAHOO.util.Number.format.defaults={format:"{prefix}{number}{suffix}",negativeFormat:null,decimalSeparator:".",decimalPlaces:null,thousandsSeparator:""};
+YAHOO.util.Number.format._applyFormat=function(a,c,b){return a.replace(/\{(\w+)\}/g,function(a,f){return f==="number"?c:f in b?b[f]:""})};
+(function(){var a=function(a,c,f){for(typeof f==="undefined"&&(f=10);parseInt(a,10)<f&&f>1;f=f/10)a=c.toString()+a;return a.toString()},c={formats:{a:function(a,c){return c.a[a.getDay()]},A:function(a,c){return c.A[a.getDay()]},b:function(a,c){return c.b[a.getMonth()]},B:function(a,c){return c.B[a.getMonth()]},C:function(b){return a(parseInt(b.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(b){return a(parseInt(c.formats.G(b)%100,10),0)},G:function(a){var d=a.getFullYear(),
+f=parseInt(c.formats.V(a),10),a=parseInt(c.formats.W(a),10);a>f?d++:a===0&&f>=52&&d--;return d},H:["getHours","0"],I:function(b){b=b.getHours()%12;return a(b===0?12:b,0)},j:function(b){var c=new Date(""+b.getFullYear()+"/1/1 GMT"),b=new Date(""+b.getFullYear()+"/"+(b.getMonth()+1)+"/"+b.getDate()+" GMT")-c,b=parseInt(b/6E4/60/24,10)+1;return a(b,0,100)},k:["getHours"," "],l:function(b){b=b.getHours()%12;return a(b===0?12:b," ")},m:function(b){return a(b.getMonth()+1,0)},M:["getMinutes","0"],p:function(a,
+c){return c.p[a.getHours()>=12?1:0]},P:function(a,c){return c.P[a.getHours()>=12?1:0]},s:function(a){return parseInt(a.getTime()/1E3,10)},S:["getSeconds","0"],u:function(a){a=a.getDay();return a===0?7:a},U:function(b){var d=parseInt(c.formats.j(b),10),b=6-b.getDay(),d=parseInt((d+b)/7,10);return a(d,0)},V:function(b){var d=parseInt(c.formats.W(b),10),f=(new Date(""+b.getFullYear()+"/1/1")).getDay(),d=d+(f>4||f<=1?0:1);d===53&&(new Date(""+b.getFullYear()+"/12/31")).getDay()<4?d=1:d===0&&(d=c.formats.V(new Date(""+
+(b.getFullYear()-1)+"/12/31")));return a(d,0)},w:"getDay",W:function(b){var d=parseInt(c.formats.j(b),10),b=7-c.formats.u(b),d=parseInt((d+b)/7,10);return a(d,0,10)},y:function(b){return a(b.getFullYear()%100,0)},Y:"getFullYear",z:function(b){var b=b.getTimezoneOffset(),c=a(parseInt(Math.abs(b/60),10),0),f=a(Math.abs(b%60),0);return(b>0?"-":"+")+c+f},Z:function(a){var d=a.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");d.length>4&&(d=c.formats.z(a));
+return d},"%":function(){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(b,d,f){d=d||{};if(!(b instanceof Date))return YAHOO.lang.isValue(b)?b:"";d=d.format||"%m/%d/%Y";d==="YYYY/MM/DD"?d="%Y/%m/%d":d==="DD/MM/YYYY"?d="%d/%m/%Y":d==="MM/DD/YYYY"&&(d="%m/%d/%Y");f=f||"en";f in YAHOO.util.DateLocale||(f=f.replace(/-[a-zA-Z]+$/,"")in YAHOO.util.DateLocale?f.replace(/-[a-zA-Z]+$/,""):"en");for(var g=
+YAHOO.util.DateLocale[f],f=function(a,e){var b=c.aggregates[e];return b==="locale"?g[e]:b},j=function(d,e){var i=c.formats[e];return typeof i==="string"?b[i]():typeof i==="function"?i.call(b,b,g):typeof i==="object"&&typeof i[0]==="string"?a(b[i[0]](),i[1]):e};d.match(/%[cDFhnrRtTxX]/);)d=d.replace(/%([cDFhnrRtTxX])/g,f);d=d.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,j);f=j=void 0;return d}};YAHOO.namespace("YAHOO.util");YAHOO.util.Date=c;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.9.0",build:"2800"});YAHOO.util.Chain=function(){this.q=[].slice.call(arguments);this.createEvent("end")};
+YAHOO.util.Chain.prototype={id:0,run:function(){var a=this.q[0],c;if(a){if(this.id)return this}else{this.fireEvent("end");return this}c=a.method||a;if(typeof c==="function"){var b=a.scope||{},d=a.argument||[],f=a.timeout||0,g=this;d instanceof Array||(d=[d]);if(f<0){this.id=f;if(a.until)for(;!a.until();)c.apply(b,d);else if(a.iterations)for(;a.iterations-- >0;)c.apply(b,d);else c.apply(b,d);this.q.shift();this.id=0;return this.run()}if(a.until){if(a.until()){this.q.shift();return this.run()}}else(!a.iterations||
+!--a.iterations)&&this.q.shift();this.id=setTimeout(function(){c.apply(b,d);if(g.id){g.id=0;g.run()}},f)}return this},add:function(a){this.q.push(a);return this},pause:function(){this.id>0&&clearTimeout(this.id);this.id=0;return this},stop:function(){this.pause();this.q=[];return this}};YAHOO.lang.augmentProto(YAHOO.util.Chain,YAHOO.util.EventProvider);
+(function(){var a=YAHOO.util.Event,c=YAHOO.lang,b=[],d=function(a,b,c){return!a||a===c?false:YAHOO.util.Selector.test(a,b)?a:d(a.parentNode,b,c)};c.augmentObject(a,{_createDelegate:function(b,g,j,h){return function(e){var i=a.getTarget(e),k=g,l=this.nodeType===9,q;if(c.isFunction(g))q=g(i);else if(c.isString(g)){if(!l){(k=this.id)||(k=a.generateId(this));k="#"+k+" ";k=(k+g).replace(/,/gi,","+k)}YAHOO.util.Selector.test(i,k)?q=i:YAHOO.util.Selector.test(i,k.replace(/,/gi," *,")+" *")&&(q=d(i,k,this))}if(q){i=
+q;h&&(i=h===true?j:h);return b.call(i,e,q,this,j)}}},delegate:function(d,g,j,h,e,i){var k=g,l;if(c.isString(h)&&!YAHOO.util.Selector)return false;if(g=="mouseenter"||g=="mouseleave"){if(!a._createMouseDelegate)return false;k=a._getType(g);l=a._createMouseDelegate(j,e,i);g=a._createDelegate(function(a,e,b){return l.call(e,a,b)},h,e,i)}else g=a._createDelegate(j,h,e,i);b.push([d,k,j,g]);return a.on(d,k,g)},removeDelegate:function(c,d,j){var h=d,e=false,i;if(d=="mouseenter"||d=="mouseleave")h=a._getType(d);
+d=a._getCacheIndex(b,c,h,j);d>=0&&(i=b[d]);if(c&&i)if(e=a.removeListener(i[0],i[1],i[3])){delete b[d][2];delete b[d][3];b.splice(d,1)}return e}})})();
+(function(){var a=YAHOO.util.Event,c=YAHOO.lang,b=a.addListener,d=a.removeListener,f=a.getListeners,g=[],j={mouseenter:"mouseover",mouseleave:"mouseout"},h=function(e,b,c){var c=a._getCacheIndex(g,e,b,c),f,h;c>=0&&(f=g[c]);if(e&&f)if(h=d.call(a,f[0],b,f[3])){delete g[c][2];delete g[c][3];g.splice(c,1)}return h};c.augmentObject(a._specialTypes,j);c.augmentObject(a,{_createMouseDelegate:function(e,b,c){return function(d,f){var g=a.getRelatedTarget(d),h;if(this!=g&&!YAHOO.util.Dom.isAncestor(this,g)){g=
+this;c&&(g=c===true?b:c);h=[d,b];f&&h.splice(1,0,this,f);return e.apply(g,h)}}},addListener:function(e,c,d,f,h){var p;if(j[c]){p=a._createMouseDelegate(d,f,h);p.mouseDelegate=true;g.push([e,c,d,p]);p=b.call(a,e,c,p)}else p=b.apply(a,arguments);return p},removeListener:function(e,b,c){return j[b]?h.apply(a,arguments):d.apply(a,arguments)},getListeners:function(e,b){var c=[],d,g=b==="mouseover"||b==="mouseout",h,n,o;if(b&&(g||j[b])){if(d=f.call(a,e,this._getType(b)))for(n=d.length-1;n>-1;n--){o=d[n];
+h=o.fn.mouseDelegate;(j[b]&&h||g&&!h)&&c.push(o)}}else c=f.apply(a,arguments);return c&&c.length?c:null}},true);a.on=a.addListener})();YAHOO.register("event-mouseenter",YAHOO.util.Event,{version:"2.9.0",build:"2800"});Y=YAHOO;Y_DOM=YAHOO.util.Dom;EMPTY_ARRAY=[];Y_UA=Y.env.ua;Y_Lang=Y.lang;Y_DOC=document;Y_DOCUMENT_ELEMENT=Y_DOC.documentElement;Y_DOM_inDoc=Y_DOM.inDocument;Y_mix=Y_Lang.augmentObject;Y_guid=Y_DOM.generateId;
+Y_getDoc=function(a){var c=Y_DOC;a&&(c=a.nodeType===9?a:a.ownerDocument||a.document||Y_DOC);return c};Y_Array=function(a,c){var b,d,f=c||0;try{return Array.prototype.slice.call(a,f)}catch(g){d=[];for(b=a.length;f<b;f++)d.push(a[f]);return d}};
+Y_DOM_allById=function(a,c){var c=c||Y_DOC,b=[],d=[],f,g;if(c.querySelectorAll)d=c.querySelectorAll('[id="'+a+'"]');else if(c.all){if(b=c.all(a)){if(b.nodeName)if(b.id===a){d.push(b);b=EMPTY_ARRAY}else b=[b];if(b.length)for(f=0;g=b[f++];)(g.id===a||g.attributes&&g.attributes.id&&g.attributes.id.value===a)&&d.push(g)}}else d=[Y_getDoc(c).getElementById(a)];return d};COMPARE_DOCUMENT_POSITION="compareDocumentPosition";OWNER_DOCUMENT="ownerDocument";
+Selector={_foundCache:[],useNative:!0,_compare:"sourceIndex"in Y_DOCUMENT_ELEMENT?function(a,c){var b=a.sourceIndex,d=c.sourceIndex;return b===d?0:b>d?1:-1}:Y_DOCUMENT_ELEMENT[COMPARE_DOCUMENT_POSITION]?function(a,c){return a[COMPARE_DOCUMENT_POSITION](c)&4?-1:1}:function(a,c){var b,d;if(a&&c){b=a[OWNER_DOCUMENT].createRange();b.setStart(a,0);d=c[OWNER_DOCUMENT].createRange();d.setStart(c,0);b=b.compareBoundaryPoints(1,d)}return b},_sort:function(a){if(a){a=Y_Array(a,0,true);a.sort&&a.sort(Selector._compare)}return a},
+_deDupe:function(a){var c=[],b,d;for(b=0;d=a[b++];)if(!d._found){c[c.length]=d;d._found=true}for(b=0;d=c[b++];){d._found=null;d.removeAttribute("_found")}return c},query:function(a,c,b,d){if(typeof c=="string"){c=Y_DOM.get(c);if(!c)return b?null:[]}else c=c||Y_DOC;var f=[],g=Selector.useNative&&Y_DOC.querySelector&&!d,j=[[a,c]],h=g?Selector._nativeQuery:Selector._bruteQuery;if(a&&h){if(!d&&(!g||c.tagName))j=Selector._splitQueries(a,c);for(c=0;d=j[c++];){d=h(d[0],d[1],b);b||(d=Y_Array(d,0,true));d&&
+(f=f.concat(d))}j.length>1&&(f=Selector._sort(Selector._deDupe(f)))}Y.log("query: "+a+" returning: "+f.length,"info","Selector");return b?f[0]||null:f},_splitQueries:function(a,c){var b=a.split(","),d=[],f="",g,j;if(c){if(c.tagName){c.id=c.id||Y_guid();f='[id="'+c.id+'"] '}g=0;for(j=b.length;g<j;++g){a=f+b[g];d.push([a,c])}}return d},_nativeQuery:function(a,c,b){if(Y_UA.webkit&&a.indexOf(":checked")>-1&&Selector.pseudos&&Selector.pseudos.checked)return Selector.query(a,c,b,true);try{return c["querySelector"+
+(b?"":"All")](a)}catch(d){return Selector.query(a,c,b,true)}},filter:function(a,c){var b=[],d,f;if(a&&c)for(d=0;f=a[d++];)Selector.test(f,c)&&(b[b.length]=f);else Y.log("invalid filter input (nodes: "+a+", selector: "+c+")","warn","Selector");return b},test:function(a,c,b){var d=false,c=c.split(","),f=false,g,j,h,e,i;if(a&&a.tagName){if(!b&&!Y_DOM_inDoc(a)){b=a.parentNode;if(!b){h=a[OWNER_DOCUMENT].createDocumentFragment();h.appendChild(a);b=h;f=true}}b=b||a[OWNER_DOCUMENT];if(!a.id)a.id=Y_guid();
+for(e=0;g=c[e++];){g=g+('[id="'+a.id+'"]');j=Selector.query(g,b);for(i=0;g=j[i++];)if(g===a){d=true;break}if(d)break}f&&h.removeChild(a)}return d}};YAHOO.util.Selector=Selector;PARENT_NODE="parentNode";TAG_NAME="tagName";ATTRIBUTES="attributes";COMBINATOR="combinator";PSEUDOS="pseudos";
+SelectorCSS2={_reRegExpTokens:/([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,SORT_RESULTS:!0,_children:function(a,c){var b=a.children,d,f,g;if(a.children&&c&&a.children.tags)a.children.tags(c);else if(!b&&a[TAG_NAME]||b&&c){f=b||a.childNodes;b=[];for(d=0;g=f[d++];)g.tagName&&(!c||c===g.tagName)&&b.push(g)}return b||[]},_re:{attr:/(\[[^\]]*\])/g,esc:/\\[:\[\]\(\)#\.\'\>+~"]/gi,pseudos:/(\([^\)]*\))/g},shorthand:{"\\#(-?[_a-z]+[-\\w\\uE000]*)":"[id=$1]","\\.(-?[_a-z]+[-\\w\\uE000]*)":"[className~=$1]"},operators:{"":function(a,
+c){return!!a.getAttribute(c)},"~=":"(?:^|\\s+){val}(?:\\s+|$)","|=":"^{val}(?:-|$)"},pseudos:{"first-child":function(a){return Selector._children(a[PARENT_NODE])[0]===a}},_bruteQuery:function(a,c,b){var d=[],f=[],a=Selector._tokenize(a),g=a[a.length-1];Y_getDoc(c);var j,h;if(g){j=g.id;h=g.className;g=g.tagName||"*";if(c.getElementsByTagName)f=j&&(c.all||c.nodeType===9||Y_DOM_inDoc(c))?Y_DOM_allById(j,c):h?c.getElementsByClassName(h):c.getElementsByTagName(g);else for(c=c.firstChild;c;){c.tagName&&
+f.push(c);c=c.nextSilbing||c.firstChild}f.length&&(d=Selector._filterNodes(f,a,b))}return d},_filterNodes:function(a,c,b){for(var d=0,f,g=c.length,j=g-1,h=[],e=a[0],i=e,k=Selector.getters,l,q,p,n,o,m,d=0;i=e=a[d++];){j=g-1;p=null;a:for(;i&&i.tagName;){q=c[j];o=q.tests;if(f=o.length)for(;m=o[--f];){l=m[1];if(k[m[0]])n=k[m[0]](i,m[0]);else{n=i[m[0]];n===void 0&&i.getAttribute&&(n=i.getAttribute(m[0]))}if(l==="="&&n!==m[2]||typeof l!=="string"&&l.test&&!l.test(n)||!l.test&&typeof l==="function"&&!l(i,
+m[0],m[2])){if(i=i[p])for(;i&&(!i.tagName||q.tagName&&q.tagName!==i.tagName);)i=i[p];continue a}}j--;if(f=q.combinator){p=f.axis;for(i=i[p];i&&!i.tagName;)i=i[p];f.direct&&(p=null)}else{h.push(e);if(b)return h;break}}}return h},combinators:{" ":{axis:"parentNode"},">":{axis:"parentNode",direct:!0},"+":{axis:"previousSibling",direct:!0}},_parsers:[{name:ATTRIBUTES,re:/^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,fn:function(a,c){var b=a[2]||"",d=Selector.operators,f=
+a[3]?a[3].replace(/\\/g,""):"";if(a[1]==="id"&&b==="="||a[1]==="className"&&Y_DOCUMENT_ELEMENT.getElementsByClassName&&(b==="~="||b==="=")){c.prefilter=a[1];a[3]=f;c[a[1]]=a[1]==="id"?a[3]:f}if(b in d){b=d[b];if(typeof b==="string"){a[3]=f.replace(Selector._reRegExpTokens,"\\$1");b=RegExp(b.replace("{val}",a[3]))}a[2]=b}if(!c.last||c.prefilter!==a[1])return a.slice(1)}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(a,c){var b=a[1].toUpperCase();c.tagName=b;if(b!=="*"&&(!c.last||c.prefilter))return[TAG_NAME,
+"=",b];if(!c.prefilter)c.prefilter="tagName"}},{name:COMBINATOR,re:/^\s*([>+~]|\s)\s*/,fn:function(){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,fn:function(a){var c=Selector[PSEUDOS][a[1]];if(c){a[2]&&(a[2]=a[2].replace(/\\/g,""));return[a[2],c]}return false}}],_getToken:function(){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]}},_tokenize:function(a){var a=Selector._replaceShorthand(Y_Lang.trim(a||"")),c=Selector._getToken(),b=a,d=
+[],f=false,g,j,h;a:do{f=false;for(j=0;h=Selector._parsers[j++];)if(g=h.re.exec(a)){if(h.name!==COMBINATOR)c.selector=a;a=a.replace(g[0],"");if(!a.length)c.last=true;Selector._attrFilters[g[1]]&&(g[1]=Selector._attrFilters[g[1]]);f=h.fn(g,c);if(f===false){f=false;break a}else f&&c.tests.push(f);if(!a.length||h.name===COMBINATOR){d.push(c);c=Selector._getToken(c);if(h.name===COMBINATOR)c.combinator=Selector.combinators[g[1]]}f=true}}while(f&&a.length);if(!f||a.length){Y.log("query: "+b+" contains unsupported token in: "+
+a,"warn","Selector");d=[]}return d},_replaceShorthand:function(a){var c=Selector.shorthand,b=a.match(Selector._re.esc),d,f,g;b&&(a=a.replace(Selector._re.esc,"\ue000"));d=a.match(Selector._re.attr);f=a.match(Selector._re.pseudos);d&&(a=a.replace(Selector._re.attr,"\ue001"));f&&(a=a.replace(Selector._re.pseudos,"\ue002"));for(g in c)c.hasOwnProperty(g)&&(a=a.replace(RegExp(g,"gi"),c[g]));if(d){c=0;for(g=d.length;c<g;++c)a=a.replace(/\uE001/,d[c])}if(f){c=0;for(g=f.length;c<g;++c)a=a.replace(/\uE002/,
+f[c])}a=a.replace(/\[/g,"\ue003");a=a.replace(/\]/g,"\ue004");a=a.replace(/\(/g,"\ue005");a=a.replace(/\)/g,"\ue006");if(b){c=0;for(g=b.length;c<g;++c)a=a.replace("\ue000",b[c])}return a},_attrFilters:{"class":"className","for":"htmlFor"},getters:{href:function(a,c){return Y_DOM.getAttribute(a,c)}}};Y_mix(Selector,SelectorCSS2,!0);Selector.getters.src=Selector.getters.rel=Selector.getters.href;Selector.useNative&&Y_DOC.querySelector&&(Selector.shorthand["\\.([^\\s\\\\(\\[:]*)"]="[class~=$1]");
+Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
+Selector._getNth=function(a,c,b,d){Selector._reNth.test(c);var c=parseInt(RegExp.$1,10),f=RegExp.$2,g=RegExp.$3,j=parseInt(RegExp.$4,10)||0,b=Selector._children(a.parentNode,b);if(g){c=2;j=g==="odd"?1:0}else isNaN(c)&&(c=f?1:0);if(c===0){d&&(j=b.length-j+1);return b[j-1]===a?true:false}if(c<0){d=!!d;c=Math.abs(c)}if(d){d=b.length-j;for(f=b.length;d>=0;d=d-c)if(d<f&&b[d]===a)return true}else{d=j-1;for(f=b.length;d<f;d=d+c)if(d>=0&&b[d]===a)return true}return false};
+Y_mix(Selector.pseudos,{root:function(a){return a===a.ownerDocument.documentElement},"nth-child":function(a,c){return Selector._getNth(a,c)},"nth-last-child":function(a,c){return Selector._getNth(a,c,null,true)},"nth-of-type":function(a,c){return Selector._getNth(a,c,a.tagName)},"nth-last-of-type":function(a,c){return Selector._getNth(a,c,a.tagName,true)},"last-child":function(a){var c=Selector._children(a.parentNode);return c[c.length-1]===a},"first-of-type":function(a){return Selector._children(a.parentNode,
+a.tagName)[0]===a},"last-of-type":function(a){var c=Selector._children(a.parentNode,a.tagName);return c[c.length-1]===a},"only-child":function(a){var c=Selector._children(a.parentNode);return c.length===1&&c[0]===a},"only-of-type":function(a){var c=Selector._children(a.parentNode,a.tagName);return c.length===1&&c[0]===a},empty:function(a){return a.childNodes.length===0},not:function(a,c){return!Selector.test(a,c)},contains:function(a,c){return(a.innerText||a.textContent||"").indexOf(c)>-1},checked:function(a){return a.checked===
+true||a.selected===true},enabled:function(a){return a.disabled!==void 0&&!a.disabled},disabled:function(a){return a.disabled}});Y_mix(Selector.operators,{"^=":"^{val}","!=":function(a,c,b){return a[c]!==b},"$=":"{val}$","*=":"{val}"});Selector.combinators["~"]={axis:"previousSibling"};YAHOO.register("selector",YAHOO.util.Selector,{version:"2.9.0",build:"2800"});var Dom=YAHOO.util.Dom;
+YAHOO.widget.ColumnSet=function(a){this._sId=Dom.generateId(null,"yui-cs");a=YAHOO.widget.DataTable._cloneObject(a);this._init(a);YAHOO.widget.ColumnSet._nCount++};YAHOO.widget.ColumnSet._nCount=0;
+YAHOO.widget.ColumnSet.prototype={_sId:null,_aDefinitions:null,tree:null,flat:null,keys:null,headers:null,_init:function(a){var c=[],b=[],d=[],f=[],g=-1,j=function(a,i){g++;c[g]||(c[g]=[]);for(var k=0;k<a.length;k++){var f=a[k],h=new YAHOO.widget.Column(f);f.yuiColumnId=h._sId;b.push(h);if(i)h._oParent=i;if(YAHOO.lang.isArray(f.children)){h.children=f.children;var p=0,n=function(a){for(var a=a.children,e=0;e<a.length;e++)YAHOO.lang.isArray(a[e].children)?n(a[e]):p++};n(f);h._nColspan=p;for(var f=
+f.children,o=0;o<f.length;o++){var m=f[o];if(h.className&&m.className===void 0)m.className=h.className;if(h.editor&&m.editor===void 0)m.editor=h.editor;if(h.editorOptions&&m.editorOptions===void 0)m.editorOptions=h.editorOptions;if(h.formatter&&m.formatter===void 0)m.formatter=h.formatter;if(h.resizeable&&m.resizeable===void 0)m.resizeable=h.resizeable;if(h.sortable&&m.sortable===void 0)m.sortable=h.sortable;if(h.hidden)m.hidden=true;if(h.width&&m.width===void 0)m.width=h.width;if(h.minWidth&&m.minWidth===
+void 0)m.minWidth=h.minWidth;if(h.maxAutoWidth&&m.maxAutoWidth===void 0)m.maxAutoWidth=h.maxAutoWidth;if(h.type&&m.type===void 0)m.type=h.type;if(h.type&&!h.formatter)h.formatter=h.type;if(h.text&&!YAHOO.lang.isValue(h.label))h.label=h.text}c[g+1]||(c[g+1]=[]);j(f,h)}else{h._nKeyIndex=d.length;h._nColspan=1;d.push(h)}c[g].push(h)}g--};if(YAHOO.lang.isArray(a)){j(a);this._aDefinitions=a}else return null;(function(a){for(var b=1,c,d,f=function(a,e){for(var e=e||1,c=0;c<a.length;c++){var d=a[c];if(YAHOO.lang.isArray(d.children)){e++;
+f(d.children,e);e--}else e>b&&(b=e)}},g=0;g<a.length;g++){c=a[g];f(c);for(var h=0;h<c.length;h++){d=c[h];d._nRowspan=YAHOO.lang.isArray(d.children)?1:b}b=1}})(c);for(a=0;a<c[0].length;a++)c[0][a]._nTreeIndex=a;for(var h=function(a,b){f[a].push(b.getSanitizedKey());b._oParent&&h(a,b._oParent)},a=0;a<d.length;a++){f[a]=[];h(a,d[a]);f[a]=f[a].reverse()}this.tree=c;this.flat=b;this.keys=d;this.headers=f},getId:function(){return this._sId},toString:function(){return"ColumnSet instance "+this._sId},getDefinitions:function(){var a=
+this._aDefinitions,c=function(a,d){for(var f=0;f<a.length;f++){var g=a[f],j=d.getColumnById(g.yuiColumnId);if(j){var j=j.getDefinition(),h;for(h in j)YAHOO.lang.hasOwnProperty(j,h)&&(g[h]=j[h])}YAHOO.lang.isArray(g.children)&&c(g.children,d)}};c(a,this);return this._aDefinitions=a},getColumnById:function(a){if(YAHOO.lang.isString(a))for(var c=this.flat,b=c.length-1;b>-1;b--)if(c[b]._sId===a)return c[b];return null},getColumn:function(a){if(YAHOO.lang.isNumber(a)&&this.keys[a])return this.keys[a];
+if(YAHOO.lang.isString(a)){for(var c=this.flat,b=[],d=0;d<c.length;d++)c[d].key===a&&b.push(c[d]);if(b.length===1)return b[0];if(b.length>1)return b}return null},getDescendants:function(a){var c=this,b=[],d,f=function(a){b.push(a);if(a.children)for(d=0;d<a.children.length;d++)f(c.getColumn(a.children[d].key))};f(a);return b}};
+YAHOO.widget.Column=function(a){this._sId=Dom.generateId(null,"yui-col");if(a&&YAHOO.lang.isObject(a))for(var c in a)c&&(this[c]=a[c]);if(!YAHOO.lang.isValue(this.key))this.key=Dom.generateId(null,"yui-dt-col");if(!YAHOO.lang.isValue(this.field))this.field=this.key;YAHOO.widget.Column._nCount++;if(this.width&&!YAHOO.lang.isNumber(this.width))this.width=null;if(this.editor&&YAHOO.lang.isString(this.editor))this.editor=new YAHOO.widget.CellEditor(this.editor,this.editorOptions)};
+YAHOO.lang.augmentObject(YAHOO.widget.Column,{_nCount:0,formatCheckbox:function(a,c,b,d){YAHOO.widget.DataTable.formatCheckbox(a,c,b,d)},formatCurrency:function(a,c,b,d){YAHOO.widget.DataTable.formatCurrency(a,c,b,d)},formatDate:function(a,c,b,d){YAHOO.widget.DataTable.formatDate(a,c,b,d)},formatEmail:function(a,c,b,d){YAHOO.widget.DataTable.formatEmail(a,c,b,d)},formatLink:function(a,c,b,d){YAHOO.widget.DataTable.formatLink(a,c,b,d)},formatNumber:function(a,c,b,d){YAHOO.widget.DataTable.formatNumber(a,
+c,b,d)},formatSelect:function(a,c,b,d){YAHOO.widget.DataTable.formatDropdown(a,c,b,d)}});
+YAHOO.widget.Column.prototype={_sId:null,_nKeyIndex:null,_nTreeIndex:null,_nColspan:1,_nRowspan:1,_oParent:null,_elTh:null,_elThLiner:null,_elThLabel:null,_elResizer:null,_nWidth:null,_dd:null,_ddResizer:null,key:null,field:null,label:null,abbr:null,children:null,width:null,minWidth:null,maxAutoWidth:null,hidden:!1,selected:!1,className:null,formatter:null,currencyOptions:null,dateOptions:null,dropdownOptions:null,editor:null,resizeable:!1,sortable:!1,sortOptions:null,getId:function(){return this._sId},
+toString:function(){return"Column instance "+this._sId},getDefinition:function(){var a={};a.abbr=this.abbr;a.className=this.className;a.editor=this.editor;a.editorOptions=this.editorOptions;a.field=this.field;a.formatter=this.formatter;a.hidden=this.hidden;a.key=this.key;a.label=this.label;a.minWidth=this.minWidth;a.maxAutoWidth=this.maxAutoWidth;a.resizeable=this.resizeable;a.selected=this.selected;a.sortable=this.sortable;a.sortOptions=this.sortOptions;a.width=this.width;a._calculatedWidth=this._calculatedWidth;
+return a},getKey:function(){return this.key},getField:function(){return this.field},getSanitizedKey:function(){return this.getKey().replace(/[^\w\-]/g,"")},getKeyIndex:function(){return this._nKeyIndex},getTreeIndex:function(){return this._nTreeIndex},getParent:function(){return this._oParent},getColspan:function(){return this._nColspan},getColSpan:function(){return this.getColspan()},getRowspan:function(){return this._nRowspan},getThEl:function(){return this._elTh},getThLinerEl:function(){return this._elThLiner},
+getResizerEl:function(){return this._elResizer},getColEl:function(){return this.getThEl()},getIndex:function(){return this.getKeyIndex()},format:function(){}};YAHOO.util.Sort={compare:function(a,c,b){if(a===null||typeof a=="undefined")return c===null||typeof c=="undefined"?0:1;if(c===null||typeof c=="undefined")return-1;a.constructor==String&&(a=a.toLowerCase());c.constructor==String&&(c=c.toLowerCase());return a<c?b?1:-1:a>c?b?-1:1:0}};
+YAHOO.widget.ColumnDD=function(a,c,b,d){if(a&&c&&b&&d){this.datatable=a;this.table=a.getTableEl();this.column=c;this.headCell=b;this.pointer=d;this.newIndex=null;this.init(b);this.initFrame();this.invalidHandleTypes={};this.setPadding(10,0,this.datatable.getTheadEl().offsetHeight+10,0);YAHOO.util.Event.on(window,"resize",function(){this.initConstraints()},this,true)}};
+YAHOO.util.DDProxy&&YAHOO.extend(YAHOO.widget.ColumnDD,YAHOO.util.DDProxy,{initConstraints:function(){var a=YAHOO.util.Dom.getRegion(this.table),c=this.getEl(),b=YAHOO.util.Dom.getXY(c),d=parseInt(YAHOO.util.Dom.getStyle(c,"width"),10);parseInt(YAHOO.util.Dom.getStyle(c,"height"),10);this.setXConstraint(b[0]-a.left+15,a.right-b[0]-d+15);this.setYConstraint(10,10)},_resizeProxy:function(){YAHOO.widget.ColumnDD.superclass._resizeProxy.apply(this,arguments);var a=this.getDragEl(),c=this.getEl();YAHOO.util.Dom.setStyle(this.pointer,
+"height",this.table.parentNode.offsetHeight+10+"px");YAHOO.util.Dom.setStyle(this.pointer,"display","block");c=YAHOO.util.Dom.getXY(c);YAHOO.util.Dom.setXY(this.pointer,[c[0],c[1]-5]);YAHOO.util.Dom.setStyle(a,"height",this.datatable.getContainerEl().offsetHeight+"px");YAHOO.util.Dom.setStyle(a,"width",parseInt(YAHOO.util.Dom.getStyle(a,"width"),10)+4+"px");YAHOO.util.Dom.setXY(this.dragEl,c)},onMouseDown:function(){this.initConstraints();this.resetConstraints()},clickValidator:function(a){if(!this.column.hidden){a=
+YAHOO.util.Event.getTarget(a);return this.isValidHandleChild(a)&&(this.id==this.handleElId||this.DDM.handleWasClicked(a,this.id))}},onDragOver:function(a,c){var b=this.datatable.getColumn(c);if(b){for(var d=b.getTreeIndex();d===null&&b.getParent();){b=b.getParent();d=b.getTreeIndex()}if(d!==null){var f=b.getThEl(),b=d,g=YAHOO.util.Event.getPageX(a),j=YAHOO.util.Dom.getX(f),h=j+YAHOO.util.Dom.get(f).offsetWidth/2,e=this.column.getTreeIndex();if(g<h)YAHOO.util.Dom.setX(this.pointer,j);else{f=parseInt(f.offsetWidth,
+10);YAHOO.util.Dom.setX(this.pointer,j+f);b++}d>e&&b--;if(b<0)b=0;else if(b>this.datatable.getColumnSet().tree[0].length)b=this.datatable.getColumnSet().tree[0].length;this.newIndex=b}}},onDragDrop:function(){this.datatable.reorderColumn(this.column,this.newIndex)},endDrag:function(){this.newIndex=null;YAHOO.util.Dom.setStyle(this.pointer,"display","none")}});
+YAHOO.util.ColumnResizer=function(a,c,b,d,f){if(a&&c&&b&&d){this.datatable=a;this.column=c;this.headCell=b;this.headCellLiner=c.getThLinerEl();this.resizerLiner=b.firstChild;this.init(d,d,{dragOnly:true,dragElId:f.id});this.initFrame();this.resetResizerEl();this.setPadding(0,1,0,0)}};
+YAHOO.util.DD&&YAHOO.extend(YAHOO.util.ColumnResizer,YAHOO.util.DDProxy,{resetResizerEl:function(){var a=YAHOO.util.Dom.get(this.handleElId).style;a.left="auto";a.right=0;a.top="auto";a.bottom=0;a.height=this.headCell.offsetHeight+"px"},onMouseUp:function(){for(var a=this.datatable.getColumnSet().keys,c,b=0,d=a.length;b<d;b++){c=a[b];c._ddResizer&&c._ddResizer.resetResizerEl()}this.resetResizerEl();a=this.headCellLiner;this.datatable.fireEvent("columnResizeEvent",{column:this.column,target:this.headCell,
+width:a.offsetWidth-(parseInt(YAHOO.util.Dom.getStyle(a,"paddingLeft"),10)|0)-(parseInt(YAHOO.util.Dom.getStyle(a,"paddingRight"),10)|0)})},onMouseDown:function(a){this.startWidth=this.headCellLiner.offsetWidth;this.startX=YAHOO.util.Event.getXY(a)[0];this.nLinerPadding=(parseInt(YAHOO.util.Dom.getStyle(this.headCellLiner,"paddingLeft"),10)|0)+(parseInt(YAHOO.util.Dom.getStyle(this.headCellLiner,"paddingRight"),10)|0)},clickValidator:function(a){if(!this.column.hidden){a=YAHOO.util.Event.getTarget(a);
+return this.isValidHandleChild(a)&&(this.id==this.handleElId||this.DDM.handleWasClicked(a,this.id))}},startDrag:function(){var a=this.datatable.getColumnSet().keys;this.column.getKeyIndex();for(var c,b=0,d=a.length;b<d;b++){c=a[b];if(c._ddResizer)YAHOO.util.Dom.get(c._ddResizer.handleElId).style.height="1em"}},onDrag:function(a){a=YAHOO.util.Event.getXY(a)[0];if(a>YAHOO.util.Dom.getX(this.headCellLiner)){a=this.startWidth+(a-this.startX)-this.nLinerPadding;a>0&&this.datatable.setColumnWidth(this.column,
+a)}}});
+(function(){var a=YAHOO.lang,c=YAHOO.util,b=YAHOO.widget,d=c.Dom;YAHOO.widget.RecordSet=function(a){this._init(a)};var f=b.RecordSet;f._nCount=0;f.prototype={_sId:null,_init:function(c){this._sId=d.generateId(null,"yui-rs");b.RecordSet._nCount++;this._records=[];this._initEvents();c&&(a.isArray(c)?this.addRecords(c):a.isObject(c)&&this.addRecord(c))},_initEvents:function(){this.createEvent("recordAddEvent");this.createEvent("recordsAddEvent");this.createEvent("recordSetEvent");this.createEvent("recordsSetEvent");this.createEvent("recordUpdateEvent");
+this.createEvent("recordDeleteEvent");this.createEvent("recordsDeleteEvent");this.createEvent("resetEvent");this.createEvent("recordValueUpdateEvent")},_addRecord:function(a,b){var c=new YAHOO.widget.Record(a);YAHOO.lang.isNumber(b)&&b>-1?this._records.splice(b,0,c):this._records[this._records.length]=c;return c},_setRecord:function(c,d){if(!a.isNumber(d)||d<0)d=this._records.length;return this._records[d]=new b.Record(c)},_deleteRecord:function(b,c){if(!a.isNumber(c)||c<0)c=1;this._records.splice(b,
+c)},getId:function(){return this._sId},toString:function(){return"RecordSet instance "+this._sId},getLength:function(){return this._records.length},getRecord:function(c){var d;if(c instanceof b.Record)for(d=0;d<this._records.length;d++){if(this._records[d]&&this._records[d]._sId===c._sId)return c}else if(a.isNumber(c)){if(c>-1&&c<this.getLength())return this._records[c]}else if(a.isString(c))for(d=0;d<this._records.length;d++)if(this._records[d]&&this._records[d]._sId===c)return this._records[d];
+return null},getRecords:function(b,c){return!a.isNumber(b)?this._records:!a.isNumber(c)?this._records.slice(b):this._records.slice(b,b+c)},hasRecords:function(a,b){for(var c=this.getRecords(a,b),e=0;e<b;++e)if(typeof c[e]==="undefined")return false;return true},getRecordIndex:function(a){if(a)for(var b=this._records.length-1;b>-1;b--)if(this._records[b]&&a.getId()===this._records[b].getId())return b;return null},addRecord:function(b,c){if(a.isObject(b)){var d=this._addRecord(b,c);this.fireEvent("recordAddEvent",
+{record:d,data:b});return d}return null},addRecords:function(b,c){if(a.isArray(b)){var d=[],e,i,k;e=c=a.isNumber(c)?c:this._records.length;i=0;for(k=b.length;i<k;++i)if(a.isObject(b[i])){var f=this._addRecord(b[i],e++);d.push(f)}this.fireEvent("recordsAddEvent",{records:d,data:b});return d}if(a.isObject(b)){d=this._addRecord(b);this.fireEvent("recordsAddEvent",{records:[d],data:b});return d}return null},setRecord:function(b,c){if(a.isObject(b)){var d=this._setRecord(b,c);this.fireEvent("recordSetEvent",
+{record:d,data:b});return d}return null},setRecords:function(c,d){for(var f=b.Record,e=a.isArray(c)?c:[c],i=[],k=0,l=e.length,q=0,d=parseInt(d,10)|0;k<l;++k)typeof e[k]==="object"&&e[k]&&(i[q++]=this._records[d+k]=new f(e[k]));this.fireEvent("recordsSetEvent",{records:i,data:c});this.fireEvent("recordsSet",{records:i,data:c});return i},updateRecord:function(b,c){var d=this.getRecord(b);if(d&&a.isObject(c)){var e={},i;for(i in d._oData)a.hasOwnProperty(d._oData,i)&&(e[i]=d._oData[i]);d._oData=c;this.fireEvent("recordUpdateEvent",
+{record:d,newData:c,oldData:e});return d}return null},updateKey:function(a,b,c){this.updateRecordValue(a,b,c)},updateRecordValue:function(b,c,d){if(b=this.getRecord(b)){var e=null,i=b._oData[c];if(i&&a.isObject(i)){var e={},k;for(k in i)a.hasOwnProperty(i,k)&&(e[k]=i[k])}else e=i;b._oData[c]=d;this.fireEvent("keyUpdateEvent",{record:b,key:c,newData:d,oldData:e});this.fireEvent("recordValueUpdateEvent",{record:b,key:c,newData:d,oldData:e})}},replaceRecords:function(a){this.reset();return this.addRecords(a)},
+sortRecords:function(a,b,c){return this._records.sort(function(e,i){return a(e,i,b,c)})},reverseRecords:function(){return this._records.reverse()},deleteRecord:function(b){if(a.isNumber(b)&&b>-1&&b<this.getLength()){var c=this.getRecord(b).getData();this._deleteRecord(b);this.fireEvent("recordDeleteEvent",{data:c,index:b});return c}return null},deleteRecords:function(b,c){a.isNumber(c)||(c=1);if(a.isNumber(b)&&b>-1&&b<this.getLength()){for(var d=this.getRecords(b,c),e=[],i=[],k=0;k<d.length;k++){e[e.length]=
+d[k];i[i.length]=d[k].getData()}this._deleteRecord(b,c);this.fireEvent("recordsDeleteEvent",{data:e,deletedData:i,index:b});return e}return null},reset:function(){this._records=[];this.fireEvent("resetEvent")}};a.augmentProto(f,c.EventProvider);YAHOO.widget.Record=function(c){this._nCount=b.Record._nCount;this._sId=d.generateId(null,"yui-rec");b.Record._nCount++;this._oData={};if(a.isObject(c))for(var f in c)a.hasOwnProperty(c,f)&&(this._oData[f]=c[f])};YAHOO.widget.Record._nCount=0;YAHOO.widget.Record.prototype=
+{_nCount:null,_sId:null,_oData:null,getCount:function(){return this._nCount},getId:function(){return this._sId},getData:function(b){return a.isString(b)?this._oData[b]:this._oData},setData:function(a,b){this._oData[a]=b}}})();
+(function(){var a=YAHOO.lang,c=YAHOO.util,b=YAHOO.widget,d=YAHOO.env.ua,f=c.Dom,g=c.Event,j=c.DataSourceBase;YAHOO.widget.DataTable=function(a,c,d,l){var h=b.DataTable;if(l&&l.scrollable)return new YAHOO.widget.ScrollingDataTable(a,c,d,l);this._nIndex=h._nCount;this._sId=f.generateId(null,"yui-dt");this._oChainRender=new YAHOO.util.Chain;this._oChainRender.subscribe("end",this._onRenderChainEnd,this,true);this._initConfigs(l);this._initDataSource(d);if(this._oDataSource){this._initColumnSet(c);if(this._oColumnSet){this._initRecordSet();
+h.superclass.constructor.call(this,a,this.configs);if(this._initDomElements(a)){this.showTableMessage(this.get("MSG_LOADING"),h.CLASS_LOADING);this._initEvents();h._nCount++;h._nCurrentCount++;a={success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,scope:this,argument:this.getState()};c=this.get("initialLoad");if(c===true)this._oDataSource.sendRequest(this.get("initialRequest"),a);else if(c===false)this.showTableMessage(this.get("MSG_EMPTY"),h.CLASS_EMPTY);else{h=c||{};a.argument=h.argument||
+{};this._oDataSource.sendRequest(h.request,a)}}}}};var h=b.DataTable;a.augmentObject(h,{CLASS_DATATABLE:"yui-dt",CLASS_LINER:"yui-dt-liner",CLASS_LABEL:"yui-dt-label",CLASS_MESSAGE:"yui-dt-message",CLASS_MASK:"yui-dt-mask",CLASS_DATA:"yui-dt-data",CLASS_COLTARGET:"yui-dt-coltarget",CLASS_RESIZER:"yui-dt-resizer",CLASS_RESIZERLINER:"yui-dt-resizerliner",CLASS_RESIZERPROXY:"yui-dt-resizerproxy",CLASS_EDITOR:"yui-dt-editor",CLASS_EDITOR_SHIM:"yui-dt-editor-shim",CLASS_PAGINATOR:"yui-dt-paginator",CLASS_PAGE:"yui-dt-page",
+CLASS_DEFAULT:"yui-dt-default",CLASS_PREVIOUS:"yui-dt-previous",CLASS_NEXT:"yui-dt-next",CLASS_FIRST:"yui-dt-first",CLASS_LAST:"yui-dt-last",CLASS_REC:"yui-dt-rec",CLASS_EVEN:"yui-dt-even",CLASS_ODD:"yui-dt-odd",CLASS_SELECTED:"yui-dt-selected",CLASS_HIGHLIGHTED:"yui-dt-highlighted",CLASS_HIDDEN:"yui-dt-hidden",CLASS_DISABLED:"yui-dt-disabled",CLASS_EMPTY:"yui-dt-empty",CLASS_LOADING:"yui-dt-loading",CLASS_ERROR:"yui-dt-error",CLASS_EDITABLE:"yui-dt-editable",CLASS_DRAGGABLE:"yui-dt-draggable",CLASS_RESIZEABLE:"yui-dt-resizeable",
+CLASS_SCROLLABLE:"yui-dt-scrollable",CLASS_SORTABLE:"yui-dt-sortable",CLASS_ASC:"yui-dt-asc",CLASS_DESC:"yui-dt-desc",CLASS_BUTTON:"yui-dt-button",CLASS_CHECKBOX:"yui-dt-checkbox",CLASS_DROPDOWN:"yui-dt-dropdown",CLASS_RADIO:"yui-dt-radio",_nCount:0,_nCurrentCount:0,_elDynStyleNode:null,_bDynStylesFallback:d.ie?true:false,_oDynStyles:{},_cloneObject:function(e){if(!a.isValue(e))return e;var b={};if(e instanceof YAHOO.widget.BaseCellEditor)b=e;else if(Object.prototype.toString.apply(e)==="[object RegExp]")b=
+e;else if(a.isFunction(e))b=e;else if(a.isArray(e))for(var b=[],c=0,d=e.length;c<d;c++)b[c]=h._cloneObject(e[c]);else if(a.isObject(e))for(c in e)a.hasOwnProperty(e,c)&&(b[c]=a.isValue(e[c])&&a.isObject(e[c])||a.isArray(e[c])?h._cloneObject(e[c]):e[c]);else b=e;return b},formatButton:function(e,b,c,d){b=a.isValue(d)?d:"Click";e.innerHTML='<button type="button" class="'+h.CLASS_BUTTON+'">'+b+"</button>"},formatCheckbox:function(a,b,c,d){a.innerHTML='<input type="checkbox"'+(d?' checked="checked"':
+"")+' class="'+h.CLASS_CHECKBOX+'" />'},formatCurrency:function(a,b,d,f,h){a.innerHTML=c.Number.format(f,d.currencyOptions||(h||this).get("currencyOptions"))},formatDate:function(a,b,d,f,h){b=d.dateOptions||(h||this).get("dateOptions");a.innerHTML=c.Date.format(f,b,b.locale)},formatDropdown:function(e,b,c,d,f){var j=f||this,b=a.isValue(d)?d:b.getData(c.field),c=a.isArray(c.dropdownOptions)?c.dropdownOptions:null,n=e.getElementsByTagName("select");if(n.length===0){f=document.createElement("select");
+f.className=h.CLASS_DROPDOWN;f=e.appendChild(f);g.addListener(f,"change",j._onDropdownChange,j)}if(f=n[0]){f.innerHTML="";if(c)for(e=0;e<c.length;e++){d=c[e];j=document.createElement("option");j.value=a.isValue(d.value)?d.value:d;j.innerHTML=a.isValue(d.text)?d.text:a.isValue(d.label)?d.label:d;j=f.appendChild(j);if(j.value==b)j.selected=true}else f.innerHTML='<option selected value="'+b+'">'+b+"</option>"}else e.innerHTML=a.isValue(d)?d:""},formatEmail:function(e,b,c,d){if(a.isString(d)){d=a.escapeHTML(d);
+e.innerHTML='<a href="mailto:'+d+'">'+d+"</a>"}else e.innerHTML=a.isValue(d)?a.escapeHTML(d.toString()):""},formatLink:function(e,b,c,d){if(a.isString(d)){d=a.escapeHTML(d);e.innerHTML='<a href="'+d+'">'+d+"</a>"}else e.innerHTML=a.isValue(d)?a.escapeHTML(d.toString()):""},formatNumber:function(a,b,d,f,h){a.innerHTML=c.Number.format(f,d.numberOptions||(h||this).get("numberOptions"))},formatRadio:function(a,b,c,d,f){a.innerHTML='<input type="radio"'+(d?' checked="checked"':"")+' name="'+(f||this).getId()+
+"-col-"+c.getSanitizedKey()+'" class="'+h.CLASS_RADIO+'" />'},formatText:function(e,b,c,d){b=a.isValue(d)?d:"";e.innerHTML=a.escapeHTML(b.toString())},formatTextarea:function(e,b,c,d){b="<textarea>"+(a.isValue(d)?a.escapeHTML(d.toString()):"")+"</textarea>";e.innerHTML=b},formatTextbox:function(e,b,c,d){b='<input type="text" value="'+(a.isValue(d)?a.escapeHTML(d.toString()):"")+'" />';e.innerHTML=b},formatDefault:function(e,b,c,d){e.innerHTML=a.isValue(d)&&d!==""?d.toString():"&#160;"},validateNumber:function(e){e=
+e*1;if(a.isNumber(e))return e}});h.Formatter={button:h.formatButton,checkbox:h.formatCheckbox,currency:h.formatCurrency,date:h.formatDate,dropdown:h.formatDropdown,email:h.formatEmail,link:h.formatLink,number:h.formatNumber,radio:h.formatRadio,text:h.formatText,textarea:h.formatTextarea,textbox:h.formatTextbox,defaultFormatter:h.formatDefault};a.extend(h,c.Element,{initAttributes:function(e){e=e||{};h.superclass.initAttributes.call(this,e);this.setAttributeConfig("summary",{value:"",validator:a.isString,
+method:function(a){if(this._elTable)this._elTable.summary=a}});this.setAttributeConfig("selectionMode",{value:"standard",validator:a.isString});this.setAttributeConfig("sortedBy",{value:null,validator:function(e){return e?a.isObject(e)&&e.key:e===null},method:function(a){var e=this.get("sortedBy");this._configs.sortedBy.value=a;var b,c,d;if(this._elThead){if(e&&e.key&&e.dir){b=this._oColumnSet.getColumn(e.key);c=b.getKeyIndex();var g=b.getThEl();f.removeClass(g,e.dir);this.formatTheadCell(b.getThLinerEl().firstChild,
+b,a)}if(a){b=a.column?a.column:this._oColumnSet.getColumn(a.key);d=b.getKeyIndex();g=b.getThEl();a.dir&&(a.dir=="asc"||a.dir=="desc")?f.addClass(g,a.dir=="desc"?h.CLASS_DESC:h.CLASS_ASC):f.addClass(g,a.dir||h.CLASS_ASC);this.formatTheadCell(b.getThLinerEl().firstChild,b,a)}}if(this._elTbody){this._elTbody.style.display="none";b=this._elTbody.rows;for(var j=b.length-1;j>-1;j--){g=b[j].childNodes;g[c]&&f.removeClass(g[c],e.dir);g[d]&&f.addClass(g[d],a.dir)}this._elTbody.style.display=""}this._clearTrTemplateEl()}});
+this.setAttributeConfig("paginator",{value:null,validator:function(a){return a===null||a instanceof b.Paginator},method:function(){this._updatePaginator.apply(this,arguments)}});this.setAttributeConfig("caption",{value:null,validator:a.isString,method:function(a){this._initCaptionEl(a)}});this.setAttributeConfig("draggableColumns",{value:false,validator:a.isBoolean,method:function(a){this._elThead&&(a?this._initDraggableColumns():this._destroyDraggableColumns())}});this.setAttributeConfig("renderLoopSize",
+{value:0,validator:a.isNumber});this.setAttributeConfig("sortFunction",{value:function(a,e,b,c){var d=YAHOO.util.Sort.compare,c=d(a.getData(c),e.getData(c),b);return c===0?d(a.getCount(),e.getCount(),b):c}});this.setAttributeConfig("formatRow",{value:null,validator:a.isFunction});this.setAttributeConfig("generateRequest",{value:function(a,e){var a=a||{pagination:null,sortedBy:null},b=encodeURIComponent(a.sortedBy?a.sortedBy.key:e.getColumnSet().keys[0].getKey()),c=a.pagination?a.pagination.rowsPerPage:
+null;return"sort="+b+"&dir="+(a.sortedBy&&a.sortedBy.dir===YAHOO.widget.DataTable.CLASS_DESC?"desc":"asc")+"&startIndex="+(a.pagination?a.pagination.recordOffset:0)+(c!==null?"&results="+c:"")},validator:a.isFunction});this.setAttributeConfig("initialRequest",{value:null});this.setAttributeConfig("initialLoad",{value:true});this.setAttributeConfig("dynamicData",{value:false,validator:a.isBoolean});this.setAttributeConfig("MSG_EMPTY",{value:"No records found.",validator:a.isString});this.setAttributeConfig("MSG_LOADING",
+{value:"Loading...",validator:a.isString});this.setAttributeConfig("MSG_ERROR",{value:"Data error.",validator:a.isString});this.setAttributeConfig("MSG_SORTASC",{value:"Click to sort ascending",validator:a.isString,method:function(a){if(this._elThead)for(var e=0,b=this.getColumnSet().keys,c=b.length;e<c;e++)if(b[e].sortable&&this.getColumnSortDir(b[e])===h.CLASS_ASC)b[e]._elThLabel.firstChild.title=a}});this.setAttributeConfig("MSG_SORTDESC",{value:"Click to sort descending",validator:a.isString,
+method:function(a){if(this._elThead)for(var e=0,b=this.getColumnSet().keys,c=b.length;e<c;e++)if(b[e].sortable&&this.getColumnSortDir(b[e])===h.CLASS_DESC)b[e]._elThLabel.firstChild.title=a}});this.setAttributeConfig("currencySymbol",{value:"$",validator:a.isString});this.setAttributeConfig("currencyOptions",{value:{prefix:this.get("currencySymbol"),decimalPlaces:2,decimalSeparator:".",thousandsSeparator:","}});this.setAttributeConfig("dateOptions",{value:{format:"%m/%d/%Y",locale:"en"}});this.setAttributeConfig("numberOptions",
+{value:{decimalPlaces:0,thousandsSeparator:","}})},_bInit:true,_nIndex:null,_nTrCount:0,_nTdCount:0,_sId:null,_oChainRender:null,_elContainer:null,_elMask:null,_elTable:null,_elCaption:null,_elColgroup:null,_elThead:null,_elTbody:null,_elMsgTbody:null,_elMsgTr:null,_elMsgTd:null,_elColumnDragTarget:null,_elColumnResizerProxy:null,_oDataSource:null,_oColumnSet:null,_oRecordSet:null,_oCellEditor:null,_sFirstTrId:null,_sLastTrId:null,_elTrTemplate:null,_aDynFunctions:[],_disabled:false,clearTextSelection:function(){var a;
+if(window.getSelection)a=window.getSelection();else if(document.getSelection)a=document.getSelection();else if(document.selection)a=document.selection;a&&(a.empty?a.empty():a.removeAllRanges?a.removeAllRanges():a.collapse&&a.collapse())},_focusEl:function(a){a=a||this._elTbody;setTimeout(function(){try{a.focus()}catch(b){}},0)},_repaintGecko:d.gecko?function(a){var a=a||this._elContainer,b=a.parentNode,c=a.nextSibling;b.insertBefore(b.removeChild(a),c)}:function(){},_repaintOpera:d.opera?function(){if(d.opera){document.documentElement.className=
+document.documentElement.className+" ";document.documentElement.className=YAHOO.lang.trim(document.documentElement.className)}}:function(){},_repaintWebkit:d.webkit?function(a){var a=a||this._elContainer,b=a.parentNode,c=a.nextSibling;b.insertBefore(b.removeChild(a),c)}:function(){},_initConfigs:function(e){if(!e||!a.isObject(e))e={};this.configs=e},_initColumnSet:function(e){var b,c,d;if(this._oColumnSet){c=0;for(d=this._oColumnSet.keys.length;c<d;c++){b=this._oColumnSet.keys[c];h._oDynStyles["."+
+this.getId()+"-col-"+b.getSanitizedKey()+" ."+h.CLASS_LINER]=void 0;b.editor&&b.editor.unsubscribeAll&&b.editor.unsubscribeAll()}this._oColumnSet=null;this._clearTrTemplateEl()}if(a.isArray(e))this._oColumnSet=new YAHOO.widget.ColumnSet(e);else if(e instanceof YAHOO.widget.ColumnSet)this._oColumnSet=e;e=this._oColumnSet.keys;c=0;for(d=e.length;c<d;c++){b=e[c];if(b.editor&&b.editor.subscribe){b.editor.subscribe("showEvent",this._onEditorShowEvent,this,true);b.editor.subscribe("keydownEvent",this._onEditorKeydownEvent,
+this,true);b.editor.subscribe("revertEvent",this._onEditorRevertEvent,this,true);b.editor.subscribe("saveEvent",this._onEditorSaveEvent,this,true);b.editor.subscribe("cancelEvent",this._onEditorCancelEvent,this,true);b.editor.subscribe("blurEvent",this._onEditorBlurEvent,this,true);b.editor.subscribe("blockEvent",this._onEditorBlockEvent,this,true);b.editor.subscribe("unblockEvent",this._onEditorUnblockEvent,this,true)}}},_initDataSource:function(e){this._oDataSource=null;if(e&&a.isFunction(e.sendRequest))this._oDataSource=
+e;else{var e=null,b=this._elContainer,c=0;if(b.hasChildNodes()){b=b.childNodes;for(c=0;c<b.length;c++)if(b[c].nodeName&&b[c].nodeName.toLowerCase()=="table"){e=b[c];break}if(e){for(b=[];c<this._oColumnSet.keys.length;c++)b.push({key:this._oColumnSet.keys[c].key});this._oDataSource=new j(e);this._oDataSource.responseType=j.TYPE_HTMLTABLE;this._oDataSource.responseSchema={fields:b}}}}},_initRecordSet:function(){this._oRecordSet?this._oRecordSet.reset():this._oRecordSet=new YAHOO.widget.RecordSet},_initDomElements:function(a){this._initContainerEl(a);
+this._initTableEl(this._elContainer);this._initColgroupEl(this._elTable);this._initTheadEl(this._elTable);this._initMsgTbodyEl(this._elTable);this._initTbodyEl(this._elTable);return!this._elContainer||!this._elTable||!this._elColgroup||!this._elThead||!this._elTbody||!this._elMsgTbody?false:true},_destroyContainerEl:function(a){var b=this._oColumnSet.keys,c;f.removeClass(a,h.CLASS_DATATABLE);g.purgeElement(a);g.purgeElement(this._elThead,true);g.purgeElement(this._elTbody);g.purgeElement(this._elMsgTbody);
+c=a.getElementsByTagName("select");c.length&&g.detachListener(c,"change");for(c=b.length-1;c>=0;--c)b[c].editor&&g.purgeElement(b[c].editor._elContainer);a.innerHTML="";this._elTbody=this._elThead=this._elColgroup=this._elContainer=null},_initContainerEl:function(a){if((a=f.get(a))&&a.nodeName&&a.nodeName.toLowerCase()=="div"){this._destroyContainerEl(a);f.addClass(a,h.CLASS_DATATABLE);g.addListener(a,"focus",this._onTableFocus,this);g.addListener(a,"dblclick",this._onTableDblclick,this);this._elContainer=
+a;var b=document.createElement("div");b.className=h.CLASS_MASK;b.style.display="none";this._elMask=a.appendChild(b)}},_destroyTableEl:function(){var a=this._elTable;if(a){g.purgeElement(a,true);a.parentNode.removeChild(a);this._elTbody=this._elThead=this._elColgroup=this._elCaption=null}},_initCaptionEl:function(a){if(this._elTable&&a){if(!this._elCaption)this._elCaption=this._elTable.createCaption();this._elCaption.innerHTML=a}else this._elCaption&&this._elCaption.parentNode.removeChild(this._elCaption)},
+_initTableEl:function(a){if(a){this._destroyTableEl();this._elTable=a.appendChild(document.createElement("table"));this._elTable.summary=this.get("summary");this.get("caption")&&this._initCaptionEl(this.get("caption"));g.delegate(this._elTable,"mouseenter",this._onTableMouseover,"thead ."+h.CLASS_LABEL,this);g.delegate(this._elTable,"mouseleave",this._onTableMouseout,"thead ."+h.CLASS_LABEL,this);g.delegate(this._elTable,"mouseenter",this._onTableMouseover,"tbody.yui-dt-data>tr>td",this);g.delegate(this._elTable,
+"mouseleave",this._onTableMouseout,"tbody.yui-dt-data>tr>td",this);g.delegate(this._elTable,"mouseenter",this._onTableMouseover,"tbody.yui-dt-message>tr>td",this);g.delegate(this._elTable,"mouseleave",this._onTableMouseout,"tbody.yui-dt-message>tr>td",this)}},_destroyColgroupEl:function(){var a=this._elColgroup;if(a){var b=a.parentNode;g.purgeElement(a,true);b.removeChild(a);this._elColgroup=null}},_initColgroupEl:function(a){if(a){this._destroyColgroupEl();for(var b=this._oColumnSet.keys,c=0,d=(this._aColIds||
+[]).length,f=document.createDocumentFragment(),h=document.createElement("col"),c=0,d=b.length;c<d;c++)f.appendChild(h.cloneNode(false));a=a.insertBefore(document.createElement("colgroup"),a.firstChild);a.appendChild(f);this._elColgroup=a}},_insertColgroupColEl:function(e){if(a.isNumber(e)&&this._elColgroup){e=this._elColgroup.childNodes[e]||null;this._elColgroup.insertBefore(document.createElement("col"),e)}},_removeColgroupColEl:function(e){a.isNumber(e)&&(this._elColgroup&&this._elColgroup.childNodes[e])&&
+this._elColgroup.removeChild(this._elColgroup.childNodes[e])},_reorderColgroupColEl:function(e,b){if(a.isArray(e)&&a.isNumber(b)&&this._elColgroup&&this._elColgroup.childNodes.length>e[e.length-1]){var c,d=[];for(c=e.length-1;c>-1;c--)d.push(this._elColgroup.removeChild(this._elColgroup.childNodes[e[c]]));var f=this._elColgroup.childNodes[b]||null;for(c=d.length-1;c>-1;c--)this._elColgroup.insertBefore(d[c],f)}},_destroyTheadEl:function(){var a=this._elThead;if(a){var b=a.parentNode;g.purgeElement(a,
+true);this._destroyColumnHelpers();b.removeChild(a);this._elThead=null}},_initTheadEl:function(a){if(a=a||this._elTable){this._destroyTheadEl();var b=this._elColgroup?a.insertBefore(document.createElement("thead"),this._elColgroup.nextSibling):a.appendChild(document.createElement("thead"));g.addListener(b,"focus",this._onTheadFocus,this);g.addListener(b,"keydown",this._onTheadKeydown,this);g.addListener(b,"mousedown",this._onTableMousedown,this);g.addListener(b,"mouseup",this._onTableMouseup,this);
+g.addListener(b,"click",this._onTheadClick,this);for(var c=this._oColumnSet,l,j,p=c.tree,n,a=0;a<p.length;a++){var o=b.appendChild(document.createElement("tr"));for(j=0;j<p[a].length;j++){l=p[a][j];n=o.appendChild(document.createElement("th"));this._initThEl(n,l)}a===0&&f.addClass(o,h.CLASS_FIRST);a===p.length-1&&f.addClass(o,h.CLASS_LAST)}l=c.headers[0]||[];for(a=0;a<l.length;a++)f.addClass(f.get(this.getId()+"-th-"+l[a]),h.CLASS_FIRST);c=c.headers[c.headers.length-1]||[];for(a=0;a<c.length;a++)f.addClass(f.get(this.getId()+
+"-th-"+c[a]),h.CLASS_LAST);if(d.webkit&&d.webkit<420){setTimeout(function(){b.style.display=""},0);b.style.display="none"}this._elThead=b;this._initColumnHelpers()}},_initThEl:function(a,b){a.id=this.getId()+"-th-"+b.getSanitizedKey();a.innerHTML="";a.rowSpan=b.getRowspan();a.colSpan=b.getColspan();b._elTh=a;var c=a.appendChild(document.createElement("div"));c.id=a.id+"-liner";c.className=h.CLASS_LINER;b._elThLiner=c;c=c.appendChild(document.createElement("span"));c.className=h.CLASS_LABEL;if(b.abbr)a.abbr=
+b.abbr;b.hidden&&this._clearMinWidth(b);a.className=this._getColumnClassNames(b);if(b.width){var d=b.minWidth&&b.width<b.minWidth?b.minWidth:b.width;if(h._bDynStylesFallback){a.firstChild.style.overflow="hidden";a.firstChild.style.width=d+"px"}else this._setColumnWidthDynStyles(b,d+"px","hidden")}this.formatTheadCell(c,b,this.get("sortedBy"));b._elThLabel=c},formatTheadCell:function(e,b,c){var d=b.getKey(),d=a.isValue(b.label)?b.label:d;if(b.sortable){var f=this.getColumnSortDir(b,c)===h.CLASS_DESC;
+c&&b.key===c.key&&(f=c.dir!==h.CLASS_DESC);b=this.getId()+"-href-"+b.getSanitizedKey();c=f?this.get("MSG_SORTDESC"):this.get("MSG_SORTASC");e.innerHTML='<a href="'+b+'" title="'+c+'" class="'+h.CLASS_SORTABLE+'">'+d+"</a>"}else e.innerHTML=d},_destroyDraggableColumns:function(){for(var a,b=0,c=this._oColumnSet.tree[0].length;b<c;b++){a=this._oColumnSet.tree[0][b];if(a._dd){a._dd=a._dd.unreg();f.removeClass(a.getThEl(),h.CLASS_DRAGGABLE)}}this._destroyColumnDragTargetEl()},_initDraggableColumns:function(){this._destroyDraggableColumns();
+if(c.DD)for(var a,b,d,l=0,g=this._oColumnSet.tree[0].length;l<g;l++){a=this._oColumnSet.tree[0][l];b=a.getThEl();f.addClass(b,h.CLASS_DRAGGABLE);d=this._initColumnDragTargetEl();a._dd=new YAHOO.widget.ColumnDD(this,a,b,d)}},_destroyColumnDragTargetEl:function(){if(this._elColumnDragTarget){var a=this._elColumnDragTarget;YAHOO.util.Event.purgeElement(a);a.parentNode.removeChild(a);this._elColumnDragTarget=null}},_initColumnDragTargetEl:function(){if(!this._elColumnDragTarget){var a=document.createElement("div");
+a.id=this.getId()+"-coltarget";a.className=h.CLASS_COLTARGET;a.style.display="none";document.body.insertBefore(a,document.body.firstChild);this._elColumnDragTarget=a}return this._elColumnDragTarget},_destroyResizeableColumns:function(){for(var a=this._oColumnSet.keys,b=0,c=a.length;b<c;b++)if(a[b]._ddResizer){a[b]._ddResizer=a[b]._ddResizer.unreg();f.removeClass(a[b].getThEl(),h.CLASS_RESIZEABLE)}this._destroyColumnResizerProxyEl()},_initResizeableColumns:function(){this._destroyResizeableColumns();
+if(c.DD)for(var a,b,d,l,j=0,p=this._oColumnSet.keys.length;j<p;j++){a=this._oColumnSet.keys[j];if(a.resizeable){b=a.getThEl();f.addClass(b,h.CLASS_RESIZEABLE);d=a.getThLinerEl();l=b.appendChild(document.createElement("div"));l.className=h.CLASS_RESIZERLINER;l.appendChild(d);d=l.appendChild(document.createElement("div"));d.id=b.id+"-resizer";d.className=h.CLASS_RESIZER;a._elResizer=d;l=this._initColumnResizerProxyEl();a._ddResizer=new YAHOO.util.ColumnResizer(this,a,b,d,l);a=function(a){g.stopPropagation(a)};
+g.addListener(d,"click",a)}}},_destroyColumnResizerProxyEl:function(){if(this._elColumnResizerProxy){var a=this._elColumnResizerProxy;YAHOO.util.Event.purgeElement(a);a.parentNode.removeChild(a);this._elColumnResizerProxy=null}},_initColumnResizerProxyEl:function(){if(!this._elColumnResizerProxy){var a=document.createElement("div");a.id=this.getId()+"-colresizerproxy";a.className=h.CLASS_RESIZERPROXY;document.body.insertBefore(a,document.body.firstChild);this._elColumnResizerProxy=a}return this._elColumnResizerProxy},
+_destroyColumnHelpers:function(){this._destroyDraggableColumns();this._destroyResizeableColumns()},_initColumnHelpers:function(){this.get("draggableColumns")&&this._initDraggableColumns();this._initResizeableColumns()},_destroyTbodyEl:function(){var a=this._elTbody;if(a){var b=a.parentNode;g.purgeElement(a,true);b.removeChild(a);this._elTbody=null}},_initTbodyEl:function(a){if(a){this._destroyTbodyEl();a=a.appendChild(document.createElement("tbody"));a.tabIndex=0;a.className=h.CLASS_DATA;g.addListener(a,
+"focus",this._onTbodyFocus,this);g.addListener(a,"mousedown",this._onTableMousedown,this);g.addListener(a,"mouseup",this._onTableMouseup,this);g.addListener(a,"keydown",this._onTbodyKeydown,this);g.addListener(a,"click",this._onTbodyClick,this);if(d.ie)a.hideFocus=true;this._elTbody=a}},_destroyMsgTbodyEl:function(){var a=this._elMsgTbody;if(a){var b=a.parentNode;g.purgeElement(a,true);b.removeChild(a);this._elTbody=null}},_initMsgTbodyEl:function(a){if(a){var b=document.createElement("tbody");b.className=
+h.CLASS_MESSAGE;var c=b.appendChild(document.createElement("tr"));c.className=h.CLASS_FIRST+" "+h.CLASS_LAST;this._elMsgTr=c;c=c.appendChild(document.createElement("td"));c.colSpan=this._oColumnSet.keys.length||1;c.className=h.CLASS_FIRST+" "+h.CLASS_LAST;this._elMsgTd=c;b=a.insertBefore(b,this._elTbody);c.appendChild(document.createElement("div")).className=h.CLASS_LINER;this._elMsgTbody=b;g.addListener(b,"focus",this._onTbodyFocus,this);g.addListener(b,"mousedown",this._onTableMousedown,this);g.addListener(b,
+"mouseup",this._onTableMouseup,this);g.addListener(b,"keydown",this._onTbodyKeydown,this);g.addListener(b,"click",this._onTbodyClick,this)}},_initEvents:function(){this._initColumnSort();YAHOO.util.Event.addListener(document,"click",this._onDocumentClick,this);this.subscribe("paginatorChange",function(){this._handlePaginatorChange.apply(this,arguments)});this.subscribe("initEvent",function(){this.renderPaginator()});this._initCellEditing()},_initColumnSort:function(){this.subscribe("theadCellClickEvent",
+this.onEventSortColumn);var a=this.get("sortedBy");if(a)if(a.dir=="desc")this._configs.sortedBy.value.dir=h.CLASS_DESC;else if(a.dir=="asc")this._configs.sortedBy.value.dir=h.CLASS_ASC},_initCellEditing:function(){this.subscribe("editorBlurEvent",function(){this.onEditorBlurEvent.apply(this,arguments)});this.subscribe("editorBlockEvent",function(){this.onEditorBlockEvent.apply(this,arguments)});this.subscribe("editorUnblockEvent",function(){this.onEditorUnblockEvent.apply(this,arguments)})},_getColumnClassNames:function(e,
+b){var c;c=a.isString(e.className)?[e.className]:a.isArray(e.className)?e.className:[];c[c.length]=this.getId()+"-col-"+e.getSanitizedKey();c[c.length]="yui-dt-col-"+e.getSanitizedKey();var d=this.get("sortedBy")||{};e.key===d.key&&(c[c.length]=d.dir||"");if(e.hidden)c[c.length]=h.CLASS_HIDDEN;if(e.selected)c[c.length]=h.CLASS_SELECTED;if(e.sortable)c[c.length]=h.CLASS_SORTABLE;if(e.resizeable)c[c.length]=h.CLASS_RESIZEABLE;if(e.editor)c[c.length]=h.CLASS_EDITABLE;b&&(c=c.concat(b));return c.join(" ")},
+_clearTrTemplateEl:function(){this._elTrTemplate=null},_getTrTemplateEl:function(){if(this._elTrTemplate)return this._elTrTemplate;var a=document,b=a.createElement("tr"),c=a.createElement("td"),a=a.createElement("div");c.appendChild(a);for(var a=document.createDocumentFragment(),d=this._oColumnSet.keys,f,g=0,j=d.length;g<j;g++){f=c.cloneNode(true);f=this._formatTdEl(d[g],f,g,g===j-1);a.appendChild(f)}b.appendChild(a);b.className=h.CLASS_REC;return this._elTrTemplate=b},_formatTdEl:function(a,b,c,
+d){for(var f=this._oColumnSet.headers[c],g="",j,o=0,m=f.length;o<m;o++){j=this._sId+"-th-"+f[o]+" ";g=g+j}b.headers=g;f=[];if(c===0)f[f.length]=h.CLASS_FIRST;if(d)f[f.length]=h.CLASS_LAST;b.className=this._getColumnClassNames(a,f);b.firstChild.className=h.CLASS_LINER;if(a.width&&h._bDynStylesFallback){a=a.minWidth&&a.width<a.minWidth?a.minWidth:a.width;b.firstChild.style.overflow="hidden";b.firstChild.style.width=a+"px"}return b},_addTrEl:function(a){return this._updateTrEl(this._getTrTemplateEl().cloneNode(true),
+a)},_updateTrEl:function(a,b){if(this.get("formatRow")?this.get("formatRow").call(this,a,b):1){a.style.display="none";for(var c=a.childNodes,d=0,f=c.length;d<f;++d)this.formatCell(c[d].firstChild,b,this._oColumnSet.keys[d]);a.style.display=""}c=a.id;d=b.getId();if(this._sFirstTrId===c)this._sFirstTrId=d;if(this._sLastTrId===c)this._sLastTrId=d;a.id=d;return a},_deleteTrEl:function(e){var b;b=a.isNumber(e)?e:f.get(e).sectionRowIndex;return a.isNumber(b)&&b>-2&&b<this._elTbody.rows.length?this._elTbody.removeChild(this._elTbody.rows[e]):
+null},_unsetFirstRow:function(){if(this._sFirstTrId){f.removeClass(this._sFirstTrId,h.CLASS_FIRST);this._sFirstTrId=null}},_setFirstRow:function(){this._unsetFirstRow();var a=this.getFirstTrEl();if(a){f.addClass(a,h.CLASS_FIRST);this._sFirstTrId=a.id}},_unsetLastRow:function(){if(this._sLastTrId){f.removeClass(this._sLastTrId,h.CLASS_LAST);this._sLastTrId=null}},_setLastRow:function(){this._unsetLastRow();var a=this.getLastTrEl();if(a){f.addClass(a,h.CLASS_LAST);this._sLastTrId=a.id}},_setRowStripes:function(e,
+b){var c=this._elTbody.rows,d=0,g=c.length,j=[],n=0,o=[],m=0;if(e!==null&&e!==void 0){var r=this.getTrEl(e);if(r){d=r.sectionRowIndex;a.isNumber(b)&&b>1&&(g=d+b)}}for(;d<g;d++)d%2?j[n++]=c[d]:o[m++]=c[d];j.length&&f.replaceClass(j,h.CLASS_EVEN,h.CLASS_ODD);o.length&&f.replaceClass(o,h.CLASS_ODD,h.CLASS_EVEN)},_setSelections:function(){var a=this.getSelectedRows(),b=this.getSelectedCells();if(a.length>0||b.length>0){for(var c=this._oColumnSet,d,g=0;g<a.length;g++)(d=f.get(a[g]))&&f.addClass(d,h.CLASS_SELECTED);
+for(g=0;g<b.length;g++)(d=f.get(b[g].recordId))&&f.addClass(d.childNodes[c.getColumn(b[g].columnKey).getKeyIndex()],h.CLASS_SELECTED)}},_onRenderChainEnd:function(){this.hideTableMessage();this._elTbody.rows.length===0&&this.showTableMessage(this.get("MSG_EMPTY"),h.CLASS_EMPTY);var a=this;setTimeout(function(){if(a instanceof h&&a._sId){if(a._bInit){a._bInit=false;a.fireEvent("initEvent")}a.fireEvent("renderEvent");a.fireEvent("refreshEvent");a.validateColumnWidths();a.fireEvent("postRenderEvent")}},
+0)},_onDocumentClick:function(a,b){var c=g.getTarget(a);c.nodeName.toLowerCase();if(!f.isAncestor(b._elContainer,c)){b.fireEvent("tableBlurEvent");if(b._oCellEditor)if(b._oCellEditor.getContainerEl){var d=b._oCellEditor.getContainerEl();!f.isAncestor(d,c)&&d.id!==c.id&&b._oCellEditor.fireEvent("blurEvent",{editor:b._oCellEditor})}else b._oCellEditor.isActive&&!f.isAncestor(b._oCellEditor.container,c)&&b._oCellEditor.container.id!==c.id&&b.fireEvent("editorBlurEvent",{editor:b._oCellEditor})}},_onTableFocus:function(a,
+b){b.fireEvent("tableFocusEvent")},_onTheadFocus:function(a,b){b.fireEvent("theadFocusEvent");b.fireEvent("tableFocusEvent")},_onTbodyFocus:function(a,b){b.fireEvent("tbodyFocusEvent");b.fireEvent("tableFocusEvent")},_onTableMouseover:function(a,b,c,d){for(var c=b.nodeName&&b.nodeName.toLowerCase(),g=true;b&&c!="table";){switch(c){case "body":return;case "td":g=d.fireEvent("cellMouseoverEvent",{target:b,event:a});break;case "span":if(f.hasClass(b,h.CLASS_LABEL)){d.fireEvent("theadLabelMouseoverEvent",
+{target:b,event:a});g=d.fireEvent("headerLabelMouseoverEvent",{target:b,event:a})}break;case "th":d.fireEvent("theadCellMouseoverEvent",{target:b,event:a});g=d.fireEvent("headerCellMouseoverEvent",{target:b,event:a});break;case "tr":if(b.parentNode.nodeName.toLowerCase()=="thead"){d.fireEvent("theadRowMouseoverEvent",{target:b,event:a});g=d.fireEvent("headerRowMouseoverEvent",{target:b,event:a})}else g=d.fireEvent("rowMouseoverEvent",{target:b,event:a})}if(g===false)return;(b=b.parentNode)&&(c=b.nodeName.toLowerCase())}d.fireEvent("tableMouseoverEvent",
+{target:b||d._elContainer,event:a})},_onTableMouseout:function(a,b,c,d){for(var c=b.nodeName&&b.nodeName.toLowerCase(),g=true;b&&c!="table";){switch(c){case "body":return;case "td":g=d.fireEvent("cellMouseoutEvent",{target:b,event:a});break;case "span":if(f.hasClass(b,h.CLASS_LABEL)){d.fireEvent("theadLabelMouseoutEvent",{target:b,event:a});g=d.fireEvent("headerLabelMouseoutEvent",{target:b,event:a})}break;case "th":d.fireEvent("theadCellMouseoutEvent",{target:b,event:a});g=d.fireEvent("headerCellMouseoutEvent",
+{target:b,event:a});break;case "tr":if(b.parentNode.nodeName.toLowerCase()=="thead"){d.fireEvent("theadRowMouseoutEvent",{target:b,event:a});g=d.fireEvent("headerRowMouseoutEvent",{target:b,event:a})}else g=d.fireEvent("rowMouseoutEvent",{target:b,event:a})}if(g===false)return;(b=b.parentNode)&&(c=b.nodeName.toLowerCase())}d.fireEvent("tableMouseoutEvent",{target:b||d._elContainer,event:a})},_onTableMousedown:function(a,b){for(var c=g.getTarget(a),d=c.nodeName&&c.nodeName.toLowerCase(),j=true;c&&
+d!="table";){switch(d){case "body":return;case "td":j=b.fireEvent("cellMousedownEvent",{target:c,event:a});break;case "span":if(f.hasClass(c,h.CLASS_LABEL)){b.fireEvent("theadLabelMousedownEvent",{target:c,event:a});j=b.fireEvent("headerLabelMousedownEvent",{target:c,event:a})}break;case "th":b.fireEvent("theadCellMousedownEvent",{target:c,event:a});j=b.fireEvent("headerCellMousedownEvent",{target:c,event:a});break;case "tr":if(c.parentNode.nodeName.toLowerCase()=="thead"){b.fireEvent("theadRowMousedownEvent",
+{target:c,event:a});j=b.fireEvent("headerRowMousedownEvent",{target:c,event:a})}else j=b.fireEvent("rowMousedownEvent",{target:c,event:a})}if(j===false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableMousedownEvent",{target:c||b._elContainer,event:a})},_onTableMouseup:function(a,b){for(var c=g.getTarget(a),d=c.nodeName&&c.nodeName.toLowerCase(),j=true;c&&d!="table";){switch(d){case "body":return;case "td":j=b.fireEvent("cellMouseupEvent",{target:c,event:a});break;case "span":if(f.hasClass(c,
+h.CLASS_LABEL)){b.fireEvent("theadLabelMouseupEvent",{target:c,event:a});j=b.fireEvent("headerLabelMouseupEvent",{target:c,event:a})}break;case "th":b.fireEvent("theadCellMouseupEvent",{target:c,event:a});j=b.fireEvent("headerCellMouseupEvent",{target:c,event:a});break;case "tr":if(c.parentNode.nodeName.toLowerCase()=="thead"){b.fireEvent("theadRowMouseupEvent",{target:c,event:a});j=b.fireEvent("headerRowMouseupEvent",{target:c,event:a})}else j=b.fireEvent("rowMouseupEvent",{target:c,event:a})}if(j===
+false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableMouseupEvent",{target:c||b._elContainer,event:a})},_onTableDblclick:function(a,b){for(var c=g.getTarget(a),d=c.nodeName&&c.nodeName.toLowerCase(),j=true;c&&d!="table";){switch(d){case "body":return;case "td":j=b.fireEvent("cellDblclickEvent",{target:c,event:a});break;case "span":if(f.hasClass(c,h.CLASS_LABEL)){b.fireEvent("theadLabelDblclickEvent",{target:c,event:a});j=b.fireEvent("headerLabelDblclickEvent",{target:c,event:a})}break;
+case "th":b.fireEvent("theadCellDblclickEvent",{target:c,event:a});j=b.fireEvent("headerCellDblclickEvent",{target:c,event:a});break;case "tr":if(c.parentNode.nodeName.toLowerCase()=="thead"){b.fireEvent("theadRowDblclickEvent",{target:c,event:a});j=b.fireEvent("headerRowDblclickEvent",{target:c,event:a})}else j=b.fireEvent("rowDblclickEvent",{target:c,event:a})}if(j===false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableDblclickEvent",{target:c||b._elContainer,event:a})},
+_onTheadKeydown:function(a,b){for(var c=g.getTarget(a),d=c.nodeName&&c.nodeName.toLowerCase(),f=true;c&&d!="table";){switch(d){case "body":return;case "thead":f=b.fireEvent("theadKeyEvent",{target:c,event:a})}if(f===false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableKeyEvent",{target:c||b._elContainer,event:a})},_onTbodyKeydown:function(a,b){var c=b.get("selectionMode");c=="standard"?b._handleStandardSelectionByKey(a):c=="single"?b._handleSingleSelectionByKey(a):c=="cellblock"?
+b._handleCellBlockSelectionByKey(a):c=="cellrange"?b._handleCellRangeSelectionByKey(a):c=="singlecell"&&b._handleSingleCellSelectionByKey(a);b._oCellEditor&&(b._oCellEditor.fireEvent?b._oCellEditor.fireEvent("blurEvent",{editor:b._oCellEditor}):b._oCellEditor.isActive&&b.fireEvent("editorBlurEvent",{editor:b._oCellEditor}));for(var c=g.getTarget(a),d=c.nodeName&&c.nodeName.toLowerCase(),f=true;c&&d!="table";){switch(d){case "body":return;case "tbody":f=b.fireEvent("tbodyKeyEvent",{target:c,event:a})}if(f===
+false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableKeyEvent",{target:c||b._elContainer,event:a})},_onTheadClick:function(a,b){b._oCellEditor&&(b._oCellEditor.fireEvent?b._oCellEditor.fireEvent("blurEvent",{editor:b._oCellEditor}):b._oCellEditor.isActive&&b.fireEvent("editorBlurEvent",{editor:b._oCellEditor}));for(var c=g.getTarget(a),d=c.nodeName&&c.nodeName.toLowerCase(),j=true;c&&d!="table";){switch(d){case "body":return;case "input":var p=c.type.toLowerCase();p=="checkbox"?
+j=b.fireEvent("theadCheckboxClickEvent",{target:c,event:a}):p=="radio"?j=b.fireEvent("theadRadioClickEvent",{target:c,event:a}):p=="button"||p=="image"||p=="submit"||p=="reset"?j=c.disabled?false:b.fireEvent("theadButtonClickEvent",{target:c,event:a}):c.disabled&&(j=false);break;case "a":j=b.fireEvent("theadLinkClickEvent",{target:c,event:a});break;case "button":j=c.disabled?false:b.fireEvent("theadButtonClickEvent",{target:c,event:a});break;case "span":if(f.hasClass(c,h.CLASS_LABEL)){b.fireEvent("theadLabelClickEvent",
+{target:c,event:a});j=b.fireEvent("headerLabelClickEvent",{target:c,event:a})}break;case "th":b.fireEvent("theadCellClickEvent",{target:c,event:a});j=b.fireEvent("headerCellClickEvent",{target:c,event:a});break;case "tr":b.fireEvent("theadRowClickEvent",{target:c,event:a});j=b.fireEvent("headerRowClickEvent",{target:c,event:a})}if(j===false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableClickEvent",{target:c||b._elContainer,event:a})},_onTbodyClick:function(a,b){b._oCellEditor&&
+(b._oCellEditor.fireEvent?b._oCellEditor.fireEvent("blurEvent",{editor:b._oCellEditor}):b._oCellEditor.isActive&&b.fireEvent("editorBlurEvent",{editor:b._oCellEditor}));for(var c=g.getTarget(a),d=c.nodeName&&c.nodeName.toLowerCase(),f=true;c&&d!="table";){switch(d){case "body":return;case "input":var h=c.type.toLowerCase();h=="checkbox"?f=b.fireEvent("checkboxClickEvent",{target:c,event:a}):h=="radio"?f=b.fireEvent("radioClickEvent",{target:c,event:a}):h=="button"||h=="image"||h=="submit"||h=="reset"?
+f=c.disabled?false:b.fireEvent("buttonClickEvent",{target:c,event:a}):c.disabled&&(f=false);break;case "a":f=b.fireEvent("linkClickEvent",{target:c,event:a});break;case "button":f=c.disabled?false:b.fireEvent("buttonClickEvent",{target:c,event:a});break;case "td":f=b.fireEvent("cellClickEvent",{target:c,event:a});break;case "tr":f=b.fireEvent("rowClickEvent",{target:c,event:a})}if(f===false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableClickEvent",{target:c||b._elContainer,
+event:a})},_onDropdownChange:function(a,b){var c=g.getTarget(a);b.fireEvent("dropdownChangeEvent",{event:a,target:c})},configs:null,getId:function(){return this._sId},toString:function(){return"DataTable instance "+this._sId},getDataSource:function(){return this._oDataSource},getColumnSet:function(){return this._oColumnSet},getRecordSet:function(){return this._oRecordSet},getState:function(){return{totalRecords:this.get("paginator")?this.get("paginator").get("totalRecords"):this._oRecordSet.getLength(),
+pagination:this.get("paginator")?this.get("paginator").getState():null,sortedBy:this.get("sortedBy"),selectedRows:this.getSelectedRows(),selectedCells:this.getSelectedCells()}},getContainerEl:function(){return this._elContainer},getTableEl:function(){return this._elTable},getTheadEl:function(){return this._elThead},getTbodyEl:function(){return this._elTbody},getMsgTbodyEl:function(){return this._elMsgTbody},getMsgTdEl:function(){return this._elMsgTd},getTrEl:function(e){if(e instanceof YAHOO.widget.Record)return document.getElementById(e.getId());
+if(a.isNumber(e)){var b=f.getElementsByClassName(h.CLASS_REC,"tr",this._elTbody);return b&&b[e]?b[e]:null}if(e)if((e=a.isString(e)?document.getElementById(e):e)&&e.ownerDocument==document){e.nodeName.toLowerCase()!="tr"&&(e=f.getAncestorByTagName(e,"tr"));return e}return null},getFirstTrEl:function(){for(var a=this._elTbody.rows,b=0;a[b];){if(this.getRecord(a[b]))return a[b];b++}return null},getLastTrEl:function(){for(var a=this._elTbody.rows,b=a.length-1;b>-1;){if(this.getRecord(a[b]))return a[b];
+b--}return null},getNextTrEl:function(a,b){var c=this.getTrIndex(a);if(c!==null){var d=this._elTbody.rows;if(b)for(;c<d.length-1;){a=d[c+1];if(this.getRecord(a))return a;c++}else if(c<d.length-1)return d[c+1]}return null},getPreviousTrEl:function(a,b){var c=this.getTrIndex(a);if(c!==null){var d=this._elTbody.rows;if(b)for(;c>0;){a=d[c-1];if(this.getRecord(a))return a;c--}else if(c>0)return d[c-1]}return null},getCellIndex:function(a){if(a=this.getTdEl(a))if(d.ie>0)for(var b=0,c=a.parentNode.childNodes,
+f=c.length;b<f;b++){if(c[b]==a)return b}else return a.cellIndex},getTdLinerEl:function(a){return this.getTdEl(a).firstChild||null},getTdEl:function(e){var b,c=f.get(e);if(c&&c.ownerDocument==document){if((b=c.nodeName.toLowerCase()!="td"?f.getAncestorByTagName(c,"td"):c)&&(b.parentNode.parentNode==this._elTbody||b.parentNode.parentNode===null||b.parentNode.parentNode.nodeType===11))return b}else if(e){var d;if(a.isString(e.columnKey)&&a.isString(e.recordId)){d=this.getRecord(e.recordId);(c=this.getColumn(e.columnKey))&&
+(b=c.getKeyIndex())}if(e.record&&e.column&&e.column.getKeyIndex){d=e.record;b=e.column.getKeyIndex()}e=this.getTrEl(d);if(b!==null&&e&&e.cells&&e.cells.length>0)return e.cells[b]||null}return null},getFirstTdEl:function(e){if(e=a.isValue(e)?this.getTrEl(e):this.getFirstTrEl()){if(e.cells&&e.cells.length>0)return e.cells[0];if(e.childNodes&&e.childNodes.length>0)return e.childNodes[0]}return null},getLastTdEl:function(e){if(e=a.isValue(e)?this.getTrEl(e):this.getLastTrEl()){if(e.cells&&e.cells.length>
+0)return e.cells[e.cells.length-1];if(e.childNodes&&e.childNodes.length>0)return e.childNodes[e.childNodes.length-1]}return null},getNextTdEl:function(a){var b=this.getTdEl(a);if(b){a=this.getCellIndex(b);b=this.getTrEl(b);if(b.cells&&b.cells.length>0&&a<b.cells.length-1)return b.cells[a+1];if(b.childNodes&&b.childNodes.length>0&&a<b.childNodes.length-1)return b.childNodes[a+1];if(a=this.getNextTrEl(b))return a.cells[0]}return null},getPreviousTdEl:function(a){var b=this.getTdEl(a);if(b){a=this.getCellIndex(b);
+b=this.getTrEl(b);if(a>0){if(b.cells&&b.cells.length>0)return b.cells[a-1];if(b.childNodes&&b.childNodes.length>0)return b.childNodes[a-1]}else if(a=this.getPreviousTrEl(b))return this.getLastTdEl(a)}return null},getAboveTdEl:function(a,b){var c=this.getTdEl(a);if(c){var d=this.getPreviousTrEl(c,b);if(d){c=this.getCellIndex(c);if(d.cells&&d.cells.length>0)return d.cells[c]?d.cells[c]:null;if(d.childNodes&&d.childNodes.length>0)return d.childNodes[c]?d.childNodes[c]:null}}return null},getBelowTdEl:function(a,
+b){var c=this.getTdEl(a);if(c){var d=this.getNextTrEl(c,b);if(d){c=this.getCellIndex(c);if(d.cells&&d.cells.length>0)return d.cells[c]?d.cells[c]:null;if(d.childNodes&&d.childNodes.length>0)return d.childNodes[c]?d.childNodes[c]:null}}return null},getThLinerEl:function(a){return(a=this.getColumn(a))?a.getThLinerEl():null},getThEl:function(a){if(a instanceof YAHOO.widget.Column){if(a=a.getThEl())return a}else if((a=f.get(a))&&a.ownerDocument==document)return a=a.nodeName.toLowerCase()!="th"?f.getAncestorByTagName(a,
+"th"):a;return null},getTrIndex:function(a){var b=this.getRecord(a),a=this.getRecordIndex(b);if(b){if(b=this.getTrEl(b))return b.sectionRowIndex;return(b=this.get("paginator"))?b.get("recordOffset")+a:a}return null},load:function(a){a=a||{};(a.datasource||this._oDataSource).sendRequest(a.request||this.get("initialRequest"),a.callback||{success:this.onDataReturnInitializeTable,failure:this.onDataReturnInitializeTable,scope:this,argument:this.getState()})},initializeTable:function(){this._bInit=true;
+this._oRecordSet.reset();var a=this.get("paginator");a&&a.set("totalRecords",0);this._unselectAllTrEls();this._unselectAllTdEls();this._oAnchorCell=this._oAnchorRecord=this._aSelections=null;this.set("sortedBy",null)},_runRenderChain:function(){this._oChainRender.run()},_getViewRecords:function(){var a=this.get("paginator");return a?this._oRecordSet.getRecords(a.getStartIndex(),a.getRowsPerPage()):this._oRecordSet.getRecords()},render:function(){this._oChainRender.stop();this.fireEvent("beforeRenderEvent");
+var a=this._getViewRecords(),b=this._elTbody,c=this.get("renderLoopSize"),d=a.length;if(d>0){for(b.style.display="none";b.lastChild;)b.removeChild(b.lastChild);b.style.display="";this._oChainRender.add({method:function(c){if(this instanceof h&&this._sId){var k=c.nCurrentRecord,g=c.nCurrentRecord+c.nLoopLength>d?d:c.nCurrentRecord+c.nLoopLength,j,q;for(b.style.display="none";k<g;k++){j=(j=f.get(a[k].getId()))||this._addTrEl(a[k]);q=b.childNodes[k]||null;b.insertBefore(j,q)}b.style.display="";c.nCurrentRecord=
+k}},scope:this,iterations:c>0?Math.ceil(d/c):1,argument:{nCurrentRecord:0,nLoopLength:c>0?c:d},timeout:c>0?0:-1});this._oChainRender.add({method:function(){if(this instanceof h&&this._sId){for(;b.rows.length>d;)b.removeChild(b.lastChild);this._setFirstRow();this._setLastRow();this._setRowStripes();this._setSelections()}},scope:this,timeout:c>0?0:-1})}else{var g=b.rows.length;g>0&&this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){var e=a.nCurrent,c=a.nLoopLength,c=e-c<0?0:
+e-c;for(b.style.display="none";e>c;e--)b.deleteRow(-1);b.style.display="";a.nCurrent=e}},scope:this,iterations:c>0?Math.ceil(g/c):1,argument:{nCurrent:g,nLoopLength:c>0?c:g},timeout:c>0?0:-1})}this._runRenderChain()},disable:function(){this._disabled=true;var a=this._elTable,b=this._elMask;b.style.width=a.offsetWidth+"px";b.style.height=a.offsetHeight+"px";b.style.left=a.offsetLeft+"px";b.style.display="";this.fireEvent("disableEvent")},undisable:function(){this._disabled=false;this._elMask.style.display=
+"none";this.fireEvent("undisableEvent")},isDisabled:function(){return this._disabled},destroy:function(){this._oChainRender.stop();this._destroyColumnHelpers();for(var b,c=0,d=this._oColumnSet.flat.length;c<d;c++)if((b=this._oColumnSet.flat[c].editor)&&b.destroy){b.destroy();this._oColumnSet.flat[c].editor=null}this._destroyPaginator();this._oRecordSet.unsubscribeAll();this.unsubscribeAll();g.removeListener(document,"click",this._onDocumentClick);this._destroyContainerEl(this._elContainer);for(var f in this)a.hasOwnProperty(this,
+f)&&(this[f]=null);h._nCurrentCount--;if(h._nCurrentCount<1&&h._elDynStyleNode){document.getElementsByTagName("head")[0].removeChild(h._elDynStyleNode);h._elDynStyleNode=null}},showTableMessage:function(b,c){var d=this._elMsgTd;if(a.isString(b))d.firstChild.innerHTML=b;if(a.isString(c))d.className=c;this._elMsgTbody.style.display="";this.fireEvent("tableMsgShowEvent",{html:b,className:c})},hideTableMessage:function(){if(this._elMsgTbody.style.display!="none"){this._elMsgTbody.style.display="none";
+this._elMsgTbody.parentNode.style.width="";this.fireEvent("tableMsgHideEvent")}},focus:function(){this.focusTbodyEl()},focusTheadEl:function(){this._focusEl(this._elThead)},focusTbodyEl:function(){this._focusEl(this._elTbody)},onShow:function(){this.validateColumnWidths();for(var a=this._oColumnSet.keys,b=0,c=a.length,d;b<c;b++){d=a[b];d._ddResizer&&d._ddResizer.resetResizerEl()}},getRecordIndex:function(b){var c;if(a.isNumber(b))c=b;else{if(b instanceof YAHOO.widget.Record)return this._oRecordSet.getRecordIndex(b);
+if(b=this.getTrEl(b))c=b.sectionRowIndex}if(a.isNumber(c))return(b=this.get("paginator"))?b.get("recordOffset")+c:c;return null},getRecord:function(a){var b=this._oRecordSet.getRecord(a);if(!b)(a=this.getTrEl(a))&&(b=this._oRecordSet.getRecord(a.id));return b instanceof YAHOO.widget.Record?this._oRecordSet.getRecord(b):null},getColumn:function(a){var b=this._oColumnSet.getColumn(a);if(!b){var c=this.getTdEl(a);if(c)b=this._oColumnSet.getColumn(this.getCellIndex(c));else if(c=this.getThEl(a))for(var a=
+this._oColumnSet.flat,d=0,f=a.length;d<f;d++)a[d].getThEl().id===c.id&&(b=a[d])}return b},getColumnById:function(a){return this._oColumnSet.getColumnById(a)},getColumnSortDir:function(a,b){if(a.sortOptions&&a.sortOptions.defaultDir)if(a.sortOptions.defaultDir=="asc")a.sortOptions.defaultDir=h.CLASS_ASC;else if(a.sortOptions.defaultDir=="desc")a.sortOptions.defaultDir=h.CLASS_DESC;var c=a.sortOptions&&a.sortOptions.defaultDir?a.sortOptions.defaultDir:h.CLASS_ASC;(b=b||this.get("sortedBy"))&&b.key===
+a.key&&(c=b.dir?b.dir===h.CLASS_ASC?h.CLASS_DESC:h.CLASS_ASC:c===h.CLASS_ASC?h.CLASS_DESC:h.CLASS_ASC);return c},doBeforeSortColumn:function(){this.showTableMessage(this.get("MSG_LOADING"),h.CLASS_LOADING);return true},sortColumn:function(b,c){if(b&&b instanceof YAHOO.widget.Column){b.sortable||f.addClass(this.getThEl(b),h.CLASS_SORTABLE);c&&(c!==h.CLASS_ASC&&c!==h.CLASS_DESC)&&(c=null);var d=c||this.getColumnSortDir(b),g=(this.get("sortedBy")||{}).key===b.key?true:false;if(this.doBeforeSortColumn(b,
+d)){if(this.get("dynamicData")){g=this.getState();if(g.pagination)g.pagination.recordOffset=0;g.sortedBy={key:b.key,dir:d};var j=this.get("generateRequest")(g,this);this.unselectAllRows();this.unselectAllCells();this._oDataSource.sendRequest(j,{success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,argument:g,scope:this})}else{j=b.sortOptions&&a.isFunction(b.sortOptions.sortFunction)?b.sortOptions.sortFunction:null;if(!g||c||j){j=j||this.get("sortFunction");this._oRecordSet.sortRecords(j,
+d==h.CLASS_DESC?true:false,b.sortOptions&&b.sortOptions.field?b.sortOptions.field:b.field)}else this._oRecordSet.reverseRecords();(g=this.get("paginator"))&&g.setPage(1,true);this.render();this.set("sortedBy",{key:b.key,dir:d,column:b})}this.fireEvent("columnSortEvent",{column:b,dir:d})}}},setColumnWidth:function(b,c){b instanceof YAHOO.widget.Column||(b=this.getColumn(b));if(b){if(a.isNumber(c)){c=c>b.minWidth?c:b.minWidth;b.width=c;this._setColumnWidth(b,c+"px");this.fireEvent("columnSetWidthEvent",
+{column:b,width:c})}else if(c===null){b.width=c;this._setColumnWidth(b,"auto");this.validateColumnWidths(b);this.fireEvent("columnUnsetWidthEvent",{column:b})}this._clearTrTemplateEl()}},_setColumnWidth:function(a,b,c){if(a&&a.getKeyIndex()!==null){c=c||(b===""||b==="auto"?"visible":"hidden");h._bDynStylesFallback?this._setColumnWidthDynFunction(a,b,c):this._setColumnWidthDynStyles(a,b,c)}},_setColumnWidthDynStyles:function(a,b,c){var d=h._elDynStyleNode,f;if(!d){d=document.createElement("style");
+d.type="text/css";d=document.getElementsByTagName("head").item(0).appendChild(d);h._elDynStyleNode=d}if(d){var g="."+this.getId()+"-col-"+a.getSanitizedKey()+" ."+h.CLASS_LINER;if(this._elTbody)this._elTbody.style.display="none";if(f=h._oDynStyles[g]){f.style.overflow=c;f.style.width=b}else if(d.styleSheet&&d.styleSheet.addRule){d.styleSheet.addRule(g,"overflow:"+c);d.styleSheet.addRule(g,"width:"+b);f=d.styleSheet.rules[d.styleSheet.rules.length-1];h._oDynStyles[g]=f}else if(d.sheet&&d.sheet.insertRule){d.sheet.insertRule(g+
+" {overflow:"+c+";width:"+b+";}",d.sheet.cssRules.length);f=d.sheet.cssRules[d.sheet.cssRules.length-1];h._oDynStyles[g]=f}if(this._elTbody)this._elTbody.style.display=""}if(!f){h._bDynStylesFallback=true;this._setColumnWidthDynFunction(a,b)}},_setColumnWidthDynFunction:function(a,b,c){b=="auto"&&(b="");var d=this._elTbody?this._elTbody.rows.length:0;if(!this._aDynFunctions[d]){var f,h,g=["var colIdx=oColumn.getKeyIndex();","oColumn.getThLinerEl().style.overflow="];f=d-1;for(h=2;f>=0;--f){g[h++]=
+"this._elTbody.rows[";g[h++]=f;g[h++]="].cells[colIdx].firstChild.style.overflow="}g[h]="sOverflow;";g[h+1]="oColumn.getThLinerEl().style.width=";f=d-1;for(h=h+2;f>=0;--f){g[h++]="this._elTbody.rows[";g[h++]=f;g[h++]="].cells[colIdx].firstChild.style.width="}g[h]="sWidth;";this._aDynFunctions[d]=new Function("oColumn","sWidth","sOverflow",g.join(""))}(d=this._aDynFunctions[d])&&d.call(this,a,b,c)},validateColumnWidths:function(a){var b=this._elColgroup,c=b.cloneNode(true),d=false,h=this._oColumnSet.keys,
+g;if(a&&!a.hidden&&!a.width&&a.getKeyIndex()!==null){g=a.getThLinerEl();if(a.minWidth>0&&g.offsetWidth<a.minWidth){c.childNodes[a.getKeyIndex()].style.width=a.minWidth+(parseInt(f.getStyle(g,"paddingLeft"),10)|0)+(parseInt(f.getStyle(g,"paddingRight"),10)|0)+"px";d=true}else a.maxAutoWidth>0&&g.offsetWidth>a.maxAutoWidth&&this._setColumnWidth(a,a.maxAutoWidth+"px","hidden")}else for(var j=0,o=h.length;j<o;j++){a=h[j];if(!a.hidden&&!a.width){g=a.getThLinerEl();if(a.minWidth>0&&g.offsetWidth<a.minWidth){c.childNodes[j].style.width=
+a.minWidth+(parseInt(f.getStyle(g,"paddingLeft"),10)|0)+(parseInt(f.getStyle(g,"paddingRight"),10)|0)+"px";d=true}else a.maxAutoWidth>0&&g.offsetWidth>a.maxAutoWidth&&this._setColumnWidth(a,a.maxAutoWidth+"px","hidden")}}if(d){b.parentNode.replaceChild(c,b);this._elColgroup=c}},_clearMinWidth:function(a){if(a.getKeyIndex()!==null)this._elColgroup.childNodes[a.getKeyIndex()].style.width=""},_restoreMinWidth:function(a){if(a.minWidth&&a.getKeyIndex()!==null)this._elColgroup.childNodes[a.getKeyIndex()].style.width=
+a.minWidth+"px"},hideColumn:function(a){a instanceof YAHOO.widget.Column||(a=this.getColumn(a));if(a&&!a.hidden&&a.getTreeIndex()!==null){for(var b=this.getTbodyEl().rows,c=b.length,d=this._oColumnSet.getDescendants(a),g=0,j=d.length;g<j;g++){var n=d[g];n.hidden=true;f.addClass(n.getThEl(),h.CLASS_HIDDEN);var o=n.getKeyIndex();if(o!==null){this._clearMinWidth(a);for(var m=0;m<c;m++)f.addClass(b[m].cells[o],h.CLASS_HIDDEN)}this.fireEvent("columnHideEvent",{column:n})}this._repaintOpera();this._clearTrTemplateEl()}},
+showColumn:function(a){a instanceof YAHOO.widget.Column||(a=this.getColumn(a));if(a&&a.hidden&&a.getTreeIndex()!==null){for(var b=this.getTbodyEl().rows,c=b.length,d=this._oColumnSet.getDescendants(a),g=0,j=d.length;g<j;g++){var n=d[g];n.hidden=false;f.removeClass(n.getThEl(),h.CLASS_HIDDEN);var o=n.getKeyIndex();if(o!==null){this._restoreMinWidth(a);for(var m=0;m<c;m++)f.removeClass(b[m].cells[o],h.CLASS_HIDDEN)}this.fireEvent("columnShowEvent",{column:n})}this._clearTrTemplateEl()}},removeColumn:function(a){a instanceof
+YAHOO.widget.Column||(a=this.getColumn(a));if(a){var b=a.getTreeIndex();if(b!==null){var c,d=a.getKeyIndex();if(d===null){var f=[],g=this._oColumnSet.getDescendants(a);c=0;for(a=g.length;c<a;c++){var j=g[c].getKeyIndex();j!==null&&(f[f.length]=j)}f.length>0&&(d=f)}else d=[d];if(d!==null){d.sort(function(a,b){return YAHOO.util.Sort.compare(a,b)});this._destroyTheadEl();c=this._oColumnSet.getDefinitions();a=c.splice(b,1)[0];this._initColumnSet(c);this._initTheadEl();for(c=d.length-1;c>-1;c--)this._removeColgroupColEl(d[c]);
+var o=this._elTbody.rows;if(o.length>0){var m=this.get("renderLoopSize"),b=o.length;this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){for(var b=a.nCurrentRow,e=m>0?Math.min(b+m,o.length):o.length,c=a.aIndexes,d;b<e;++b)for(d=c.length-1;d>-1;d--)o[b].removeChild(o[b].childNodes[c[d]]);a.nCurrentRow=b}},iterations:m>0?Math.ceil(b/m):1,argument:{nCurrentRow:0,aIndexes:d},scope:this,timeout:m>0?0:-1});this._runRenderChain()}this.fireEvent("columnRemoveEvent",{column:a});return a}}}},
+insertColumn:function(b,c){if(b instanceof YAHOO.widget.Column)b=b.getDefinition();else if(b.constructor!==Object)return;var d=this._oColumnSet;if(!a.isValue(c)||!a.isNumber(c))c=d.tree[0].length;this._destroyTheadEl();var f=this._oColumnSet.getDefinitions();f.splice(c,0,b);this._initColumnSet(f);this._initTheadEl();var d=this._oColumnSet,f=d.tree[0][c],g,j=[],n=d.getDescendants(f),d=0;for(g=n.length;d<g;d++){var o=n[d].getKeyIndex();o!==null&&(j[j.length]=o)}if(j.length>0){for(var m=j.sort(function(a,
+b){return YAHOO.util.Sort.compare(a,b)})[0],d=j.length-1;d>-1;d--)this._insertColgroupColEl(j[d]);var r=this._elTbody.rows;if(r.length>0){var s=this.get("renderLoopSize"),n=r.length,o=[],t,d=0;for(g=j.length;d<g;d++){var u=j[d];t=this._getTrTemplateEl().childNodes[d].cloneNode(true);t=this._formatTdEl(this._oColumnSet.keys[u],t,u,u===this._oColumnSet.keys.length-1);o[u]=t}this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){for(var b=a.nCurrentRow,e,c=a.descKeyIndexes,d=s>0?
+Math.min(b+s,r.length):r.length,i;b<d;++b){i=r[b].childNodes[m]||null;for(e=c.length-1;e>-1;e--)r[b].insertBefore(a.aTdTemplates[c[e]].cloneNode(true),i)}a.nCurrentRow=b}},iterations:s>0?Math.ceil(n/s):1,argument:{nCurrentRow:0,aTdTemplates:o,descKeyIndexes:j},scope:this,timeout:s>0?0:-1});this._runRenderChain()}this.fireEvent("columnInsertEvent",{column:b,index:c});return f}},reorderColumn:function(a,b){a instanceof YAHOO.widget.Column||(a=this.getColumn(a));if(a&&YAHOO.lang.isNumber(b)){var c=a.getTreeIndex();
+if(c!==null&&c!==b){var d,f,g=a.getKeyIndex(),j,o=[],m;if(g===null){j=this._oColumnSet.getDescendants(a);d=0;for(f=j.length;d<f;d++){m=j[d].getKeyIndex();m!==null&&(o[o.length]=m)}o.length>0&&(g=o)}else g=[g];if(g!==null){g.sort(function(a,b){return YAHOO.util.Sort.compare(a,b)});this._destroyTheadEl();var r=this._oColumnSet.getDefinitions();d=r.splice(c,1)[0];r.splice(b,0,d);this._initColumnSet(r);this._initTheadEl();var r=this._oColumnSet.tree[0][b],s=r.getKeyIndex();if(s===null){o=[];j=this._oColumnSet.getDescendants(r);
+d=0;for(f=j.length;d<f;d++){m=j[d].getKeyIndex();m!==null&&(o[o.length]=m)}o.length>0&&(s=o)}else s=[s];var t=s.sort(function(a,b){return YAHOO.util.Sort.compare(a,b)})[0];this._reorderColgroupColEl(g,t);var u=this._elTbody.rows;if(u.length>0){var w=this.get("renderLoopSize");d=u.length;this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){for(var b=a.nCurrentRow,e,c,d,i=w>0?Math.min(b+w,u.length):u.length,f=a.aIndexes,k;b<i;++b){c=[];k=u[b];for(e=f.length-1;e>-1;e--)c.push(k.removeChild(k.childNodes[f[e]]));
+d=k.childNodes[t]||null;for(e=c.length-1;e>-1;e--)k.insertBefore(c[e],d)}a.nCurrentRow=b}},iterations:w>0?Math.ceil(d/w):1,argument:{nCurrentRow:0,aIndexes:g},scope:this,timeout:w>0?0:-1});this._runRenderChain()}this.fireEvent("columnReorderEvent",{column:r,oldIndex:c});return r}}}},selectColumn:function(a){if((a=this.getColumn(a))&&!a.selected&&a.getKeyIndex()!==null){a.selected=true;var b=a.getThEl();f.addClass(b,h.CLASS_SELECTED);var c=this.getTbodyEl().rows;this._oChainRender.add({method:function(a){this instanceof
+h&&(this._sId&&c[a.rowIndex]&&c[a.rowIndex].cells[a.cellIndex])&&f.addClass(c[a.rowIndex].cells[a.cellIndex],h.CLASS_SELECTED);a.rowIndex++},scope:this,iterations:c.length,argument:{rowIndex:0,cellIndex:a.getKeyIndex()}});this._clearTrTemplateEl();this._elTbody.style.display="none";this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnSelectEvent",{column:a})}},unselectColumn:function(a){if((a=this.getColumn(a))&&a.selected&&a.getKeyIndex()!==null){a.selected=false;var b=a.getThEl();
+f.removeClass(b,h.CLASS_SELECTED);var c=this.getTbodyEl().rows;this._oChainRender.add({method:function(a){this instanceof h&&(this._sId&&c[a.rowIndex]&&c[a.rowIndex].cells[a.cellIndex])&&f.removeClass(c[a.rowIndex].cells[a.cellIndex],h.CLASS_SELECTED);a.rowIndex++},scope:this,iterations:c.length,argument:{rowIndex:0,cellIndex:a.getKeyIndex()}});this._clearTrTemplateEl();this._elTbody.style.display="none";this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnUnselectEvent",{column:a})}},
+getSelectedColumns:function(){for(var a=[],b=this._oColumnSet.keys,c=0,d=b.length;c<d;c++)b[c].selected&&(a[a.length]=b[c]);return a},highlightColumn:function(a){if((a=this.getColumn(a))&&a.getKeyIndex()!==null){var b=a.getThEl();f.addClass(b,h.CLASS_HIGHLIGHTED);var c=this.getTbodyEl().rows;this._oChainRender.add({method:function(a){this instanceof h&&(this._sId&&c[a.rowIndex]&&c[a.rowIndex].cells[a.cellIndex])&&f.addClass(c[a.rowIndex].cells[a.cellIndex],h.CLASS_HIGHLIGHTED);a.rowIndex++},scope:this,
+iterations:c.length,argument:{rowIndex:0,cellIndex:a.getKeyIndex()},timeout:-1});this._elTbody.style.display="none";this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnHighlightEvent",{column:a})}},unhighlightColumn:function(a){if((a=this.getColumn(a))&&a.getKeyIndex()!==null){var b=a.getThEl();f.removeClass(b,h.CLASS_HIGHLIGHTED);var c=this.getTbodyEl().rows;this._oChainRender.add({method:function(a){this instanceof h&&(this._sId&&c[a.rowIndex]&&c[a.rowIndex].cells[a.cellIndex])&&
+f.removeClass(c[a.rowIndex].cells[a.cellIndex],h.CLASS_HIGHLIGHTED);a.rowIndex++},scope:this,iterations:c.length,argument:{rowIndex:0,cellIndex:a.getKeyIndex()},timeout:-1});this._elTbody.style.display="none";this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnUnhighlightEvent",{column:a})}},addRow:function(e,c){if((!a.isNumber(c)||!(c<0||c>this._oRecordSet.getLength()))&&e&&a.isObject(e)){var d=this._oRecordSet.addRecord(e,c);if(d){var f,g=this.get("paginator");if(g){f=g.get("totalRecords");
+f!==b.Paginator.VALUE_UNLIMITED&&g.set("totalRecords",f+1);f=this.getRecordIndex(d);g=g.getPageRecords()[1];f<=g&&this.render();this.fireEvent("rowAddEvent",{record:d})}else{f=this.getRecordIndex(d);if(a.isNumber(f)){this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){var b=a.record,a=a.recIndex,e=this._addTrEl(b);if(e){var c=this._elTbody.rows[a]?this._elTbody.rows[a]:null;this._elTbody.insertBefore(e,c);a===0&&this._setFirstRow();c===null&&this._setLastRow();this._setRowStripes();
+this.hideTableMessage();this.fireEvent("rowAddEvent",{record:b})}}},argument:{record:d,recIndex:f},scope:this,timeout:this.get("renderLoopSize")>0?0:-1});this._runRenderChain()}}}}},addRows:function(e,c){if((!a.isNumber(c)||!(c<0||c>this._oRecordSet.getLength()))&&a.isArray(e)){var d=this._oRecordSet.addRecords(e,c);if(d){var f=this.getRecordIndex(d[0]),g=this.get("paginator");if(g){var j=g.get("totalRecords");j!==b.Paginator.VALUE_UNLIMITED&&g.set("totalRecords",j+d.length);g=g.getPageRecords()[1];
+f<=g&&this.render();this.fireEvent("rowsAddEvent",{records:d})}else{var n=this.get("renderLoopSize"),o=f+e.length,g=f>=this._elTbody.rows.length;this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){for(var b=a.aRecords,e=a.nCurrentRow,c=a.nCurrentRecord,d=n>0?Math.min(e+n,o):o,i=document.createDocumentFragment(),f=this._elTbody.rows[e]?this._elTbody.rows[e]:null;e<d;e++,c++)i.appendChild(this._addTrEl(b[c]));this._elTbody.insertBefore(i,f);a.nCurrentRow=e;a.nCurrentRecord=c}},
+iterations:n>0?Math.ceil(o/n):1,argument:{nCurrentRow:f,nCurrentRecord:0,aRecords:d},scope:this,timeout:n>0?0:-1});this._oChainRender.add({method:function(a){a.recIndex===0&&this._setFirstRow();a.isLast&&this._setLastRow();this._setRowStripes();this.fireEvent("rowsAddEvent",{records:d})},argument:{recIndex:f,isLast:g},scope:this,timeout:-1});this._runRenderChain();this.hideTableMessage()}}}},updateRow:function(b,c){var d=b;a.isNumber(d)||(d=this.getRecordIndex(b));if(a.isNumber(d)&&d>=0){var f=this._oRecordSet.getRecord(d);
+if(f){var g=this._oRecordSet.setRecord(c,d),j=this.getTrEl(f),n=f?f.getData():null;if(g){for(var o=this._aSelections||[],m=0,f=f.getId(),r=g.getId();m<o.length;m++)if(o[m]===f)o[m]=r;else if(o[m].recordId===f)o[m].recordId=r;if(this._oAnchorRecord&&this._oAnchorRecord.getId()===f)this._oAnchorRecord=g;if(this._oAnchorCell&&this._oAnchorCell.record.getId()===f)this._oAnchorCell.record=g;this._oChainRender.add({method:function(){if(this instanceof h&&this._sId){var a=this.get("paginator");if(a){var b=
+a.getPageRecords()[0],a=a.getPageRecords()[1];(d>=b||d<=a)&&this.render()}else j?this._updateTrEl(j,g):this.getTbodyEl().appendChild(this._addTrEl(g));this.fireEvent("rowUpdateEvent",{record:g,oldData:n})}},scope:this,timeout:this.get("renderLoopSize")>0?0:-1});this._runRenderChain()}}}},updateRows:function(b,c){if(a.isArray(c)){var d=b,f=this._oRecordSet,g=f.getLength();a.isNumber(b)||(d=this.getRecordIndex(b));if(a.isNumber(d)&&d>=0&&d<f.getLength()){var j=d+c.length,n=f.getRecords(d,c.length),
+o=f.setRecords(c,d);if(o){for(var f=this._aSelections||[],m=0,r,s,t,u,w=this._oAnchorRecord?this._oAnchorRecord.getId():null,x=this._oAnchorCell?this._oAnchorCell.record.getId():null;m<n.length;m++){u=n[m].getId();s=o[m];t=s.getId();for(r=0;r<f.length;r++)if(f[r]===u)f[r]=t;else if(f[r].recordId===u)f[r].recordId=t;if(w&&w===u)this._oAnchorRecord=s;if(x&&x===u)this._oAnchorCell.record=s}if(m=this.get("paginator")){f=m.getPageRecords()[0];m=m.getPageRecords()[1];(d>=f||j<=m)&&this.render();this.fireEvent("rowsAddEvent",
+{newRecords:o,oldRecords:n})}else{var v=this.get("renderLoopSize"),f=c.length,m=j>=g,y=j>g;this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){for(var b=a.aRecords,e=a.nCurrentRow,c=a.nDataPointer,i=v>0?Math.min(e+v,d+b.length):d+b.length;e<i;e++,c++)y&&e>=g?this._elTbody.appendChild(this._addTrEl(b[c])):this._updateTrEl(this._elTbody.rows[e],b[c]);a.nCurrentRow=e;a.nDataPointer=c}},iterations:v>0?Math.ceil(f/v):1,argument:{nCurrentRow:d,aRecords:o,nDataPointer:0,isAdding:y},
+scope:this,timeout:v>0?0:-1});this._oChainRender.add({method:function(a){a.recIndex===0&&this._setFirstRow();a.isLast&&this._setLastRow();this._setRowStripes();this.fireEvent("rowsAddEvent",{newRecords:o,oldRecords:n})},argument:{recIndex:d,isLast:m},scope:this,timeout:-1});this._runRenderChain();this.hideTableMessage()}}}}},deleteRow:function(e){var c=a.isNumber(e)?e:this.getRecordIndex(e);if(a.isNumber(c))if(e=this.getRecord(c)){for(var d=this.getTrIndex(c),e=e.getId(),f=this._aSelections||[],g=
+f.length-1;g>-1;g--)(a.isString(f[g])&&f[g]===e||a.isObject(f[g])&&f[g].recordId===e)&&f.splice(g,1);var j=this._oRecordSet.deleteRecord(c);if(j)if(e=this.get("paginator")){f=e.get("totalRecords");g=e.getPageRecords();f!==b.Paginator.VALUE_UNLIMITED&&e.set("totalRecords",f-1);(!g||c<=g[1])&&this.render();this._oChainRender.add({method:function(){this instanceof h&&this._sId&&this.fireEvent("rowDeleteEvent",{recordIndex:c,oldData:j,trElIndex:d})},scope:this,timeout:this.get("renderLoopSize")>0?0:-1});
+this._runRenderChain()}else if(a.isNumber(d)){this._oChainRender.add({method:function(){if(this instanceof h&&this._sId){var a=c===this._oRecordSet.getLength();this._deleteTrEl(d);if(this._elTbody.rows.length>0){d===0&&this._setFirstRow();a&&this._setLastRow();d!=this._elTbody.rows.length&&this._setRowStripes(d)}this.fireEvent("rowDeleteEvent",{recordIndex:c,oldData:j,trElIndex:d})}},scope:this,timeout:this.get("renderLoopSize")>0?0:-1});this._runRenderChain();return}}return null},deleteRows:function(e,
+c){var d=a.isNumber(e)?e:this.getRecordIndex(e);if(a.isNumber(d)){var f=this.getRecord(d);if(f){for(var g=this.getTrIndex(d),f=f.getId(),j=this._aSelections||[],n=j.length-1;n>-1;n--)(a.isString(j[n])&&j[n]===f||a.isObject(j[n])&&j[n].recordId===f)&&j.splice(n,1);var o=f=d;if(c&&a.isNumber(c)){f=c>0?d+c-1:d;o=c>0?d:d+c+1;c=c>0?c:c*-1;if(o<0){o=0;c=f-o+1}}else c=1;var m=this._oRecordSet.deleteRecords(o,c);if(m){var d=this.get("paginator"),r=this.get("renderLoopSize");if(d){g=d.get("totalRecords");
+f=d.getPageRecords();g!==b.Paginator.VALUE_UNLIMITED&&d.set("totalRecords",g-m.length);(!f||o<=f[1])&&this.render();this._oChainRender.add({method:function(){this instanceof h&&this._sId&&this.fireEvent("rowsDeleteEvent",{recordIndex:o,oldData:m,count:c})},scope:this,timeout:r>0?0:-1});this._runRenderChain();return}if(a.isNumber(g)){var s=o;this._oChainRender.add({method:function(a){if(this instanceof h&&this._sId){for(var b=a.nCurrentRow,e=r>0?Math.max(b-r,s)-1:s-1;b>e;--b)this._deleteTrEl(b);a.nCurrentRow=
+b}},iterations:r>0?Math.ceil(c/r):1,argument:{nCurrentRow:f},scope:this,timeout:r>0?0:-1});this._oChainRender.add({method:function(){if(this._elTbody.rows.length>0){this._setFirstRow();this._setLastRow();this._setRowStripes()}this.fireEvent("rowsDeleteEvent",{recordIndex:o,oldData:m,count:c})},scope:this,timeout:-1});this._runRenderChain();return}}}}return null},formatCell:function(a,b,c){b||(b=this.getRecord(a));c||(c=this.getColumn(this.getCellIndex(a.parentNode)));if(b&&c){var d=b.getData(c.field),
+f=typeof c.formatter==="function"?c.formatter:h.Formatter[c.formatter+""]||h.Formatter.defaultFormatter;f?f.call(this,a,b,c,d):a.innerHTML=d;this.fireEvent("cellFormatEvent",{record:b,column:c,key:c.key,el:a})}},updateCell:function(a,b,c,d){if((b=b instanceof YAHOO.widget.Column?b:this.getColumn(b))&&b.getField()&&a instanceof YAHOO.widget.Record){var f=b.getField(),g=a.getData(f);this._oRecordSet.updateRecordValue(a,f,c);var j=this.getTdEl({record:a,column:b});if(j){this._oChainRender.add({method:function(){if(this instanceof
+h&&this._sId){this.formatCell(j.firstChild,a,b);this.fireEvent("cellUpdateEvent",{record:a,column:b,oldData:g})}},scope:this,timeout:this.get("renderLoopSize")>0?0:-1});d||this._runRenderChain()}else this.fireEvent("cellUpdateEvent",{record:a,column:b,oldData:g})}},_updatePaginator:function(a){var b=this.get("paginator");b&&a!==b&&b.unsubscribe("changeRequest",this.onPaginatorChangeRequest,this,true);a&&a.subscribe("changeRequest",this.onPaginatorChangeRequest,this,true)},_handlePaginatorChange:function(a){if(a.prevValue!==
+a.newValue){var b=a.newValue,c=a.prevValue,a=this._defaultPaginatorContainers();if(c){c.getContainerNodes()[0]==a[0]&&c.set("containers",[]);c.destroy();if(a[0])if(b&&!b.getContainerNodes().length)b.set("containers",a);else for(c=a.length-1;c>=0;--c)a[c]&&a[c].parentNode.removeChild(a[c])}this._bInit||this.render();b&&this.renderPaginator()}},_defaultPaginatorContainers:function(a){var b=this._sId+"-paginator0",c=this._sId+"-paginator1",d=f.get(b),g=f.get(c);if(a&&(!d||!g)){if(!d){d=document.createElement("div");
+d.id=b;f.addClass(d,h.CLASS_PAGINATOR);this._elContainer.insertBefore(d,this._elContainer.firstChild)}if(!g){g=document.createElement("div");g.id=c;f.addClass(g,h.CLASS_PAGINATOR);this._elContainer.appendChild(g)}}return[d,g]},_destroyPaginator:function(){var a=this.get("paginator");a&&a.destroy()},renderPaginator:function(){var a=this.get("paginator");if(a){a.getContainerNodes().length||a.set("containers",this._defaultPaginatorContainers(true));a.render()}},doBeforePaginatorChange:function(){this.showTableMessage(this.get("MSG_LOADING"),
+h.CLASS_LOADING);return true},onPaginatorChangeRequest:function(a){if(this.doBeforePaginatorChange(a))if(this.get("dynamicData")){var b=this.getState();b.pagination=a;a=this.get("generateRequest")(b,this);this.unselectAllRows();this.unselectAllCells();this._oDataSource.sendRequest(a,{success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,argument:b,scope:this})}else{a.paginator.setStartIndex(a.recordOffset,true);a.paginator.setRowsPerPage(a.rowsPerPage,true);this.render()}},_elLastHighlightedTd:null,
+_aSelections:null,_oAnchorRecord:null,_oAnchorCell:null,_unselectAllTrEls:function(){var a=f.getElementsByClassName(h.CLASS_SELECTED,"tr",this._elTbody);f.removeClass(a,h.CLASS_SELECTED)},_getSelectionTrigger:function(){var a=this.get("selectionMode"),b={},c,d,f,g;if(a=="cellblock"||a=="cellrange"||a=="singlecell"){if(a=this.getLastSelectedCell()){c=this.getRecord(a.recordId);d=this.getRecordIndex(c);f=this.getTrEl(c);g=this.getTrIndex(f);if(g===null)return null;b.record=c;b.recordIndex=d;b.el=this.getTdEl(a);
+b.trIndex=g;b.column=this.getColumn(a.columnKey);b.colKeyIndex=b.column.getKeyIndex();b.cell=a;return b}}else if(c=this.getLastSelectedRecord()){c=this.getRecord(c);d=this.getRecordIndex(c);f=this.getTrEl(c);g=this.getTrIndex(f);if(g===null)return null;b.record=c;b.recordIndex=d;b.el=f;b.trIndex=g;return b}return null},_getSelectionAnchor:function(a){var b=this.get("selectionMode"),c={},d;if(b=="cellblock"||b=="cellrange"||b=="singlecell"){var f=this._oAnchorCell;if(!f)if(a)f=this._oAnchorCell=a.cell;
+else return null;b=this._oAnchorCell.record;a=this._oRecordSet.getRecordIndex(b);d=this.getTrIndex(b);d===null&&(d=a<this.getRecordIndex(this.getFirstTrEl())?0:this.getRecordIndex(this.getLastTrEl()));c.record=b;c.recordIndex=a;c.trIndex=d;c.column=this._oAnchorCell.column;c.colKeyIndex=c.column.getKeyIndex();c.cell=f}else{b=this._oAnchorRecord;if(!b)if(a)b=this._oAnchorRecord=a.record;else return null;a=this.getRecordIndex(b);d=this.getTrIndex(b);d===null&&(d=a<this.getRecordIndex(this.getFirstTrEl())?
+0:this.getRecordIndex(this.getLastTrEl()));c.record=b;c.recordIndex=a;c.trIndex=d}return c},_handleStandardSelectionByMouse:function(a){var b=this.getTrEl(a.target);if(b){var c=a.event,d=c.shiftKey,c=c.ctrlKey||navigator.userAgent.toLowerCase().indexOf("mac")!=-1&&c.metaKey,b=this.getRecord(b),f=this._oRecordSet.getRecordIndex(b),g=this._getSelectionAnchor();if(d&&c)if(g)if(this.isSelected(g.record))if(g.recordIndex<f)for(a=g.recordIndex+1;a<=f;a++)this.isSelected(a)||this.selectRow(a);else for(a=
+g.recordIndex-1;a>=f;a--)this.isSelected(a)||this.selectRow(a);else{if(g.recordIndex<f)for(a=g.recordIndex+1;a<=f-1;a++)this.isSelected(a)&&this.unselectRow(a);else for(a=f+1;a<=g.recordIndex-1;a++)this.isSelected(a)&&this.unselectRow(a);this.selectRow(b)}else{this._oAnchorRecord=b;this.isSelected(b)?this.unselectRow(b):this.selectRow(b)}else if(d){this.unselectAllRows();if(g)if(g.recordIndex<f)for(a=g.recordIndex;a<=f;a++)this.selectRow(a);else for(a=g.recordIndex;a>=f;a--)this.selectRow(a);else{this._oAnchorRecord=
+b;this.selectRow(b)}}else if(c){this._oAnchorRecord=b;this.isSelected(b)?this.unselectRow(b):this.selectRow(b)}else this._handleSingleSelectionByMouse(a)}},_handleStandardSelectionByKey:function(a){var b=g.getCharCode(a);if(b==38||b==40){var c=a.shiftKey,d=this._getSelectionTrigger();if(!d)return null;g.stopEvent(a);var f=this._getSelectionAnchor(d);c?b==40&&f.recordIndex<=d.trIndex?this.selectRow(this.getNextTrEl(d.el)):b==38&&f.recordIndex>=d.trIndex?this.selectRow(this.getPreviousTrEl(d.el)):this.unselectRow(d.el):
+this._handleSingleSelectionByKey(a)}},_handleSingleSelectionByMouse:function(a){if(a=this.getTrEl(a.target)){this._oAnchorRecord=a=this.getRecord(a);this.unselectAllRows();this.selectRow(a)}},_handleSingleSelectionByKey:function(a){var b=g.getCharCode(a);if(b==38||b==40){var c=this._getSelectionTrigger();if(!c)return null;g.stopEvent(a);var d;if(b==38){d=this.getPreviousTrEl(c.el);d===null&&(d=this.getFirstTrEl())}else if(b==40){d=this.getNextTrEl(c.el);d===null&&(d=this.getLastTrEl())}this.unselectAllRows();
+this.selectRow(d);this._oAnchorRecord=this.getRecord(d)}},_handleCellBlockSelectionByMouse:function(a){var b=this.getTdEl(a.target);if(b){var c=a.event,d=c.shiftKey,f=c.ctrlKey||navigator.userAgent.toLowerCase().indexOf("mac")!=-1&&c.metaKey,g=this.getTrEl(b),c=this.getTrIndex(g),h=this.getColumn(b),j=h.getKeyIndex(),m=this.getRecord(g),r=this._oRecordSet.getRecordIndex(m),s={record:m,column:h},h=this._getSelectionAnchor(),m=this.getTbodyEl().rows;if(d&&f)if(h)if(this.isSelected(h.cell))if(h.recordIndex===
+r)if(h.colKeyIndex<j)for(a=h.colKeyIndex+1;a<=j;a++)this.selectCell(g.cells[a]);else{if(j<h.colKeyIndex)for(a=j;a<h.colKeyIndex;a++)this.selectCell(g.cells[a])}else if(h.recordIndex<r){b=Math.min(h.colKeyIndex,j);j=Math.max(h.colKeyIndex,j);for(a=h.trIndex;a<=c;a++)for(d=b;d<=j;d++)this.selectCell(m[a].cells[d])}else{b=Math.min(h.trIndex,j);j=Math.max(h.trIndex,j);for(a=h.trIndex;a>=c;a--)for(d=j;d>=b;d--)this.selectCell(m[a].cells[d])}else{if(h.recordIndex===r)if(h.colKeyIndex<j)for(a=h.colKeyIndex+
+1;a<j;a++)this.unselectCell(g.cells[a]);else if(j<h.colKeyIndex)for(a=j+1;a<h.colKeyIndex;a++)this.unselectCell(g.cells[a]);if(h.recordIndex<r)for(a=h.trIndex;a<=c;a++){g=m[a];for(d=0;d<g.cells.length;d++)g.sectionRowIndex===h.trIndex?d>h.colKeyIndex&&this.unselectCell(g.cells[d]):g.sectionRowIndex===c?d<j&&this.unselectCell(g.cells[d]):this.unselectCell(g.cells[d])}else for(a=c;a<=h.trIndex;a++){g=m[a];for(d=0;d<g.cells.length;d++)g.sectionRowIndex==c?d>j&&this.unselectCell(g.cells[d]):g.sectionRowIndex==
+h.trIndex?d<h.colKeyIndex&&this.unselectCell(g.cells[d]):this.unselectCell(g.cells[d])}this.selectCell(b)}else{this._oAnchorCell=s;this.isSelected(s)?this.unselectCell(s):this.selectCell(s)}else if(d){this.unselectAllCells();if(h)if(h.recordIndex===r)if(h.colKeyIndex<j)for(a=h.colKeyIndex;a<=j;a++)this.selectCell(g.cells[a]);else{if(j<h.colKeyIndex)for(a=j;a<=h.colKeyIndex;a++)this.selectCell(g.cells[a])}else if(h.recordIndex<r){b=Math.min(h.colKeyIndex,j);j=Math.max(h.colKeyIndex,j);for(a=h.trIndex;a<=
+c;a++)for(d=b;d<=j;d++)this.selectCell(m[a].cells[d])}else{b=Math.min(h.colKeyIndex,j);j=Math.max(h.colKeyIndex,j);for(a=c;a<=h.trIndex;a++)for(d=b;d<=j;d++)this.selectCell(m[a].cells[d])}else{this._oAnchorCell=s;this.selectCell(s)}}else if(f){this._oAnchorCell=s;this.isSelected(s)?this.unselectCell(s):this.selectCell(s)}else this._handleSingleCellSelectionByMouse(a)}},_handleCellBlockSelectionByKey:function(a){var b=g.getCharCode(a),c=a.shiftKey;if(b==9||!c)this._handleSingleCellSelectionByKey(a);
+else if(b>36&&b<41){c=this._getSelectionTrigger();if(!c)return null;g.stopEvent(a);var d=this._getSelectionAnchor(c),f,h,a=this.getTbodyEl().rows;h=c.el.parentNode;if(b==40)if(d.recordIndex<=c.recordIndex){if(a=this.getNextTrEl(c.el)){f=d.colKeyIndex;b=c.colKeyIndex;if(f>b)for(d=f;d>=b;d--){h=a.cells[d];this.selectCell(h)}else for(d=f;d<=b;d++){h=a.cells[d];this.selectCell(h)}}}else{f=Math.min(d.colKeyIndex,c.colKeyIndex);b=Math.max(d.colKeyIndex,c.colKeyIndex);for(d=f;d<=b;d++)this.unselectCell(h.cells[d])}else if(b==
+38)if(d.recordIndex>=c.recordIndex){if(a=this.getPreviousTrEl(c.el)){f=d.colKeyIndex;b=c.colKeyIndex;if(f>b)for(d=f;d>=b;d--){h=a.cells[d];this.selectCell(h)}else for(d=f;d<=b;d++){h=a.cells[d];this.selectCell(h)}}}else{f=Math.min(d.colKeyIndex,c.colKeyIndex);b=Math.max(d.colKeyIndex,c.colKeyIndex);for(d=f;d<=b;d++)this.unselectCell(h.cells[d])}else if(b==39)if(d.colKeyIndex<=c.colKeyIndex){if(c.colKeyIndex<h.cells.length-1){f=d.trIndex;b=c.trIndex;if(f>b)for(d=f;d>=b;d--){h=a[d].cells[c.colKeyIndex+
+1];this.selectCell(h)}else for(d=f;d<=b;d++){h=a[d].cells[c.colKeyIndex+1];this.selectCell(h)}}}else{f=Math.min(d.trIndex,c.trIndex);b=Math.max(d.trIndex,c.trIndex);for(d=f;d<=b;d++)this.unselectCell(a[d].cells[c.colKeyIndex])}else if(b==37)if(d.colKeyIndex>=c.colKeyIndex){if(c.colKeyIndex>0){f=d.trIndex;b=c.trIndex;if(f>b)for(d=f;d>=b;d--){h=a[d].cells[c.colKeyIndex-1];this.selectCell(h)}else for(d=f;d<=b;d++){h=a[d].cells[c.colKeyIndex-1];this.selectCell(h)}}}else{f=Math.min(d.trIndex,c.trIndex);
+b=Math.max(d.trIndex,c.trIndex);for(d=f;d<=b;d++)this.unselectCell(a[d].cells[c.colKeyIndex])}}},_handleCellRangeSelectionByMouse:function(a){var b=this.getTdEl(a.target);if(b){var c=a.event,d=c.shiftKey,f=c.ctrlKey||navigator.userAgent.toLowerCase().indexOf("mac")!=-1&&c.metaKey,g=this.getTrEl(b),c=this.getTrIndex(g),h=this.getColumn(b),j=h.getKeyIndex(),m=this.getRecord(g),r=this._oRecordSet.getRecordIndex(m),s={record:m,column:h},h=this._getSelectionAnchor(),m=this.getTbodyEl().rows;if(d&&f)if(h)if(this.isSelected(h.cell))if(h.recordIndex===
+r)if(h.colKeyIndex<j)for(a=h.colKeyIndex+1;a<=j;a++)this.selectCell(g.cells[a]);else{if(j<h.colKeyIndex)for(a=j;a<h.colKeyIndex;a++)this.selectCell(g.cells[a])}else if(h.recordIndex<r){for(a=h.colKeyIndex+1;a<g.cells.length;a++)this.selectCell(g.cells[a]);for(a=h.trIndex+1;a<c;a++)for(d=0;d<m[a].cells.length;d++)this.selectCell(m[a].cells[d]);for(a=0;a<=j;a++)this.selectCell(g.cells[a])}else{for(a=j;a<g.cells.length;a++)this.selectCell(g.cells[a]);for(a=c+1;a<h.trIndex;a++)for(d=0;d<m[a].cells.length;d++)this.selectCell(m[a].cells[d]);
+for(a=0;a<h.colKeyIndex;a++)this.selectCell(g.cells[a])}else{if(h.recordIndex===r)if(h.colKeyIndex<j)for(a=h.colKeyIndex+1;a<j;a++)this.unselectCell(g.cells[a]);else if(j<h.colKeyIndex)for(a=j+1;a<h.colKeyIndex;a++)this.unselectCell(g.cells[a]);if(h.recordIndex<r)for(a=h.trIndex;a<=c;a++){g=m[a];for(d=0;d<g.cells.length;d++)g.sectionRowIndex===h.trIndex?d>h.colKeyIndex&&this.unselectCell(g.cells[d]):g.sectionRowIndex===c?d<j&&this.unselectCell(g.cells[d]):this.unselectCell(g.cells[d])}else for(a=
+c;a<=h.trIndex;a++){g=m[a];for(d=0;d<g.cells.length;d++)g.sectionRowIndex==c?d>j&&this.unselectCell(g.cells[d]):g.sectionRowIndex==h.trIndex?d<h.colKeyIndex&&this.unselectCell(g.cells[d]):this.unselectCell(g.cells[d])}this.selectCell(b)}else{this._oAnchorCell=s;this.isSelected(s)?this.unselectCell(s):this.selectCell(s)}else if(d){this.unselectAllCells();if(h)if(h.recordIndex===r)if(h.colKeyIndex<j)for(a=h.colKeyIndex;a<=j;a++)this.selectCell(g.cells[a]);else{if(j<h.colKeyIndex)for(a=j;a<=h.colKeyIndex;a++)this.selectCell(g.cells[a])}else if(h.recordIndex<
+r)for(a=h.trIndex;a<=c;a++){g=m[a];for(d=0;d<g.cells.length;d++)g.sectionRowIndex==h.trIndex?d>=h.colKeyIndex&&this.selectCell(g.cells[d]):g.sectionRowIndex==c?d<=j&&this.selectCell(g.cells[d]):this.selectCell(g.cells[d])}else for(a=c;a<=h.trIndex;a++){g=m[a];for(d=0;d<g.cells.length;d++)g.sectionRowIndex==c?d>=j&&this.selectCell(g.cells[d]):g.sectionRowIndex==h.trIndex?d<=h.colKeyIndex&&this.selectCell(g.cells[d]):this.selectCell(g.cells[d])}else{this._oAnchorCell=s;this.selectCell(s)}}else if(f){this._oAnchorCell=
+s;this.isSelected(s)?this.unselectCell(s):this.selectCell(s)}else this._handleSingleCellSelectionByMouse(a)}},_handleCellRangeSelectionByKey:function(a){var b=g.getCharCode(a),c=a.shiftKey;if(b==9||!c)this._handleSingleCellSelectionByKey(a);else if(b>36&&b<41){c=this._getSelectionTrigger();if(!c)return null;g.stopEvent(a);var d=this._getSelectionAnchor(c),f;f=this.getTbodyEl().rows;a=c.el.parentNode;if(b==40){b=this.getNextTrEl(c.el);if(d.recordIndex<=c.recordIndex){for(d=c.colKeyIndex+1;d<a.cells.length;d++){f=
+a.cells[d];this.selectCell(f)}if(b)for(d=0;d<=c.colKeyIndex;d++){f=b.cells[d];this.selectCell(f)}}else{for(d=c.colKeyIndex;d<a.cells.length;d++)this.unselectCell(a.cells[d]);if(b)for(d=0;d<c.colKeyIndex;d++)this.unselectCell(b.cells[d])}}else if(b==38){b=this.getPreviousTrEl(c.el);if(d.recordIndex>=c.recordIndex){for(d=c.colKeyIndex-1;d>-1;d--){f=a.cells[d];this.selectCell(f)}if(b)for(d=a.cells.length-1;d>=c.colKeyIndex;d--){f=b.cells[d];this.selectCell(f)}}else{for(d=c.colKeyIndex;d>-1;d--)this.unselectCell(a.cells[d]);
+if(b)for(d=a.cells.length-1;d>c.colKeyIndex;d--)this.unselectCell(b.cells[d])}}else if(b==39){b=this.getNextTrEl(c.el);if(d.recordIndex<c.recordIndex)if(c.colKeyIndex<a.cells.length-1){f=a.cells[c.colKeyIndex+1];this.selectCell(f)}else{if(b){f=b.cells[0];this.selectCell(f)}}else if(d.recordIndex>c.recordIndex)this.unselectCell(a.cells[c.colKeyIndex]);else if(d.colKeyIndex<=c.colKeyIndex)if(c.colKeyIndex<a.cells.length-1){f=a.cells[c.colKeyIndex+1];this.selectCell(f)}else{if(c.trIndex<f.length-1){f=
+b.cells[0];this.selectCell(f)}}else this.unselectCell(a.cells[c.colKeyIndex])}else if(b==37){b=this.getPreviousTrEl(c.el);if(d.recordIndex<c.recordIndex)this.unselectCell(a.cells[c.colKeyIndex]);else if(d.recordIndex>c.recordIndex)if(c.colKeyIndex>0){f=a.cells[c.colKeyIndex-1];this.selectCell(f)}else{if(c.trIndex>0){f=b.cells[b.cells.length-1];this.selectCell(f)}}else if(d.colKeyIndex>=c.colKeyIndex)if(c.colKeyIndex>0){f=a.cells[c.colKeyIndex-1];this.selectCell(f)}else{if(c.trIndex>0){f=b.cells[b.cells.length-
+1];this.selectCell(f)}}else this.unselectCell(a.cells[c.colKeyIndex])}}},_handleSingleCellSelectionByMouse:function(a){var b=this.getTdEl(a.target);if(b){a=this.getRecord(this.getTrEl(b));b=this.getColumn(b);this._oAnchorCell=a={record:a,column:b};this.unselectAllCells();this.selectCell(a)}},_handleSingleCellSelectionByKey:function(a){var b=g.getCharCode(a);if(b==9||b>36&&b<41){var c=a.shiftKey,d=this._getSelectionTrigger();if(!d)return null;var f;if(b==40){f=this.getBelowTdEl(d.el);if(f===null)f=
+d.el}else if(b==38){f=this.getAboveTdEl(d.el);if(f===null)f=d.el}else if(b==39||!c&&b==9){f=this.getNextTdEl(d.el);if(f===null)return}else if(b==37||c&&b==9){f=this.getPreviousTdEl(d.el);if(f===null)return}g.stopEvent(a);this.unselectAllCells();this.selectCell(f);this._oAnchorCell={record:this.getRecord(f),column:this.getColumn(f)}}},getSelectedTrEls:function(){return f.getElementsByClassName(h.CLASS_SELECTED,"tr",this._elTbody)},selectRow:function(b){var c;if(b instanceof YAHOO.widget.Record){b=
+this._oRecordSet.getRecord(b);c=this.getTrEl(b)}else if(a.isNumber(b)){b=this.getRecord(b);c=this.getTrEl(b)}else{c=this.getTrEl(b);b=this.getRecord(c)}if(b){var d=this._aSelections||[],g=b.getId(),j=-1;if(d.indexOf)j=d.indexOf(g);else for(var p=d.length-1;p>-1;p--)if(d[p]===g){j=p;break}j>-1&&d.splice(j,1);d.push(g);this._aSelections=d;if(!this._oAnchorRecord)this._oAnchorRecord=b;c&&f.addClass(c,h.CLASS_SELECTED);this.fireEvent("rowSelectEvent",{record:b,el:c})}},unselectRow:function(b){var c=this.getTrEl(b);
+if(b=b instanceof YAHOO.widget.Record?this._oRecordSet.getRecord(b):a.isNumber(b)?this.getRecord(b):this.getRecord(c)){var d=this._aSelections||[],g=b.getId(),j=-1;if(d.indexOf)j=d.indexOf(g);else for(var p=d.length-1;p>-1;p--)if(d[p]===g){j=p;break}if(j>-1){d.splice(j,1);this._aSelections=d;f.removeClass(c,h.CLASS_SELECTED);this.fireEvent("rowUnselectEvent",{record:b,el:c})}}},unselectAllRows:function(){for(var b=this._aSelections||[],c,d=[],f=b.length-1;f>-1;f--)if(a.isString(b[f])){c=b.splice(f,
+1);d[d.length]=this.getRecord(a.isArray(c)?c[0]:c)}this._aSelections=b;this._unselectAllTrEls();this.fireEvent("unselectAllRowsEvent",{records:d})},_unselectAllTdEls:function(){var a=f.getElementsByClassName(h.CLASS_SELECTED,"td",this._elTbody);f.removeClass(a,h.CLASS_SELECTED)},getSelectedTdEls:function(){return f.getElementsByClassName(h.CLASS_SELECTED,"td",this._elTbody)},selectCell:function(a){if(a=this.getTdEl(a)){var b=this.getRecord(a),c=this.getColumn(this.getCellIndex(a)),d=c.getKey();if(b&&
+d){for(var g=this._aSelections||[],j=b.getId(),n=g.length-1;n>-1;n--)if(g[n].recordId===j&&g[n].columnKey===d){g.splice(n,1);break}g.push({recordId:j,columnKey:d});this._aSelections=g;if(!this._oAnchorCell)this._oAnchorCell={record:b,column:c};f.addClass(a,h.CLASS_SELECTED);this.fireEvent("cellSelectEvent",{record:b,column:c,key:d,el:a})}}},unselectCell:function(a){if(a=this.getTdEl(a)){var b=this.getRecord(a),c=this.getColumn(this.getCellIndex(a)),d=c.getKey();if(b&&d)for(var g=this._aSelections||
+[],j=b.getId(),n=g.length-1;n>-1;n--)if(g[n].recordId===j&&g[n].columnKey===d){g.splice(n,1);this._aSelections=g;f.removeClass(a,h.CLASS_SELECTED);this.fireEvent("cellUnselectEvent",{record:b,column:c,key:d,el:a});break}}},unselectAllCells:function(){for(var b=this._aSelections||[],c=b.length-1;c>-1;c--)a.isObject(b[c])&&b.splice(c,1);this._aSelections=b;this._unselectAllTdEls();this.fireEvent("unselectAllCellsEvent")},isSelected:function(b){if(b&&b.ownerDocument==document)return f.hasClass(this.getTdEl(b),
+h.CLASS_SELECTED)||f.hasClass(this.getTrEl(b),h.CLASS_SELECTED);var c,d=this._aSelections;if(d&&d.length>0){b instanceof YAHOO.widget.Record?c=b:a.isNumber(b)&&(c=this.getRecord(b));if(c){c=c.getId();if(d.indexOf){if(d.indexOf(c)>-1)return true}else for(b=d.length-1;b>-1;b--)if(d[b]===c)return true}else if(b.record&&b.column){c=b.record.getId();for(var g=b.column.getKey(),b=d.length-1;b>-1;b--)if(d[b].recordId===c&&d[b].columnKey===g)return true}}return false},getSelectedRows:function(){for(var b=
+[],c=this._aSelections||[],d=0;d<c.length;d++)a.isString(c[d])&&b.push(c[d]);return b},getSelectedCells:function(){for(var b=[],c=this._aSelections||[],d=0;d<c.length;d++)c[d]&&a.isObject(c[d])&&b.push(c[d]);return b},getLastSelectedRecord:function(){var b=this._aSelections;if(b&&b.length>0)for(var c=b.length-1;c>-1;c--)if(a.isString(b[c]))return b[c]},getLastSelectedCell:function(){var a=this._aSelections;if(a&&a.length>0)for(var b=a.length-1;b>-1;b--)if(a[b].recordId&&a[b].columnKey)return a[b]},
+highlightRow:function(a){if(a=this.getTrEl(a)){var b=this.getRecord(a);f.addClass(a,h.CLASS_HIGHLIGHTED);this.fireEvent("rowHighlightEvent",{record:b,el:a})}},unhighlightRow:function(a){if(a=this.getTrEl(a)){var b=this.getRecord(a);f.removeClass(a,h.CLASS_HIGHLIGHTED);this.fireEvent("rowUnhighlightEvent",{record:b,el:a})}},highlightCell:function(a){if(a=this.getTdEl(a)){this._elLastHighlightedTd&&this.unhighlightCell(this._elLastHighlightedTd);var b=this.getRecord(a),c=this.getColumn(this.getCellIndex(a)),
+d=c.getKey();f.addClass(a,h.CLASS_HIGHLIGHTED);this._elLastHighlightedTd=a;this.fireEvent("cellHighlightEvent",{record:b,column:c,key:d,el:a})}},unhighlightCell:function(a){if(a=this.getTdEl(a)){var b=this.getRecord(a);f.removeClass(a,h.CLASS_HIGHLIGHTED);this._elLastHighlightedTd=null;this.fireEvent("cellUnhighlightEvent",{record:b,column:this.getColumn(this.getCellIndex(a)),key:this.getColumn(this.getCellIndex(a)).getKey(),el:a})}},addCellEditor:function(a,b){a.editor=b;a.editor.subscribe("showEvent",
+this._onEditorShowEvent,this,true);a.editor.subscribe("keydownEvent",this._onEditorKeydownEvent,this,true);a.editor.subscribe("revertEvent",this._onEditorRevertEvent,this,true);a.editor.subscribe("saveEvent",this._onEditorSaveEvent,this,true);a.editor.subscribe("cancelEvent",this._onEditorCancelEvent,this,true);a.editor.subscribe("blurEvent",this._onEditorBlurEvent,this,true);a.editor.subscribe("blockEvent",this._onEditorBlockEvent,this,true);a.editor.subscribe("unblockEvent",this._onEditorUnblockEvent,
+this,true)},getCellEditor:function(){return this._oCellEditor},showCellEditor:function(b,c,d){if(b=this.getTdEl(b))if((d=this.getColumn(b))&&d.editor){var j=this._oCellEditor;j&&(this._oCellEditor.cancel?this._oCellEditor.cancel():j.isActive&&this.cancelCellEditor());if(d.editor instanceof YAHOO.widget.BaseCellEditor){j=d.editor;if(b=j.attach(this,b)){j.render();j.move();if(b=this.doBeforeShowCellEditor(j)){j.show();this._oCellEditor=j}}}else{if(!c||!(c instanceof YAHOO.widget.Record))c=this.getRecord(b);
+if(!d||!(d instanceof YAHOO.widget.Column))d=this.getColumn(b);if(c&&d){(!this._oCellEditor||this._oCellEditor.container)&&this._initCellEditorEl();j=this._oCellEditor;j.cell=b;j.record=c;j.column=d;j.validator=d.editorOptions&&a.isFunction(d.editorOptions.validator)?d.editorOptions.validator:null;j.value=c.getData(d.key);j.defaultValue=null;var c=j.container,q=f.getX(b),p=f.getY(b);if(isNaN(q)||isNaN(p)){q=b.offsetLeft+f.getX(this._elTbody.parentNode)-this._elTbody.scrollLeft;p=b.offsetTop+f.getY(this._elTbody.parentNode)-
+this._elTbody.scrollTop+this._elThead.offsetHeight}c.style.left=q+"px";c.style.top=p+"px";this.doBeforeShowCellEditor(this._oCellEditor);c.style.display="";g.addListener(c,"keydown",function(a,b){if(a.keyCode==27){b.cancelCellEditor();b.focusTbodyEl()}else b.fireEvent("editorKeydownEvent",{editor:b._oCellEditor,event:a})},this);var n;if(a.isString(d.editor))switch(d.editor){case "checkbox":n=h.editCheckbox;break;case "date":n=h.editDate;break;case "dropdown":n=h.editDropdown;break;case "radio":n=
+h.editRadio;break;case "textarea":n=h.editTextarea;break;case "textbox":n=h.editTextbox;break;default:n=null}else if(a.isFunction(d.editor))n=d.editor;if(n){n(this._oCellEditor,this);(!d.editorOptions||!d.editorOptions.disableBtns)&&this.showCellEditorBtns(c);j.isActive=true;this.fireEvent("editorShowEvent",{editor:j})}}}}},_initCellEditorEl:function(){var a=document.createElement("div");a.id=this._sId+"-celleditor";a.style.display="none";a.tabIndex=0;f.addClass(a,h.CLASS_EDITOR);var b=f.getFirstChild(document.body),
+a=b?f.insertBefore(a,b):document.body.appendChild(a),b={};b.container=a;b.value=null;b.isActive=false;this._oCellEditor=b},doBeforeShowCellEditor:function(){return true},saveCellEditor:function(){if(this._oCellEditor)if(this._oCellEditor.save)this._oCellEditor.save();else if(this._oCellEditor.isActive){var a=this._oCellEditor.value,b=this._oCellEditor.record.getData(this._oCellEditor.column.key);if(this._oCellEditor.validator){a=this._oCellEditor.value=this._oCellEditor.validator.call(this,a,b,this._oCellEditor);
+if(a===null){this.resetCellEditor();this.fireEvent("editorRevertEvent",{editor:this._oCellEditor,oldData:b,newData:a});return}}this._oRecordSet.updateRecordValue(this._oCellEditor.record,this._oCellEditor.column.key,this._oCellEditor.value);this.formatCell(this._oCellEditor.cell.firstChild,this._oCellEditor.record,this._oCellEditor.column);this._oChainRender.add({method:function(){this.validateColumnWidths()},scope:this});this._oChainRender.run();this.resetCellEditor();this.fireEvent("editorSaveEvent",
+{editor:this._oCellEditor,oldData:b,newData:a})}},cancelCellEditor:function(){if(this._oCellEditor)if(this._oCellEditor.cancel)this._oCellEditor.cancel();else if(this._oCellEditor.isActive){this.resetCellEditor();this.fireEvent("editorCancelEvent",{editor:this._oCellEditor})}},destroyCellEditor:function(){if(this._oCellEditor){this._oCellEditor.destroy();this._oCellEditor=null}},_onEditorShowEvent:function(a){this.fireEvent("editorShowEvent",a)},_onEditorKeydownEvent:function(a){this.fireEvent("editorKeydownEvent",
+a)},_onEditorRevertEvent:function(a){this.fireEvent("editorRevertEvent",a)},_onEditorSaveEvent:function(a){this.fireEvent("editorSaveEvent",a)},_onEditorCancelEvent:function(a){this.fireEvent("editorCancelEvent",a)},_onEditorBlurEvent:function(a){this.fireEvent("editorBlurEvent",a)},_onEditorBlockEvent:function(a){this.fireEvent("editorBlockEvent",a)},_onEditorUnblockEvent:function(a){this.fireEvent("editorUnblockEvent",a)},onEditorBlurEvent:function(a){a.editor.disableBtns?a.editor.save&&a.editor.save():
+a.editor.cancel&&a.editor.cancel()},onEditorBlockEvent:function(){this.disable()},onEditorUnblockEvent:function(){this.undisable()},doBeforeLoadData:function(){return true},onEventSortColumn:function(a){var b=a.event,a=a.target;if(a=this.getThEl(a)||this.getTdEl(a)){a=this.getColumn(a);if(a.sortable){g.stopEvent(b);this.sortColumn(a)}}},onEventSelectColumn:function(a){this.selectColumn(a.target)},onEventHighlightColumn:function(a){this.highlightColumn(a.target)},onEventUnhighlightColumn:function(a){this.unhighlightColumn(a.target)},
+onEventSelectRow:function(a){this.get("selectionMode")=="single"?this._handleSingleSelectionByMouse(a):this._handleStandardSelectionByMouse(a)},onEventSelectCell:function(a){var b=this.get("selectionMode");b=="cellblock"?this._handleCellBlockSelectionByMouse(a):b=="cellrange"?this._handleCellRangeSelectionByMouse(a):this._handleSingleCellSelectionByMouse(a)},onEventHighlightRow:function(a){this.highlightRow(a.target)},onEventUnhighlightRow:function(a){this.unhighlightRow(a.target)},onEventHighlightCell:function(a){this.highlightCell(a.target)},
+onEventUnhighlightCell:function(a){this.unhighlightCell(a.target)},onEventFormatCell:function(a){if(a=this.getTdEl(a.target)){var b=this.getColumn(this.getCellIndex(a));this.formatCell(a.firstChild,this.getRecord(a),b)}},onEventShowCellEditor:function(a){this.isDisabled()||this.showCellEditor(a.target)},onEventSaveCellEditor:function(){this._oCellEditor&&(this._oCellEditor.save?this._oCellEditor.save():this.saveCellEditor())},onEventCancelCellEditor:function(){this._oCellEditor&&(this._oCellEditor.cancel?
+this._oCellEditor.cancel():this.cancelCellEditor())},onDataReturnInitializeTable:function(a,b,c){if(this instanceof h&&this._sId){this.initializeTable();this.onDataReturnSetRows(a,b,c)}},onDataReturnReplaceRows:function(b,c,d){if(this instanceof h&&this._sId){this.fireEvent("dataReturnEvent",{request:b,response:c,payload:d});var f=this.doBeforeLoadData(b,c,d),g=this.get("paginator"),j=0;if(f&&c&&!c.error&&a.isArray(c.results)){this._oRecordSet.reset();if(this.get("dynamicData"))d&&d.pagination&&a.isNumber(d.pagination.recordOffset)?
+j=d.pagination.recordOffset:g&&(j=g.getStartIndex());this._oRecordSet.setRecords(c.results,j|0);this._handleDataReturnPayload(b,c,d);this.render()}else f&&c.error&&this.showTableMessage(this.get("MSG_ERROR"),h.CLASS_ERROR)}},onDataReturnAppendRows:function(b,c,d){if(this instanceof h&&this._sId){this.fireEvent("dataReturnEvent",{request:b,response:c,payload:d});var f=this.doBeforeLoadData(b,c,d);if(f&&c&&!c.error&&a.isArray(c.results)){this.addRows(c.results);this._handleDataReturnPayload(b,c,d)}else f&&
+c.error&&this.showTableMessage(this.get("MSG_ERROR"),h.CLASS_ERROR)}},onDataReturnInsertRows:function(b,c,d){if(this instanceof h&&this._sId){this.fireEvent("dataReturnEvent",{request:b,response:c,payload:d});var f=this.doBeforeLoadData(b,c,d);if(f&&c&&!c.error&&a.isArray(c.results)){this.addRows(c.results,d?d.insertIndex:0);this._handleDataReturnPayload(b,c,d)}else f&&c.error&&this.showTableMessage(this.get("MSG_ERROR"),h.CLASS_ERROR)}},onDataReturnUpdateRows:function(b,c,d){if(this instanceof h&&
+this._sId){this.fireEvent("dataReturnEvent",{request:b,response:c,payload:d});var f=this.doBeforeLoadData(b,c,d);if(f&&c&&!c.error&&a.isArray(c.results)){this.updateRows(d?d.updateIndex:0,c.results);this._handleDataReturnPayload(b,c,d)}else f&&c.error&&this.showTableMessage(this.get("MSG_ERROR"),h.CLASS_ERROR)}},onDataReturnSetRows:function(b,c,d){if(this instanceof h&&this._sId){this.fireEvent("dataReturnEvent",{request:b,response:c,payload:d});var f=this.doBeforeLoadData(b,c,d),g=this.get("paginator"),
+j=0;if(f&&c&&!c.error&&a.isArray(c.results)){if(this.get("dynamicData")){d&&d.pagination&&a.isNumber(d.pagination.recordOffset)?j=d.pagination.recordOffset:g&&(j=g.getStartIndex());this._oRecordSet.reset()}this._oRecordSet.setRecords(c.results,j|0);this._handleDataReturnPayload(b,c,d);this.render()}else f&&c.error&&this.showTableMessage(this.get("MSG_ERROR"),h.CLASS_ERROR)}},handleDataReturnPayload:function(a,b,c){return c||{}},_handleDataReturnPayload:function(c,d,f){if(f=this.handleDataReturnPayload(c,
+d,f)){if(c=this.get("paginator")){this.get("dynamicData")?b.Paginator.isNumeric(f.totalRecords)&&c.set("totalRecords",f.totalRecords):c.set("totalRecords",this._oRecordSet.getLength());if(a.isObject(f.pagination)){c.set("rowsPerPage",f.pagination.rowsPerPage);c.set("recordOffset",f.pagination.recordOffset)}}f.sortedBy?this.set("sortedBy",f.sortedBy):f.sorting&&this.set("sortedBy",f.sorting)}},showCellEditorBtns:function(a){a=a.appendChild(document.createElement("div"));f.addClass(a,h.CLASS_BUTTON);
+var b=a.appendChild(document.createElement("button"));f.addClass(b,h.CLASS_DEFAULT);b.innerHTML="OK";g.addListener(b,"click",function(a,b){b.onEventSaveCellEditor(a,b);b.focusTbodyEl()},this,true);a=a.appendChild(document.createElement("button"));a.innerHTML="Cancel";g.addListener(a,"click",function(a,b){b.onEventCancelCellEditor(a,b);b.focusTbodyEl()},this,true)},resetCellEditor:function(){var a=this._oCellEditor.container;a.style.display="none";g.purgeElement(a,true);a.innerHTML="";this._oCellEditor.value=
+null;this._oCellEditor.isActive=false},getBody:function(){return this.getTbodyEl()},getCell:function(a){return this.getTdEl(a)},getRow:function(a){return this.getTrEl(a)},refreshView:function(){this.render()},select:function(b){a.isArray(b)||(b=[b]);for(var c=0;c<b.length;c++)this.selectRow(b[c])},onEventEditCell:function(a){this.onEventShowCellEditor(a)},_syncColWidths:function(){this.validateColumnWidths()}});h.prototype.onDataReturnSetRecords=h.prototype.onDataReturnSetRows;h.prototype.onPaginatorChange=
+h.prototype.onPaginatorChangeRequest;h.editCheckbox=function(){};h.editDate=function(){};h.editDropdown=function(){};h.editRadio=function(){};h.editTextarea=function(){};h.editTextbox=function(){}})();
+(function(){var a=YAHOO.lang,c=YAHOO.util,b=YAHOO.widget,d=YAHOO.env.ua,f=c.Dom,g=c.Event,j=b.DataTable;b.ScrollingDataTable=function(a,c,d,f){f=f||{};if(f.scrollable)f.scrollable=false;this._init();b.ScrollingDataTable.superclass.constructor.call(this,a,c,d,f);this.subscribe("columnShowEvent",this._onColumnChange)};var h=b.ScrollingDataTable;a.augmentObject(h,{CLASS_HEADER:"yui-dt-hd",CLASS_BODY:"yui-dt-bd"});a.extend(h,j,{_elHdContainer:null,_elHdTable:null,_elBdContainer:null,_elBdThead:null,_elTmpContainer:null,
+_elTmpTable:null,_bScrollbarX:null,initAttributes:function(b){b=b||{};h.superclass.initAttributes.call(this,b);this.setAttributeConfig("width",{value:null,validator:a.isString,method:function(a){if(this._elHdContainer&&this._elBdContainer){this._elHdContainer.style.width=a;this._elBdContainer.style.width=a;this._syncScrollX();this._syncScrollOverhang()}}});this.setAttributeConfig("height",{value:null,validator:a.isString,method:function(a){if(this._elHdContainer&&this._elBdContainer){this._elBdContainer.style.height=
+a;this._syncScrollX();this._syncScrollY();this._syncScrollOverhang()}}});this.setAttributeConfig("COLOR_COLUMNFILLER",{value:"#F2F2F2",validator:a.isString,method:function(a){if(this._elHdContainer)this._elHdContainer.style.backgroundColor=a}})},_init:function(){this._elTmpTable=this._elTmpContainer=this._elBdThead=this._elBdContainer=this._elHdTable=this._elHdContainer=null},_initDomElements:function(a){this._initContainerEl(a);if(this._elContainer&&this._elHdContainer&&this._elBdContainer){this._initTableEl();
+if(this._elHdTable&&this._elTable){this._initColgroupEl(this._elHdTable);this._initTheadEl(this._elHdTable,this._elTable);this._initTbodyEl(this._elTable);this._initMsgTbodyEl(this._elTable)}}return!this._elContainer||!this._elTable||!this._elColgroup||!this._elThead||!this._elTbody||!this._elMsgTbody||!this._elHdTable||!this._elBdThead?false:true},_destroyContainerEl:function(a){f.removeClass(a,j.CLASS_SCROLLABLE);h.superclass._destroyContainerEl.call(this,a);this._elBdContainer=this._elHdContainer=
+null},_initContainerEl:function(a){h.superclass._initContainerEl.call(this,a);if(this._elContainer){a=this._elContainer;f.addClass(a,j.CLASS_SCROLLABLE);var b=document.createElement("div");b.style.width=this.get("width")||"";b.style.backgroundColor=this.get("COLOR_COLUMNFILLER");f.addClass(b,h.CLASS_HEADER);this._elHdContainer=b;a.appendChild(b);b=document.createElement("div");b.style.width=this.get("width")||"";b.style.height=this.get("height")||"";f.addClass(b,h.CLASS_BODY);g.addListener(b,"scroll",
+this._onScroll,this);this._elBdContainer=b;a.appendChild(b)}},_initCaptionEl:function(){},_destroyHdTableEl:function(){var a=this._elHdTable;if(a){g.purgeElement(a,true);a.parentNode.removeChild(a);this._elBdThead=null}},_initTableEl:function(){if(this._elHdContainer){this._destroyHdTableEl();this._elHdTable=this._elHdContainer.appendChild(document.createElement("table"));g.delegate(this._elHdTable,"mouseenter",this._onTableMouseover,"thead ."+j.CLASS_LABEL,this);g.delegate(this._elHdTable,"mouseleave",
+this._onTableMouseout,"thead ."+j.CLASS_LABEL,this)}h.superclass._initTableEl.call(this,this._elBdContainer)},_initTheadEl:function(a,b){a=a||this._elHdTable;b=b||this._elTable;this._initBdTheadEl(b);h.superclass._initTheadEl.call(this,a)},_initThEl:function(a,b){h.superclass._initThEl.call(this,a,b);a.id=this.getId()+"-fixedth-"+b.getSanitizedKey()},_destroyBdTheadEl:function(){var a=this._elBdThead;if(a){var b=a.parentNode;g.purgeElement(a,true);b.removeChild(a);this._elBdThead=null;this._destroyColumnHelpers()}},
+_initBdTheadEl:function(a){if(a){this._destroyBdTheadEl();var a=a.insertBefore(document.createElement("thead"),a.firstChild),b=this._oColumnSet.tree,c,d,f,g,h,j,m;g=0;for(j=b.length;g<j;g++){d=a.appendChild(document.createElement("tr"));h=0;for(m=b[g].length;h<m;h++){f=b[g][h];c=d.appendChild(document.createElement("th"));this._initBdThEl(c,f,g,h)}}this._elBdThead=a}},_initBdThEl:function(b,c){b.id=this.getId()+"-th-"+c.getSanitizedKey();b.rowSpan=c.getRowspan();b.colSpan=c.getColspan();if(c.abbr)b.abbr=
+c.abbr;var d=c.getKey(),d=a.isValue(c.label)?c.label:d;b.innerHTML=d},_initTbodyEl:function(a){h.superclass._initTbodyEl.call(this,a);a.style.marginTop=this._elTbody.offsetTop>0?"-"+this._elTbody.offsetTop+"px":0},_focusEl:function(a){var a=a||this._elTbody,b=this;this._storeScrollPositions();setTimeout(function(){setTimeout(function(){try{a.focus();b._restoreScrollPositions()}catch(c){}},0)},0)},_runRenderChain:function(){this._storeScrollPositions();this._oChainRender.run()},_storeScrollPositions:function(){this._nScrollTop=
+this._elBdContainer.scrollTop;this._nScrollLeft=this._elBdContainer.scrollLeft},clearScrollPositions:function(){this._nScrollLeft=this._nScrollTop=0},_restoreScrollPositions:function(){if(this._nScrollTop){this._elBdContainer.scrollTop=this._nScrollTop;this._nScrollTop=null}if(this._nScrollLeft){this._elBdContainer.scrollLeft=this._nScrollLeft;this._elHdContainer.scrollLeft=this._nScrollLeft;this._nScrollLeft=null}},_validateColumnWidth:function(a,b){if(!a.width&&!a.hidden){var c=a.getThEl();a._calculatedWidth&&
+this._setColumnWidth(a,"auto","visible");if(c.offsetWidth!==b.offsetWidth){var c=c.offsetWidth>b.offsetWidth?a.getThLinerEl():b.firstChild,c=Math.max(0,c.offsetWidth-(parseInt(f.getStyle(c,"paddingLeft"),10)|0)-(parseInt(f.getStyle(c,"paddingRight"),10)|0),a.minWidth),d="visible";if(a.maxAutoWidth>0&&c>a.maxAutoWidth){c=a.maxAutoWidth;d="hidden"}this._elTbody.style.display="none";this._setColumnWidth(a,c+"px",d);a._calculatedWidth=c;this._elTbody.style.display=""}}},validateColumnWidths:function(b){var c=
+this._oColumnSet.keys,g=c.length,h=this.getFirstTrEl();d.ie&&this._setOverhangValue(1);if(c&&h&&h.childNodes.length===g){var j=this.get("width");if(j){this._elHdContainer.style.width="";this._elBdContainer.style.width=""}this._elContainer.style.width="";if(b&&a.isNumber(b.getKeyIndex()))this._validateColumnWidth(b,h.childNodes[b.getKeyIndex()]);else{var p,n=[],o;for(o=0;o<g;o++){b=c[o];!b.width&&(!b.hidden&&b._calculatedWidth)&&(n[n.length]=b)}this._elTbody.style.display="none";o=0;for(b=n.length;o<
+b;o++)this._setColumnWidth(n[o],"auto","visible");this._elTbody.style.display="";n=[];for(o=0;o<g;o++){b=c[o];p=h.childNodes[o];if(!b.width&&!b.hidden){var m=b.getThEl();if(m.offsetWidth!==p.offsetWidth){p=m.offsetWidth>p.offsetWidth?b.getThLinerEl():p.firstChild;p=Math.max(0,p.offsetWidth-(parseInt(f.getStyle(p,"paddingLeft"),10)|0)-(parseInt(f.getStyle(p,"paddingRight"),10)|0),b.minWidth);m="visible";if(b.maxAutoWidth>0&&p>b.maxAutoWidth){p=b.maxAutoWidth;m="hidden"}n[n.length]=[b,p,m]}}}this._elTbody.style.display=
+"none";o=0;for(b=n.length;o<b;o++){c=n[o];this._setColumnWidth(c[0],c[1]+"px",c[2]);c[0]._calculatedWidth=c[1]}this._elTbody.style.display=""}if(j){this._elHdContainer.style.width=j;this._elBdContainer.style.width=j}}this._syncScroll();this._restoreScrollPositions()},_syncScroll:function(){this._syncScrollX();this._syncScrollY();this._syncScrollOverhang();if(d.opera){this._elHdContainer.scrollLeft=this._elBdContainer.scrollLeft;if(!this.get("width"))document.body.style=document.body.style+""}},_syncScrollY:function(){var a=
+this._elTbody,b=this._elBdContainer;if(!this.get("width"))this._elContainer.style.width=b.scrollHeight>b.clientHeight?a.parentNode.clientWidth+19+"px":a.parentNode.clientWidth+2+"px"},_syncScrollX:function(){var a=this._elTbody,b=this._elBdContainer;if(!this.get("height")&&d.ie)b.style.height=b.scrollWidth>b.offsetWidth?a.parentNode.offsetHeight+18+"px":a.parentNode.offsetHeight+"px";this._elMsgTbody.parentNode.style.width=this._elTbody.rows.length===0?this.getTheadEl().parentNode.offsetWidth+"px":
+""},_syncScrollOverhang:function(){var a=this._elBdContainer,b=1;a.scrollHeight>a.clientHeight&&a.scrollWidth>a.clientWidth&&(b=18);this._setOverhangValue(b)},_setOverhangValue:function(a){var b=this._oColumnSet.headers[this._oColumnSet.headers.length-1]||[],c=b.length,d=this._sId+"-fixedth-",a=a+"px solid "+this.get("COLOR_COLUMNFILLER");this._elThead.style.display="none";for(var g=0;g<c;g++)f.get(d+b[g]).style.borderRight=a;this._elThead.style.display=""},getHdContainerEl:function(){return this._elHdContainer},
+getBdContainerEl:function(){return this._elBdContainer},getHdTableEl:function(){return this._elHdTable},getBdTableEl:function(){return this._elTable},disable:function(){var a=this._elMask;a.style.width=this._elBdContainer.offsetWidth+"px";a.style.height=this._elHdContainer.offsetHeight+this._elBdContainer.offsetHeight+"px";a.style.display="";this.fireEvent("disableEvent")},removeColumn:function(a){var b=this._elHdContainer.scrollLeft,c=this._elBdContainer.scrollLeft,a=h.superclass.removeColumn.call(this,
+a);this._elHdContainer.scrollLeft=b;this._elBdContainer.scrollLeft=c;return a},insertColumn:function(a,b){var c=this._elHdContainer.scrollLeft,d=this._elBdContainer.scrollLeft,f=h.superclass.insertColumn.call(this,a,b);this._elHdContainer.scrollLeft=c;this._elBdContainer.scrollLeft=d;return f},reorderColumn:function(a,b){var c=this._elHdContainer.scrollLeft,d=this._elBdContainer.scrollLeft,f=h.superclass.reorderColumn.call(this,a,b);this._elHdContainer.scrollLeft=c;this._elBdContainer.scrollLeft=
+d;return f},setColumnWidth:function(b,c){if(b=this.getColumn(b)){this._storeScrollPositions();if(a.isNumber(c)){c=c>b.minWidth?c:b.minWidth;b.width=c;this._setColumnWidth(b,c+"px");this._syncScroll();this.fireEvent("columnSetWidthEvent",{column:b,width:c})}else if(c===null){b.width=c;this._setColumnWidth(b,"auto");this.validateColumnWidths(b);this.fireEvent("columnUnsetWidthEvent",{column:b})}this._clearTrTemplateEl()}},scrollTo:function(a){var b=this.getTdEl(a);if(b){this.clearScrollPositions();
+this.getBdContainerEl().scrollLeft=b.offsetLeft;this.getBdContainerEl().scrollTop=b.parentNode.offsetTop}else if(a=this.getTrEl(a)){this.clearScrollPositions();this.getBdContainerEl().scrollTop=a.offsetTop}},showTableMessage:function(b,c){var d=this._elMsgTd;if(a.isString(b))d.firstChild.innerHTML=b;a.isString(c)&&f.addClass(d.firstChild,c);this.getTheadEl();this._elMsgTbody.parentNode.style.width=this.getTheadEl().parentNode.offsetWidth+"px";this._elMsgTbody.style.display="";this.fireEvent("tableMsgShowEvent",
+{html:b,className:c})},_onColumnChange:function(a){a=a.column?a.column:a.editor?a.editor.column:null;this._storeScrollPositions();this.validateColumnWidths(a)},_onScroll:function(a,b){b._elHdContainer.scrollLeft=b._elBdContainer.scrollLeft;if(b._oCellEditor&&b._oCellEditor.isActive){b.fireEvent("editorBlurEvent",{editor:b._oCellEditor});b.cancelCellEditor()}var c=g.getTarget(a);c.nodeName.toLowerCase();b.fireEvent("tableScrollEvent",{event:a,target:c})},_onTheadKeydown:function(a,b){g.getCharCode(a)===
+9&&setTimeout(function(){if(b instanceof h&&b._sId)b._elBdContainer.scrollLeft=b._elHdContainer.scrollLeft},0);for(var c=g.getTarget(a),d=c.nodeName.toLowerCase(),f=true;c&&d!="table";){switch(d){case "body":return;case "thead":f=b.fireEvent("theadKeyEvent",{target:c,event:a})}if(f===false)return;(c=c.parentNode)&&(d=c.nodeName.toLowerCase())}b.fireEvent("tableKeyEvent",{target:c||b._elContainer,event:a})}})})();
+(function(){var a=YAHOO.lang,c=YAHOO.util,b=YAHOO.widget,d=YAHOO.env.ua,f=c.Dom,g=c.Event,j=b.DataTable;b.BaseCellEditor=function(a,b){this._sId=this._sId||f.generateId(null,"yui-ceditor");YAHOO.widget.BaseCellEditor._nCount++;this._sType=a;this._initConfigs(b);this._initEvents();this._needsRender=true};var h=b.BaseCellEditor;a.augmentObject(h,{_nCount:0,CLASS_CELLEDITOR:"yui-ceditor"});h.prototype={_sId:null,_sType:null,_oDataTable:null,_oColumn:null,_oRecord:null,_elTd:null,_elContainer:null,_elCancelBtn:null,
+_elSaveBtn:null,_initConfigs:function(a){if(a&&YAHOO.lang.isObject(a))for(var b in a)b&&(this[b]=a[b])},_initEvents:function(){this.createEvent("showEvent");this.createEvent("keydownEvent");this.createEvent("invalidDataEvent");this.createEvent("revertEvent");this.createEvent("saveEvent");this.createEvent("cancelEvent");this.createEvent("blurEvent");this.createEvent("blockEvent");this.createEvent("unblockEvent")},_initContainerEl:function(){if(this._elContainer){YAHOO.util.Event.purgeElement(this._elContainer,
+true);this._elContainer.innerHTML=""}var b=document.createElement("div");b.id=this.getId()+"-container";b.style.display="none";b.tabIndex=0;this.className=a.isArray(this.className)?this.className:this.className?[this.className]:[];this.className[this.className.length]=j.CLASS_EDITOR;b.className=this.className.join(" ");document.body.insertBefore(b,document.body.firstChild);this._elContainer=b},_initShimEl:function(){if(this.useIFrame&&!this._elIFrame){var a=document.createElement("iframe");a.src=
+"javascript:false";a.frameBorder=0;a.scrolling="no";a.style.display="none";a.className=j.CLASS_EDITOR_SHIM;a.tabIndex=-1;a.role="presentation";a.title="Presentational iframe shim";document.body.insertBefore(a,document.body.firstChild);this._elIFrame=a}},_hide:function(){this.getContainerEl().style.display="none";if(this._elIFrame)this._elIFrame.style.display="none";this.isActive=false;this.getDataTable()._oCellEditor=null},asyncSubmitter:null,value:null,defaultValue:null,validator:null,resetInvalidData:true,
+isActive:false,LABEL_SAVE:"Save",LABEL_CANCEL:"Cancel",disableBtns:false,useIFrame:false,className:null,toString:function(){return"CellEditor instance "+this._sId},getId:function(){return this._sId},getDataTable:function(){return this._oDataTable},getColumn:function(){return this._oColumn},getRecord:function(){return this._oRecord},getTdEl:function(){return this._elTd},getContainerEl:function(){return this._elContainer},destroy:function(){this.unsubscribeAll();var a=this.getColumn();if(a)a.editor=
+null;if(a=this.getContainerEl()){g.purgeElement(a,true);a.parentNode.removeChild(a)}},render:function(){if(this._needsRender){this._initContainerEl();this._initShimEl();g.addListener(this.getContainerEl(),"keydown",function(a,b){if(a.keyCode==27){var c=g.getTarget(a);c.nodeName&&c.nodeName.toLowerCase()==="select"&&c.blur();b.cancel()}b.fireEvent("keydownEvent",{editor:b,event:a})},this);this.renderForm();this.disableBtns||this.renderBtns();this.doAfterRender();this._needsRender=false}},renderBtns:function(){var a=
+this.getContainerEl().appendChild(document.createElement("div"));a.className=j.CLASS_BUTTON;var b=a.appendChild(document.createElement("button"));b.className=j.CLASS_DEFAULT;b.innerHTML=this.LABEL_SAVE;g.addListener(b,"click",function(){this.save()},this,true);this._elSaveBtn=b;a=a.appendChild(document.createElement("button"));a.innerHTML=this.LABEL_CANCEL;g.addListener(a,"click",function(){this.cancel()},this,true);this._elCancelBtn=a},attach:function(a,b){if(a instanceof YAHOO.widget.DataTable){this._oDataTable=
+a;if(b=a.getTdEl(b)){this._elTd=b;var c=a.getColumn(b);if(c){this._oColumn=c;if(c=a.getRecord(b)){this._oRecord=c;c=c.getData(this.getColumn().getField());this.value=c!==void 0?c:this.defaultValue;return true}}}}return false},move:function(){var a=this.getContainerEl(),b=this.getTdEl(),c=f.getX(b),d=f.getY(b);if(isNaN(c)||isNaN(d)){d=this.getDataTable().getTbodyEl();c=b.offsetLeft+f.getX(d.parentNode)-d.scrollLeft;d=b.offsetTop+f.getY(d.parentNode)-d.scrollTop+this.getDataTable().getTheadEl().offsetHeight}a.style.left=
+c+"px";a.style.top=d+"px";if(this._elIFrame){this._elIFrame.style.left=c+"px";this._elIFrame.style.top=d+"px"}},show:function(){var a=this.getContainerEl(),b=this._elIFrame;this.resetForm();this.isActive=true;a.style.display="";if(b){b.style.width=a.offsetWidth+"px";b.style.height=a.offsetHeight+"px";b.style.display=""}this.focus();this.fireEvent("showEvent",{editor:this})},block:function(){this.fireEvent("blockEvent",{editor:this})},unblock:function(){this.fireEvent("unblockEvent",{editor:this})},
+save:function(){var b=this.getInputValue(),c=b;if(this.validator){c=this.validator.call(this.getDataTable(),b,this.value,this);if(c===void 0){this.resetInvalidData&&this.resetForm();this.fireEvent("invalidDataEvent",{editor:this,oldData:this.value,newData:b});return}}var d=this,b=function(a,b){var c=d.value;if(a){d.value=b;d.getDataTable().updateCell(d.getRecord(),d.getColumn(),b);d._hide();d.fireEvent("saveEvent",{editor:d,oldData:c,newData:d.value})}else{d.resetForm();d.fireEvent("revertEvent",
+{editor:d,oldData:c,newData:b})}d.unblock()};this.block();a.isFunction(this.asyncSubmitter)?this.asyncSubmitter.call(this,b,c):b(true,c)},cancel:function(){if(this.isActive){this._hide();this.fireEvent("cancelEvent",{editor:this})}},renderForm:function(){},doAfterRender:function(){},handleDisabledBtns:function(){},resetForm:function(){},focus:function(){},getInputValue:function(){}};a.augmentProto(h,c.EventProvider);b.CheckboxCellEditor=function(a){a=a||{};this._sId=this._sId||f.generateId(null,"yui-checkboxceditor");
+YAHOO.widget.BaseCellEditor._nCount++;b.CheckboxCellEditor.superclass.constructor.call(this,a.type||"checkbox",a)};a.extend(b.CheckboxCellEditor,h,{checkboxOptions:null,checkboxes:null,value:null,renderForm:function(){if(a.isArray(this.checkboxOptions)){var b,c,d,f,g;f=0;for(g=this.checkboxOptions.length;f<g;f++){b=this.checkboxOptions[f];c=a.isValue(b.value)?b.value:b;d=this.getId()+"-chk"+f;this.getContainerEl().innerHTML+='<input type="checkbox" id="'+d+'" value="'+c+'" />';c=this.getContainerEl().appendChild(document.createElement("label"));
+c.htmlFor=d;c.innerHTML=a.isValue(b.label)?b.label:b}b=[];for(f=0;f<g;f++)b[b.length]=this.getContainerEl().childNodes[f*2];this.checkboxes=b;this.disableBtns&&this.handleDisabledBtns()}},handleDisabledBtns:function(){g.addListener(this.getContainerEl(),"click",function(a){g.getTarget(a).tagName.toLowerCase()==="input"&&this.save()},this,true)},resetForm:function(){for(var b=a.isArray(this.value)?this.value:[this.value],c=0,d=this.checkboxes.length;c<d;c++){this.checkboxes[c].checked=false;for(var f=
+0,g=b.length;f<g;f++)if(this.checkboxes[c].value==b[f])this.checkboxes[c].checked=true}},focus:function(){this.checkboxes[0].focus()},getInputValue:function(){for(var a=[],b=0,c=this.checkboxes.length;b<c;b++)if(this.checkboxes[b].checked)a[a.length]=this.checkboxes[b].value;return a}});a.augmentObject(b.CheckboxCellEditor,h);b.DateCellEditor=function(a){a=a||{};this._sId=this._sId||f.generateId(null,"yui-dateceditor");YAHOO.widget.BaseCellEditor._nCount++;b.DateCellEditor.superclass.constructor.call(this,
+a.type||"date",a)};a.extend(b.DateCellEditor,h,{calendar:null,calendarOptions:null,defaultValue:new Date,renderForm:function(){if(YAHOO.widget.Calendar){var a=this.getContainerEl().appendChild(document.createElement("div"));a.id=this.getId()+"-dateContainer";var b=new YAHOO.widget.Calendar(this.getId()+"-date",a.id,this.calendarOptions);b.render();a.style.cssFloat="none";b.hideEvent.subscribe(function(){this.cancel()},this,true);if(d.ie)this.getContainerEl().appendChild(document.createElement("div")).style.clear=
+"both";this.calendar=b;this.disableBtns&&this.handleDisabledBtns()}},handleDisabledBtns:function(){this.calendar.selectEvent.subscribe(function(){this.save()},this,true)},resetForm:function(){var a=this.value||new Date;this.calendar.select(a);this.calendar.cfg.setProperty("pagedate",a,false);this.calendar.render();this.calendar.show()},focus:function(){},getInputValue:function(){return this.calendar.getSelectedDates()[0]}});a.augmentObject(b.DateCellEditor,h);b.DropdownCellEditor=function(a){a=a||
+{};this._sId=this._sId||f.generateId(null,"yui-dropdownceditor");YAHOO.widget.BaseCellEditor._nCount++;b.DropdownCellEditor.superclass.constructor.call(this,a.type||"dropdown",a)};a.extend(b.DropdownCellEditor,h,{dropdownOptions:null,dropdown:null,multiple:false,size:null,renderForm:function(){var b=this.getContainerEl().appendChild(document.createElement("select"));b.style.zoom=1;if(this.multiple)b.multiple="multiple";if(a.isNumber(this.size))b.size=this.size;this.dropdown=b;if(a.isArray(this.dropdownOptions)){for(var c,
+d,f=0,g=this.dropdownOptions.length;f<g;f++){c=this.dropdownOptions[f];d=document.createElement("option");d.value=a.isValue(c.value)?c.value:c;d.innerHTML=a.isValue(c.label)?c.label:c;b.appendChild(d)}this.disableBtns&&this.handleDisabledBtns()}},handleDisabledBtns:function(){if(this.multiple)g.addListener(this.dropdown,"blur",function(){this.save()},this,true);else if(d.ie){g.addListener(this.dropdown,"blur",function(){this.save()},this,true);g.addListener(this.dropdown,"click",function(){this.save()},
+this,true)}else g.addListener(this.dropdown,"change",function(){this.save()},this,true)},resetForm:function(){var b=this.dropdown.options,c=0,d=b.length;if(a.isArray(this.value)){for(var f=this.value,g=0,h=f.length,j={};c<d;c++){b[c].selected=false;j[b[c].value]=b[c]}for(;g<h;g++)if(j[f[g]])j[f[g]].selected=true}else for(;c<d;c++)if(this.value==b[c].value)b[c].selected=true},focus:function(){this.getDataTable()._focusEl(this.dropdown)},getInputValue:function(){var a=this.dropdown.options;if(this.multiple){for(var b=
+[],c=0,d=a.length;c<d;c++)a[c].selected&&b.push(a[c].value);return b}return a[a.selectedIndex].value}});a.augmentObject(b.DropdownCellEditor,h);b.RadioCellEditor=function(a){a=a||{};this._sId=this._sId||f.generateId(null,"yui-radioceditor");YAHOO.widget.BaseCellEditor._nCount++;b.RadioCellEditor.superclass.constructor.call(this,a.type||"radio",a)};a.extend(b.RadioCellEditor,h,{radios:null,radioOptions:null,renderForm:function(){if(a.isArray(this.radioOptions)){for(var b,c,d,f=0,g=this.radioOptions.length;f<
+g;f++){b=this.radioOptions[f];c=a.isValue(b.value)?b.value:b;d=this.getId()+"-radio"+f;this.getContainerEl().innerHTML+='<input type="radio" name="'+this.getId()+'" value="'+c+'" id="'+d+'" />';c=this.getContainerEl().appendChild(document.createElement("label"));c.htmlFor=d;c.innerHTML=a.isValue(b.label)?b.label:b}b=[];for(f=0;f<g;f++){d=this.getContainerEl().childNodes[f*2];b[b.length]=d}this.radios=b;this.disableBtns&&this.handleDisabledBtns()}},handleDisabledBtns:function(){g.addListener(this.getContainerEl(),
+"click",function(a){g.getTarget(a).tagName.toLowerCase()==="input"&&this.save()},this,true)},resetForm:function(){for(var a=0,b=this.radios.length;a<b;a++){var c=this.radios[a];if(this.value==c.value){c.checked=true;break}}},focus:function(){for(var a=0,b=this.radios.length;a<b;a++)if(this.radios[a].checked){this.radios[a].focus();break}},getInputValue:function(){for(var a=0,b=this.radios.length;a<b;a++)if(this.radios[a].checked)return this.radios[a].value}});a.augmentObject(b.RadioCellEditor,h);
+b.TextareaCellEditor=function(a){a=a||{};this._sId=this._sId||f.generateId(null,"yui-textareaceditor");YAHOO.widget.BaseCellEditor._nCount++;b.TextareaCellEditor.superclass.constructor.call(this,a.type||"textarea",a)};a.extend(b.TextareaCellEditor,h,{textarea:null,renderForm:function(){this.textarea=this.getContainerEl().appendChild(document.createElement("textarea"));this.disableBtns&&this.handleDisabledBtns()},handleDisabledBtns:function(){g.addListener(this.textarea,"blur",function(){this.save()},
+this,true)},move:function(){this.textarea.style.width=this.getTdEl().offsetWidth+"px";this.textarea.style.height="3em";YAHOO.widget.TextareaCellEditor.superclass.move.call(this)},resetForm:function(){this.textarea.value=this.value},focus:function(){this.getDataTable()._focusEl(this.textarea);this.textarea.select()},getInputValue:function(){return this.textarea.value}});a.augmentObject(b.TextareaCellEditor,h);b.TextboxCellEditor=function(a){a=a||{};this._sId=this._sId||f.generateId(null,"yui-textboxceditor");
+YAHOO.widget.BaseCellEditor._nCount++;b.TextboxCellEditor.superclass.constructor.call(this,a.type||"textbox",a)};a.extend(b.TextboxCellEditor,h,{textbox:null,renderForm:function(){var a;a=d.webkit>420?this.getContainerEl().appendChild(document.createElement("form")).appendChild(document.createElement("input")):this.getContainerEl().appendChild(document.createElement("input"));a.type="text";this.textbox=a;g.addListener(a,"keypress",function(a){if(a.keyCode===13){YAHOO.util.Event.preventDefault(a);
+this.save()}},this,true);this.disableBtns&&this.handleDisabledBtns()},move:function(){this.textbox.style.width=this.getTdEl().offsetWidth+"px";b.TextboxCellEditor.superclass.move.call(this)},resetForm:function(){this.textbox.value=a.isValue(this.value)?this.value.toString():""},focus:function(){this.getDataTable()._focusEl(this.textbox);this.textbox.select()},getInputValue:function(){return this.textbox.value}});a.augmentObject(b.TextboxCellEditor,h);j.Editors={checkbox:b.CheckboxCellEditor,date:b.DateCellEditor,
+dropdown:b.DropdownCellEditor,radio:b.RadioCellEditor,textarea:b.TextareaCellEditor,textbox:b.TextboxCellEditor};b.CellEditor=function(b,c){if(b&&j.Editors[b]){a.augmentObject(h,j.Editors[b]);return new j.Editors[b](c)}return new h(null,c)};a.augmentObject(b.CellEditor,h)})();YAHOO.register("datatable",YAHOO.widget.DataTable,{version:"2.9.0",build:"2800"});
 /*
 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
 Code licensed under the BSD License:
 http://developer.yahoo.com/yui/license.html
 version: 2.9.0
 */
-if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var b=arguments,g=null,e,c,f;for(e=0;e<b.length;e=e+1){f=(""+b[e]).split(".");g=YAHOO;for(c=(f[0]=="YAHOO")?1:0;c<f.length;c=c+1){g[f[c]]=g[f[c]]||{};g=g[f[c]];}}return g;};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,f,e){var k=YAHOO.env.modules,c,j,h,g,d;if(!k[a]){k[a]={versions:[],builds:[]};}c=k[a];j=e.version;h=e.build;g=YAHOO.env.listeners;c.name=a;c.version=j;c.build=h;c.versions.push(j);c.builds.push(h);c.mainClass=f;for(d=0;d<g.length;d=d+1){g[d](c);}if(f){f.VERSION=j;f.BUILD=h;}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.parseUA=function(d){var e=function(i){var j=0;return parseFloat(i.replace(/\./g,function(){return(j++==1)?"":".";}));},h=navigator,g={ie:0,opera:0,gecko:0,webkit:0,chrome:0,mobile:null,air:0,ipad:0,iphone:0,ipod:0,ios:null,android:0,webos:0,caja:h&&h.cajaVersion,secure:false,os:null},c=d||(navigator&&navigator.userAgent),f=window&&window.location,b=f&&f.href,a;g.secure=b&&(b.toLowerCase().indexOf("https")===0);if(c){if((/windows|win32/i).test(c)){g.os="windows";}else{if((/macintosh/i).test(c)){g.os="macintosh";}else{if((/rhino/i).test(c)){g.os="rhino";}}}if((/KHTML/).test(c)){g.webkit=1;}a=c.match(/AppleWebKit\/([^\s]*)/);if(a&&a[1]){g.webkit=e(a[1]);if(/ Mobile\//.test(c)){g.mobile="Apple";a=c.match(/OS ([^\s]*)/);if(a&&a[1]){a=e(a[1].replace("_","."));}g.ios=a;g.ipad=g.ipod=g.iphone=0;a=c.match(/iPad|iPod|iPhone/);if(a&&a[0]){g[a[0].toLowerCase()]=g.ios;}}else{a=c.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/);if(a){g.mobile=a[0];}if(/webOS/.test(c)){g.mobile="WebOS";a=c.match(/webOS\/([^\s]*);/);if(a&&a[1]){g.webos=e(a[1]);}}if(/ Android/.test(c)){g.mobile="Android";a=c.match(/Android ([^\s]*);/);if(a&&a[1]){g.android=e(a[1]);}}}a=c.match(/Chrome\/([^\s]*)/);if(a&&a[1]){g.chrome=e(a[1]);}else{a=c.match(/AdobeAIR\/([^\s]*)/);if(a){g.air=a[0];}}}if(!g.webkit){a=c.match(/Opera[\s\/]([^\s]*)/);if(a&&a[1]){g.opera=e(a[1]);a=c.match(/Version\/([^\s]*)/);if(a&&a[1]){g.opera=e(a[1]);}a=c.match(/Opera Mini[^;]*/);if(a){g.mobile=a[0];}}else{a=c.match(/MSIE\s([^;]*)/);if(a&&a[1]){g.ie=e(a[1]);}else{a=c.match(/Gecko\/([^\s]*)/);if(a){g.gecko=1;a=c.match(/rv:([^\s\)]*)/);if(a&&a[1]){g.gecko=e(a[1]);}}}}}}return g;};YAHOO.env.ua=YAHOO.env.parseUA();(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 f=YAHOO.lang,a=Object.prototype,c="[object Array]",h="[object Function]",i="[object Object]",b=[],g={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;","`":"&#x60;"},d=["toString","valueOf"],e={isArray:function(j){return a.toString.apply(j)===c;},isBoolean:function(j){return typeof j==="boolean";},isFunction:function(j){return(typeof j==="function")||a.toString.apply(j)===h;},isNull:function(j){return j===null;},isNumber:function(j){return typeof j==="number"&&isFinite(j);},isObject:function(j){return(j&&(typeof j==="object"||f.isFunction(j)))||false;},isString:function(j){return typeof j==="string";},isUndefined:function(j){return typeof j==="undefined";},_IEEnumFix:(YAHOO.env.ua.ie)?function(l,k){var j,n,m;for(j=0;j<d.length;j=j+1){n=d[j];m=k[n];if(f.isFunction(m)&&m!=a[n]){l[n]=m;}}}:function(){},escapeHTML:function(j){return j.replace(/[&<>"'\/`]/g,function(k){return g[k];});},extend:function(m,n,l){if(!n||!m){throw new Error("extend failed, please check that "+"all dependencies are included.");}var k=function(){},j;k.prototype=n.prototype;m.prototype=new k();m.prototype.constructor=m;m.superclass=n.prototype;if(n.prototype.constructor==a.constructor){n.prototype.constructor=n;}if(l){for(j in l){if(f.hasOwnProperty(l,j)){m.prototype[j]=l[j];}}f._IEEnumFix(m.prototype,l);}},augmentObject:function(n,m){if(!m||!n){throw new Error("Absorb failed, verify dependencies.");}var j=arguments,l,o,k=j[2];if(k&&k!==true){for(l=2;l<j.length;l=l+1){n[j[l]]=m[j[l]];}}else{for(o in m){if(k||!(o in n)){n[o]=m[o];}}f._IEEnumFix(n,m);}return n;},augmentProto:function(m,l){if(!l||!m){throw new Error("Augment failed, verify dependencies.");}var j=[m.prototype,l.prototype],k;for(k=2;k<arguments.length;k=k+1){j.push(arguments[k]);}f.augmentObject.apply(this,j);return m;},dump:function(j,p){var l,n,r=[],t="{...}",k="f(){...}",q=", ",m=" => ";if(!f.isObject(j)){return j+"";}else{if(j instanceof Date||("nodeType" in j&&"tagName" in j)){return j;}else{if(f.isFunction(j)){return k;}}}p=(f.isNumber(p))?p:3;if(f.isArray(j)){r.push("[");for(l=0,n=j.length;l<n;l=l+1){if(f.isObject(j[l])){r.push((p>0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}if(r.length>1){r.pop();}r.push("]");}else{r.push("{");for(l in j){if(f.hasOwnProperty(j,l)){r.push(l+m);if(f.isObject(j[l])){r.push((p>0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}}if(r.length>1){r.pop();}r.push("}");}return r.join("");},substitute:function(x,y,E,l){var D,C,B,G,t,u,F=[],p,z=x.length,A="dump",r=" ",q="{",m="}",n,w;for(;;){D=x.lastIndexOf(q,z);if(D<0){break;}C=x.indexOf(m,D);if(D+1>C){break;}p=x.substring(D+1,C);G=p;u=null;B=G.indexOf(r);if(B>-1){u=G.substring(B+1);G=G.substring(0,B);}t=y[G];if(E){t=E(G,t,u);}if(f.isObject(t)){if(f.isArray(t)){t=f.dump(t,parseInt(u,10));}else{u=u||"";n=u.indexOf(A);if(n>-1){u=u.substring(4);}w=t.toString();if(w===i||n>-1){t=f.dump(t,parseInt(u,10));}else{t=w;}}}else{if(!f.isString(t)&&!f.isNumber(t)){t="~-"+F.length+"-~";F[F.length]=p;}}x=x.substring(0,D)+t+x.substring(C+1);if(l===false){z=D-1;}}for(D=F.length-1;D>=0;D=D-1){x=x.replace(new RegExp("~-"+D+"-~"),"{"+F[D]+"}","g");}return x;},trim:function(j){try{return j.replace(/^\s+|\s+$/g,"");}catch(k){return j;
-}},merge:function(){var n={},k=arguments,j=k.length,m;for(m=0;m<j;m=m+1){f.augmentObject(n,k[m],true);}return n;},later:function(t,k,u,n,p){t=t||0;k=k||{};var l=u,s=n,q,j;if(f.isString(u)){l=k[u];}if(!l){throw new TypeError("method undefined");}if(!f.isUndefined(n)&&!f.isArray(s)){s=[n];}q=function(){l.apply(k,s||b);};j=(p)?setInterval(q,t):setTimeout(q,t);return{interval:p,cancel:function(){if(this.interval){clearInterval(j);}else{clearTimeout(j);}}};},isValue:function(j){return(f.isObject(j)||f.isString(j)||f.isNumber(j)||f.isBoolean(j));}};f.hasOwnProperty=(a.hasOwnProperty)?function(j,k){return j&&j.hasOwnProperty&&j.hasOwnProperty(k);}:function(j,k){return !f.isUndefined(j[k])&&j.constructor.prototype[k]!==j[k];};e.augmentObject(f,e,true);YAHOO.util.Lang=f;f.augment=f.augmentProto;YAHOO.augment=f.augmentProto;YAHOO.extend=f.extend;})();YAHOO.register("yahoo",YAHOO,{version:"2.9.0",build:"2800"});YAHOO.util.Get=function(){var m={},k=0,r=0,l=false,n=YAHOO.env.ua,s=YAHOO.lang,q,d,e,i=function(x,t,y){var u=y||window,z=u.document,A=z.createElement(x),v;for(v in t){if(t.hasOwnProperty(v)){A.setAttribute(v,t[v]);}}return A;},h=function(u,v,t){var w={id:"yui__dyn_"+(r++),type:"text/css",rel:"stylesheet",href:u};if(t){s.augmentObject(w,t);}return i("link",w,v);},p=function(u,v,t){var w={id:"yui__dyn_"+(r++),type:"text/javascript",src:u};if(t){s.augmentObject(w,t);}return i("script",w,v);},a=function(t,u){return{tId:t.tId,win:t.win,data:t.data,nodes:t.nodes,msg:u,purge:function(){d(this.tId);}};},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;},c=function(w){YAHOO.log("Finishing transaction "+w);var u=m[w],v,t;u.finished=true;if(u.aborted){v="transaction "+w+" was aborted";q(w,v);return;}if(u.onSuccess){t=u.scope||u.win;u.onSuccess.call(t,a(u));}},o=function(v){YAHOO.log("Timeout "+v,"info","get");var u=m[v],t;if(u.onTimeout){t=u.scope||u;u.onTimeout.call(t,a(u));}},f=function(v,A){YAHOO.log("_next: "+v+", loaded: "+A,"info","Get");var u=m[v],D=u.win,C=D.document,B=C.getElementsByTagName("head")[0],x,y,t,E,z;if(u.timer){u.timer.cancel();}if(u.aborted){y="transaction "+v+" was aborted";q(v,y);return;}if(A){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;}}if(u.url.length===0){if(u.type==="script"&&n.webkit&&n.webkit<420&&!u.finalpass&&!u.varName){z=p(null,u.win,u.attributes);z.innerHTML='YAHOO.util.Get._finalize("'+v+'");';u.nodes.push(z);B.appendChild(z);}else{c(v);}return;}t=u.url[0];if(!t){u.url.shift();YAHOO.log("skipping empty url");return f(v);}YAHOO.log("attempting to load "+t,"info","Get");if(u.timeout){u.timer=s.later(u.timeout,u,o,v);}if(u.type==="script"){x=p(t,D,u.attributes);}else{x=h(t,D,u.attributes);}e(u.type,x,v,t,D,u.url.length);u.nodes.push(x);if(u.insertBefore){E=b(u.insertBefore,v);if(E){E.parentNode.insertBefore(x,E);}}else{B.appendChild(x);}YAHOO.log("Appending node: "+t,"info","Get");if((n.webkit||n.gecko)&&u.type==="css"){f(v,t);}},j=function(){if(l){return;}l=true;var t,u;for(t in m){if(m.hasOwnProperty(t)){u=m[t];if(u.autopurge&&u.finished){d(u.tId);delete m[t];}}}l=false;},g=function(u,t,v){var x="q"+(k++),w;v=v||{};if(k%YAHOO.util.Get.PURGE_THRESH===0){j();}m[x]=s.merge(v,{tId:x,type:u,url:t,finished:false,aborted:false,nodes:[]});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;w.attributes=w.attributes||{};w.attributes.charset=v.charset||w.attributes.charset||"utf-8";s.later(0,w,f,x);return{tId:x};};e=function(H,z,x,u,D,E,G){var F=G||f,B,t,I,v,J,A,C,y;if(n.ie){z.onreadystatechange=function(){B=this.readyState;if("loaded"===B||"complete"===B){YAHOO.log(x+" onload "+u,"info","Get");z.onreadystatechange=null;F(x,u);}};}else{if(n.webkit){if(H==="script"){if(n.webkit>=420){z.addEventListener("load",function(){YAHOO.log(x+" DOM2 onload "+u,"info","Get");F(x,u);});}else{t=m[x];if(t.varName){v=YAHOO.util.Get.POLL_FREQ;YAHOO.log("Polling for "+t.varName[0]);t.maxattempts=YAHOO.util.Get.TIMEOUT/v;t.attempts=0;t._cache=t.varName[0].split(".");t.timer=s.later(v,t,function(w){I=this._cache;A=I.length;J=this.win;for(C=0;C<A;C=C+1){J=J[I[C]];if(!J){this.attempts++;if(this.attempts++>this.maxattempts){y="Over retry limit, giving up";t.timer.cancel();q(x,y);}else{YAHOO.log(I[C]+" failed, retrying");}return;}}YAHOO.log("Safari poll complete");t.timer.cancel();F(x,u);},null,true);}else{s.later(YAHOO.util.Get.POLL_FREQ,null,F,[x,u]);}}}}else{z.onload=function(){YAHOO.log(x+" onload "+u,"info","Get");F(x,u);};}}};q=function(w,v){YAHOO.log("get failure: "+v,"warn","Get");var u=m[w],t;if(u.onFailure){t=u.scope||u.win;u.onFailure.call(t,a(u,v));}};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){if(w.hasOwnProperty(B)){delete w[B];}}}A.removeChild(w);}t.nodes=[];}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(t){YAHOO.log(t+" finalized ","info","Get");s.later(0,null,c,t);},abort:function(u){var v=(s.isString(u))?u:u.tId,t=m[v];if(t){YAHOO.log("Aborting "+v,"info","Get");t.aborted=true;}},script:function(t,u){return g("script",t,u);},css:function(t,u){return g("css",t,u);}};}();YAHOO.register("get",YAHOO.util.Get,{version:"2.9.0",build:"2800"});(function(){var Y=YAHOO,util=Y.util,lang=Y.lang,env=Y.env,PROV="_provides",SUPER="_supersedes",REQ="expanded",AFTER="_after",VERSION="2.9.0";var YUI={dupsAllowed:{"yahoo":true,"get":true},info:{"root":VERSION+"/build/","base":"http://yui.yahooapis.com/"+VERSION+"/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:["datemath"],"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);}if(YUI.ArrayUtil.indexOf(m.requires,smod)==-1){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});}else{this.loadNext();}};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){var self=this,success=function(o){var idx=o.argument[0],name=o.argument[2];self._scriptText[idx]=o.responseText;if(self.onProgress){self.onProgress.call(self.scope,{name:name,scriptText:o.responseText,xhrResponse:o,data:self.data});}self._loadCount++;if(self._loadCount>=self._stopCount){var v=self.varName||"YAHOO";var t="(function() {\n";var b="\nreturn "+v+";\n})();";var ref=eval(t+self._scriptText.join("\n")+b);self._pushEvents(ref);if(ref){self.onSuccess.call(self.scope,{reference:ref,data:self.data});}else{self._onFailure.call(self.varName+" reference failure");}}},failure=function(o){self.onFailure.call(self.scope,{msg:"XHR failure",xhrResponse:o,data:self.data});};self._config(o);if(!self.onSuccess){throw new Error("You must supply an onSuccess handler for your sandbox");}self._sandbox=true;if(!type||type!=="js"){self._internalCallback=function(){self._internalCallback=null;self.sandbox(null,"js");};self.insert(null,"css");return;}if(!util.Connect){var ld=new YAHOO.util.YUILoader();ld.insert({base:self.base,filter:self.filter,require:"connection",insertBefore:self.insertBefore,charset:self.charset,onSuccess:function(){self.sandbox(null,"js");},scope:self},"js");return;}self._scriptText=[];self._loadCount=0;self._stopCount=self.sorted.length;self._xhr=[];self.calculate();var s=self.sorted,l=s.length,i,m,url;for(i=0;i<l;i=i+1){m=self.moduleInfo[s[i]];if(!m){self._onFailure("undefined module "+m);for(var j=0;j<self._xhr.length;j=j+1){self._xhr[j].abort();}return;}if(m.type!=="js"){self._loadCount++;continue;}url=m.fullpath;url=(url)?self._filter(url):self._url(m.path);var xhrData={success:success,failure:failure,scope:self,argument:[i,url,s[i]]};self._xhr.push(util.Connect.asyncRequest("GET",url,xhrData));}},loadNext:function(mname){if(!this._loading){return;}var self=this,donext=function(o){self.loadNext(o.data);},successfn,s=this.sorted,len=s.length,i,fn,m,url;if(mname){if(mname!==this._loading){return;}this.inserted[mname]=true;if(this.onProgress){this.onProgress.call(this.scope,{name:mname,data:this.data});}}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){successfn=donext;this._loading=s[i];fn=(m.type==="css")?util.Get.css:util.Get.script;url=m.fullpath;url=(url)?this._filter(url):this._url(m.path);if(env.ua.webkit&&env.ua.webkit<420&&m.type==="js"&&!m.varName){successfn=null;this._useYahooListener=true;}fn(url,{data:s[i],onSuccess:successfn,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.9.0",build:"2800"});(function(){YAHOO.env._id_counter=YAHOO.env._id_counter||0;var e=YAHOO.util,k=YAHOO.lang,L=YAHOO.env.ua,a=YAHOO.lang.trim,B={},F={},m=/^t(?:able|d|h)$/i,w=/color$/i,j=window.document,v=j.documentElement,C="ownerDocument",M="defaultView",U="documentElement",S="compatMode",z="offsetLeft",o="offsetTop",T="offsetParent",x="parentNode",K="nodeType",c="tagName",n="scrollLeft",H="scrollTop",p="getBoundingClientRect",V="getComputedStyle",y="currentStyle",l="CSS1Compat",A="BackCompat",E="class",f="className",i="",b=" ",R="(?:^|\\s)",J="(?= |$)",t="g",O="position",D="fixed",u="relative",I="left",N="top",Q="medium",P="borderLeftWidth",q="borderTopWidth",d=L.opera,h=L.webkit,g=L.gecko,s=L.ie;e.Dom={CUSTOM_ATTRIBUTES:(!v.hasAttribute)?{"for":"htmlFor","class":f}:{"htmlFor":"for","className":E},DOT_ATTRIBUTES:{checked:true},get:function(aa){var ac,X,ab,Z,W,G,Y=null;if(aa){if(typeof aa=="string"||typeof aa=="number"){ac=aa+"";aa=j.getElementById(aa);G=(aa)?aa.attributes:null;if(aa&&G&&G.id&&G.id.value===ac){return aa;}else{if(aa&&j.all){aa=null;X=j.all[ac];if(X&&X.length){for(Z=0,W=X.length;Z<W;++Z){if(X[Z].id===ac){return X[Z];}}}}}}else{if(e.Element&&aa instanceof e.Element){aa=aa.get("element");}else{if(!aa.nodeType&&"length" in aa){ab=[];for(Z=0,W=aa.length;Z<W;++Z){ab[ab.length]=e.Dom.get(aa[Z]);}aa=ab;}}}Y=aa;}return Y;},getComputedStyle:function(G,W){if(window[V]){return G[C][M][V](G,null)[W];}else{if(G[y]){return e.Dom.IE_ComputedStyle.get(G,W);}}},getStyle:function(G,W){return e.Dom.batch(G,e.Dom._getStyle,W);},_getStyle:function(){if(window[V]){return function(G,Y){Y=(Y==="float")?Y="cssFloat":e.Dom._toCamel(Y);var X=G.style[Y],W;if(!X){W=G[C][M][V](G,null);if(W){X=W[Y];}}return X;};}else{if(v[y]){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(W){}}return X/100;case"float":Y="styleFloat";default:Y=e.Dom._toCamel(Y);X=G[y]?G[y][Y]:null;return(G.style[Y]||X);}};}}}(),setStyle:function(G,W,X){e.Dom.batch(G,e.Dom._setStyle,{prop:W,val:X});},_setStyle:function(){if(!window.getComputedStyle&&j.documentElement.currentStyle){return function(W,G){var X=e.Dom._toCamel(G.prop),Y=G.val;if(W){switch(X){case"opacity":if(Y===""||Y===null||Y===1){W.style.removeAttribute("filter");}else{if(k.isString(W.style.filter)){W.style.filter="alpha(opacity="+Y*100+")";if(!W[y]||!W[y].hasLayout){W.style.zoom=1;}}}break;case"float":X="styleFloat";default:W.style[X]=Y;}}else{}};}else{return function(W,G){var X=e.Dom._toCamel(G.prop),Y=G.val;if(W){if(X=="float"){X="cssFloat";}W.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(W){var X,G,Z,ab,Y,aa,ac=Math.round,ad=false;if(e.Dom._canPosition(W)){Z=W[p]();ab=W[C];X=e.Dom.getDocumentScrollLeft(ab);G=e.Dom.getDocumentScrollTop(ab);ad=[Z[I],Z[N]];if(Y||aa){ad[0]-=aa;ad[1]-=Y;}if((G||X)){ad[0]+=X;ad[1]+=G;}ad[0]=ac(ad[0]);ad[1]=ac(ad[1]);}else{}return ad;},getX:function(G){var W=function(X){return e.Dom.getXY(X)[0];};return e.Dom.batch(G,W,e.Dom,true);},getY:function(G){var W=function(X){return e.Dom.getXY(X)[1];};return e.Dom.batch(G,W,e.Dom,true);},setXY:function(G,X,W){e.Dom.batch(G,e.Dom._setXY,{pos:X,noRetry:W});},_setXY:function(G,Z){var aa=e.Dom._getStyle(G,O),Y=e.Dom.setStyle,ad=Z.pos,W=Z.noRetry,ab=[parseInt(e.Dom.getComputedStyle(G,I),10),parseInt(e.Dom.getComputedStyle(G,N),10)],ac,X;ac=e.Dom._getXY(G);if(!ad||ac===false){return false;}if(aa=="static"){aa=u;Y(G,O,aa);}if(isNaN(ab[0])){ab[0]=(aa==u)?0:G[z];}if(isNaN(ab[1])){ab[1]=(aa==u)?0:G[o];}if(ad[0]!==null){Y(G,I,ad[0]-ac[0]+ab[0]+"px");}if(ad[1]!==null){Y(G,N,ad[1]-ac[1]+ab[1]+"px");}if(!W){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(W,G){e.Dom.setXY(W,[G,null]);},setY:function(G,W){e.Dom.setXY(G,[null,W]);},getRegion:function(G){var W=function(X){var Y=false;if(e.Dom._canPosition(X)){Y=e.Region.getRegion(X);}else{}return Y;};return e.Dom.batch(G,W,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||j;if(!ac){return[];}var W=[],G=ac.getElementsByTagName(af),Z=e.Dom.hasClass;for(var Y=0,aa=G.length;Y<aa;++Y){if(Z(G[Y],ab)){W[W.length]=G[Y];}}if(ae){e.Dom.batch(W,ae,X,ad);}return W;},hasClass:function(W,G){return e.Dom.batch(W,e.Dom._hasClass,G);},_hasClass:function(X,W){var G=false,Y;if(X&&W){Y=e.Dom._getAttribute(X,f)||i;if(Y){Y=Y.replace(/\s+/g,b);}if(W.exec){G=W.test(Y);}else{G=W&&(b+Y+b).indexOf(b+W+b)>-1;}}else{}return G;},addClass:function(W,G){return e.Dom.batch(W,e.Dom._addClass,G);},_addClass:function(X,W){var G=false,Y;if(X&&W){Y=e.Dom._getAttribute(X,f)||i;if(!e.Dom._hasClass(X,W)){e.Dom.setAttribute(X,f,a(Y+b+W));G=true;}}else{}return G;},removeClass:function(W,G){return e.Dom.batch(W,e.Dom._removeClass,G);},_removeClass:function(Y,X){var W=false,aa,Z,G;if(Y&&X){aa=e.Dom._getAttribute(Y,f)||i;e.Dom.setAttribute(Y,f,aa.replace(e.Dom._getClassRegex(X),i));Z=e.Dom._getAttribute(Y,f);if(aa!==Z){e.Dom.setAttribute(Y,f,a(Z));W=true;if(e.Dom._getAttribute(Y,f)===""){G=(Y.hasAttribute&&Y.hasAttribute(E))?E:f;Y.removeAttribute(G);}}}else{}return W;},replaceClass:function(X,W,G){return e.Dom.batch(X,e.Dom._replaceClass,{from:W,to:G});},_replaceClass:function(Y,X){var W,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)||i;W=(b+Z.replace(e.Dom._getClassRegex(ab),b+aa).replace(/\s+/g,b)).split(e.Dom._getClassRegex(aa));W.splice(1,0,b+aa);e.Dom.setAttribute(Y,f,a(W.join(i)));G=true;}}}}else{}return G;},generateId:function(G,X){X=X||"yui-gen";var W=function(Y){if(Y&&Y.id){return Y.id;}var Z=X+YAHOO.env._id_counter++;
-if(Y){if(Y[C]&&Y[C].getElementById(Z)){return e.Dom.generateId(Y,Z+X);}Y.id=Z;}return Z;};return e.Dom.batch(G,W,e.Dom,true)||W.apply(e.Dom,arguments);},isAncestor:function(W,X){W=e.Dom.get(W);X=e.Dom.get(X);var G=false;if((W&&X)&&(W[K]&&X[K])){if(W.contains&&W!==X){G=W.contains(X);}else{if(W.compareDocumentPosition){G=!!(W.compareDocumentPosition(X)&16);}}}else{}return G;},inDocument:function(G,W){return e.Dom._inDoc(e.Dom.get(G),W);},_inDoc:function(W,X){var G=false;if(W&&W[c]){X=X||W[C];G=e.Dom.isAncestor(X[U],W);}else{}return G;},getElementsBy:function(W,af,ab,ad,X,ac,ae){af=af||"*";ab=(ab)?e.Dom.get(ab):null||j;var aa=(ae)?null:[],G;if(ab){G=ab.getElementsByTagName(af);for(var Y=0,Z=G.length;Y<Z;++Y){if(W(G[Y])){if(ae){aa=G[Y];break;}else{aa[aa.length]=G[Y];}}}if(ad){e.Dom.batch(aa,ad,X,ac);}}return aa;},getElementBy:function(X,G,W){return e.Dom.getElementsBy(X,G,W,null,null,null,true);},batch:function(X,ab,aa,Z){var Y=[],W=(Z)?aa:null;X=(X&&(X[c]||X.item))?X:e.Dom.get(X);if(X&&ab){if(X[c]||X.length===undefined){return ab.call(W,X,aa);}for(var G=0;G<X.length;++G){Y[Y.length]=ab.call(W||X[G],X[G],aa);}}else{return false;}return Y;},getDocumentHeight:function(){var W=(j[S]!=l||h)?j.body.scrollHeight:v.scrollHeight,G=Math.max(W,e.Dom.getViewportHeight());return G;},getDocumentWidth:function(){var W=(j[S]!=l||h)?j.body.scrollWidth:v.scrollWidth,G=Math.max(W,e.Dom.getViewportWidth());return G;},getViewportHeight:function(){var G=self.innerHeight,W=j[S];if((W||s)&&!d){G=(W==l)?v.clientHeight:j.body.clientHeight;}return G;},getViewportWidth:function(){var G=self.innerWidth,W=j[S];if(W||s){G=(W==l)?v.clientWidth:j.body.clientWidth;}return G;},getAncestorBy:function(G,W){while((G=G[x])){if(e.Dom._testElement(G,W)){return G;}}return null;},getAncestorByClassName:function(W,G){W=e.Dom.get(W);if(!W){return null;}var X=function(Y){return e.Dom.hasClass(Y,G);};return e.Dom.getAncestorBy(W,X);},getAncestorByTagName:function(W,G){W=e.Dom.get(W);if(!W){return null;}var X=function(Y){return Y[c]&&Y[c].toUpperCase()==G.toUpperCase();};return e.Dom.getAncestorBy(W,X);},getPreviousSiblingBy:function(G,W){while(G){G=G.previousSibling;if(e.Dom._testElement(G,W)){return G;}}return null;},getPreviousSibling:function(G){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getPreviousSiblingBy(G);},getNextSiblingBy:function(G,W){while(G){G=G.nextSibling;if(e.Dom._testElement(G,W)){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 W=(e.Dom._testElement(G.firstChild,X))?G.firstChild:null;return W||e.Dom.getNextSiblingBy(G.firstChild,X);},getFirstChild:function(G,W){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getFirstChildBy(G);},getLastChildBy:function(G,X){if(!G){return null;}var W=(e.Dom._testElement(G.lastChild,X))?G.lastChild:null;return W||e.Dom.getPreviousSiblingBy(G.lastChild,X);},getLastChild:function(G){G=e.Dom.get(G);return e.Dom.getLastChildBy(G);},getChildrenBy:function(W,Y){var X=e.Dom.getFirstChildBy(W,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||j;return Math.max(G[U].scrollLeft,G.body.scrollLeft);},getDocumentScrollTop:function(G){G=G||j;return Math.max(G[U].scrollTop,G.body.scrollTop);},insertBefore:function(W,G){W=e.Dom.get(W);G=e.Dom.get(G);if(!W||!G||!G[x]){return null;}return G[x].insertBefore(W,G);},insertAfter:function(W,G){W=e.Dom.get(W);G=e.Dom.get(G);if(!W||!G||!G[x]){return null;}if(G.nextSibling){return G[x].insertBefore(W,G.nextSibling);}else{return G[x].appendChild(W);}},getClientRegion:function(){var X=e.Dom.getDocumentScrollTop(),W=e.Dom.getDocumentScrollLeft(),Y=e.Dom.getViewportWidth()+W,G=e.Dom.getViewportHeight()+X;return new e.Region(X,Y,G,W);},setAttribute:function(W,G,X){e.Dom.batch(W,e.Dom._setAttribute,{attr:G,val:X});},_setAttribute:function(X,W){var G=e.Dom._toCamel(W.attr),Y=W.val;if(X&&X.setAttribute){if(e.Dom.DOT_ATTRIBUTES[G]&&X.tagName&&X.tagName!="BUTTON"){X[G]=Y;}else{G=e.Dom.CUSTOM_ATTRIBUTES[G]||G;X.setAttribute(G,Y);}}else{}},getAttribute:function(W,G){return e.Dom.batch(W,e.Dom._getAttribute,G);},_getAttribute:function(W,G){var X;G=e.Dom.CUSTOM_ATTRIBUTES[G]||G;if(e.Dom.DOT_ATTRIBUTES[G]){X=W[G];}else{if(W&&"getAttribute" in W){if(/^(?:href|src)$/.test(G)){X=W.getAttribute(G,2);}else{X=W.getAttribute(G);}}else{}}return X;},_toCamel:function(W){var X=B;function G(Y,Z){return Z.toUpperCase();}return X[W]||(X[W]=W.indexOf("-")===-1?W:W.replace(/-([a-z])/gi,G));},_getClassRegex:function(W){var G;if(W!==undefined){if(W.exec){G=W;}else{G=F[W];if(!G){W=W.replace(e.Dom._patterns.CLASS_RE_TOKENS,"\\$1");W=W.replace(/\s+/g,b);G=F[W]=new RegExp(R+W+J,t);}}}return G;},_patterns:{ROOT_TAG:/^body|html$/i,CLASS_RE_TOKENS:/([\.\(\)\^\$\*\+\?\|\[\]\{\}\\])/g},_testElement:function(G,W){return G&&G[K]==1&&(!W||W(G));},_calcBorders:function(X,Y){var W=parseInt(e.Dom[V](X,q),10)||0,G=parseInt(e.Dom[V](X,P),10)||0;if(g){if(m.test(X[c])){W=0;G=0;}}Y[0]+=G;Y[1]+=W;return Y;}};var r=e.Dom[V];if(L.opera){e.Dom[V]=function(W,G){var X=r(W,G);if(w.test(G)){X=e.Dom.Color.toRGB(X);}return X;};}if(L.webkit){e.Dom[V]=function(W,G){var X=r(W,G);if(X==="rgba(0, 0, 0, 0)"){X="transparent";}return X;};}if(L.ie&&L.ie>=8){e.Dom.DOT_ATTRIBUTES.type=true;}})();YAHOO.util.Region=function(d,e,a,c){this.top=d;this.y=d;this[1]=d;this.right=e;this.bottom=a;this.left=c;this.x=c;this[0]=c;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(f){var d=Math.max(this.top,f.top),e=Math.min(this.right,f.right),a=Math.min(this.bottom,f.bottom),c=Math.max(this.left,f.left);
-if(a>=d&&e>=c){return new YAHOO.util.Region(d,e,a,c);}else{return null;}};YAHOO.util.Region.prototype.union=function(f){var d=Math.min(this.top,f.top),e=Math.max(this.right,f.right),a=Math.max(this.bottom,f.bottom),c=Math.min(this.left,f.left);return new YAHOO.util.Region(d,e,a,c);};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(e){var g=YAHOO.util.Dom.getXY(e),d=g[1],f=g[0]+e.offsetWidth,a=g[1]+e.offsetHeight,c=g[0];return new YAHOO.util.Region(d,f,a,c);};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(f){f=d.Dom.Color.KEYWORDS[f]||f;if(d.Dom.Color.re_RGB.exec(f)){f=[Number(b.$1).toString(16),Number(b.$2).toString(16),Number(b.$3).toString(16)];for(var e=0;e<f.length;e++){if(f[e].length<2){f[e]="0"+f[e];}}f=f.join("");}if(f.length<6){f=f.replace(d.Dom.Color.re_hex3,"$1$1");}if(f!=="transparent"&&f.indexOf("#")<0){f="#"+f;}return f.toUpperCase();}};}());YAHOO.register("dom",YAHOO.util.Dom,{version:"2.9.0",build:"2800"});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||!g.fn){b=true;}else{c=this.notify(g,d);if(false===c){if(!this.silent){}break;}}}return(c!==false);},notify:function(g,c){var b,i=null,f=g.getScope(this.scope),a=YAHOO.util.Event.throwErrors;if(!this.silent){}if(this.signature==YAHOO.util.CustomEvent.FLAT){if(c.length>0){i=c[0];}try{b=g.fn.call(f,i,g.obj);}catch(h){this.lastError=h;if(a){throw h;}}}else{try{b=g.fn.call(f,this.type,c,g.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 null;}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(n,q,r,p){for(var o=0,m=n.length;o<m;o=o+1){var k=n[o];if(k&&k[this.FN]==p&&k[this.EL]==q&&k[this.TYPE]==r){return o;}}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(p,q,s){var n=(YAHOO.lang.isString(p))?this.getEl(p):p;var r=this.getListeners(n,s),o,k;if(r){for(o=r.length-1;o>-1;o--){var m=r[o];this.removeListener(n,m.type,m.fn);}}if(q&&n&&n.childNodes){for(o=0,k=n.childNodes.length;o<k;++o){this.purgeElement(n.childNodes[o],q,s);}}},getListeners:function(n,k){var q=[],m;if(!k){m=[h,j];}else{if(k==="unload"){m=[j];}else{k=this._getType(k);m=[h];}}var s=(YAHOO.lang.isString(n))?this.getEl(n):n;for(var p=0;p<m.length;p=p+1){var u=m[p];if(u){for(var r=0,t=u.length;r<t;++r){var o=u[r];if(o&&o[this.EL]===s&&(!k||k===o[this.TYPE])){q.push({type:o[this.TYPE],fn:o[this.FN],obj:o[this.OBJ],adjust:o[this.OVERRIDE],scope:o[this.ADJ_SCOPE],index:r});}}}}return(q.length)?q:null;},_unload:function(s){var m=YAHOO.util.Event,p,o,n,r,q,t=j.slice(),k;for(p=0,r=j.length;p<r;++p){n=t[p];if(n){try{k=window;if(n[m.ADJ_SCOPE]){if(n[m.ADJ_SCOPE]===true){k=n[m.UNLOAD_OBJ];}else{k=n[m.ADJ_SCOPE];}}n[m.FN].call(k,m.getEvent(s,n[m.EL]),n[m.UNLOAD_OBJ]);}catch(w){}t[p]=null;}}n=null;k=null;j=null;if(h){for(o=h.length-1;o>-1;o--){n=h[o];if(n){try{m.removeListener(n[m.EL],n[m.TYPE],n[m.FN],o);}catch(v){}}}n=null;}try{m._simpleRemove(window,"unload",m._unload);m._simpleRemove(window,"load",m._load);}catch(u){}},_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 a=YAHOO.util.Event;a.on=a.addListener;a.onFocus=a.addFocusListener;a.onBlur=a.addBlurListener;
-/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
-if(a.isIE){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;a._ready();}};}else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var b=document.createElement("p");a._dri=setInterval(function(){try{b.doScroll("left");clearInterval(a._dri);a._dri=null;a._ready();b=null;}catch(c){}},a.POLL_INTERVAL);}}else{if(a.webkit&&a.webkit<525){a._dri=setInterval(function(){var c=document.readyState;if("loaded"==c||"complete"==c){clearInterval(a._dri);a._dri=null;a._ready();}},a.POLL_INTERVAL);}else{a._simpleAdd(document,"DOMContentLoaded",a._ready);}}a._simpleAdd(window,"load",a._load);a._simpleAdd(window,"unload",a._unload);a._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.9.0",build:"2800"});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,_isFormSubmit:false,_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;this._use_default_post_header=true;}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(g){var d,a,b;try{a=new XMLHttpRequest();d={conn:a,tId:g,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:g,xhr:true};break;}catch(f){}}}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(h,d,g,a){var b=g&&g.argument?g.argument:null,e=this,f,c;if(this._isFileUpload){c="upload";}else{if(g&&g.xdr){c="xdr";}}f=this.getConnectionObject(c);if(!f){return null;}else{if(g&&g.customevents){this.initCustomEvents(f,g);}if(this._isFormSubmit){if(this._isFileUpload){window.setTimeout(function(){e.uploadFile(f,g,d,a);},10);return f;}if(h.toUpperCase()=="GET"){if(this._sFormData.length!==0){d+=((d.indexOf("?")==-1)?"?":"&")+this._sFormData;}}else{if(h.toUpperCase()=="POST"){a=a?this._sFormData+"&"+a:this._sFormData;}}}if(h.toUpperCase()=="GET"&&(g&&g.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((h.toUpperCase()==="POST"&&this._use_default_post_header)&&this._isFormSubmit===false){this.initHeader("Content-Type",this._default_post_header);}if(f.xdr){this.xdr(f,h,d,g,a);return f;}f.conn.open(h,d,true);if(this._has_default_headers||this._has_http_headers){this.setHeader(f);}this.handleReadyState(f,g);f.conn.send(a||"");if(this._isFormSubmit===true){this.resetFormState();}this.startEvent.fire(f,b);if(f.startEvent){f.startEvent.fire(f,b);}return f;}},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,j,d){var f,a,h=(j&&j.argument)?j.argument:null,c=(b.r&&b.r.statusText==="xdr:success")?true:false,i=(b.r&&b.r.statusText==="xdr:failure")?true:false,k=d;try{if((b.conn.status!==undefined&&b.conn.status!==0)||c){f=b.conn.status;}else{if(i&&!k){f=0;}else{f=13030;}}}catch(g){f=13030;}if((f>=200&&f<300)||f===1223||c){a=b.xdr?b.r:this.createResponseObject(b,h);if(j&&j.success){if(!j.scope){j.success(a);}else{j.success.apply(j.scope,[a]);}}this.successEvent.fire(a);if(b.successEvent){b.successEvent.fire(a);}}else{switch(f){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:a=this.createExceptionObject(b.tId,h,(d?d:false));if(j&&j.failure){if(!j.scope){j.failure(a);}else{j.failure.apply(j.scope,[a]);}}break;default:a=(b.xdr)?b.response:this.createResponseObject(b,h);if(j&&j.failure){if(!j.scope){j.failure(a);}else{j.failure.apply(j.scope,[a]);}}}this.failureEvent.fire(a);if(b.failureEvent){b.failureEvent.fire(a);}}this.releaseObject(b);a=null;},createResponseObject:function(a,h){var d={},k={},f,c,g,b;try{c=a.conn.getAllResponseHeaders();g=c.split("\n");for(f=0;f<g.length;f++){b=g[f].indexOf(":");if(b!=-1){k[g[f].substring(0,b)]=YAHOO.lang.trim(g[f].substring(b+2));}}}catch(j){}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=k;d.getAllResponseHeaders=c;d.responseText=a.conn.responseText;d.responseXML=a.conn.responseXML;if(h){d.argument=h;}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,n,k){h[parseInt(l.tId)]={"o":l,"c":n};if(k){n.method=i;n.data=k;}l.conn.send(j,n,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 e=YAHOO.util.Connect,g=YAHOO.util.Event,a=document.documentMode?document.documentMode:false;e._isFileUpload=false;e._formNode=null;e._sFormData=null;e._submitElementValue=null;e.uploadEvent=new YAHOO.util.CustomEvent("upload");e._hasSubmitListener=function(){if(g){g.addListener(document,"click",function(k){var j=g.getTarget(k),i=j.nodeName.toLowerCase();if((i==="input"||i==="button")&&(j.type&&j.type.toLowerCase()=="submit")){e._submitElementValue=encodeURIComponent(j.name)+"="+encodeURIComponent(j.value);}});return true;}return false;}();function h(w,r,m){var v,l,u,s,z,t=false,p=[],y=0,o,q,n,x,k;this.resetFormState();if(typeof w=="string"){v=(document.getElementById(w)||document.forms[w]);}else{if(typeof w=="object"){v=w;}else{return;}}if(r){this.createFrame(m?m:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=v;return;}for(o=0,q=v.elements.length;o<q;++o){l=v.elements[o];z=l.disabled;u=l.name;if(!z&&u){u=encodeURIComponent(u)+"=";s=encodeURIComponent(l.value);switch(l.type){case"select-one":if(l.selectedIndex>-1){k=l.options[l.selectedIndex];p[y++]=u+encodeURIComponent((k.attributes.value&&k.attributes.value.specified)?k.value:k.text);}break;case"select-multiple":if(l.selectedIndex>-1){for(n=l.selectedIndex,x=l.options.length;n<x;++n){k=l.options[n];if(k.selected){p[y++]=u+encodeURIComponent((k.attributes.value&&k.attributes.value.specified)?k.value:k.text);}}}break;case"radio":case"checkbox":if(l.checked){p[y++]=u+s;}break;case"file":case undefined:case"reset":case"button":break;case"submit":if(t===false){if(this._hasSubmitListener&&this._submitElementValue){p[y++]=this._submitElementValue;}t=true;}break;default:p[y++]=u+s;}}}this._isFormSubmit=true;this._sFormData=p.join("&");this.initHeader("Content-Type",this._default_form_header);return this._sFormData;}function d(){this._isFormSubmit=false;this._isFileUpload=false;this._formNode=null;this._sFormData="";}function c(i){var j="yuiIO"+this._transaction_id,l=(a===9)?true:false,k;if(YAHOO.env.ua.ie&&!l){k=document.createElement('<iframe id="'+j+'" name="'+j+'" />');if(typeof i=="boolean"){k.src="javascript:false";}}else{k=document.createElement("iframe");k.id=j;k.name=j;}k.style.position="absolute";k.style.top="-1000px";k.style.left="-1000px";document.body.appendChild(k);}function f(j){var m=[],k=j.split("&"),l,n;for(l=0;l<k.length;l++){n=k[l].indexOf("=");if(n!=-1){m[l]=document.createElement("input");m[l].type="hidden";m[l].name=decodeURIComponent(k[l].substring(0,n));m[l].value=decodeURIComponent(k[l].substring(n+1));this._formNode.appendChild(m[l]);}}return m;}function b(m,y,n,l){var t="yuiIO"+m.tId,u="multipart/form-data",w=document.getElementById(t),p=(a>=8)?true:false,z=this,v=(y&&y.argument)?y.argument:null,x,s,k,r,j,q;j={action:this._formNode.getAttribute("action"),method:this._formNode.getAttribute("method"),target:this._formNode.getAttribute("target")};this._formNode.setAttribute("action",n);this._formNode.setAttribute("method","POST");this._formNode.setAttribute("target",t);if(YAHOO.env.ua.ie&&!p){this._formNode.setAttribute("encoding",u);}else{this._formNode.setAttribute("enctype",u);}if(l){x=this.appendPostData(l);}this._formNode.submit();this.startEvent.fire(m,v);if(m.startEvent){m.startEvent.fire(m,v);}if(y&&y.timeout){this._timeOut[m.tId]=window.setTimeout(function(){z.abort(m,y,true);},y.timeout);}if(x&&x.length>0){for(s=0;s<x.length;s++){this._formNode.removeChild(x[s]);}}for(k in j){if(YAHOO.lang.hasOwnProperty(j,k)){if(j[k]){this._formNode.setAttribute(k,j[k]);}else{this._formNode.removeAttribute(k);}}}this.resetFormState();
-q=function(){var i,A,B;if(y&&y.timeout){window.clearTimeout(z._timeOut[m.tId]);delete z._timeOut[m.tId];}z.completeEvent.fire(m,v);if(m.completeEvent){m.completeEvent.fire(m,v);}r={tId:m.tId,argument:v};try{i=w.contentWindow.document.getElementsByTagName("body")[0];A=w.contentWindow.document.getElementsByTagName("pre")[0];if(i){if(A){B=A.textContent?A.textContent:A.innerText;}else{B=i.textContent?i.textContent:i.innerText;}}r.responseText=B;r.responseXML=w.contentWindow.document.XMLDocument?w.contentWindow.document.XMLDocument:w.contentWindow.document;}catch(o){}if(y&&y.upload){if(!y.scope){y.upload(r);}else{y.upload.apply(y.scope,[r]);}}z.uploadEvent.fire(r);if(m.uploadEvent){m.uploadEvent.fire(r);}g.removeListener(w,"load",q);setTimeout(function(){document.body.removeChild(w);z.releaseObject(m);},100);};g.addListener(w,"load",q);}e.setForm=h;e.resetFormState=d;e.createFrame=c;e.appendPostData=f;e.uploadFile=b;})();YAHOO.register("connection",YAHOO.util.Connect,{version:"2.9.0",build:"2800"});(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 j;var e;var f=this.attributes;this.runtimeAttributes[d]={};var h=function(i){return(typeof i!=="undefined");};if(!h(f[d]["to"])&&!h(f[d]["by"])){return false;}j=(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(j.constructor==Array){e=[];for(var g=0,c=j.length;g<c;++g){e[g]=j[g]+f[d]["by"][g]*1;}}else{e=j+f[d]["by"]*1;}}}this.runtimeAttributes[d].start=j;this.runtimeAttributes[d].end=e;this.runtimeAttributes[d].unit=(h(f[d].unit))?f[d]["unit"]:this.getDefaultUnit(d);return true;},init:function(f,c,h,i){var d=false;var e=null;var g=0;f=b.Dom.get(f);this.attributes=c||{};this.duration=!YAHOO.lang.isUndefined(h)?h:1;this.method=i||b.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=b.AnimMgr.fps;this.setEl=function(j){f=b.Dom.get(j);};this.getEl=function(){return f;};this.isAnimated=function(){return d;};this.getStartTime=function(){return e;};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(j){if(!this.isAnimated()){return false;}if(j){this.currentFrame=this.totalFrames;this._onTween.fire();}b.AnimMgr.stop(this);};this._handleStart=function(){this.onStart.fire();this.runtimeAttributes={};for(var j in this.attributes){if(this.attributes.hasOwnProperty(j)){this.setRuntimeAttribute(j);}}d=true;g=0;e=new Date();};this._handleTween=function(){var l={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};l.toString=function(){return("duration: "+l.duration+", currentFrame: "+l.currentFrame);};this.onTween.fire(l);var k=this.runtimeAttributes;for(var j in k){if(k.hasOwnProperty(j)){this.setAttribute(j,this.doMethod(j,k[j].start,k[j].end),k[j].unit);}}this.afterTween.fire(l);g+=1;};this._handleComplete=function(){var j=(new Date()-e)/1000;var k={duration:j,frames:g,fps:g/j};k.toString=function(){return("duration: "+k.duration+", frames: "+k.frames+", fps: "+k.fps);};d=false;g=0;this.onComplete.fire(k);};this._onStart=new b.CustomEvent("_start",this,true);this.onStart=new b.CustomEvent("start",this);this.onTween=new b.CustomEvent("tween",this);this.afterTween=new b.CustomEvent("afterTween",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(this._handleStart);this._onTween.subscribe(this._handleTween);this._onComplete.subscribe(this._handleComplete);}};b.Anim=a;})();YAHOO.util.AnimMgr=new function(){var e=null;var c=[];var g=0;this.fps=1000;this.delay=20;this.registerElement=function(j){c[c.length]=j;g+=1;j._onStart.fire();this.start();};var f=[];var d=false;var h=function(){var j=f.shift();b.apply(YAHOO.util.AnimMgr,j);if(f.length){arguments.callee();}};var b=function(k,j){j=j||a(k);if(!k.isAnimated()||j===-1){return false;}k._onComplete.fire();c.splice(j,1);g-=1;if(g<=0){this.stop();}return true;};this.unRegister=function(){f.push(arguments);if(!d){d=true;h();d=false;}};this.start=function(){if(e===null){e=setInterval(this.run,this.delay);}};this.stop=function(l){if(!l){clearInterval(e);for(var k=0,j=c.length;k<j;++k){this.unRegister(c[0],0);}c=[];e=null;g=0;}else{this.unRegister(l);}};this.run=function(){for(var l=0,j=c.length;l<j;++l){var k=c[l];if(!k||!k.isAnimated()){continue;}if(k.currentFrame<k.totalFrames||k.totalFrames===null){k.currentFrame+=1;if(k.useSeconds){i(k);}k._onTween.fire();}else{YAHOO.util.AnimMgr.stop(k,l);}}};var a=function(l){for(var k=0,j=c.length;k<j;++k){if(c[k]===l){return k;}}return -1;};var i=function(k){var n=k.totalFrames;var m=k.currentFrame;var l=(k.currentFrame*k.duration*1000/k.totalFrames);var j=(new Date()-k.getStartTime());var o=0;if(j<k.duration*1000){o=Math.round((j/l-1)*k.currentFrame);}else{o=n-(m+1);}if(o>0&&isFinite(o)){if(k.currentFrame+o>=n){o=n-(m+1);}k.currentFrame+=o;}};this._queue=c;this._getIndex=a;};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,k,g){var j;if(this.patterns.color.test(f)){j=[];for(var h=0,e=k.length;h<e;++h){j[h]=d.doMethod.call(this,f,k[h],g[h]);}j="rgb("+Math.floor(j[0])+","+Math.floor(j[1])+","+Math.floor(j[2])+")";}else{j=d.doMethod.call(this,f,k,g);}return j;};b.setRuntimeAttribute=function(f){d.setRuntimeAttribute.call(this,f);if(this.patterns.color.test(f)){var h=this.attributes;var k=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 j=0,e=k.length;j<e;++j){g[j]=k[j]+g[j];}}this.runtimeAttributes[f].start=k;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(e,a,g,f){return g*e/f+a;},easeIn:function(e,a,g,f){return g*(e/=f)*e+a;},easeOut:function(e,a,g,f){return -g*(e/=f)*(e-2)+a;},easeBoth:function(e,a,g,f){if((e/=f/2)<1){return g/2*e*e+a;}return -g/2*((--e)*(e-2)-1)+a;},easeInStrong:function(e,a,g,f){return g*(e/=f)*e*e*e+a;},easeOutStrong:function(e,a,g,f){return -g*((e=e/f-1)*e*e*e-1)+a;},easeBothStrong:function(e,a,g,f){if((e/=f/2)<1){return g/2*e*e*e*e+a;}return -g/2*((e-=2)*e*e*e-2)+a;},elasticIn:function(g,e,k,j,f,i){if(g==0){return e;}if((g/=j)==1){return e+k;}if(!i){i=j*0.3;}if(!f||f<Math.abs(k)){f=k;var h=i/4;}else{var h=i/(2*Math.PI)*Math.asin(k/f);}return -(f*Math.pow(2,10*(g-=1))*Math.sin((g*j-h)*(2*Math.PI)/i))+e;},elasticOut:function(g,e,k,j,f,i){if(g==0){return e;}if((g/=j)==1){return e+k;}if(!i){i=j*0.3;}if(!f||f<Math.abs(k)){f=k;var h=i/4;}else{var h=i/(2*Math.PI)*Math.asin(k/f);}return f*Math.pow(2,-10*g)*Math.sin((g*j-h)*(2*Math.PI)/i)+k+e;},elasticBoth:function(g,e,k,j,f,i){if(g==0){return e;}if((g/=j/2)==2){return e+k;}if(!i){i=j*(0.3*1.5);}if(!f||f<Math.abs(k)){f=k;var h=i/4;}else{var h=i/(2*Math.PI)*Math.asin(k/f);}if(g<1){return -0.5*(f*Math.pow(2,10*(g-=1))*Math.sin((g*j-h)*(2*Math.PI)/i))+e;}return f*Math.pow(2,-10*(g-=1))*Math.sin((g*j-h)*(2*Math.PI)/i)*0.5+k+e;},backIn:function(e,a,h,g,f){if(typeof f=="undefined"){f=1.70158;}return h*(e/=g)*e*((f+1)*e-f)+a;},backOut:function(e,a,h,g,f){if(typeof f=="undefined"){f=1.70158;}return h*((e=e/g-1)*e*((f+1)*e+f)+1)+a;},backBoth:function(e,a,h,g,f){if(typeof f=="undefined"){f=1.70158;}if((e/=g/2)<1){return h/2*(e*e*(((f*=(1.525))+1)*e-f))+a;}return h/2*((e-=2)*e*(((f*=(1.525))+1)*e+f)+2)+a;},bounceIn:function(e,a,g,f){return g-YAHOO.util.Easing.bounceOut(f-e,0,g,f)+a;},bounceOut:function(e,a,g,f){if((e/=f)<(1/2.75)){return g*(7.5625*e*e)+a;}else{if(e<(2/2.75)){return g*(7.5625*(e-=(1.5/2.75))*e+0.75)+a;}else{if(e<(2.5/2.75)){return g*(7.5625*(e-=(2.25/2.75))*e+0.9375)+a;}}}return g*(7.5625*(e-=(2.625/2.75))*e+0.984375)+a;},bounceBoth:function(e,a,g,f){if(e<f/2){return YAHOO.util.Easing.bounceIn(e*2,0,g,f)*0.5+a;}return YAHOO.util.Easing.bounceOut(e*2-f,0,g,f)*0.5+g*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(q){if(this.patterns.points.test(q)){var h=this.getEl();var k=this.attributes;var g;var m=k["points"]["control"]||[];var j;var n,p;if(m.length>0&&!(m[0] instanceof Array)){m=[m];}else{var l=[];for(n=0,p=m.length;n<p;++n){l[n]=m[n];}m=l;}if(e.Dom.getStyle(h,"position")=="static"){e.Dom.setStyle(h,"position","relative");}if(d(k["points"]["from"])){e.Dom.setXY(h,k["points"]["from"]);}else{e.Dom.setXY(h,e.Dom.getXY(h));}g=this.getAttribute("points");if(d(k["points"]["to"])){j=b.call(this,k["points"]["to"],g);var o=e.Dom.getXY(this.getEl());for(n=0,p=m.length;n<p;++n){m[n]=b.call(this,m[n],g);}}else{if(d(k["points"]["by"])){j=[g[0]+k["points"]["by"][0],g[1]+k["points"]["by"][1]];for(n=0,p=m.length;n<p;++n){m[n]=[g[0]+m[n][0],g[1]+m[n][1]];}}}this.runtimeAttributes[q]=[g];if(m.length>0){this.runtimeAttributes[q]=this.runtimeAttributes[q].concat(m);}this.runtimeAttributes[q][this.runtimeAttributes[q].length]=j;}else{f.setRuntimeAttribute.call(this,q);}};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.9.0",build:"2800"});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.env.ua.ie&&(YAHOO.env.ua.ie<9)&&!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(W,M){var c=this.dragCurrent;if(!c||c.isLocked()||c.dragOnly){return;}var O=YAHOO.util.Event.getPageX(W),N=YAHOO.util.Event.getPageY(W),Q=new YAHOO.util.Point(O,N),K=c.getTargetCoord(Q.x,Q.y),F=c.getDragEl(),E=["out","over","drop","enter"],V=new YAHOO.util.Region(K.y,K.x+F.offsetWidth,K.y+F.offsetHeight,K.x),I=[],D={},L={},R=[],d={outEvts:[],overEvts:[],dropEvts:[],enterEvts:[]};for(var T in this.dragOvers){var f=this.dragOvers[T];if(!this.isTypeOfDD(f)){continue;
-}if(!this.isOverTarget(Q,f,this.mode,V)){d.outEvts.push(f);}I[T]=true;delete this.dragOvers[T];}for(var S in c.groups){if("string"!=typeof S){continue;}for(T in this.ids[S]){var G=this.ids[S][T];if(!this.isTypeOfDD(G)){continue;}if(G.isTarget&&!G.isLocked()&&G!=c){if(this.isOverTarget(Q,G,this.mode,V)){D[S]=true;if(M){d.dropEvts.push(G);}else{if(!I[G.id]){d.enterEvts.push(G);}else{d.overEvts.push(G);}this.dragOvers[G.id]=G;}}}}}this.interactionInfo={out:d.outEvts,enter:d.enterEvts,over:d.overEvts,drop:d.dropEvts,point:Q,draggedRegion:V,sourceRegion:this.locationCache[c.id],validDrop:M};for(var C in D){R.push(C);}if(M&&!d.dropEvts.length){this.interactionInfo.validDrop=false;if(c.events.invalidDrop){c.onInvalidDrop(W);c.fireEvent("invalidDropEvent",{e:W});}}for(T=0;T<E.length;T++){var Z=null;if(d[E[T]+"Evts"]){Z=d[E[T]+"Evts"];}if(Z&&Z.length){var H=E[T].charAt(0).toUpperCase()+E[T].substr(1),Y="onDrag"+H,J="b4Drag"+H,P="drag"+H+"Event",X="drag"+H;if(this.mode){if(c.events[J]){c[J](W,Z,R);L[Y]=c.fireEvent(J+"Event",{event:W,info:Z,group:R});}if(c.events[X]&&(L[Y]!==false)){c[Y](W,Z,R);c.fireEvent(P,{event:W,info:Z,group:R});}}else{for(var a=0,U=Z.length;a<U;++a){if(c.events[J]){c[J](W,Z[a].id,R[0]);L[Y]=c.fireEvent(J+"Event",{event:W,info:Z[a].id,group:R[0]});}if(c.events[X]&&(L[Y]!==false)){c[Y](W,Z[a].id,R[0]);c.fireEvent(P,{event:W,info:Z[a].id,group:R[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){if(E===false){H=false;}else{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.9.0",build:"2800"});YAHOO.util.Attribute=function(b,a){if(a){this.owner=a;this.configure(b,true);}};YAHOO.util.Attribute.INVALID_VALUE={};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,g=YAHOO.util.Attribute.INVALID_VALUE,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(f===g){return false;}}if(this.method){if(this.method.call(a,f,this.name)===g){return false;}}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(l,h){var f={},j=this._configOrder;for(var k=0,e=j.length;k<e;++k){if(l[j[k]]!==undefined){f[j[k]]=true;this.set(j[k],l[j[k]],h);}}for(var g in l){if(l.hasOwnProperty(g)&&!f[g]){this.set(g,l[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.9.0",build:"2800"});YAHOO.register("utilities", YAHOO, {version: "2.9.0", build: "2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-(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,_cloneObject:function(o){if(!lang.isValue(o)){return o;}var copy={};if(Object.prototype.toString.apply(o)==="[object RegExp]"){copy=o;}else{if(lang.isFunction(o)){copy=o;}else{if(lang.isArray(o)){var array=[];for(var i=0,len=o.length;i<len;i++){array[i]=DS._cloneObject(o[i]);}copy=array;}else{if(lang.isObject(o)){for(var x in o){if(lang.hasOwnProperty(o,x)){if(lang.isValue(o[x])&&lang.isObject(o[x])||lang.isArray(o[x])){copy[x]=DS._cloneObject(o[x]);}else{copy[x]=o[x];}}}}else{copy=o;}}}}return copy;},_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(lang.isValue(oData)&&!(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,cloneBeforeCaching: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();}oResponse=(this.cloneBeforeCaching)?DS._cloneObject(oResponse):oResponse;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.call(this,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,oCallback):this.liveData(oRequest,oCallback);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){return new util.LocalDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_XHR){return new util.XHRDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_SCRIPTNODE){return new util.ScriptNodeDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_JSFUNCTION){return new util.FunctionDataSource(oLiveData,oConfigs);}}}}}if(YAHOO.lang.isString(oLiveData)){return new util.XHRDataSource(oLiveData,oConfigs);}else{if(YAHOO.lang.isFunction(oLiveData)){return new util.FunctionDataSource(oLiveData,oConfigs);}else{return new util.LocalDataSource(oLiveData,oConfigs);}}};lang.augmentObject(util.DataSource,DS);})();YAHOO.util.Number={format:function(e,k){if(e===""||e===null||!isFinite(e)){return"";}e=+e;k=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,(k||{}));var j=e+"",l=Math.abs(e),b=k.decimalPlaces||0,r=k.thousandsSeparator,f=k.negativeFormat||("-"+k.format),q,p,g,h;if(f.indexOf("#")>-1){f=f.replace(/#/,k.format);}if(b<0){q=l-(l%1)+"";g=q.length+b;if(g>0){q=Number("."+q).toFixed(g).slice(2)+new Array(q.length-g+1).join("0");}else{q="0";}}else{var a=l+"";if(b>0||a.indexOf(".")>0){var d=Math.pow(10,b);q=Math.round(l*d)/d+"";var c=q.indexOf("."),m,o;if(c<0){m=b;o=(Math.pow(10,m)+"").substring(1);if(b>0){q=q+"."+o;}}else{m=b-(q.length-c-1);o=(Math.pow(10,m)+"").substring(1);q=q+o;}}else{q=l.toFixed(b)+"";}}p=q.split(/\D/);if(l>=1000){g=p[0].length%3||3;p[0]=p[0].slice(0,g)+p[0].slice(g).replace(/(\d{3})/g,r+"$1");}return YAHOO.util.Number.format._applyFormat((e<0?f:k.format),p.join(k.decimalSeparator),k);}};YAHOO.util.Number.format.defaults={format:"{prefix}{number}{suffix}",negativeFormat:null,decimalSeparator:".",decimalPlaces:null,thousandsSeparator:""};YAHOO.util.Number.format._applyFormat=function(a,b,c){return a.replace(/\{(\w+)\}/g,function(d,e){return e==="number"?b:e in c?c[e]:"";});};(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(e,c){return c.a[e.getDay()];},A:function(e,c){return c.A[e.getDay()];},b:function(e,c){return c.b[e.getMonth()];},B:function(e,c){return c.B[e.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(f){var g=f.getFullYear();var e=parseInt(b.formats.V(f),10);var c=parseInt(b.formats.W(f),10);if(c>e){g++;}else{if(c===0&&e>=52){g--;}}return g;},H:["getHours","0"],I:function(e){var c=e.getHours()%12;return a(c===0?12:c,0);},j:function(h){var g=new Date(""+h.getFullYear()+"/1/1 GMT");var e=new Date(""+h.getFullYear()+"/"+(h.getMonth()+1)+"/"+h.getDate()+" GMT");var c=e-g;var f=parseInt(c/60000/60/24,10)+1;return a(f,0,100);},k:["getHours"," "],l:function(e){var c=e.getHours()%12;return a(c===0?12:c," ");},m:function(c){return a(c.getMonth()+1,0);},M:["getMinutes","0"],p:function(e,c){return c.p[e.getHours()>=12?1:0];},P:function(e,c){return c.P[e.getHours()>=12?1:0];},s:function(e,c){return parseInt(e.getTime()/1000,10);},S:["getSeconds","0"],u:function(c){var e=c.getDay();return e===0?7:e;},U:function(g){var c=parseInt(b.formats.j(g),10);var f=6-g.getDay();var e=parseInt((c+f)/7,10);return a(e,0);},V:function(g){var f=parseInt(b.formats.W(g),10);var c=(new Date(""+g.getFullYear()+"/1/1")).getDay();var e=f+(c>4||c<=1?0:1);if(e===53&&(new Date(""+g.getFullYear()+"/12/31")).getDay()<4){e=1;}else{if(e===0){e=b.formats.V(new Date(""+(g.getFullYear()-1)+"/12/31"));}}return a(e,0);},w:"getDay",W:function(g){var c=parseInt(b.formats.j(g),10);var f=7-b.formats.u(g);var e=parseInt((c+f)/7,10);
-return a(e,0,10);},y:function(c){return a(c.getFullYear()%100,0);},Y:"getFullYear",z:function(f){var e=f.getTimezoneOffset();var c=a(parseInt(Math.abs(e/60),10),0);var g=a(Math.abs(e%60),0);return(e>0?"-":"+")+c+g;},Z:function(c){var e=c.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(e.length>4){e=b.formats.z(c);}return e;},"%":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.9.0",build:"2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-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.dataRequestCancelEvent=new YAHOO.util.CustomEvent("dataRequestCancel",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(l,n,r,m){if(m&&m.argument&&YAHOO.lang.isValue(m.argument.query)){l=m.argument.query;}if(l&&l!==""){r=YAHOO.widget.AutoComplete._cloneObject(r);var j=m.scope,q=this,c=r.results,o=[],b=j.maxResultsDisplayed,k=(q.queryMatchCase||j.queryMatchCase),a=(q.queryMatchContains||j.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 p=this.responseSchema.fields[0].key||this.responseSchema.fields[0];e=f[p];}else{if(this.key){e=f[this.key];}}}}if(YAHOO.lang.isString(e)){var g=(k)?e.indexOf(decodeURIComponent(l)):e.toLowerCase().indexOf(decodeURIComponent(l).toLowerCase());if((!a&&(g===0))||(a&&(g>-1))){o.push(f);}}if(h>b&&o.length===b){break;}}r.results=o;}else{}return r;};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.formatEscapedResult=function(c,d,b){var a=(b)?b:"";return YAHOO.lang.escapeHTML(a);};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.dataRequestCancelEvent=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);if(b!==undefined){this.dataRequestEvent.fire(this,d,b);this.dataSource.sendRequest(b,{success:this.handleResponse,failure:this.handleResponse,scope:this,argument:{query:d}});}else{this.dataRequestCancelEvent.fire(this,d);}};YAHOO.widget.AutoComplete.prototype._populateListItem=function(b,a,c){b.innerHTML=this.formatResult(a,c,b._sResultMatch);};YAHOO.widget.AutoComplete.prototype._populateList=function(n,f,c){if(this._nTypeAheadDelayID!=-1){clearTimeout(this._nTypeAheadDelayID);}n=(c&&c.query)?c.query:n;var h=this.doBeforeLoadData(n,f,c);if(h&&!f.error){this.dataReturnEvent.fire(this,n,f.results);if(this._bFocused){var p=decodeURIComponent(n);this._sCurQuery=p;this._bItemSelected=false;var u=f.results,a=Math.min(u.length,this.maxResultsDisplayed),m=(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 l=this._elList.childNodes;for(var t=a-1;t>=0;t--){var s=l[t],e=u[t];if(this.resultTypeList){var b=[];b[0]=(YAHOO.lang.isString(e))?e:e[m]||e[this.key];var o=this.dataSource.responseSchema.fields;if(YAHOO.lang.isArray(o)&&(o.length>1)){for(var q=1,v=o.length;q<v;q++){b[b.length]=e[o[q].key||o[q]];}}else{if(YAHOO.lang.isArray(e)){b=e;}else{if(YAHOO.lang.isString(e)){b=[e];}else{b[1]=e;}}}e=b;}s._sResultMatch=(YAHOO.lang.isString(e))?e:(YAHOO.lang.isArray(e))?e[0]:(e[m]||"");s._oResultData=e;this._populateListItem(s,e,p);s.style.display="";}if(a<l.length){var g;for(var r=l.length-1;r>=a;r--){g=l[r];g.style.display="none";}}this._nDisplayedItems=a;this.containerPopulateEvent.fire(this,n,u);if(this.autoHighlight){var d=this._elList.firstChild;this._toggleHighlight(d,"to");this.itemArrowToEvent.fire(this,d);this._typeAhead(d,n);}else{this._toggleHighlight(this._elCurListItem,"from");}h=this._doBeforeExpandContainer(this._elTextbox,this._elContainer,n,u);this._toggleContainer(h);}else{this._toggleContainer(false);}return;}}else{this.dataErrorEvent.fire(this,n,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._sCurQuery=b._sResultMatch;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);this._sCurQuery=f._sResultMatch;}}};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.9.0",build:"2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-(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(d in this.initialConfig){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(v,r){v=v.toLowerCase();var u=this.config[v],l=false,k,g,h,j,p,t,f,n,o,d,m,w,e;if(u&&u.event){if(!b.isUndefined(r)&&u.validator&&!u.validator(r)){return false;}else{if(!b.isUndefined(r)){u.value=r;}else{r=u.value;}l=false;k=this.eventQueue.length;for(m=0;m<k;m++){g=this.eventQueue[m];if(g){h=g[0];j=g[1];if(h==v){this.eventQueue[m]=null;this.eventQueue.push([v,(!b.isUndefined(r)?r:j)]);l=true;break;}}}if(!l&&!b.isUndefined(r)){this.eventQueue.push([v,r]);}}if(u.supercedes){p=u.supercedes.length;for(w=0;w<p;w++){t=u.supercedes[w];f=this.eventQueue.length;for(e=0;e<f;e++){n=this.eventQueue[e];if(n){o=n[0];d=n[1];if(o==t.toLowerCase()){this.eventQueue.push([o,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,j){var f=e.subscribers.length,d,g;if(f>0){g=f-1;do{d=e.subscribers[g];if(d&&d.obj==j&&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,{handler:this.configEffect,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.tabIndex=-1;s.setAttribute("role","presentation");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(q){var r,s=!(q);if(this.element){n.purgeElement(this.element,s);r=this.element.parentNode;}if(r){r.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){if(this.beforeShowEvent.fire()){f.setStyle(this.element,"display","block");this.showEvent.fire();}}else{if(this.beforeHideEvent.fire()){f.setStyle(this.element,"display","none");this.hideEvent.fire();}}},configEffect:function(r,q,s){this._cachedEffects=(this.cacheEffects)?this._createEffects(q[0]):null;},cacheEffects:true,_createEffects:function(t){var q=null,u,r,s;if(t){if(t instanceof Array){q=[];u=t.length;for(r=0;r<u;r++){s=t[r];if(s.effect){q[q.length]=s.effect(this,s.duration);}}}else{if(t.effect){q=[t.effect(this,t.duration)];}}}return q;},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(x,w,t){var p=w[0],B=f.getStyle(this.element,"visibility"),o=this._cachedEffects||this._createEffects(this.cfg.getProperty("effect")),A=(this.platform=="mac"&&k.gecko),y=d.alreadySubscribed,q,v,s,r,u,z;if(B=="inherit"){v=this.element.parentNode;while(v.nodeType!=9&&v.nodeType!=11){B=f.getStyle(v,"visibility");if(B!="inherit"){break;}v=v.parentNode;}if(B=="inherit"){B="visible";}}if(p){if(A){this.showMacGeckoScrollbars();}if(o){if(p){if(B!="visible"||B===""||this._fadingOut){if(this.beforeShowEvent.fire()){z=o.length;for(s=0;s<z;s++){q=o[s];if(s===0&&!y(q.animateInCompleteEvent,this.showEvent.fire,this.showEvent)){q.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true);}q.animateIn();}}}}}else{if(B!="visible"||B===""){if(this.beforeShowEvent.fire()){this._setDomVisibility(true);this.cfg.refireEvent("iframe");this.showEvent.fire();}}else{this._setDomVisibility(true);}}}else{if(A){this.hideMacGeckoScrollbars();}if(o){if(B=="visible"||this._fadingIn){if(this.beforeHideEvent.fire()){z=o.length;for(r=0;r<z;r++){u=o[r];if(r===0&&!y(u.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)){u.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true);}u.animateOut();}}}else{if(B===""){this._setDomVisibility(false);}}}else{if(B=="visible"||B===""){if(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,v,r){var q,u;for(var p=0,o=s.length;p<o;++p){q=s[p];u=this._findTriggerCE(q);if(u){u[v](r,this,true);}else{this[v](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(y,p){var t=this.element,r=b.VIEWPORT_OFFSET,A=(y=="x"),z=(A)?t.offsetWidth:t.offsetHeight,s=(A)?f.getViewportWidth():f.getViewportHeight(),D=(A)?f.getDocumentScrollLeft():f.getDocumentScrollTop(),C=(A)?b.PREVENT_OVERLAP_X:b.PREVENT_OVERLAP_Y,o=this.cfg.getProperty("context"),u=(z+r<s),w=this.cfg.getProperty("preventcontextoverlap")&&o&&C[(o[1]+o[2])],v=D+r,B=D+s-z-r,q=p;if(p<v||p>B){if(w){q=this._preventOverlap(y,o[0],z,s,D);}else{if(u){if(p<v){q=v;}else{if(p>B){q=B;}}}else{q=v;}}}return q;},_preventOverlap:function(y,w,z,u,C){var A=(y=="x"),t=b.VIEWPORT_OFFSET,s=this,q=((A)?f.getX(w):f.getY(w))-C,o=(A)?w.offsetWidth:w.offsetHeight,p=q-t,r=(u-(q+o))-t,D=false,v=function(){var x;if((s.cfg.getProperty(y)-C)>q){x=(q-z);}else{x=(q+o);}s.cfg.setProperty(y,(x+C),true);return x;},B=function(){var E=((s.cfg.getProperty(y)-C)>q)?r:p,x;if(z>E){if(D){v();}else{v();D=true;x=B();}}return x;};B();return this.cfg.getProperty(y);},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(o){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,o);},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 k=false,h,j;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);k=true;}else{if(g instanceof Array){for(h=0,j=g.length;h<j;h++){k=this.register(g[h])||k;}}}return k;},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 l=g instanceof d,j=this.overlays,p=j.length,k=null,m,h;if(l||typeof g=="string"){for(h=p-1;h>=0;h--){m=j[h];if((l&&(m===g))||(m.id==g)){k=m;break;}}}return k;},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,j=h.length,g;for(g=j-1;g>=0;g--){h[g].show();}},hideAll:function(){var h=this.overlays,j=h.length,g;for(g=j-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={"BEFORE_SHOW_MASK":"beforeShowMask","BEFORE_HIDE_MASK":"beforeHideMask","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._focusOnShow);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{this._focusFirstModal();}catch(w){try{if(v&&y!==document.body){y.blur();}}catch(u){}}}}},_focusFirstModal:function(){var u=this.firstElement;if(u){u.focus();}else{if(this._modalFocus){this._modalFocus.focus();}else{this.innerElement.focus();}}},_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;}},_focusOnShow:function(v,u,w){if(u&&u[1]){t.stopEvent(u[1]);}if(!this.focusFirst(v,u,w)){if(this.cfg.getProperty("modal")){this._focusFirstModal();}}},focusFirst:function(w,u,z){var v=this.firstElement,y=false;if(u&&u[1]){t.stopEvent(u[1]);}if(v){try{v.focus();y=true;}catch(x){}}return y;},focusLast:function(w,u,z){var v=this.lastElement,y=false;if(u&&u[1]){t.stopEvent(u[1]);}if(v){try{v.focus();y=true;}catch(x){}}return y;},_setTabLoop:function(u,v){this.setTabLoop(u,v);},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(v){v=v||this.innerElement;var x={},u=this;for(var w=0;w<o.FOCUSABLE.length;w++){x[o.FOCUSABLE[w]]=true;}return a.getElementsBy(function(y){return u._testIfFocusable(y,x);},null,v);},_testIfFocusable:function(u,v){if(u.focus&&u.type!=="hidden"&&!u.disabled&&v[u.tagName.toLowerCase()]){return true;}return false;},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.beforeShowMaskEvent=this.createEvent(d.BEFORE_SHOW_MASK);this.beforeShowMaskEvent.signature=u;this.hideMaskEvent=this.createEvent(d.HIDE_MASK);this.hideMaskEvent.signature=u;this.beforeHideMaskEvent=this.createEvent(d.BEFORE_HIDE_MASK);this.beforeHideMaskEvent.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(y,v,z){var A=v[0],x=this.close,u=this.cfg.getProperty("strings"),w;if(A){if(!x){if(!c){c=document.createElement("a");c.className="container-close";c.href="#";}x=c.cloneNode(true);w=this.innerElement.firstChild;if(w){this.innerElement.insertBefore(x,w);}else{this.innerElement.appendChild(x);}x.innerHTML=(u&&u.close)?u.close:"&#160;";t.on(x,"click",this._doClose,this,true);this.close=x;}else{x.style.display="block";}}else{if(x){x.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.beforeHideMaskEvent.fire()){this.mask.style.display="none";a.removeClass(document.body,"masked");this.hideMaskEvent.fire();}},showMask:function(){if(this.cfg.getProperty("modal")&&this.mask&&this.beforeShowMaskEvent.fire()){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(u){h.windowResizeEvent.unsubscribe(this.sizeMask,this);this.removeMask();if(this.close){t.purgeElement(this.close);}o.superclass.destroy.call(this,u);},forceUnderlayRedraw:function(){var v=this.underlay;a.addClass(v,"yui-force-redraw");
-setTimeout(function(){a.removeClass(v,"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 m=this._aButtons,k,l,j;if(f.isArray(m)){k=m.length;if(k>0){j=k-1;do{l=m[j];if(YAHOO.widget.Button&&l instanceof YAHOO.widget.Button){l.destroy();}else{if(l.tagName.toUpperCase()=="BUTTON"){b.purgeElement(l);b.purgeElement(l,false);}}}while(j--);}}}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.beforeHideEvent.subscribe(this.blurButtons,this,true);this.subscribe("changeBody",this.registerForm);this.initEvent.fire(a);},doSubmit:function(){var q=YAHOO.util.Connect,r=this.form,l=false,o=false,s,n,m,j;switch(this.cfg.getProperty("postmethod")){case"async":s=r.elements;n=s.length;if(n>0){m=n-1;do{if(s[m].type=="file"){l=true;break;}}while(m--);}if(l&&YAHOO.env.ua.ie&&this.isSecure){o=true;}j=this._getFormAttributes(r);q.setForm(r,l,o);var k=this.cfg.getProperty("postdata");var p=q.asyncRequest(j.method,j.action,this.callback,k);this.asyncSubmitEvent.fire(p);break;case"form":r.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=j||this.lastButton;a.superclass.setTabLoop.call(this,i,j);},_setTabLoop:function(i,j){i=i||this.firstButton;j=this.lastButton||j;this.setTabLoop(i,j);},setFirstLastFocusable:function(){a.superclass.setFirstLastFocusable.call(this);var k,j,m,n=this.focusableElements;this.firstFormElement=null;this.lastFormElement=null;if(this.form&&n&&n.length>0){j=n.length;for(k=0;k<j;++k){m=n[k];if(this.form===m.form){this.firstFormElement=m;break;}}for(k=j-1;k>=0;--k){m=n[k];if(this.form===m.form){this.lastFormElement=m;break;}}}},configClose:function(j,i,k){a.superclass.configClose.apply(this,arguments);},_doClose:function(i){b.preventDefault(i);this.cancel();},configButtons:function(t,s,n){var o=YAHOO.widget.Button,v=s[0],l=this.innerElement,u,q,k,r,p,j,m;d.call(this);this._aButtons=null;if(f.isArray(v)){p=document.createElement("span");p.className="button-group";r=v.length;this._aButtons=[];this.defaultHtmlButton=null;for(m=0;m<r;m++){u=v[m];if(o){k=new o({label:u.text,type:u.type});k.appendTo(p);q=k.get("element");if(u.isDefault){k.addClass("default");this.defaultHtmlButton=q;}if(f.isFunction(u.handler)){k.set("onclick",{fn:u.handler,obj:this,scope:this});}else{if(f.isObject(u.handler)&&f.isFunction(u.handler.fn)){k.set("onclick",{fn:u.handler.fn,obj:((!f.isUndefined(u.handler.obj))?u.handler.obj:this),scope:(u.handler.scope||this)});}}this._aButtons[this._aButtons.length]=k;}else{q=document.createElement("button");q.setAttribute("type","button");if(u.isDefault){q.className="default";this.defaultHtmlButton=q;}q.innerHTML=u.text;if(f.isFunction(u.handler)){b.on(q,"click",u.handler,this,true);}else{if(f.isObject(u.handler)&&f.isFunction(u.handler.fn)){b.on(q,"click",u.handler.fn,((!f.isUndefined(u.handler.obj))?u.handler.obj:this),(u.handler.scope||this));}}p.appendChild(q);this._aButtons[this._aButtons.length]=q;}u.htmlButton=q;if(m===0){this.firstButton=q;}if(m==(r-1)){this.lastButton=q;}}this.setFooter(p);j=this.footer;if(e.inDocument(this.element)&&!e.isAncestor(l,j)){l.appendChild(j);}this.buttonSpan=p;}else{p=this.buttonSpan;
-j=this.footer;if(p&&j){j.removeChild(p);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,n){var j=this.firstFormElement,m=false;if(i&&i[1]){b.stopEvent(i[1]);if(i[0]===9&&this.firstElement){j=this.firstElement;}}if(j){try{j.focus();m=true;}catch(l){}}else{if(this.defaultHtmlButton){m=this.focusDefaultButton();}else{m=this.focusFirstButton();}}return m;},focusLast:function(k,i,n){var o=this.cfg.getProperty("buttons"),j=this.lastFormElement,m=false;if(i&&i[1]){b.stopEvent(i[1]);if(i[0]===9&&this.lastElement){j=this.lastElement;}}if(o&&f.isArray(o)){m=this.focusLastButton();}else{if(j){try{j.focus();m=true;}catch(l){}}}return m;},_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),k=false;if(i){try{i.focus();k=true;}catch(j){}}return k;},blurButtons:function(){var o=this.cfg.getProperty("buttons"),l,n,k,j;if(o&&f.isArray(o)){l=o.length;if(l>0){j=(l-1);do{n=o[j];if(n){k=this._getButton(n.htmlButton);if(k){try{k.blur();}catch(m){}}}}while(j--);}}},focusFirstButton:function(){var m=this.cfg.getProperty("buttons"),k,i,l=false;if(m&&f.isArray(m)){k=m[0];if(k){i=this._getButton(k.htmlButton);if(i){try{i.focus();l=true;}catch(j){}}}}return l;},focusLastButton:function(){var n=this.cfg.getProperty("buttons"),j,l,i,m=false;if(n&&f.isArray(n)){j=n.length;if(j>0){l=n[(j-1)];if(l){i=this._getButton(l.htmlButton);if(i){try{i.focus();m=true;}catch(k){}}}}}return m;},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 A=this.form,k,t,w,m,u,r,q,j,x,l,y,B,p,C,o,z,v;function s(n){var i=n.tagName.toUpperCase();return((i=="INPUT"||i=="TEXTAREA"||i=="SELECT")&&n.name==m);}if(A){k=A.elements;t=k.length;w={};for(z=0;z<t;z++){m=k[z].name;u=e.getElementsBy(s,"*",A);r=u.length;if(r>0){if(r==1){u=u[0];q=u.type;j=u.tagName.toUpperCase();switch(j){case"INPUT":if(q=="checkbox"){w[m]=u.checked;}else{if(q!="radio"){w[m]=u.value;}}break;case"TEXTAREA":w[m]=u.value;break;case"SELECT":x=u.options;l=x.length;y=[];for(v=0;v<l;v++){B=x[v];if(B.selected){o=B.attributes.value;y[y.length]=(o&&o.specified)?B.value:B.text;}}w[m]=y;break;}}else{q=u[0].type;switch(q){case"radio":for(v=0;v<r;v++){p=u[v];if(p.checked){w[m]=p.value;break;}}break;case"checkbox":y=[];for(v=0;v<r;v++){C=u[v];if(C.checked){y[y.length]=C.value;}}w[m]=y;break;}}}}}return w;},destroy:function(i){d.call(this);this._aButtons=null;var j=this.element.getElementsByTagName("form"),k;if(j.length>0){k=j[0];if(k){b.purgeElement(k);if(k.parentNode){k.parentNode.removeChild(k);}this.form=null;}}a.superclass.destroy.call(this,i);},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);var e=this.form.ownerDocument,d=e.createElement("input");d.type="hidden";d.name=this.id;d.value="";this.form.appendChild(d);},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){l.overlay._fadingIn=true;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){l.overlay._fadingIn=false;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){l.overlay._fadingOut=true;b.addClass(l.overlay.element,"hide-select");l.handleUnderlayStart();};h.handleCompleteAnimateOut=function(k,j,l){l.overlay._fadingOut=false;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._stopAnims(this.lastFrameOnStop);this.beforeAnimateInEvent.fire();this.animIn.animate();},animateOut:function(){this._stopAnims(this.lastFrameOnStop);this.beforeAnimateOutEvent.fire();this.animOut.animate();},lastFrameOnStop:true,_stopAnims:function(d){if(this.animOut&&this.animOut.isAnimated()){this.animOut.stop(d);}if(this.animIn&&this.animIn.isAnimated()){this.animIn.stop(d);}},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.9.0",build:"2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-var Y=YAHOO,Y_DOM=YAHOO.util.Dom,EMPTY_ARRAY=[],Y_UA=Y.env.ua,Y_Lang=Y.lang,Y_DOC=document,Y_DOCUMENT_ELEMENT=Y_DOC.documentElement,Y_DOM_inDoc=Y_DOM.inDocument,Y_mix=Y_Lang.augmentObject,Y_guid=Y_DOM.generateId,Y_getDoc=function(a){var b=Y_DOC;if(a){b=(a.nodeType===9)?a:a.ownerDocument||a.document||Y_DOC;}return b;},Y_Array=function(g,d){var c,b,h=d||0;try{return Array.prototype.slice.call(g,h);}catch(f){b=[];c=g.length;for(;h<c;h++){b.push(g[h]);}return b;}},Y_DOM_allById=function(f,a){a=a||Y_DOC;var b=[],c=[],d,e;if(a.querySelectorAll){c=a.querySelectorAll('[id="'+f+'"]');}else{if(a.all){b=a.all(f);if(b){if(b.nodeName){if(b.id===f){c.push(b);b=EMPTY_ARRAY;}else{b=[b];}}if(b.length){for(d=0;e=b[d++];){if(e.id===f||(e.attributes&&e.attributes.id&&e.attributes.id.value===f)){c.push(e);}}}}}else{c=[Y_getDoc(a).getElementById(f)];}}return c;};var COMPARE_DOCUMENT_POSITION="compareDocumentPosition",OWNER_DOCUMENT="ownerDocument",Selector={_foundCache:[],useNative:true,_compare:("sourceIndex" in Y_DOCUMENT_ELEMENT)?function(f,e){var d=f.sourceIndex,c=e.sourceIndex;if(d===c){return 0;}else{if(d>c){return 1;}}return -1;}:(Y_DOCUMENT_ELEMENT[COMPARE_DOCUMENT_POSITION]?function(b,a){if(b[COMPARE_DOCUMENT_POSITION](a)&4){return -1;}else{return 1;}}:function(e,d){var c,a,b;if(e&&d){c=e[OWNER_DOCUMENT].createRange();c.setStart(e,0);a=d[OWNER_DOCUMENT].createRange();a.setStart(d,0);b=c.compareBoundaryPoints(1,a);}return b;}),_sort:function(a){if(a){a=Y_Array(a,0,true);if(a.sort){a.sort(Selector._compare);}}return a;},_deDupe:function(a){var b=[],c,d;for(c=0;(d=a[c++]);){if(!d._found){b[b.length]=d;d._found=true;}}for(c=0;(d=b[c++]);){d._found=null;d.removeAttribute("_found");}return b;},query:function(b,j,k,a){if(j&&typeof j=="string"){j=Y_DOM.get(j);if(!j){return(k)?null:[];}}else{j=j||Y_DOC;}var f=[],c=(Selector.useNative&&Y_DOC.querySelector&&!a),e=[[b,j]],g,l,d,h=(c)?Selector._nativeQuery:Selector._bruteQuery;if(b&&h){if(!a&&(!c||j.tagName)){e=Selector._splitQueries(b,j);}for(d=0;(g=e[d++]);){l=h(g[0],g[1],k);if(!k){l=Y_Array(l,0,true);}if(l){f=f.concat(l);}}if(e.length>1){f=Selector._sort(Selector._deDupe(f));}}return(k)?(f[0]||null):f;},_splitQueries:function(c,f){var b=c.split(","),d=[],g="",e,a;if(f){if(f.tagName){f.id=f.id||Y_guid();g='[id="'+f.id+'"] ';}for(e=0,a=b.length;e<a;++e){c=g+b[e];d.push([c,f]);}}return d;},_nativeQuery:function(a,b,c){if(Y_UA.webkit&&a.indexOf(":checked")>-1&&(Selector.pseudos&&Selector.pseudos.checked)){return Selector.query(a,b,c,true);}try{return b["querySelector"+(c?"":"All")](a);}catch(d){return Selector.query(a,b,c,true);}},filter:function(b,a){var c=[],d,e;if(b&&a){for(d=0;(e=b[d++]);){if(Selector.test(e,a)){c[c.length]=e;}}}else{}return c;},test:function(c,d,k){var g=false,b=d.split(","),a=false,l,o,h,n,f,e,m;if(c&&c.tagName){if(!k&&!Y_DOM_inDoc(c)){l=c.parentNode;if(l){k=l;}else{n=c[OWNER_DOCUMENT].createDocumentFragment();n.appendChild(c);k=n;a=true;}}k=k||c[OWNER_DOCUMENT];if(!c.id){c.id=Y_guid();}for(f=0;(m=b[f++]);){m+='[id="'+c.id+'"]';h=Selector.query(m,k);for(e=0;o=h[e++];){if(o===c){g=true;break;}}if(g){break;}}if(a){n.removeChild(c);}}return g;}};YAHOO.util.Selector=Selector;var PARENT_NODE="parentNode",TAG_NAME="tagName",ATTRIBUTES="attributes",COMBINATOR="combinator",PSEUDOS="pseudos",SelectorCSS2={_reRegExpTokens:/([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,SORT_RESULTS:true,_children:function(e,a){var b=e.children,d,c=[],f,g;if(e.children&&a&&e.children.tags){c=e.children.tags(a);}else{if((!b&&e[TAG_NAME])||(b&&a)){f=b||e.childNodes;b=[];for(d=0;(g=f[d++]);){if(g.tagName){if(!a||a===g.tagName){b.push(g);}}}}}return b||[];},_re:{attr:/(\[[^\]]*\])/g,esc:/\\[:\[\]\(\)#\.\'\>+~"]/gi,pseudos:/(\([^\)]*\))/g},shorthand:{"\\#(-?[_a-z]+[-\\w\\uE000]*)":"[id=$1]","\\.(-?[_a-z]+[-\\w\\uE000]*)":"[className~=$1]"},operators:{"":function(b,a){return !!b.getAttribute(a);},"~=":"(?:^|\\s+){val}(?:\\s+|$)","|=":"^{val}(?:-|$)"},pseudos:{"first-child":function(a){return Selector._children(a[PARENT_NODE])[0]===a;}},_bruteQuery:function(f,j,l){var g=[],a=[],i=Selector._tokenize(f),e=i[i.length-1],k=Y_getDoc(j),c,b,h,d;if(e){b=e.id;h=e.className;d=e.tagName||"*";if(j.getElementsByTagName){if(b&&(j.all||(j.nodeType===9||Y_DOM_inDoc(j)))){a=Y_DOM_allById(b,j);}else{if(h){a=j.getElementsByClassName(h);}else{a=j.getElementsByTagName(d);}}}else{c=j.firstChild;while(c){if(c.tagName){a.push(c);}c=c.nextSilbing||c.firstChild;}}if(a.length){g=Selector._filterNodes(a,i,l);}}return g;},_filterNodes:function(l,f,h){var r=0,q,s=f.length,k=s-1,e=[],o=l[0],v=o,t=Selector.getters,d,p,c,g,a,m,b,u;for(r=0;(v=o=l[r++]);){k=s-1;g=null;testLoop:while(v&&v.tagName){c=f[k];b=c.tests;q=b.length;if(q&&!a){while((u=b[--q])){d=u[1];if(t[u[0]]){m=t[u[0]](v,u[0]);}else{m=v[u[0]];if(m===undefined&&v.getAttribute){m=v.getAttribute(u[0]);}}if((d==="="&&m!==u[2])||(typeof d!=="string"&&d.test&&!d.test(m))||(!d.test&&typeof d==="function"&&!d(v,u[0],u[2]))){if((v=v[g])){while(v&&(!v.tagName||(c.tagName&&c.tagName!==v.tagName))){v=v[g];}}continue testLoop;}}}k--;if(!a&&(p=c.combinator)){g=p.axis;v=v[g];while(v&&!v.tagName){v=v[g];}if(p.direct){g=null;}}else{e.push(o);if(h){return e;}break;}}}o=v=null;return e;},combinators:{" ":{axis:"parentNode"},">":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:ATTRIBUTES,re:/^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,fn:function(d,e){var c=d[2]||"",a=Selector.operators,b=(d[3])?d[3].replace(/\\/g,""):"",f;if((d[1]==="id"&&c==="=")||(d[1]==="className"&&Y_DOCUMENT_ELEMENT.getElementsByClassName&&(c==="~="||c==="="))){e.prefilter=d[1];d[3]=b;e[d[1]]=(d[1]==="id")?d[3]:b;}if(c in a){f=a[c];if(typeof f==="string"){d[3]=b.replace(Selector._reRegExpTokens,"\\$1");f=new RegExp(f.replace("{val}",d[3]));}d[2]=f;}if(!e.last||e.prefilter!==d[1]){return d.slice(1);}}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(b,c){var a=b[1].toUpperCase();c.tagName=a;if(a!=="*"&&(!c.last||c.prefilter)){return[TAG_NAME,"=",a];
-}if(!c.prefilter){c.prefilter="tagName";}}},{name:COMBINATOR,re:/^\s*([>+~]|\s)\s*/,fn:function(a,b){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,fn:function(a,b){var c=Selector[PSEUDOS][a[1]];if(c){if(a[2]){a[2]=a[2].replace(/\\/g,"");}return[a[2],c];}else{return false;}}}],_getToken:function(a){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(c){c=c||"";c=Selector._replaceShorthand(Y_Lang.trim(c));var b=Selector._getToken(),h=c,g=[],j=false,e,f,d,a;outer:do{j=false;for(d=0;(a=Selector._parsers[d++]);){if((e=a.re.exec(c))){if(a.name!==COMBINATOR){b.selector=c;}c=c.replace(e[0],"");if(!c.length){b.last=true;}if(Selector._attrFilters[e[1]]){e[1]=Selector._attrFilters[e[1]];}f=a.fn(e,b);if(f===false){j=false;break outer;}else{if(f){b.tests.push(f);}}if(!c.length||a.name===COMBINATOR){g.push(b);b=Selector._getToken(b);if(a.name===COMBINATOR){b.combinator=Selector.combinators[e[1]];}}j=true;}}}while(j&&c.length);if(!j||c.length){g=[];}return g;},_replaceShorthand:function(b){var d=Selector.shorthand,c=b.match(Selector._re.esc),e,h,g,f,a;if(c){b=b.replace(Selector._re.esc,"\uE000");}e=b.match(Selector._re.attr);h=b.match(Selector._re.pseudos);if(e){b=b.replace(Selector._re.attr,"\uE001");}if(h){b=b.replace(Selector._re.pseudos,"\uE002");}for(g in d){if(d.hasOwnProperty(g)){b=b.replace(new RegExp(g,"gi"),d[g]);}}if(e){for(f=0,a=e.length;f<a;++f){b=b.replace(/\uE001/,e[f]);}}if(h){for(f=0,a=h.length;f<a;++f){b=b.replace(/\uE002/,h[f]);}}b=b.replace(/\[/g,"\uE003");b=b.replace(/\]/g,"\uE004");b=b.replace(/\(/g,"\uE005");b=b.replace(/\)/g,"\uE006");if(c){for(f=0,a=c.length;f<a;++f){b=b.replace("\uE000",c[f]);}}return b;},_attrFilters:{"class":"className","for":"htmlFor"},getters:{href:function(b,a){return Y_DOM.getAttribute(b,a);}}};Y_mix(Selector,SelectorCSS2,true);Selector.getters.src=Selector.getters.rel=Selector.getters.href;if(Selector.useNative&&Y_DOC.querySelector){Selector.shorthand["\\.([^\\s\\\\(\\[:]*)"]="[class~=$1]";}Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;Selector._getNth=function(d,o,q,h){Selector._reNth.test(o);var m=parseInt(RegExp.$1,10),c=RegExp.$2,j=RegExp.$3,k=parseInt(RegExp.$4,10)||0,p=[],l=Selector._children(d.parentNode,q),f;if(j){m=2;f="+";c="n";k=(j==="odd")?1:0;}else{if(isNaN(m)){m=(c)?1:0;}}if(m===0){if(h){k=l.length-k+1;}if(l[k-1]===d){return true;}else{return false;}}else{if(m<0){h=!!h;m=Math.abs(m);}}if(!h){for(var e=k-1,g=l.length;e<g;e+=m){if(e>=0&&l[e]===d){return true;}}}else{for(var e=l.length-k,g=l.length;e>=0;e-=m){if(e<g&&l[e]===d){return true;}}}return false;};Y_mix(Selector.pseudos,{"root":function(a){return a===a.ownerDocument.documentElement;},"nth-child":function(a,b){return Selector._getNth(a,b);},"nth-last-child":function(a,b){return Selector._getNth(a,b,null,true);},"nth-of-type":function(a,b){return Selector._getNth(a,b,a.tagName);},"nth-last-of-type":function(a,b){return Selector._getNth(a,b,a.tagName,true);},"last-child":function(b){var a=Selector._children(b.parentNode);return a[a.length-1]===b;},"first-of-type":function(a){return Selector._children(a.parentNode,a.tagName)[0]===a;},"last-of-type":function(b){var a=Selector._children(b.parentNode,b.tagName);return a[a.length-1]===b;},"only-child":function(b){var a=Selector._children(b.parentNode);return a.length===1&&a[0]===b;},"only-of-type":function(b){var a=Selector._children(b.parentNode,b.tagName);return a.length===1&&a[0]===b;},"empty":function(a){return a.childNodes.length===0;},"not":function(a,b){return !Selector.test(a,b);},"contains":function(a,b){var c=a.innerText||a.textContent||"";return c.indexOf(b)>-1;},"checked":function(a){return(a.checked===true||a.selected===true);},enabled:function(a){return(a.disabled!==undefined&&!a.disabled);},disabled:function(a){return(a.disabled);}});Y_mix(Selector.operators,{"^=":"^{val}","!=":function(b,a,c){return b[a]!==c;},"$=":"{val}$","*=":"{val}"});Selector.combinators["~"]={axis:"previousSibling"};YAHOO.register("selector",YAHOO.util.Selector,{version:"2.9.0",build:"2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-(function(){var A=YAHOO.util.Event,C=YAHOO.lang,B=[],D=function(H,E,F){var G;if(!H||H===F){G=false;}else{G=YAHOO.util.Selector.test(H,E)?H:D(H.parentNode,E,F);}return G;};C.augmentObject(A,{_createDelegate:function(F,E,G,H){return function(I){var J=this,N=A.getTarget(I),L=E,P=(J.nodeType===9),Q,K,O,M;if(C.isFunction(E)){Q=E(N);}else{if(C.isString(E)){if(!P){O=J.id;if(!O){O=A.generateId(J);}M=("#"+O+" ");L=(M+E).replace(/,/gi,(","+M));}if(YAHOO.util.Selector.test(N,L)){Q=N;}else{if(YAHOO.util.Selector.test(N,((L.replace(/,/gi," *,"))+" *"))){Q=D(N,L,J);}}}}if(Q){K=Q;if(H){if(H===true){K=G;}else{K=H;}}return F.call(K,I,Q,J,G);}};},delegate:function(F,J,L,G,H,I){var E=J,K,M;if(C.isString(G)&&!YAHOO.util.Selector){return false;}if(J=="mouseenter"||J=="mouseleave"){if(!A._createMouseDelegate){return false;}E=A._getType(J);K=A._createMouseDelegate(L,H,I);M=A._createDelegate(function(P,O,N){return K.call(O,P,N);},G,H,I);}else{M=A._createDelegate(L,G,H,I);}B.push([F,E,L,M]);return A.on(F,E,M);},removeDelegate:function(F,J,I){var K=J,H=false,G,E;if(J=="mouseenter"||J=="mouseleave"){K=A._getType(J);}G=A._getCacheIndex(B,F,K,I);if(G>=0){E=B[G];}if(F&&E){H=A.removeListener(E[0],E[1],E[3]);if(H){delete B[G][2];delete B[G][3];B.splice(G,1);}}return H;}});}());YAHOO.register("event-delegate",YAHOO.util.Event,{version:"2.9.0",build:"2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-(function(){var l=YAHOO.lang,isFunction=l.isFunction,isObject=l.isObject,isArray=l.isArray,_toStr=Object.prototype.toString,Native=(YAHOO.env.ua.caja?window:this).JSON,_UNICODE_EXCEPTIONS=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_ESCAPES=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,_VALUES=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,_BRACKETS=/(?:^|:|,)(?:\s*\[)+/g,_UNSAFE=/[^\],:{}\s]/,_SPECIAL_CHARS=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_CHARS={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},UNDEFINED="undefined",OBJECT="object",NULL="null",STRING="string",NUMBER="number",BOOLEAN="boolean",DATE="date",_allowable={"undefined":UNDEFINED,"string":STRING,"[object String]":STRING,"number":NUMBER,"[object Number]":NUMBER,"boolean":BOOLEAN,"[object Boolean]":BOOLEAN,"[object Date]":DATE,"[object RegExp]":OBJECT},EMPTY="",OPEN_O="{",CLOSE_O="}",OPEN_A="[",CLOSE_A="]",COMMA=",",COMMA_CR=",\n",CR="\n",COLON=":",COLON_SP=": ",QUOTE='"';Native=_toStr.call(Native)==="[object JSON]"&&Native;function _char(c){if(!_CHARS[c]){_CHARS[c]="\\u"+("0000"+(+(c.charCodeAt(0))).toString(16)).slice(-4);}return _CHARS[c];}function _revive(data,reviver){var walk=function(o,key){var k,v,value=o[key];if(value&&typeof value==="object"){for(k in value){if(l.hasOwnProperty(value,k)){v=walk(value,k);if(v===undefined){delete value[k];}else{value[k]=v;}}}}return reviver.call(o,key,value);};return typeof reviver==="function"?walk({"":data},""):data;}function _prepare(s){return s.replace(_UNICODE_EXCEPTIONS,_char);}function _isSafe(str){return l.isString(str)&&!_UNSAFE.test(str.replace(_ESCAPES,"@").replace(_VALUES,"]").replace(_BRACKETS,""));}function _parse(s,reviver){s=_prepare(s);if(_isSafe(s)){return _revive(eval("("+s+")"),reviver);}throw new SyntaxError("JSON.parse");}function _type(o){var t=typeof o;return _allowable[t]||_allowable[_toStr.call(o)]||(t===OBJECT?(o?OBJECT:NULL):UNDEFINED);}function _string(s){return QUOTE+s.replace(_SPECIAL_CHARS,_char)+QUOTE;}function _indent(s,space){return s.replace(/^/gm,space);}function _stringify(o,w,space){if(o===undefined){return undefined;}var replacer=isFunction(w)?w:null,format=_toStr.call(space).match(/String|Number/)||[],_date=YAHOO.lang.JSON.dateToString,stack=[],tmp,i,len;if(replacer||!isArray(w)){w=undefined;}if(w){tmp={};for(i=0,len=w.length;i<len;++i){tmp[w[i]]=true;}w=tmp;}space=format[0]==="Number"?new Array(Math.min(Math.max(0,space),10)+1).join(" "):(space||EMPTY).slice(0,10);function _serialize(h,key){var value=h[key],t=_type(value),a=[],colon=space?COLON_SP:COLON,arr,i,keys,k,v;if(isObject(value)&&isFunction(value.toJSON)){value=value.toJSON(key);}else{if(t===DATE){value=_date(value);}}if(isFunction(replacer)){value=replacer.call(h,key,value);}if(value!==h[key]){t=_type(value);}switch(t){case DATE:case OBJECT:break;case STRING:return _string(value);case NUMBER:return isFinite(value)?value+EMPTY:NULL;case BOOLEAN:return value+EMPTY;case NULL:return NULL;default:return undefined;}for(i=stack.length-1;i>=0;--i){if(stack[i]===value){throw new Error("JSON.stringify. Cyclical reference");}}arr=isArray(value);stack.push(value);if(arr){for(i=value.length-1;i>=0;--i){a[i]=_serialize(value,i)||NULL;}}else{keys=w||value;i=0;for(k in keys){if(l.hasOwnProperty(keys,k)){v=_serialize(value,k);if(v){a[i++]=_string(k)+colon+v;}}}}stack.pop();if(space&&a.length){return arr?OPEN_A+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_A:OPEN_O+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_O;}else{return arr?OPEN_A+a.join(COMMA)+CLOSE_A:OPEN_O+a.join(COMMA)+CLOSE_O;}}return _serialize({"":o},"");}YAHOO.lang.JSON={useNativeParse:!!Native,useNativeStringify:!!Native,isSafe:function(s){return _isSafe(_prepare(s));},parse:function(s,reviver){if(typeof s!=="string"){s+="";}return Native&&YAHOO.lang.JSON.useNativeParse?Native.parse(s,reviver):_parse(s,reviver);},stringify:function(o,w,space){return Native&&YAHOO.lang.JSON.useNativeStringify?Native.stringify(o,w,space):_stringify(o,w,space);},dateToString:function(d){function _zeroPad(v){return v<10?"0"+v:v;}return d.getUTCFullYear()+"-"+_zeroPad(d.getUTCMonth()+1)+"-"+_zeroPad(d.getUTCDate())+"T"+_zeroPad(d.getUTCHours())+COLON+_zeroPad(d.getUTCMinutes())+COLON+_zeroPad(d.getUTCSeconds())+"Z";},stringToDate:function(str){var m=str.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3}))?Z$/);if(m){var d=new Date();d.setUTCFullYear(m[1],m[2]-1,m[3]);d.setUTCHours(m[4],m[5],m[6],(m[7]||0));return d;}return str;}};YAHOO.lang.JSON.isValid=YAHOO.lang.JSON.isSafe;})();YAHOO.register("json",YAHOO.lang.JSON,{version:"2.9.0",build:"2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-(function(){var b=YAHOO.util.Event,g=YAHOO.lang,e=b.addListener,f=b.removeListener,c=b.getListeners,d=[],h={mouseenter:"mouseover",mouseleave:"mouseout"},a=function(n,m,l){var j=b._getCacheIndex(d,n,m,l),i,k;if(j>=0){i=d[j];}if(n&&i){k=f.call(b,i[0],m,i[3]);if(k){delete d[j][2];delete d[j][3];d.splice(j,1);}}return k;};g.augmentObject(b._specialTypes,h);g.augmentObject(b,{_createMouseDelegate:function(i,j,k){return function(q,m){var p=this,l=b.getRelatedTarget(q),o,n;if(p!=l&&!YAHOO.util.Dom.isAncestor(p,l)){o=p;if(k){if(k===true){o=j;}else{o=k;}}n=[q,j];if(m){n.splice(1,0,p,m);}return i.apply(o,n);}};},addListener:function(m,l,k,n,o){var i,j;if(h[l]){i=b._createMouseDelegate(k,n,o);i.mouseDelegate=true;d.push([m,l,k,i]);j=e.call(b,m,l,i);}else{j=e.apply(b,arguments);}return j;},removeListener:function(l,k,j){var i;if(h[k]){i=a.apply(b,arguments);}else{i=f.apply(b,arguments);}return i;},getListeners:function(p,o){var n=[],r,m=(o==="mouseover"||o==="mouseout"),q,k,j;if(o&&(m||h[o])){r=c.call(b,p,this._getType(o));if(r){for(k=r.length-1;k>-1;k--){j=r[k];q=j.fn.mouseDelegate;if((h[o]&&q)||(m&&!q)){n.push(j);}}}}else{n=c.apply(b,arguments);}return(n&&n.length)?n:null;}},true);b.on=b.addListener;}());YAHOO.register("event-mouseenter",YAHOO.util.Event,{version:"2.9.0",build:"2800"});
-/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-(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,_cloneObject:function(o){if(!lang.isValue(o)){return o;}var copy={};if(Object.prototype.toString.apply(o)==="[object RegExp]"){copy=o;}else{if(lang.isFunction(o)){copy=o;}else{if(lang.isArray(o)){var array=[];for(var i=0,len=o.length;i<len;i++){array[i]=DS._cloneObject(o[i]);}copy=array;}else{if(lang.isObject(o)){for(var x in o){if(lang.hasOwnProperty(o,x)){if(lang.isValue(o[x])&&lang.isObject(o[x])||lang.isArray(o[x])){copy[x]=DS._cloneObject(o[x]);}else{copy[x]=o[x];}}}}else{copy=o;}}}}return copy;},_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(lang.isValue(oData)&&!(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,cloneBeforeCaching: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();}oResponse=(this.cloneBeforeCaching)?DS._cloneObject(oResponse):oResponse;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.call(this,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,oCallback):this.liveData(oRequest,oCallback);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){return new util.LocalDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_XHR){return new util.XHRDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_SCRIPTNODE){return new util.ScriptNodeDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_JSFUNCTION){return new util.FunctionDataSource(oLiveData,oConfigs);}}}}}if(YAHOO.lang.isString(oLiveData)){return new util.XHRDataSource(oLiveData,oConfigs);}else{if(YAHOO.lang.isFunction(oLiveData)){return new util.FunctionDataSource(oLiveData,oConfigs);}else{return new util.LocalDataSource(oLiveData,oConfigs);}}};lang.augmentObject(util.DataSource,DS);})();YAHOO.util.Number={format:function(e,k){if(e===""||e===null||!isFinite(e)){return"";}e=+e;k=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,(k||{}));var j=e+"",l=Math.abs(e),b=k.decimalPlaces||0,r=k.thousandsSeparator,f=k.negativeFormat||("-"+k.format),q,p,g,h;if(f.indexOf("#")>-1){f=f.replace(/#/,k.format);}if(b<0){q=l-(l%1)+"";g=q.length+b;if(g>0){q=Number("."+q).toFixed(g).slice(2)+new Array(q.length-g+1).join("0");}else{q="0";}}else{var a=l+"";if(b>0||a.indexOf(".")>0){var d=Math.pow(10,b);q=Math.round(l*d)/d+"";var c=q.indexOf("."),m,o;if(c<0){m=b;o=(Math.pow(10,m)+"").substring(1);if(b>0){q=q+"."+o;}}else{m=b-(q.length-c-1);o=(Math.pow(10,m)+"").substring(1);q=q+o;}}else{q=l.toFixed(b)+"";}}p=q.split(/\D/);if(l>=1000){g=p[0].length%3||3;p[0]=p[0].slice(0,g)+p[0].slice(g).replace(/(\d{3})/g,r+"$1");}return YAHOO.util.Number.format._applyFormat((e<0?f:k.format),p.join(k.decimalSeparator),k);}};YAHOO.util.Number.format.defaults={format:"{prefix}{number}{suffix}",negativeFormat:null,decimalSeparator:".",decimalPlaces:null,thousandsSeparator:""};YAHOO.util.Number.format._applyFormat=function(a,b,c){return a.replace(/\{(\w+)\}/g,function(d,e){return e==="number"?b:e in c?c[e]:"";});};(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(e,c){return c.a[e.getDay()];},A:function(e,c){return c.A[e.getDay()];},b:function(e,c){return c.b[e.getMonth()];},B:function(e,c){return c.B[e.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(f){var g=f.getFullYear();var e=parseInt(b.formats.V(f),10);var c=parseInt(b.formats.W(f),10);if(c>e){g++;}else{if(c===0&&e>=52){g--;}}return g;},H:["getHours","0"],I:function(e){var c=e.getHours()%12;return a(c===0?12:c,0);},j:function(h){var g=new Date(""+h.getFullYear()+"/1/1 GMT");var e=new Date(""+h.getFullYear()+"/"+(h.getMonth()+1)+"/"+h.getDate()+" GMT");var c=e-g;var f=parseInt(c/60000/60/24,10)+1;return a(f,0,100);},k:["getHours"," "],l:function(e){var c=e.getHours()%12;return a(c===0?12:c," ");},m:function(c){return a(c.getMonth()+1,0);},M:["getMinutes","0"],p:function(e,c){return c.p[e.getHours()>=12?1:0];},P:function(e,c){return c.P[e.getHours()>=12?1:0];},s:function(e,c){return parseInt(e.getTime()/1000,10);},S:["getSeconds","0"],u:function(c){var e=c.getDay();return e===0?7:e;},U:function(g){var c=parseInt(b.formats.j(g),10);var f=6-g.getDay();var e=parseInt((c+f)/7,10);return a(e,0);},V:function(g){var f=parseInt(b.formats.W(g),10);var c=(new Date(""+g.getFullYear()+"/1/1")).getDay();var e=f+(c>4||c<=1?0:1);if(e===53&&(new Date(""+g.getFullYear()+"/12/31")).getDay()<4){e=1;}else{if(e===0){e=b.formats.V(new Date(""+(g.getFullYear()-1)+"/12/31"));}}return a(e,0);},w:"getDay",W:function(g){var c=parseInt(b.formats.j(g),10);var f=7-b.formats.u(g);var e=parseInt((c+f)/7,10);
-return a(e,0,10);},y:function(c){return a(c.getFullYear()%100,0);},Y:"getFullYear",z:function(f){var e=f.getTimezoneOffset();var c=a(parseInt(Math.abs(e/60),10),0);var g=a(Math.abs(e%60),0);return(e>0?"-":"+")+c+g;},Z:function(c){var e=c.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,"$2").replace(/[a-z ]/g,"");if(e.length>4){e=b.formats.z(c);}return e;},"%":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.9.0",build:"2800"});/*
-Copyright (c) 2011, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.com/yui/license.html
-version: 2.9.0
-*/
-YAHOO.util.Chain=function(){this.q=[].slice.call(arguments);this.createEvent("end");};YAHOO.util.Chain.prototype={id:0,run:function(){var g=this.q[0],d;if(!g){this.fireEvent("end");return this;}else{if(this.id){return this;}}d=g.method||g;if(typeof d==="function"){var f=g.scope||{},b=g.argument||[],a=g.timeout||0,e=this;if(!(b instanceof Array)){b=[b];}if(a<0){this.id=a;if(g.until){for(;!g.until();){d.apply(f,b);}}else{if(g.iterations){for(;g.iterations-->0;){d.apply(f,b);}}else{d.apply(f,b);}}this.q.shift();this.id=0;return this.run();}else{if(g.until){if(g.until()){this.q.shift();return this.run();}}else{if(!g.iterations||!--g.iterations){this.q.shift();}}this.id=setTimeout(function(){d.apply(f,b);if(e.id){e.id=0;e.run();}},a);}}return this;},add:function(a){this.q.push(a);return this;},pause:function(){if(this.id>0){clearTimeout(this.id);}this.id=0;return this;},stop:function(){this.pause();this.q=[];return this;}};YAHOO.lang.augmentProto(YAHOO.util.Chain,YAHOO.util.EventProvider);(function(){var a=YAHOO.util.Event,c=YAHOO.lang,b=[],d=function(h,e,f){var g;if(!h||h===f){g=false;}else{g=YAHOO.util.Selector.test(h,e)?h:d(h.parentNode,e,f);}return g;};c.augmentObject(a,{_createDelegate:function(f,e,g,h){return function(i){var j=this,n=a.getTarget(i),l=e,p=(j.nodeType===9),q,k,o,m;if(c.isFunction(e)){q=e(n);}else{if(c.isString(e)){if(!p){o=j.id;if(!o){o=a.generateId(j);}m=("#"+o+" ");l=(m+e).replace(/,/gi,(","+m));}if(YAHOO.util.Selector.test(n,l)){q=n;}else{if(YAHOO.util.Selector.test(n,((l.replace(/,/gi," *,"))+" *"))){q=d(n,l,j);}}}}if(q){k=q;if(h){if(h===true){k=g;}else{k=h;}}return f.call(k,i,q,j,g);}};},delegate:function(f,j,l,g,h,i){var e=j,k,m;if(c.isString(g)&&!YAHOO.util.Selector){return false;}if(j=="mouseenter"||j=="mouseleave"){if(!a._createMouseDelegate){return false;}e=a._getType(j);k=a._createMouseDelegate(l,h,i);m=a._createDelegate(function(p,o,n){return k.call(o,p,n);},g,h,i);}else{m=a._createDelegate(l,g,h,i);}b.push([f,e,l,m]);return a.on(f,e,m);},removeDelegate:function(f,j,i){var k=j,h=false,g,e;if(j=="mouseenter"||j=="mouseleave"){k=a._getType(j);}g=a._getCacheIndex(b,f,k,i);if(g>=0){e=b[g];}if(f&&e){h=a.removeListener(e[0],e[1],e[3]);if(h){delete b[g][2];delete b[g][3];b.splice(g,1);}}return h;}});}());(function(){var b=YAHOO.util.Event,g=YAHOO.lang,e=b.addListener,f=b.removeListener,c=b.getListeners,d=[],h={mouseenter:"mouseover",mouseleave:"mouseout"},a=function(n,m,l){var j=b._getCacheIndex(d,n,m,l),i,k;if(j>=0){i=d[j];}if(n&&i){k=f.call(b,i[0],m,i[3]);if(k){delete d[j][2];delete d[j][3];d.splice(j,1);}}return k;};g.augmentObject(b._specialTypes,h);g.augmentObject(b,{_createMouseDelegate:function(i,j,k){return function(q,m){var p=this,l=b.getRelatedTarget(q),o,n;if(p!=l&&!YAHOO.util.Dom.isAncestor(p,l)){o=p;if(k){if(k===true){o=j;}else{o=k;}}n=[q,j];if(m){n.splice(1,0,p,m);}return i.apply(o,n);}};},addListener:function(m,l,k,n,o){var i,j;if(h[l]){i=b._createMouseDelegate(k,n,o);i.mouseDelegate=true;d.push([m,l,k,i]);j=e.call(b,m,l,i);}else{j=e.apply(b,arguments);}return j;},removeListener:function(l,k,j){var i;if(h[k]){i=a.apply(b,arguments);}else{i=f.apply(b,arguments);}return i;},getListeners:function(p,o){var n=[],r,m=(o==="mouseover"||o==="mouseout"),q,k,j;if(o&&(m||h[o])){r=c.call(b,p,this._getType(o));if(r){for(k=r.length-1;k>-1;k--){j=r[k];q=j.fn.mouseDelegate;if((h[o]&&q)||(m&&!q)){n.push(j);}}}}else{n=c.apply(b,arguments);}return(n&&n.length)?n:null;}},true);b.on=b.addListener;}());YAHOO.register("event-mouseenter",YAHOO.util.Event,{version:"2.9.0",build:"2800"});var Y=YAHOO,Y_DOM=YAHOO.util.Dom,EMPTY_ARRAY=[],Y_UA=Y.env.ua,Y_Lang=Y.lang,Y_DOC=document,Y_DOCUMENT_ELEMENT=Y_DOC.documentElement,Y_DOM_inDoc=Y_DOM.inDocument,Y_mix=Y_Lang.augmentObject,Y_guid=Y_DOM.generateId,Y_getDoc=function(a){var b=Y_DOC;if(a){b=(a.nodeType===9)?a:a.ownerDocument||a.document||Y_DOC;}return b;},Y_Array=function(g,d){var c,b,h=d||0;try{return Array.prototype.slice.call(g,h);}catch(f){b=[];c=g.length;for(;h<c;h++){b.push(g[h]);}return b;}},Y_DOM_allById=function(f,a){a=a||Y_DOC;var b=[],c=[],d,e;if(a.querySelectorAll){c=a.querySelectorAll('[id="'+f+'"]');}else{if(a.all){b=a.all(f);if(b){if(b.nodeName){if(b.id===f){c.push(b);b=EMPTY_ARRAY;}else{b=[b];}}if(b.length){for(d=0;e=b[d++];){if(e.id===f||(e.attributes&&e.attributes.id&&e.attributes.id.value===f)){c.push(e);}}}}}else{c=[Y_getDoc(a).getElementById(f)];}}return c;};var COMPARE_DOCUMENT_POSITION="compareDocumentPosition",OWNER_DOCUMENT="ownerDocument",Selector={_foundCache:[],useNative:true,_compare:("sourceIndex" in Y_DOCUMENT_ELEMENT)?function(f,e){var d=f.sourceIndex,c=e.sourceIndex;if(d===c){return 0;}else{if(d>c){return 1;}}return -1;}:(Y_DOCUMENT_ELEMENT[COMPARE_DOCUMENT_POSITION]?function(b,a){if(b[COMPARE_DOCUMENT_POSITION](a)&4){return -1;}else{return 1;}}:function(e,d){var c,a,b;if(e&&d){c=e[OWNER_DOCUMENT].createRange();c.setStart(e,0);a=d[OWNER_DOCUMENT].createRange();a.setStart(d,0);b=c.compareBoundaryPoints(1,a);}return b;}),_sort:function(a){if(a){a=Y_Array(a,0,true);if(a.sort){a.sort(Selector._compare);}}return a;},_deDupe:function(a){var b=[],c,d;for(c=0;(d=a[c++]);){if(!d._found){b[b.length]=d;d._found=true;}}for(c=0;(d=b[c++]);){d._found=null;d.removeAttribute("_found");}return b;},query:function(b,j,k,a){if(typeof j=="string"){j=Y_DOM.get(j);if(!j){return(k)?null:[];}}else{j=j||Y_DOC;}var f=[],c=(Selector.useNative&&Y_DOC.querySelector&&!a),e=[[b,j]],g,l,d,h=(c)?Selector._nativeQuery:Selector._bruteQuery;if(b&&h){if(!a&&(!c||j.tagName)){e=Selector._splitQueries(b,j);}for(d=0;(g=e[d++]);){l=h(g[0],g[1],k);if(!k){l=Y_Array(l,0,true);}if(l){f=f.concat(l);}}if(e.length>1){f=Selector._sort(Selector._deDupe(f));}}Y.log("query: "+b+" returning: "+f.length,"info","Selector");return(k)?(f[0]||null):f;},_splitQueries:function(c,f){var b=c.split(","),d=[],g="",e,a;if(f){if(f.tagName){f.id=f.id||Y_guid();g='[id="'+f.id+'"] ';}for(e=0,a=b.length;e<a;++e){c=g+b[e];d.push([c,f]);}}return d;},_nativeQuery:function(a,b,c){if(Y_UA.webkit&&a.indexOf(":checked")>-1&&(Selector.pseudos&&Selector.pseudos.checked)){return Selector.query(a,b,c,true);
-}try{return b["querySelector"+(c?"":"All")](a);}catch(d){return Selector.query(a,b,c,true);}},filter:function(b,a){var c=[],d,e;if(b&&a){for(d=0;(e=b[d++]);){if(Selector.test(e,a)){c[c.length]=e;}}}else{Y.log("invalid filter input (nodes: "+b+", selector: "+a+")","warn","Selector");}return c;},test:function(c,d,k){var g=false,b=d.split(","),a=false,l,o,h,n,f,e,m;if(c&&c.tagName){if(!k&&!Y_DOM_inDoc(c)){l=c.parentNode;if(l){k=l;}else{n=c[OWNER_DOCUMENT].createDocumentFragment();n.appendChild(c);k=n;a=true;}}k=k||c[OWNER_DOCUMENT];if(!c.id){c.id=Y_guid();}for(f=0;(m=b[f++]);){m+='[id="'+c.id+'"]';h=Selector.query(m,k);for(e=0;o=h[e++];){if(o===c){g=true;break;}}if(g){break;}}if(a){n.removeChild(c);}}return g;}};YAHOO.util.Selector=Selector;var PARENT_NODE="parentNode",TAG_NAME="tagName",ATTRIBUTES="attributes",COMBINATOR="combinator",PSEUDOS="pseudos",SelectorCSS2={_reRegExpTokens:/([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,SORT_RESULTS:true,_children:function(e,a){var b=e.children,d,c=[],f,g;if(e.children&&a&&e.children.tags){c=e.children.tags(a);}else{if((!b&&e[TAG_NAME])||(b&&a)){f=b||e.childNodes;b=[];for(d=0;(g=f[d++]);){if(g.tagName){if(!a||a===g.tagName){b.push(g);}}}}}return b||[];},_re:{attr:/(\[[^\]]*\])/g,esc:/\\[:\[\]\(\)#\.\'\>+~"]/gi,pseudos:/(\([^\)]*\))/g},shorthand:{"\\#(-?[_a-z]+[-\\w\\uE000]*)":"[id=$1]","\\.(-?[_a-z]+[-\\w\\uE000]*)":"[className~=$1]"},operators:{"":function(b,a){return !!b.getAttribute(a);},"~=":"(?:^|\\s+){val}(?:\\s+|$)","|=":"^{val}(?:-|$)"},pseudos:{"first-child":function(a){return Selector._children(a[PARENT_NODE])[0]===a;}},_bruteQuery:function(f,j,l){var g=[],a=[],i=Selector._tokenize(f),e=i[i.length-1],k=Y_getDoc(j),c,b,h,d;if(e){b=e.id;h=e.className;d=e.tagName||"*";if(j.getElementsByTagName){if(b&&(j.all||(j.nodeType===9||Y_DOM_inDoc(j)))){a=Y_DOM_allById(b,j);}else{if(h){a=j.getElementsByClassName(h);}else{a=j.getElementsByTagName(d);}}}else{c=j.firstChild;while(c){if(c.tagName){a.push(c);}c=c.nextSilbing||c.firstChild;}}if(a.length){g=Selector._filterNodes(a,i,l);}}return g;},_filterNodes:function(l,f,h){var r=0,q,s=f.length,k=s-1,e=[],o=l[0],v=o,t=Selector.getters,d,p,c,g,a,m,b,u;for(r=0;(v=o=l[r++]);){k=s-1;g=null;testLoop:while(v&&v.tagName){c=f[k];b=c.tests;q=b.length;if(q&&!a){while((u=b[--q])){d=u[1];if(t[u[0]]){m=t[u[0]](v,u[0]);}else{m=v[u[0]];if(m===undefined&&v.getAttribute){m=v.getAttribute(u[0]);}}if((d==="="&&m!==u[2])||(typeof d!=="string"&&d.test&&!d.test(m))||(!d.test&&typeof d==="function"&&!d(v,u[0],u[2]))){if((v=v[g])){while(v&&(!v.tagName||(c.tagName&&c.tagName!==v.tagName))){v=v[g];}}continue testLoop;}}}k--;if(!a&&(p=c.combinator)){g=p.axis;v=v[g];while(v&&!v.tagName){v=v[g];}if(p.direct){g=null;}}else{e.push(o);if(h){return e;}break;}}}o=v=null;return e;},combinators:{" ":{axis:"parentNode"},">":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:ATTRIBUTES,re:/^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,fn:function(d,e){var c=d[2]||"",a=Selector.operators,b=(d[3])?d[3].replace(/\\/g,""):"",f;if((d[1]==="id"&&c==="=")||(d[1]==="className"&&Y_DOCUMENT_ELEMENT.getElementsByClassName&&(c==="~="||c==="="))){e.prefilter=d[1];d[3]=b;e[d[1]]=(d[1]==="id")?d[3]:b;}if(c in a){f=a[c];if(typeof f==="string"){d[3]=b.replace(Selector._reRegExpTokens,"\\$1");f=new RegExp(f.replace("{val}",d[3]));}d[2]=f;}if(!e.last||e.prefilter!==d[1]){return d.slice(1);}}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(b,c){var a=b[1].toUpperCase();c.tagName=a;if(a!=="*"&&(!c.last||c.prefilter)){return[TAG_NAME,"=",a];}if(!c.prefilter){c.prefilter="tagName";}}},{name:COMBINATOR,re:/^\s*([>+~]|\s)\s*/,fn:function(a,b){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,fn:function(a,b){var c=Selector[PSEUDOS][a[1]];if(c){if(a[2]){a[2]=a[2].replace(/\\/g,"");}return[a[2],c];}else{return false;}}}],_getToken:function(a){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(c){c=c||"";c=Selector._replaceShorthand(Y_Lang.trim(c));var b=Selector._getToken(),h=c,g=[],j=false,e,f,d,a;outer:do{j=false;for(d=0;(a=Selector._parsers[d++]);){if((e=a.re.exec(c))){if(a.name!==COMBINATOR){b.selector=c;}c=c.replace(e[0],"");if(!c.length){b.last=true;}if(Selector._attrFilters[e[1]]){e[1]=Selector._attrFilters[e[1]];}f=a.fn(e,b);if(f===false){j=false;break outer;}else{if(f){b.tests.push(f);}}if(!c.length||a.name===COMBINATOR){g.push(b);b=Selector._getToken(b);if(a.name===COMBINATOR){b.combinator=Selector.combinators[e[1]];}}j=true;}}}while(j&&c.length);if(!j||c.length){Y.log("query: "+h+" contains unsupported token in: "+c,"warn","Selector");g=[];}return g;},_replaceShorthand:function(b){var d=Selector.shorthand,c=b.match(Selector._re.esc),e,h,g,f,a;if(c){b=b.replace(Selector._re.esc,"\uE000");}e=b.match(Selector._re.attr);h=b.match(Selector._re.pseudos);if(e){b=b.replace(Selector._re.attr,"\uE001");}if(h){b=b.replace(Selector._re.pseudos,"\uE002");}for(g in d){if(d.hasOwnProperty(g)){b=b.replace(new RegExp(g,"gi"),d[g]);}}if(e){for(f=0,a=e.length;f<a;++f){b=b.replace(/\uE001/,e[f]);}}if(h){for(f=0,a=h.length;f<a;++f){b=b.replace(/\uE002/,h[f]);}}b=b.replace(/\[/g,"\uE003");b=b.replace(/\]/g,"\uE004");b=b.replace(/\(/g,"\uE005");b=b.replace(/\)/g,"\uE006");if(c){for(f=0,a=c.length;f<a;++f){b=b.replace("\uE000",c[f]);}}return b;},_attrFilters:{"class":"className","for":"htmlFor"},getters:{href:function(b,a){return Y_DOM.getAttribute(b,a);}}};Y_mix(Selector,SelectorCSS2,true);Selector.getters.src=Selector.getters.rel=Selector.getters.href;if(Selector.useNative&&Y_DOC.querySelector){Selector.shorthand["\\.([^\\s\\\\(\\[:]*)"]="[class~=$1]";}Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;Selector._getNth=function(d,o,q,h){Selector._reNth.test(o);var m=parseInt(RegExp.$1,10),c=RegExp.$2,j=RegExp.$3,k=parseInt(RegExp.$4,10)||0,p=[],l=Selector._children(d.parentNode,q),f;if(j){m=2;f="+";c="n";k=(j==="odd")?1:0;}else{if(isNaN(m)){m=(c)?1:0;
-}}if(m===0){if(h){k=l.length-k+1;}if(l[k-1]===d){return true;}else{return false;}}else{if(m<0){h=!!h;m=Math.abs(m);}}if(!h){for(var e=k-1,g=l.length;e<g;e+=m){if(e>=0&&l[e]===d){return true;}}}else{for(var e=l.length-k,g=l.length;e>=0;e-=m){if(e<g&&l[e]===d){return true;}}}return false;};Y_mix(Selector.pseudos,{"root":function(a){return a===a.ownerDocument.documentElement;},"nth-child":function(a,b){return Selector._getNth(a,b);},"nth-last-child":function(a,b){return Selector._getNth(a,b,null,true);},"nth-of-type":function(a,b){return Selector._getNth(a,b,a.tagName);},"nth-last-of-type":function(a,b){return Selector._getNth(a,b,a.tagName,true);},"last-child":function(b){var a=Selector._children(b.parentNode);return a[a.length-1]===b;},"first-of-type":function(a){return Selector._children(a.parentNode,a.tagName)[0]===a;},"last-of-type":function(b){var a=Selector._children(b.parentNode,b.tagName);return a[a.length-1]===b;},"only-child":function(b){var a=Selector._children(b.parentNode);return a.length===1&&a[0]===b;},"only-of-type":function(b){var a=Selector._children(b.parentNode,b.tagName);return a.length===1&&a[0]===b;},"empty":function(a){return a.childNodes.length===0;},"not":function(a,b){return !Selector.test(a,b);},"contains":function(a,b){var c=a.innerText||a.textContent||"";return c.indexOf(b)>-1;},"checked":function(a){return(a.checked===true||a.selected===true);},enabled:function(a){return(a.disabled!==undefined&&!a.disabled);},disabled:function(a){return(a.disabled);}});Y_mix(Selector.operators,{"^=":"^{val}","!=":function(b,a,c){return b[a]!==c;},"$=":"{val}$","*=":"{val}"});Selector.combinators["~"]={axis:"previousSibling"};YAHOO.register("selector",YAHOO.util.Selector,{version:"2.9.0",build:"2800"});var Dom=YAHOO.util.Dom;YAHOO.widget.ColumnSet=function(a){this._sId=Dom.generateId(null,"yui-cs");a=YAHOO.widget.DataTable._cloneObject(a);this._init(a);YAHOO.widget.ColumnSet._nCount++;};YAHOO.widget.ColumnSet._nCount=0;YAHOO.widget.ColumnSet.prototype={_sId:null,_aDefinitions:null,tree:null,flat:null,keys:null,headers:null,_init:function(j){var k=[];var a=[];var g=[];var e=[];var c=-1;var b=function(m,s){c++;if(!k[c]){k[c]=[];}for(var o=0;o<m.length;o++){var i=m[o];var q=new YAHOO.widget.Column(i);i.yuiColumnId=q._sId;a.push(q);if(s){q._oParent=s;}if(YAHOO.lang.isArray(i.children)){q.children=i.children;var r=0;var p=function(v){var w=v.children;for(var u=0;u<w.length;u++){if(YAHOO.lang.isArray(w[u].children)){p(w[u]);}else{r++;}}};p(i);q._nColspan=r;var t=i.children;for(var n=0;n<t.length;n++){var l=t[n];if(q.className&&(l.className===undefined)){l.className=q.className;}if(q.editor&&(l.editor===undefined)){l.editor=q.editor;}if(q.editorOptions&&(l.editorOptions===undefined)){l.editorOptions=q.editorOptions;}if(q.formatter&&(l.formatter===undefined)){l.formatter=q.formatter;}if(q.resizeable&&(l.resizeable===undefined)){l.resizeable=q.resizeable;}if(q.sortable&&(l.sortable===undefined)){l.sortable=q.sortable;}if(q.hidden){l.hidden=true;}if(q.width&&(l.width===undefined)){l.width=q.width;}if(q.minWidth&&(l.minWidth===undefined)){l.minWidth=q.minWidth;}if(q.maxAutoWidth&&(l.maxAutoWidth===undefined)){l.maxAutoWidth=q.maxAutoWidth;}if(q.type&&(l.type===undefined)){l.type=q.type;}if(q.type&&!q.formatter){q.formatter=q.type;}if(q.text&&!YAHOO.lang.isValue(q.label)){q.label=q.text;}if(q.parser){}if(q.sortOptions&&((q.sortOptions.ascFunction)||(q.sortOptions.descFunction))){}}if(!k[c+1]){k[c+1]=[];}b(t,q);}else{q._nKeyIndex=g.length;q._nColspan=1;g.push(q);}k[c].push(q);}c--;};if(YAHOO.lang.isArray(j)){b(j);this._aDefinitions=j;}else{return null;}var f;var d=function(l){var n=1;var q;var o;var r=function(t,p){p=p||1;for(var u=0;u<t.length;u++){var m=t[u];if(YAHOO.lang.isArray(m.children)){p++;r(m.children,p);p--;}else{if(p>n){n=p;}}}};for(var i=0;i<l.length;i++){q=l[i];r(q);for(var s=0;s<q.length;s++){o=q[s];if(!YAHOO.lang.isArray(o.children)){o._nRowspan=n;}else{o._nRowspan=1;}}n=1;}};d(k);for(f=0;f<k[0].length;f++){k[0][f]._nTreeIndex=f;}var h=function(l,m){e[l].push(m.getSanitizedKey());if(m._oParent){h(l,m._oParent);}};for(f=0;f<g.length;f++){e[f]=[];h(f,g[f]);e[f]=e[f].reverse();}this.tree=k;this.flat=a;this.keys=g;this.headers=e;},getId:function(){return this._sId;},toString:function(){return"ColumnSet instance "+this._sId;},getDefinitions:function(){var a=this._aDefinitions;var b=function(e,g){for(var d=0;d<e.length;d++){var f=e[d];var i=g.getColumnById(f.yuiColumnId);if(i){var h=i.getDefinition();for(var c in h){if(YAHOO.lang.hasOwnProperty(h,c)){f[c]=h[c];}}}if(YAHOO.lang.isArray(f.children)){b(f.children,g);}}};b(a,this);this._aDefinitions=a;return a;},getColumnById:function(c){if(YAHOO.lang.isString(c)){var a=this.flat;for(var b=a.length-1;b>-1;b--){if(a[b]._sId===c){return a[b];}}}return null;},getColumn:function(c){if(YAHOO.lang.isNumber(c)&&this.keys[c]){return this.keys[c];}else{if(YAHOO.lang.isString(c)){var a=this.flat;var d=[];for(var b=0;b<a.length;b++){if(a[b].key===c){d.push(a[b]);}}if(d.length===1){return d[0];}else{if(d.length>1){return d;}}}}return null;},getDescendants:function(d){var b=this;var c=[];var a;var e=function(f){c.push(f);if(f.children){for(a=0;a<f.children.length;a++){e(b.getColumn(f.children[a].key));}}};e(d);return c;}};YAHOO.widget.Column=function(b){this._sId=Dom.generateId(null,"yui-col");if(b&&YAHOO.lang.isObject(b)){for(var a in b){if(a){this[a]=b[a];}}}if(!YAHOO.lang.isValue(this.key)){this.key=Dom.generateId(null,"yui-dt-col");}if(!YAHOO.lang.isValue(this.field)){this.field=this.key;}YAHOO.widget.Column._nCount++;if(this.width&&!YAHOO.lang.isNumber(this.width)){this.width=null;}if(this.editor&&YAHOO.lang.isString(this.editor)){this.editor=new YAHOO.widget.CellEditor(this.editor,this.editorOptions);}};YAHOO.lang.augmentObject(YAHOO.widget.Column,{_nCount:0,formatCheckbox:function(b,a,c,d){YAHOO.widget.DataTable.formatCheckbox(b,a,c,d);},formatCurrency:function(b,a,c,d){YAHOO.widget.DataTable.formatCurrency(b,a,c,d);},formatDate:function(b,a,c,d){YAHOO.widget.DataTable.formatDate(b,a,c,d);
-},formatEmail:function(b,a,c,d){YAHOO.widget.DataTable.formatEmail(b,a,c,d);},formatLink:function(b,a,c,d){YAHOO.widget.DataTable.formatLink(b,a,c,d);},formatNumber:function(b,a,c,d){YAHOO.widget.DataTable.formatNumber(b,a,c,d);},formatSelect:function(b,a,c,d){YAHOO.widget.DataTable.formatDropdown(b,a,c,d);}});YAHOO.widget.Column.prototype={_sId:null,_nKeyIndex:null,_nTreeIndex:null,_nColspan:1,_nRowspan:1,_oParent:null,_elTh:null,_elThLiner:null,_elThLabel:null,_elResizer:null,_nWidth:null,_dd:null,_ddResizer:null,key:null,field:null,label:null,abbr:null,children:null,width:null,minWidth:null,maxAutoWidth:null,hidden:false,selected:false,className:null,formatter:null,currencyOptions:null,dateOptions:null,dropdownOptions:null,editor:null,resizeable:false,sortable:false,sortOptions:null,getId:function(){return this._sId;},toString:function(){return"Column instance "+this._sId;},getDefinition:function(){var a={};a.abbr=this.abbr;a.className=this.className;a.editor=this.editor;a.editorOptions=this.editorOptions;a.field=this.field;a.formatter=this.formatter;a.hidden=this.hidden;a.key=this.key;a.label=this.label;a.minWidth=this.minWidth;a.maxAutoWidth=this.maxAutoWidth;a.resizeable=this.resizeable;a.selected=this.selected;a.sortable=this.sortable;a.sortOptions=this.sortOptions;a.width=this.width;a._calculatedWidth=this._calculatedWidth;return a;},getKey:function(){return this.key;},getField:function(){return this.field;},getSanitizedKey:function(){return this.getKey().replace(/[^\w\-]/g,"");},getKeyIndex:function(){return this._nKeyIndex;},getTreeIndex:function(){return this._nTreeIndex;},getParent:function(){return this._oParent;},getColspan:function(){return this._nColspan;},getColSpan:function(){return this.getColspan();},getRowspan:function(){return this._nRowspan;},getThEl:function(){return this._elTh;},getThLinerEl:function(){return this._elThLiner;},getResizerEl:function(){return this._elResizer;},getColEl:function(){return this.getThEl();},getIndex:function(){return this.getKeyIndex();},format:function(){}};YAHOO.util.Sort={compare:function(d,c,e){if((d===null)||(typeof d=="undefined")){if((c===null)||(typeof c=="undefined")){return 0;}else{return 1;}}else{if((c===null)||(typeof c=="undefined")){return -1;}}if(d.constructor==String){d=d.toLowerCase();}if(c.constructor==String){c=c.toLowerCase();}if(d<c){return(e)?1:-1;}else{if(d>c){return(e)?-1:1;}else{return 0;}}}};YAHOO.widget.ColumnDD=function(d,a,c,b){if(d&&a&&c&&b){this.datatable=d;this.table=d.getTableEl();this.column=a;this.headCell=c;this.pointer=b;this.newIndex=null;this.init(c);this.initFrame();this.invalidHandleTypes={};this.setPadding(10,0,(this.datatable.getTheadEl().offsetHeight+10),0);YAHOO.util.Event.on(window,"resize",function(){this.initConstraints();},this,true);}else{}};if(YAHOO.util.DDProxy){YAHOO.extend(YAHOO.widget.ColumnDD,YAHOO.util.DDProxy,{initConstraints:function(){var g=YAHOO.util.Dom.getRegion(this.table),d=this.getEl(),f=YAHOO.util.Dom.getXY(d),c=parseInt(YAHOO.util.Dom.getStyle(d,"width"),10),a=parseInt(YAHOO.util.Dom.getStyle(d,"height"),10),e=((f[0]-g.left)+15),b=((g.right-f[0]-c)+15);this.setXConstraint(e,b);this.setYConstraint(10,10);},_resizeProxy:function(){YAHOO.widget.ColumnDD.superclass._resizeProxy.apply(this,arguments);var a=this.getDragEl(),b=this.getEl();YAHOO.util.Dom.setStyle(this.pointer,"height",(this.table.parentNode.offsetHeight+10)+"px");YAHOO.util.Dom.setStyle(this.pointer,"display","block");var c=YAHOO.util.Dom.getXY(b);YAHOO.util.Dom.setXY(this.pointer,[c[0],(c[1]-5)]);YAHOO.util.Dom.setStyle(a,"height",this.datatable.getContainerEl().offsetHeight+"px");YAHOO.util.Dom.setStyle(a,"width",(parseInt(YAHOO.util.Dom.getStyle(a,"width"),10)+4)+"px");YAHOO.util.Dom.setXY(this.dragEl,c);},onMouseDown:function(){this.initConstraints();this.resetConstraints();},clickValidator:function(b){if(!this.column.hidden){var a=YAHOO.util.Event.getTarget(b);return(this.isValidHandleChild(a)&&(this.id==this.handleElId||this.DDM.handleWasClicked(a,this.id)));}},onDragOver:function(h,a){var f=this.datatable.getColumn(a);if(f){var c=f.getTreeIndex();while((c===null)&&f.getParent()){f=f.getParent();c=f.getTreeIndex();}if(c!==null){var b=f.getThEl();var k=c;var d=YAHOO.util.Event.getPageX(h),i=YAHOO.util.Dom.getX(b),j=i+((YAHOO.util.Dom.get(b).offsetWidth)/2),e=this.column.getTreeIndex();if(d<j){YAHOO.util.Dom.setX(this.pointer,i);}else{var g=parseInt(b.offsetWidth,10);YAHOO.util.Dom.setX(this.pointer,(i+g));k++;}if(c>e){k--;}if(k<0){k=0;}else{if(k>this.datatable.getColumnSet().tree[0].length){k=this.datatable.getColumnSet().tree[0].length;}}this.newIndex=k;}}},onDragDrop:function(){this.datatable.reorderColumn(this.column,this.newIndex);},endDrag:function(){this.newIndex=null;YAHOO.util.Dom.setStyle(this.pointer,"display","none");}});}YAHOO.util.ColumnResizer=function(e,c,d,a,b){if(e&&c&&d&&a){this.datatable=e;this.column=c;this.headCell=d;this.headCellLiner=c.getThLinerEl();this.resizerLiner=d.firstChild;this.init(a,a,{dragOnly:true,dragElId:b.id});this.initFrame();this.resetResizerEl();this.setPadding(0,1,0,0);}else{}};if(YAHOO.util.DD){YAHOO.extend(YAHOO.util.ColumnResizer,YAHOO.util.DDProxy,{resetResizerEl:function(){var a=YAHOO.util.Dom.get(this.handleElId).style;a.left="auto";a.right=0;a.top="auto";a.bottom=0;a.height=this.headCell.offsetHeight+"px";},onMouseUp:function(h){var f=this.datatable.getColumnSet().keys,b;for(var c=0,a=f.length;c<a;c++){b=f[c];if(b._ddResizer){b._ddResizer.resetResizerEl();}}this.resetResizerEl();var d=this.headCellLiner;var g=d.offsetWidth-(parseInt(YAHOO.util.Dom.getStyle(d,"paddingLeft"),10)|0)-(parseInt(YAHOO.util.Dom.getStyle(d,"paddingRight"),10)|0);this.datatable.fireEvent("columnResizeEvent",{column:this.column,target:this.headCell,width:g});},onMouseDown:function(a){this.startWidth=this.headCellLiner.offsetWidth;this.startX=YAHOO.util.Event.getXY(a)[0];this.nLinerPadding=(parseInt(YAHOO.util.Dom.getStyle(this.headCellLiner,"paddingLeft"),10)|0)+(parseInt(YAHOO.util.Dom.getStyle(this.headCellLiner,"paddingRight"),10)|0);
-},clickValidator:function(b){if(!this.column.hidden){var a=YAHOO.util.Event.getTarget(b);return(this.isValidHandleChild(a)&&(this.id==this.handleElId||this.DDM.handleWasClicked(a,this.id)));}},startDrag:function(){var e=this.datatable.getColumnSet().keys,d=this.column.getKeyIndex(),b;for(var c=0,a=e.length;c<a;c++){b=e[c];if(b._ddResizer){YAHOO.util.Dom.get(b._ddResizer.handleElId).style.height="1em";}}},onDrag:function(c){var d=YAHOO.util.Event.getXY(c)[0];if(d>YAHOO.util.Dom.getX(this.headCellLiner)){var a=d-this.startX;var b=this.startWidth+a-this.nLinerPadding;if(b>0){this.datatable.setColumnWidth(this.column,b);}}}});}(function(){var g=YAHOO.lang,a=YAHOO.util,e=YAHOO.widget,c=a.Dom,f=a.Event,d=e.DataTable;YAHOO.widget.RecordSet=function(h){this._init(h);};var b=e.RecordSet;b._nCount=0;b.prototype={_sId:null,_init:function(h){this._sId=c.generateId(null,"yui-rs");e.RecordSet._nCount++;this._records=[];this._initEvents();if(h){if(g.isArray(h)){this.addRecords(h);}else{if(g.isObject(h)){this.addRecord(h);}}}},_initEvents:function(){this.createEvent("recordAddEvent");this.createEvent("recordsAddEvent");this.createEvent("recordSetEvent");this.createEvent("recordsSetEvent");this.createEvent("recordUpdateEvent");this.createEvent("recordDeleteEvent");this.createEvent("recordsDeleteEvent");this.createEvent("resetEvent");this.createEvent("recordValueUpdateEvent");},_addRecord:function(j,h){var i=new YAHOO.widget.Record(j);if(YAHOO.lang.isNumber(h)&&(h>-1)){this._records.splice(h,0,i);}else{this._records[this._records.length]=i;}return i;},_setRecord:function(i,h){if(!g.isNumber(h)||h<0){h=this._records.length;}return(this._records[h]=new e.Record(i));},_deleteRecord:function(i,h){if(!g.isNumber(h)||(h<0)){h=1;}this._records.splice(i,h);},getId:function(){return this._sId;},toString:function(){return"RecordSet instance "+this._sId;},getLength:function(){return this._records.length;},getRecord:function(h){var j;if(h instanceof e.Record){for(j=0;j<this._records.length;j++){if(this._records[j]&&(this._records[j]._sId===h._sId)){return h;}}}else{if(g.isNumber(h)){if((h>-1)&&(h<this.getLength())){return this._records[h];}}else{if(g.isString(h)){for(j=0;j<this._records.length;j++){if(this._records[j]&&(this._records[j]._sId===h)){return this._records[j];}}}}}return null;},getRecords:function(i,h){if(!g.isNumber(i)){return this._records;}if(!g.isNumber(h)){return this._records.slice(i);}return this._records.slice(i,i+h);},hasRecords:function(j,h){var l=this.getRecords(j,h);for(var k=0;k<h;++k){if(typeof l[k]==="undefined"){return false;}}return true;},getRecordIndex:function(j){if(j){for(var h=this._records.length-1;h>-1;h--){if(this._records[h]&&j.getId()===this._records[h].getId()){return h;}}}return null;},addRecord:function(j,h){if(g.isObject(j)){var i=this._addRecord(j,h);this.fireEvent("recordAddEvent",{record:i,data:j});return i;}else{return null;}},addRecords:function(m,l){if(g.isArray(m)){var p=[],j,n,h;l=g.isNumber(l)?l:this._records.length;j=l;for(n=0,h=m.length;n<h;++n){if(g.isObject(m[n])){var k=this._addRecord(m[n],j++);p.push(k);}}this.fireEvent("recordsAddEvent",{records:p,data:m});return p;}else{if(g.isObject(m)){var o=this._addRecord(m);this.fireEvent("recordsAddEvent",{records:[o],data:m});return o;}else{return null;}}},setRecord:function(j,h){if(g.isObject(j)){var i=this._setRecord(j,h);this.fireEvent("recordSetEvent",{record:i,data:j});return i;}else{return null;}},setRecords:function(o,n){var r=e.Record,k=g.isArray(o)?o:[o],q=[],p=0,h=k.length,m=0;n=parseInt(n,10)|0;for(;p<h;++p){if(typeof k[p]==="object"&&k[p]){q[m++]=this._records[n+p]=new r(k[p]);}}this.fireEvent("recordsSetEvent",{records:q,data:o});this.fireEvent("recordsSet",{records:q,data:o});if(k.length&&!q.length){}return q;},updateRecord:function(h,l){var j=this.getRecord(h);if(j&&g.isObject(l)){var k={};for(var i in j._oData){if(g.hasOwnProperty(j._oData,i)){k[i]=j._oData[i];}}j._oData=l;this.fireEvent("recordUpdateEvent",{record:j,newData:l,oldData:k});return j;}else{return null;}},updateKey:function(h,i,j){this.updateRecordValue(h,i,j);},updateRecordValue:function(h,k,n){var j=this.getRecord(h);if(j){var m=null;var l=j._oData[k];if(l&&g.isObject(l)){m={};for(var i in l){if(g.hasOwnProperty(l,i)){m[i]=l[i];}}}else{m=l;}j._oData[k]=n;this.fireEvent("keyUpdateEvent",{record:j,key:k,newData:n,oldData:m});this.fireEvent("recordValueUpdateEvent",{record:j,key:k,newData:n,oldData:m});}else{}},replaceRecords:function(h){this.reset();return this.addRecords(h);},sortRecords:function(h,j,i){return this._records.sort(function(l,k){return h(l,k,j,i);});},reverseRecords:function(){return this._records.reverse();},deleteRecord:function(h){if(g.isNumber(h)&&(h>-1)&&(h<this.getLength())){var i=this.getRecord(h).getData();this._deleteRecord(h);this.fireEvent("recordDeleteEvent",{data:i,index:h});return i;}else{return null;}},deleteRecords:function(k,h){if(!g.isNumber(h)){h=1;}if(g.isNumber(k)&&(k>-1)&&(k<this.getLength())){var m=this.getRecords(k,h);var j=[],n=[];for(var l=0;l<m.length;l++){j[j.length]=m[l];n[n.length]=m[l].getData();}this._deleteRecord(k,h);this.fireEvent("recordsDeleteEvent",{data:j,deletedData:n,index:k});return j;}else{return null;}},reset:function(){this._records=[];this.fireEvent("resetEvent");}};g.augmentProto(b,a.EventProvider);YAHOO.widget.Record=function(h){this._nCount=e.Record._nCount;this._sId=c.generateId(null,"yui-rec");e.Record._nCount++;this._oData={};if(g.isObject(h)){for(var i in h){if(g.hasOwnProperty(h,i)){this._oData[i]=h[i];}}}};YAHOO.widget.Record._nCount=0;YAHOO.widget.Record.prototype={_nCount:null,_sId:null,_oData:null,getCount:function(){return this._nCount;},getId:function(){return this._sId;},getData:function(h){if(g.isString(h)){return this._oData[h];}else{return this._oData;}},setData:function(h,i){this._oData[h]=i;}};})();(function(){var h=YAHOO.lang,a=YAHOO.util,e=YAHOO.widget,b=YAHOO.env.ua,c=a.Dom,g=a.Event,f=a.DataSourceBase;YAHOO.widget.DataTable=function(i,m,o,k){var l=e.DataTable;
-if(k&&k.scrollable){return new YAHOO.widget.ScrollingDataTable(i,m,o,k);}this._nIndex=l._nCount;this._sId=c.generateId(null,"yui-dt");this._oChainRender=new YAHOO.util.Chain();this._oChainRender.subscribe("end",this._onRenderChainEnd,this,true);this._initConfigs(k);this._initDataSource(o);if(!this._oDataSource){return;}this._initColumnSet(m);if(!this._oColumnSet){return;}this._initRecordSet();if(!this._oRecordSet){}l.superclass.constructor.call(this,i,this.configs);var q=this._initDomElements(i);if(!q){return;}this.showTableMessage(this.get("MSG_LOADING"),l.CLASS_LOADING);this._initEvents();l._nCount++;l._nCurrentCount++;var n={success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,scope:this,argument:this.getState()};var p=this.get("initialLoad");if(p===true){this._oDataSource.sendRequest(this.get("initialRequest"),n);}else{if(p===false){this.showTableMessage(this.get("MSG_EMPTY"),l.CLASS_EMPTY);}else{var j=p||{};n.argument=j.argument||{};this._oDataSource.sendRequest(j.request,n);}}};var d=e.DataTable;h.augmentObject(d,{CLASS_DATATABLE:"yui-dt",CLASS_LINER:"yui-dt-liner",CLASS_LABEL:"yui-dt-label",CLASS_MESSAGE:"yui-dt-message",CLASS_MASK:"yui-dt-mask",CLASS_DATA:"yui-dt-data",CLASS_COLTARGET:"yui-dt-coltarget",CLASS_RESIZER:"yui-dt-resizer",CLASS_RESIZERLINER:"yui-dt-resizerliner",CLASS_RESIZERPROXY:"yui-dt-resizerproxy",CLASS_EDITOR:"yui-dt-editor",CLASS_EDITOR_SHIM:"yui-dt-editor-shim",CLASS_PAGINATOR:"yui-dt-paginator",CLASS_PAGE:"yui-dt-page",CLASS_DEFAULT:"yui-dt-default",CLASS_PREVIOUS:"yui-dt-previous",CLASS_NEXT:"yui-dt-next",CLASS_FIRST:"yui-dt-first",CLASS_LAST:"yui-dt-last",CLASS_REC:"yui-dt-rec",CLASS_EVEN:"yui-dt-even",CLASS_ODD:"yui-dt-odd",CLASS_SELECTED:"yui-dt-selected",CLASS_HIGHLIGHTED:"yui-dt-highlighted",CLASS_HIDDEN:"yui-dt-hidden",CLASS_DISABLED:"yui-dt-disabled",CLASS_EMPTY:"yui-dt-empty",CLASS_LOADING:"yui-dt-loading",CLASS_ERROR:"yui-dt-error",CLASS_EDITABLE:"yui-dt-editable",CLASS_DRAGGABLE:"yui-dt-draggable",CLASS_RESIZEABLE:"yui-dt-resizeable",CLASS_SCROLLABLE:"yui-dt-scrollable",CLASS_SORTABLE:"yui-dt-sortable",CLASS_ASC:"yui-dt-asc",CLASS_DESC:"yui-dt-desc",CLASS_BUTTON:"yui-dt-button",CLASS_CHECKBOX:"yui-dt-checkbox",CLASS_DROPDOWN:"yui-dt-dropdown",CLASS_RADIO:"yui-dt-radio",_nCount:0,_nCurrentCount:0,_elDynStyleNode:null,_bDynStylesFallback:(b.ie)?true:false,_oDynStyles:{},_cloneObject:function(m){if(!h.isValue(m)){return m;}var p={};if(m instanceof YAHOO.widget.BaseCellEditor){p=m;}else{if(Object.prototype.toString.apply(m)==="[object RegExp]"){p=m;}else{if(h.isFunction(m)){p=m;}else{if(h.isArray(m)){var n=[];for(var l=0,k=m.length;l<k;l++){n[l]=d._cloneObject(m[l]);}p=n;}else{if(h.isObject(m)){for(var j in m){if(h.hasOwnProperty(m,j)){if(h.isValue(m[j])&&h.isObject(m[j])||h.isArray(m[j])){p[j]=d._cloneObject(m[j]);}else{p[j]=m[j];}}}}else{p=m;}}}}}return p;},formatButton:function(i,j,k,n,m){var l=h.isValue(n)?n:"Click";i.innerHTML='<button type="button" class="'+d.CLASS_BUTTON+'">'+l+"</button>";},formatCheckbox:function(i,j,k,n,m){var l=n;l=(l)?' checked="checked"':"";i.innerHTML='<input type="checkbox"'+l+' class="'+d.CLASS_CHECKBOX+'" />';},formatCurrency:function(j,k,l,n,m){var i=m||this;j.innerHTML=a.Number.format(n,l.currencyOptions||i.get("currencyOptions"));},formatDate:function(j,l,m,o,n){var i=n||this,k=m.dateOptions||i.get("dateOptions");j.innerHTML=a.Date.format(o,k,k.locale);},formatDropdown:function(l,u,q,j,t){var s=t||this,r=(h.isValue(j))?j:u.getData(q.field),v=(h.isArray(q.dropdownOptions))?q.dropdownOptions:null,k,p=l.getElementsByTagName("select");if(p.length===0){k=document.createElement("select");k.className=d.CLASS_DROPDOWN;k=l.appendChild(k);g.addListener(k,"change",s._onDropdownChange,s);}k=p[0];if(k){k.innerHTML="";if(v){for(var n=0;n<v.length;n++){var o=v[n];var m=document.createElement("option");m.value=(h.isValue(o.value))?o.value:o;m.innerHTML=(h.isValue(o.text))?o.text:(h.isValue(o.label))?o.label:o;m=k.appendChild(m);if(m.value==r){m.selected=true;}}}else{k.innerHTML='<option selected value="'+r+'">'+r+"</option>";}}else{l.innerHTML=h.isValue(j)?j:"";}},formatEmail:function(i,j,k,m,l){if(h.isString(m)){m=h.escapeHTML(m);i.innerHTML='<a href="mailto:'+m+'">'+m+"</a>";}else{i.innerHTML=h.isValue(m)?h.escapeHTML(m.toString()):"";}},formatLink:function(i,j,k,m,l){if(h.isString(m)){m=h.escapeHTML(m);i.innerHTML='<a href="'+m+'">'+m+"</a>";}else{i.innerHTML=h.isValue(m)?h.escapeHTML(m.toString()):"";}},formatNumber:function(j,k,l,n,m){var i=m||this;j.innerHTML=a.Number.format(n,l.numberOptions||i.get("numberOptions"));},formatRadio:function(j,k,l,o,n){var i=n||this,m=o;m=(m)?' checked="checked"':"";j.innerHTML='<input type="radio"'+m+' name="'+i.getId()+"-col-"+l.getSanitizedKey()+'"'+' class="'+d.CLASS_RADIO+'" />';},formatText:function(i,j,l,n,m){var k=(h.isValue(n))?n:"";i.innerHTML=h.escapeHTML(k.toString());},formatTextarea:function(j,k,m,o,n){var l=(h.isValue(o))?h.escapeHTML(o.toString()):"",i="<textarea>"+l+"</textarea>";j.innerHTML=i;},formatTextbox:function(j,k,m,o,n){var l=(h.isValue(o))?h.escapeHTML(o.toString()):"",i='<input type="text" value="'+l+'" />';j.innerHTML=i;},formatDefault:function(i,j,k,m,l){i.innerHTML=(h.isValue(m)&&m!=="")?m.toString():"&#160;";},validateNumber:function(j){var i=j*1;if(h.isNumber(i)){return i;}else{return undefined;}}});d.Formatter={button:d.formatButton,checkbox:d.formatCheckbox,currency:d.formatCurrency,"date":d.formatDate,dropdown:d.formatDropdown,email:d.formatEmail,link:d.formatLink,"number":d.formatNumber,radio:d.formatRadio,text:d.formatText,textarea:d.formatTextarea,textbox:d.formatTextbox,defaultFormatter:d.formatDefault};h.extend(d,a.Element,{initAttributes:function(i){i=i||{};d.superclass.initAttributes.call(this,i);this.setAttributeConfig("summary",{value:"",validator:h.isString,method:function(j){if(this._elTable){this._elTable.summary=j;}}});this.setAttributeConfig("selectionMode",{value:"standard",validator:h.isString});this.setAttributeConfig("sortedBy",{value:null,validator:function(j){if(j){return(h.isObject(j)&&j.key);
-}else{return(j===null);}},method:function(k){var r=this.get("sortedBy");this._configs.sortedBy.value=k;var j,o,m,q;if(this._elThead){if(r&&r.key&&r.dir){j=this._oColumnSet.getColumn(r.key);o=j.getKeyIndex();var u=j.getThEl();c.removeClass(u,r.dir);this.formatTheadCell(j.getThLinerEl().firstChild,j,k);}if(k){m=(k.column)?k.column:this._oColumnSet.getColumn(k.key);q=m.getKeyIndex();var v=m.getThEl();if(k.dir&&((k.dir=="asc")||(k.dir=="desc"))){var p=(k.dir=="desc")?d.CLASS_DESC:d.CLASS_ASC;c.addClass(v,p);}else{var l=k.dir||d.CLASS_ASC;c.addClass(v,l);}this.formatTheadCell(m.getThLinerEl().firstChild,m,k);}}if(this._elTbody){this._elTbody.style.display="none";var s=this._elTbody.rows,t;for(var n=s.length-1;n>-1;n--){t=s[n].childNodes;if(t[o]){c.removeClass(t[o],r.dir);}if(t[q]){c.addClass(t[q],k.dir);}}this._elTbody.style.display="";}this._clearTrTemplateEl();}});this.setAttributeConfig("paginator",{value:null,validator:function(j){return j===null||j instanceof e.Paginator;},method:function(){this._updatePaginator.apply(this,arguments);}});this.setAttributeConfig("caption",{value:null,validator:h.isString,method:function(j){this._initCaptionEl(j);}});this.setAttributeConfig("draggableColumns",{value:false,validator:h.isBoolean,method:function(j){if(this._elThead){if(j){this._initDraggableColumns();}else{this._destroyDraggableColumns();}}}});this.setAttributeConfig("renderLoopSize",{value:0,validator:h.isNumber});this.setAttributeConfig("sortFunction",{value:function(k,j,o,n){var m=YAHOO.util.Sort.compare,l=m(k.getData(n),j.getData(n),o);if(l===0){return m(k.getCount(),j.getCount(),o);}else{return l;}}});this.setAttributeConfig("formatRow",{value:null,validator:h.isFunction});this.setAttributeConfig("generateRequest",{value:function(k,n){k=k||{pagination:null,sortedBy:null};var m=encodeURIComponent((k.sortedBy)?k.sortedBy.key:n.getColumnSet().keys[0].getKey());var j=(k.sortedBy&&k.sortedBy.dir===YAHOO.widget.DataTable.CLASS_DESC)?"desc":"asc";var o=(k.pagination)?k.pagination.recordOffset:0;var l=(k.pagination)?k.pagination.rowsPerPage:null;return"sort="+m+"&dir="+j+"&startIndex="+o+((l!==null)?"&results="+l:"");},validator:h.isFunction});this.setAttributeConfig("initialRequest",{value:null});this.setAttributeConfig("initialLoad",{value:true});this.setAttributeConfig("dynamicData",{value:false,validator:h.isBoolean});this.setAttributeConfig("MSG_EMPTY",{value:"No records found.",validator:h.isString});this.setAttributeConfig("MSG_LOADING",{value:"Loading...",validator:h.isString});this.setAttributeConfig("MSG_ERROR",{value:"Data error.",validator:h.isString});this.setAttributeConfig("MSG_SORTASC",{value:"Click to sort ascending",validator:h.isString,method:function(k){if(this._elThead){for(var l=0,m=this.getColumnSet().keys,j=m.length;l<j;l++){if(m[l].sortable&&this.getColumnSortDir(m[l])===d.CLASS_ASC){m[l]._elThLabel.firstChild.title=k;}}}}});this.setAttributeConfig("MSG_SORTDESC",{value:"Click to sort descending",validator:h.isString,method:function(k){if(this._elThead){for(var l=0,m=this.getColumnSet().keys,j=m.length;l<j;l++){if(m[l].sortable&&this.getColumnSortDir(m[l])===d.CLASS_DESC){m[l]._elThLabel.firstChild.title=k;}}}}});this.setAttributeConfig("currencySymbol",{value:"$",validator:h.isString});this.setAttributeConfig("currencyOptions",{value:{prefix:this.get("currencySymbol"),decimalPlaces:2,decimalSeparator:".",thousandsSeparator:","}});this.setAttributeConfig("dateOptions",{value:{format:"%m/%d/%Y",locale:"en"}});this.setAttributeConfig("numberOptions",{value:{decimalPlaces:0,thousandsSeparator:","}});},_bInit:true,_nIndex:null,_nTrCount:0,_nTdCount:0,_sId:null,_oChainRender:null,_elContainer:null,_elMask:null,_elTable:null,_elCaption:null,_elColgroup:null,_elThead:null,_elTbody:null,_elMsgTbody:null,_elMsgTr:null,_elMsgTd:null,_elColumnDragTarget:null,_elColumnResizerProxy:null,_oDataSource:null,_oColumnSet:null,_oRecordSet:null,_oCellEditor:null,_sFirstTrId:null,_sLastTrId:null,_elTrTemplate:null,_aDynFunctions:[],_disabled:false,clearTextSelection:function(){var i;if(window.getSelection){i=window.getSelection();}else{if(document.getSelection){i=document.getSelection();}else{if(document.selection){i=document.selection;}}}if(i){if(i.empty){i.empty();}else{if(i.removeAllRanges){i.removeAllRanges();}else{if(i.collapse){i.collapse();}}}}},_focusEl:function(i){i=i||this._elTbody;setTimeout(function(){try{i.focus();}catch(j){}},0);},_repaintGecko:(b.gecko)?function(j){j=j||this._elContainer;var i=j.parentNode;var k=j.nextSibling;i.insertBefore(i.removeChild(j),k);}:function(){},_repaintOpera:(b.opera)?function(){if(b.opera){document.documentElement.className+=" ";document.documentElement.className=YAHOO.lang.trim(document.documentElement.className);}}:function(){},_repaintWebkit:(b.webkit)?function(j){j=j||this._elContainer;var i=j.parentNode;var k=j.nextSibling;i.insertBefore(i.removeChild(j),k);}:function(){},_initConfigs:function(i){if(!i||!h.isObject(i)){i={};}this.configs=i;},_initColumnSet:function(n){var m,k,j;if(this._oColumnSet){for(k=0,j=this._oColumnSet.keys.length;k<j;k++){m=this._oColumnSet.keys[k];d._oDynStyles["."+this.getId()+"-col-"+m.getSanitizedKey()+" ."+d.CLASS_LINER]=undefined;if(m.editor&&m.editor.unsubscribeAll){m.editor.unsubscribeAll();}}this._oColumnSet=null;this._clearTrTemplateEl();}if(h.isArray(n)){this._oColumnSet=new YAHOO.widget.ColumnSet(n);}else{if(n instanceof YAHOO.widget.ColumnSet){this._oColumnSet=n;}}var l=this._oColumnSet.keys;for(k=0,j=l.length;k<j;k++){m=l[k];if(m.editor&&m.editor.subscribe){m.editor.subscribe("showEvent",this._onEditorShowEvent,this,true);m.editor.subscribe("keydownEvent",this._onEditorKeydownEvent,this,true);m.editor.subscribe("revertEvent",this._onEditorRevertEvent,this,true);m.editor.subscribe("saveEvent",this._onEditorSaveEvent,this,true);m.editor.subscribe("cancelEvent",this._onEditorCancelEvent,this,true);m.editor.subscribe("blurEvent",this._onEditorBlurEvent,this,true);m.editor.subscribe("blockEvent",this._onEditorBlockEvent,this,true);
-m.editor.subscribe("unblockEvent",this._onEditorUnblockEvent,this,true);}}},_initDataSource:function(j){this._oDataSource=null;if(j&&(h.isFunction(j.sendRequest))){this._oDataSource=j;}else{var k=null;var o=this._elContainer;var l=0;if(o.hasChildNodes()){var n=o.childNodes;for(l=0;l<n.length;l++){if(n[l].nodeName&&n[l].nodeName.toLowerCase()=="table"){k=n[l];break;}}if(k){var m=[];for(;l<this._oColumnSet.keys.length;l++){m.push({key:this._oColumnSet.keys[l].key});}this._oDataSource=new f(k);this._oDataSource.responseType=f.TYPE_HTMLTABLE;this._oDataSource.responseSchema={fields:m};}}}},_initRecordSet:function(){if(this._oRecordSet){this._oRecordSet.reset();}else{this._oRecordSet=new YAHOO.widget.RecordSet();}},_initDomElements:function(i){this._initContainerEl(i);this._initTableEl(this._elContainer);this._initColgroupEl(this._elTable);this._initTheadEl(this._elTable);this._initMsgTbodyEl(this._elTable);this._initTbodyEl(this._elTable);if(!this._elContainer||!this._elTable||!this._elColgroup||!this._elThead||!this._elTbody||!this._elMsgTbody){return false;}else{return true;}},_destroyContainerEl:function(m){var k=this._oColumnSet.keys,l,j;c.removeClass(m,d.CLASS_DATATABLE);g.purgeElement(m);g.purgeElement(this._elThead,true);g.purgeElement(this._elTbody);g.purgeElement(this._elMsgTbody);l=m.getElementsByTagName("select");if(l.length){g.detachListener(l,"change");}for(j=k.length-1;j>=0;--j){if(k[j].editor){g.purgeElement(k[j].editor._elContainer);}}m.innerHTML="";this._elContainer=null;this._elColgroup=null;this._elThead=null;this._elTbody=null;},_initContainerEl:function(j){j=c.get(j);if(j&&j.nodeName&&(j.nodeName.toLowerCase()=="div")){this._destroyContainerEl(j);c.addClass(j,d.CLASS_DATATABLE);g.addListener(j,"focus",this._onTableFocus,this);g.addListener(j,"dblclick",this._onTableDblclick,this);this._elContainer=j;var i=document.createElement("div");i.className=d.CLASS_MASK;i.style.display="none";this._elMask=j.appendChild(i);}},_destroyTableEl:function(){var i=this._elTable;if(i){g.purgeElement(i,true);i.parentNode.removeChild(i);this._elCaption=null;this._elColgroup=null;this._elThead=null;this._elTbody=null;}},_initCaptionEl:function(i){if(this._elTable&&i){if(!this._elCaption){this._elCaption=this._elTable.createCaption();}this._elCaption.innerHTML=i;}else{if(this._elCaption){this._elCaption.parentNode.removeChild(this._elCaption);}}},_initTableEl:function(i){if(i){this._destroyTableEl();this._elTable=i.appendChild(document.createElement("table"));this._elTable.summary=this.get("summary");if(this.get("caption")){this._initCaptionEl(this.get("caption"));}g.delegate(this._elTable,"mouseenter",this._onTableMouseover,"thead ."+d.CLASS_LABEL,this);g.delegate(this._elTable,"mouseleave",this._onTableMouseout,"thead ."+d.CLASS_LABEL,this);g.delegate(this._elTable,"mouseenter",this._onTableMouseover,"tbody.yui-dt-data>tr>td",this);g.delegate(this._elTable,"mouseleave",this._onTableMouseout,"tbody.yui-dt-data>tr>td",this);g.delegate(this._elTable,"mouseenter",this._onTableMouseover,"tbody.yui-dt-message>tr>td",this);g.delegate(this._elTable,"mouseleave",this._onTableMouseout,"tbody.yui-dt-message>tr>td",this);}},_destroyColgroupEl:function(){var i=this._elColgroup;if(i){var j=i.parentNode;g.purgeElement(i,true);j.removeChild(i);this._elColgroup=null;}},_initColgroupEl:function(s){if(s){this._destroyColgroupEl();var l=this._aColIds||[],r=this._oColumnSet.keys,m=0,p=l.length,j,o,q=document.createDocumentFragment(),n=document.createElement("col");for(m=0,p=r.length;m<p;m++){o=r[m];j=q.appendChild(n.cloneNode(false));}var k=s.insertBefore(document.createElement("colgroup"),s.firstChild);k.appendChild(q);this._elColgroup=k;}},_insertColgroupColEl:function(i){if(h.isNumber(i)&&this._elColgroup){var j=this._elColgroup.childNodes[i]||null;this._elColgroup.insertBefore(document.createElement("col"),j);}},_removeColgroupColEl:function(i){if(h.isNumber(i)&&this._elColgroup&&this._elColgroup.childNodes[i]){this._elColgroup.removeChild(this._elColgroup.childNodes[i]);}},_reorderColgroupColEl:function(l,k){if(h.isArray(l)&&h.isNumber(k)&&this._elColgroup&&(this._elColgroup.childNodes.length>l[l.length-1])){var j,n=[];for(j=l.length-1;j>-1;j--){n.push(this._elColgroup.removeChild(this._elColgroup.childNodes[l[j]]));}var m=this._elColgroup.childNodes[k]||null;for(j=n.length-1;j>-1;j--){this._elColgroup.insertBefore(n[j],m);}}},_destroyTheadEl:function(){var j=this._elThead;if(j){var i=j.parentNode;g.purgeElement(j,true);this._destroyColumnHelpers();i.removeChild(j);this._elThead=null;}},_initTheadEl:function(v){v=v||this._elTable;if(v){this._destroyTheadEl();var q=(this._elColgroup)?v.insertBefore(document.createElement("thead"),this._elColgroup.nextSibling):v.appendChild(document.createElement("thead"));g.addListener(q,"focus",this._onTheadFocus,this);g.addListener(q,"keydown",this._onTheadKeydown,this);g.addListener(q,"mousedown",this._onTableMousedown,this);g.addListener(q,"mouseup",this._onTableMouseup,this);g.addListener(q,"click",this._onTheadClick,this);var x=this._oColumnSet,t,r,p,n;var w=x.tree;var o;for(r=0;r<w.length;r++){var m=q.appendChild(document.createElement("tr"));for(p=0;p<w[r].length;p++){t=w[r][p];o=m.appendChild(document.createElement("th"));this._initThEl(o,t);}if(r===0){c.addClass(m,d.CLASS_FIRST);}if(r===(w.length-1)){c.addClass(m,d.CLASS_LAST);}}var k=x.headers[0]||[];for(r=0;r<k.length;r++){c.addClass(c.get(this.getId()+"-th-"+k[r]),d.CLASS_FIRST);}var s=x.headers[x.headers.length-1]||[];for(r=0;r<s.length;r++){c.addClass(c.get(this.getId()+"-th-"+s[r]),d.CLASS_LAST);}if(b.webkit&&b.webkit<420){var u=this;setTimeout(function(){q.style.display="";},0);q.style.display="none";}this._elThead=q;this._initColumnHelpers();}},_initThEl:function(m,l){m.id=this.getId()+"-th-"+l.getSanitizedKey();m.innerHTML="";m.rowSpan=l.getRowspan();m.colSpan=l.getColspan();l._elTh=m;var i=m.appendChild(document.createElement("div"));i.id=m.id+"-liner";i.className=d.CLASS_LINER;l._elThLiner=i;var j=i.appendChild(document.createElement("span"));
-j.className=d.CLASS_LABEL;if(l.abbr){m.abbr=l.abbr;}if(l.hidden){this._clearMinWidth(l);}m.className=this._getColumnClassNames(l);if(l.width){var k=(l.minWidth&&(l.width<l.minWidth))?l.minWidth:l.width;if(d._bDynStylesFallback){m.firstChild.style.overflow="hidden";m.firstChild.style.width=k+"px";}else{this._setColumnWidthDynStyles(l,k+"px","hidden");}}this.formatTheadCell(j,l,this.get("sortedBy"));l._elThLabel=j;},formatTheadCell:function(i,m,k){var q=m.getKey();var p=h.isValue(m.label)?m.label:q;if(m.sortable){var n=this.getColumnSortDir(m,k);var j=(n===d.CLASS_DESC);if(k&&(m.key===k.key)){j=!(k.dir===d.CLASS_DESC);}var l=this.getId()+"-href-"+m.getSanitizedKey();var o=(j)?this.get("MSG_SORTDESC"):this.get("MSG_SORTASC");i.innerHTML='<a href="'+l+'" title="'+o+'" class="'+d.CLASS_SORTABLE+'">'+p+"</a>";}else{i.innerHTML=p;}},_destroyDraggableColumns:function(){var l,m;for(var k=0,j=this._oColumnSet.tree[0].length;k<j;k++){l=this._oColumnSet.tree[0][k];if(l._dd){l._dd=l._dd.unreg();c.removeClass(l.getThEl(),d.CLASS_DRAGGABLE);}}this._destroyColumnDragTargetEl();},_initDraggableColumns:function(){this._destroyDraggableColumns();if(a.DD){var m,n,k;for(var l=0,j=this._oColumnSet.tree[0].length;l<j;l++){m=this._oColumnSet.tree[0][l];n=m.getThEl();c.addClass(n,d.CLASS_DRAGGABLE);k=this._initColumnDragTargetEl();m._dd=new YAHOO.widget.ColumnDD(this,m,n,k);}}else{}},_destroyColumnDragTargetEl:function(){if(this._elColumnDragTarget){var i=this._elColumnDragTarget;YAHOO.util.Event.purgeElement(i);i.parentNode.removeChild(i);this._elColumnDragTarget=null;}},_initColumnDragTargetEl:function(){if(!this._elColumnDragTarget){var i=document.createElement("div");i.id=this.getId()+"-coltarget";i.className=d.CLASS_COLTARGET;i.style.display="none";document.body.insertBefore(i,document.body.firstChild);this._elColumnDragTarget=i;}return this._elColumnDragTarget;},_destroyResizeableColumns:function(){var k=this._oColumnSet.keys;for(var l=0,j=k.length;l<j;l++){if(k[l]._ddResizer){k[l]._ddResizer=k[l]._ddResizer.unreg();c.removeClass(k[l].getThEl(),d.CLASS_RESIZEABLE);}}this._destroyColumnResizerProxyEl();},_initResizeableColumns:function(){this._destroyResizeableColumns();if(a.DD){var p,k,n,q,j,r,m;for(var l=0,o=this._oColumnSet.keys.length;l<o;l++){p=this._oColumnSet.keys[l];if(p.resizeable){k=p.getThEl();c.addClass(k,d.CLASS_RESIZEABLE);n=p.getThLinerEl();q=k.appendChild(document.createElement("div"));q.className=d.CLASS_RESIZERLINER;q.appendChild(n);j=q.appendChild(document.createElement("div"));j.id=k.id+"-resizer";j.className=d.CLASS_RESIZER;p._elResizer=j;r=this._initColumnResizerProxyEl();p._ddResizer=new YAHOO.util.ColumnResizer(this,p,k,j,r);m=function(i){g.stopPropagation(i);};g.addListener(j,"click",m);}}}else{}},_destroyColumnResizerProxyEl:function(){if(this._elColumnResizerProxy){var i=this._elColumnResizerProxy;YAHOO.util.Event.purgeElement(i);i.parentNode.removeChild(i);this._elColumnResizerProxy=null;}},_initColumnResizerProxyEl:function(){if(!this._elColumnResizerProxy){var i=document.createElement("div");i.id=this.getId()+"-colresizerproxy";i.className=d.CLASS_RESIZERPROXY;document.body.insertBefore(i,document.body.firstChild);this._elColumnResizerProxy=i;}return this._elColumnResizerProxy;},_destroyColumnHelpers:function(){this._destroyDraggableColumns();this._destroyResizeableColumns();},_initColumnHelpers:function(){if(this.get("draggableColumns")){this._initDraggableColumns();}this._initResizeableColumns();},_destroyTbodyEl:function(){var i=this._elTbody;if(i){var j=i.parentNode;g.purgeElement(i,true);j.removeChild(i);this._elTbody=null;}},_initTbodyEl:function(j){if(j){this._destroyTbodyEl();var i=j.appendChild(document.createElement("tbody"));i.tabIndex=0;i.className=d.CLASS_DATA;g.addListener(i,"focus",this._onTbodyFocus,this);g.addListener(i,"mousedown",this._onTableMousedown,this);g.addListener(i,"mouseup",this._onTableMouseup,this);g.addListener(i,"keydown",this._onTbodyKeydown,this);g.addListener(i,"click",this._onTbodyClick,this);if(b.ie){i.hideFocus=true;}this._elTbody=i;}},_destroyMsgTbodyEl:function(){var i=this._elMsgTbody;if(i){var j=i.parentNode;g.purgeElement(i,true);j.removeChild(i);this._elTbody=null;}},_initMsgTbodyEl:function(l){if(l){var k=document.createElement("tbody");k.className=d.CLASS_MESSAGE;var j=k.appendChild(document.createElement("tr"));j.className=d.CLASS_FIRST+" "+d.CLASS_LAST;this._elMsgTr=j;var m=j.appendChild(document.createElement("td"));m.colSpan=this._oColumnSet.keys.length||1;m.className=d.CLASS_FIRST+" "+d.CLASS_LAST;this._elMsgTd=m;k=l.insertBefore(k,this._elTbody);var i=m.appendChild(document.createElement("div"));i.className=d.CLASS_LINER;this._elMsgTbody=k;g.addListener(k,"focus",this._onTbodyFocus,this);g.addListener(k,"mousedown",this._onTableMousedown,this);g.addListener(k,"mouseup",this._onTableMouseup,this);g.addListener(k,"keydown",this._onTbodyKeydown,this);g.addListener(k,"click",this._onTbodyClick,this);}},_initEvents:function(){this._initColumnSort();YAHOO.util.Event.addListener(document,"click",this._onDocumentClick,this);this.subscribe("paginatorChange",function(){this._handlePaginatorChange.apply(this,arguments);});this.subscribe("initEvent",function(){this.renderPaginator();});this._initCellEditing();},_initColumnSort:function(){this.subscribe("theadCellClickEvent",this.onEventSortColumn);var i=this.get("sortedBy");if(i){if(i.dir=="desc"){this._configs.sortedBy.value.dir=d.CLASS_DESC;}else{if(i.dir=="asc"){this._configs.sortedBy.value.dir=d.CLASS_ASC;}}}},_initCellEditing:function(){this.subscribe("editorBlurEvent",function(){this.onEditorBlurEvent.apply(this,arguments);});this.subscribe("editorBlockEvent",function(){this.onEditorBlockEvent.apply(this,arguments);});this.subscribe("editorUnblockEvent",function(){this.onEditorUnblockEvent.apply(this,arguments);});},_getColumnClassNames:function(l,k){var i;if(h.isString(l.className)){i=[l.className];}else{if(h.isArray(l.className)){i=l.className;}else{i=[];}}i[i.length]=this.getId()+"-col-"+l.getSanitizedKey();
-i[i.length]="yui-dt-col-"+l.getSanitizedKey();var j=this.get("sortedBy")||{};if(l.key===j.key){i[i.length]=j.dir||"";}if(l.hidden){i[i.length]=d.CLASS_HIDDEN;}if(l.selected){i[i.length]=d.CLASS_SELECTED;}if(l.sortable){i[i.length]=d.CLASS_SORTABLE;}if(l.resizeable){i[i.length]=d.CLASS_RESIZEABLE;}if(l.editor){i[i.length]=d.CLASS_EDITABLE;}if(k){i=i.concat(k);}return i.join(" ");},_clearTrTemplateEl:function(){this._elTrTemplate=null;},_getTrTemplateEl:function(u,o){if(this._elTrTemplate){return this._elTrTemplate;}else{var q=document,s=q.createElement("tr"),l=q.createElement("td"),k=q.createElement("div");l.appendChild(k);var t=document.createDocumentFragment(),r=this._oColumnSet.keys,n;var p;for(var m=0,j=r.length;m<j;m++){n=l.cloneNode(true);n=this._formatTdEl(r[m],n,m,(m===j-1));t.appendChild(n);}s.appendChild(t);s.className=d.CLASS_REC;this._elTrTemplate=s;return s;}},_formatTdEl:function(n,p,q,m){var t=this._oColumnSet;var i=t.headers,k=i[q],o="",v;for(var l=0,u=k.length;l<u;l++){v=this._sId+"-th-"+k[l]+" ";o+=v;}p.headers=o;var s=[];if(q===0){s[s.length]=d.CLASS_FIRST;}if(m){s[s.length]=d.CLASS_LAST;}p.className=this._getColumnClassNames(n,s);p.firstChild.className=d.CLASS_LINER;if(n.width&&d._bDynStylesFallback){var r=(n.minWidth&&(n.width<n.minWidth))?n.minWidth:n.width;p.firstChild.style.overflow="hidden";p.firstChild.style.width=r+"px";}return p;},_addTrEl:function(k){var j=this._getTrTemplateEl();var i=j.cloneNode(true);return this._updateTrEl(i,k);},_updateTrEl:function(q,r){var p=this.get("formatRow")?this.get("formatRow").call(this,q,r):true;if(p){q.style.display="none";var o=q.childNodes,m;for(var l=0,n=o.length;l<n;++l){m=o[l];this.formatCell(o[l].firstChild,r,this._oColumnSet.keys[l]);}q.style.display="";}var j=q.id,k=r.getId();if(this._sFirstTrId===j){this._sFirstTrId=k;}if(this._sLastTrId===j){this._sLastTrId=k;}q.id=k;return q;},_deleteTrEl:function(i){var j;if(!h.isNumber(i)){j=c.get(i).sectionRowIndex;}else{j=i;}if(h.isNumber(j)&&(j>-2)&&(j<this._elTbody.rows.length)){return this._elTbody.removeChild(this._elTbody.rows[i]);}else{return null;}},_unsetFirstRow:function(){if(this._sFirstTrId){c.removeClass(this._sFirstTrId,d.CLASS_FIRST);this._sFirstTrId=null;}},_setFirstRow:function(){this._unsetFirstRow();var i=this.getFirstTrEl();if(i){c.addClass(i,d.CLASS_FIRST);this._sFirstTrId=i.id;}},_unsetLastRow:function(){if(this._sLastTrId){c.removeClass(this._sLastTrId,d.CLASS_LAST);this._sLastTrId=null;}},_setLastRow:function(){this._unsetLastRow();var i=this.getLastTrEl();if(i){c.addClass(i,d.CLASS_LAST);this._sLastTrId=i.id;}},_setRowStripes:function(t,l){var m=this._elTbody.rows,q=0,s=m.length,p=[],r=0,n=[],j=0;if((t!==null)&&(t!==undefined)){var o=this.getTrEl(t);if(o){q=o.sectionRowIndex;if(h.isNumber(l)&&(l>1)){s=q+l;}}}for(var k=q;k<s;k++){if(k%2){p[r++]=m[k];}else{n[j++]=m[k];}}if(p.length){c.replaceClass(p,d.CLASS_EVEN,d.CLASS_ODD);}if(n.length){c.replaceClass(n,d.CLASS_ODD,d.CLASS_EVEN);}},_setSelections:function(){var l=this.getSelectedRows();var n=this.getSelectedCells();if((l.length>0)||(n.length>0)){var m=this._oColumnSet,k;for(var j=0;j<l.length;j++){k=c.get(l[j]);if(k){c.addClass(k,d.CLASS_SELECTED);}}for(j=0;j<n.length;j++){k=c.get(n[j].recordId);if(k){c.addClass(k.childNodes[m.getColumn(n[j].columnKey).getKeyIndex()],d.CLASS_SELECTED);}}}},_onRenderChainEnd:function(){this.hideTableMessage();if(this._elTbody.rows.length===0){this.showTableMessage(this.get("MSG_EMPTY"),d.CLASS_EMPTY);}var i=this;setTimeout(function(){if((i instanceof d)&&i._sId){if(i._bInit){i._bInit=false;i.fireEvent("initEvent");}i.fireEvent("renderEvent");i.fireEvent("refreshEvent");i.validateColumnWidths();i.fireEvent("postRenderEvent");}},0);},_onDocumentClick:function(l,j){var m=g.getTarget(l);var i=m.nodeName.toLowerCase();if(!c.isAncestor(j._elContainer,m)){j.fireEvent("tableBlurEvent");if(j._oCellEditor){if(j._oCellEditor.getContainerEl){var k=j._oCellEditor.getContainerEl();if(!c.isAncestor(k,m)&&(k.id!==m.id)){j._oCellEditor.fireEvent("blurEvent",{editor:j._oCellEditor});}}else{if(j._oCellEditor.isActive){if(!c.isAncestor(j._oCellEditor.container,m)&&(j._oCellEditor.container.id!==m.id)){j.fireEvent("editorBlurEvent",{editor:j._oCellEditor});}}}}}},_onTableFocus:function(j,i){i.fireEvent("tableFocusEvent");},_onTheadFocus:function(j,i){i.fireEvent("theadFocusEvent");i.fireEvent("tableFocusEvent");},_onTbodyFocus:function(j,i){i.fireEvent("tbodyFocusEvent");i.fireEvent("tableFocusEvent");},_onTableMouseover:function(n,m,i,k){var o=m;var j=o.nodeName&&o.nodeName.toLowerCase();var l=true;while(o&&(j!="table")){switch(j){case"body":return;case"a":break;case"td":l=k.fireEvent("cellMouseoverEvent",{target:o,event:n});break;case"span":if(c.hasClass(o,d.CLASS_LABEL)){l=k.fireEvent("theadLabelMouseoverEvent",{target:o,event:n});l=k.fireEvent("headerLabelMouseoverEvent",{target:o,event:n});}break;case"th":l=k.fireEvent("theadCellMouseoverEvent",{target:o,event:n});l=k.fireEvent("headerCellMouseoverEvent",{target:o,event:n});break;case"tr":if(o.parentNode.nodeName.toLowerCase()=="thead"){l=k.fireEvent("theadRowMouseoverEvent",{target:o,event:n});l=k.fireEvent("headerRowMouseoverEvent",{target:o,event:n});}else{l=k.fireEvent("rowMouseoverEvent",{target:o,event:n});}break;default:break;}if(l===false){return;}else{o=o.parentNode;if(o){j=o.nodeName.toLowerCase();}}}k.fireEvent("tableMouseoverEvent",{target:(o||k._elContainer),event:n});},_onTableMouseout:function(n,m,i,k){var o=m;var j=o.nodeName&&o.nodeName.toLowerCase();var l=true;while(o&&(j!="table")){switch(j){case"body":return;case"a":break;case"td":l=k.fireEvent("cellMouseoutEvent",{target:o,event:n});break;case"span":if(c.hasClass(o,d.CLASS_LABEL)){l=k.fireEvent("theadLabelMouseoutEvent",{target:o,event:n});l=k.fireEvent("headerLabelMouseoutEvent",{target:o,event:n});}break;case"th":l=k.fireEvent("theadCellMouseoutEvent",{target:o,event:n});l=k.fireEvent("headerCellMouseoutEvent",{target:o,event:n});break;case"tr":if(o.parentNode.nodeName.toLowerCase()=="thead"){l=k.fireEvent("theadRowMouseoutEvent",{target:o,event:n});
-l=k.fireEvent("headerRowMouseoutEvent",{target:o,event:n});}else{l=k.fireEvent("rowMouseoutEvent",{target:o,event:n});}break;default:break;}if(l===false){return;}else{o=o.parentNode;if(o){j=o.nodeName.toLowerCase();}}}k.fireEvent("tableMouseoutEvent",{target:(o||k._elContainer),event:n});},_onTableMousedown:function(l,j){var m=g.getTarget(l);var i=m.nodeName&&m.nodeName.toLowerCase();var k=true;while(m&&(i!="table")){switch(i){case"body":return;case"a":break;case"td":k=j.fireEvent("cellMousedownEvent",{target:m,event:l});break;case"span":if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent("theadLabelMousedownEvent",{target:m,event:l});k=j.fireEvent("headerLabelMousedownEvent",{target:m,event:l});}break;case"th":k=j.fireEvent("theadCellMousedownEvent",{target:m,event:l});k=j.fireEvent("headerCellMousedownEvent",{target:m,event:l});break;case"tr":if(m.parentNode.nodeName.toLowerCase()=="thead"){k=j.fireEvent("theadRowMousedownEvent",{target:m,event:l});k=j.fireEvent("headerRowMousedownEvent",{target:m,event:l});}else{k=j.fireEvent("rowMousedownEvent",{target:m,event:l});}break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent("tableMousedownEvent",{target:(m||j._elContainer),event:l});},_onTableMouseup:function(l,j){var m=g.getTarget(l);var i=m.nodeName&&m.nodeName.toLowerCase();var k=true;while(m&&(i!="table")){switch(i){case"body":return;case"a":break;case"td":k=j.fireEvent("cellMouseupEvent",{target:m,event:l});break;case"span":if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent("theadLabelMouseupEvent",{target:m,event:l});k=j.fireEvent("headerLabelMouseupEvent",{target:m,event:l});}break;case"th":k=j.fireEvent("theadCellMouseupEvent",{target:m,event:l});k=j.fireEvent("headerCellMouseupEvent",{target:m,event:l});break;case"tr":if(m.parentNode.nodeName.toLowerCase()=="thead"){k=j.fireEvent("theadRowMouseupEvent",{target:m,event:l});k=j.fireEvent("headerRowMouseupEvent",{target:m,event:l});}else{k=j.fireEvent("rowMouseupEvent",{target:m,event:l});}break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent("tableMouseupEvent",{target:(m||j._elContainer),event:l});},_onTableDblclick:function(l,j){var m=g.getTarget(l);var i=m.nodeName&&m.nodeName.toLowerCase();var k=true;while(m&&(i!="table")){switch(i){case"body":return;case"td":k=j.fireEvent("cellDblclickEvent",{target:m,event:l});break;case"span":if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent("theadLabelDblclickEvent",{target:m,event:l});k=j.fireEvent("headerLabelDblclickEvent",{target:m,event:l});}break;case"th":k=j.fireEvent("theadCellDblclickEvent",{target:m,event:l});k=j.fireEvent("headerCellDblclickEvent",{target:m,event:l});break;case"tr":if(m.parentNode.nodeName.toLowerCase()=="thead"){k=j.fireEvent("theadRowDblclickEvent",{target:m,event:l});k=j.fireEvent("headerRowDblclickEvent",{target:m,event:l});}else{k=j.fireEvent("rowDblclickEvent",{target:m,event:l});}break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent("tableDblclickEvent",{target:(m||j._elContainer),event:l});},_onTheadKeydown:function(l,j){var m=g.getTarget(l);var i=m.nodeName&&m.nodeName.toLowerCase();var k=true;while(m&&(i!="table")){switch(i){case"body":return;case"input":case"textarea":break;case"thead":k=j.fireEvent("theadKeyEvent",{target:m,event:l});break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent("tableKeyEvent",{target:(m||j._elContainer),event:l});},_onTbodyKeydown:function(m,k){var j=k.get("selectionMode");if(j=="standard"){k._handleStandardSelectionByKey(m);}else{if(j=="single"){k._handleSingleSelectionByKey(m);}else{if(j=="cellblock"){k._handleCellBlockSelectionByKey(m);}else{if(j=="cellrange"){k._handleCellRangeSelectionByKey(m);}else{if(j=="singlecell"){k._handleSingleCellSelectionByKey(m);}}}}}if(k._oCellEditor){if(k._oCellEditor.fireEvent){k._oCellEditor.fireEvent("blurEvent",{editor:k._oCellEditor});}else{if(k._oCellEditor.isActive){k.fireEvent("editorBlurEvent",{editor:k._oCellEditor});}}}var n=g.getTarget(m);var i=n.nodeName&&n.nodeName.toLowerCase();var l=true;while(n&&(i!="table")){switch(i){case"body":return;case"tbody":l=k.fireEvent("tbodyKeyEvent",{target:n,event:m});break;default:break;}if(l===false){return;}else{n=n.parentNode;if(n){i=n.nodeName.toLowerCase();}}}k.fireEvent("tableKeyEvent",{target:(n||k._elContainer),event:m});},_onTheadClick:function(l,j){if(j._oCellEditor){if(j._oCellEditor.fireEvent){j._oCellEditor.fireEvent("blurEvent",{editor:j._oCellEditor});}else{if(j._oCellEditor.isActive){j.fireEvent("editorBlurEvent",{editor:j._oCellEditor});}}}var m=g.getTarget(l),i=m.nodeName&&m.nodeName.toLowerCase(),k=true;while(m&&(i!="table")){switch(i){case"body":return;case"input":var n=m.type.toLowerCase();if(n=="checkbox"){k=j.fireEvent("theadCheckboxClickEvent",{target:m,event:l});}else{if(n=="radio"){k=j.fireEvent("theadRadioClickEvent",{target:m,event:l});}else{if((n=="button")||(n=="image")||(n=="submit")||(n=="reset")){if(!m.disabled){k=j.fireEvent("theadButtonClickEvent",{target:m,event:l});}else{k=false;}}else{if(m.disabled){k=false;}}}}break;case"a":k=j.fireEvent("theadLinkClickEvent",{target:m,event:l});break;case"button":if(!m.disabled){k=j.fireEvent("theadButtonClickEvent",{target:m,event:l});}else{k=false;}break;case"span":if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent("theadLabelClickEvent",{target:m,event:l});k=j.fireEvent("headerLabelClickEvent",{target:m,event:l});}break;case"th":k=j.fireEvent("theadCellClickEvent",{target:m,event:l});k=j.fireEvent("headerCellClickEvent",{target:m,event:l});break;case"tr":k=j.fireEvent("theadRowClickEvent",{target:m,event:l});k=j.fireEvent("headerRowClickEvent",{target:m,event:l});break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent("tableClickEvent",{target:(m||j._elContainer),event:l});},_onTbodyClick:function(l,j){if(j._oCellEditor){if(j._oCellEditor.fireEvent){j._oCellEditor.fireEvent("blurEvent",{editor:j._oCellEditor});
-}else{if(j._oCellEditor.isActive){j.fireEvent("editorBlurEvent",{editor:j._oCellEditor});}}}var m=g.getTarget(l),i=m.nodeName&&m.nodeName.toLowerCase(),k=true;while(m&&(i!="table")){switch(i){case"body":return;case"input":var n=m.type.toLowerCase();if(n=="checkbox"){k=j.fireEvent("checkboxClickEvent",{target:m,event:l});}else{if(n=="radio"){k=j.fireEvent("radioClickEvent",{target:m,event:l});}else{if((n=="button")||(n=="image")||(n=="submit")||(n=="reset")){if(!m.disabled){k=j.fireEvent("buttonClickEvent",{target:m,event:l});}else{k=false;}}else{if(m.disabled){k=false;}}}}break;case"a":k=j.fireEvent("linkClickEvent",{target:m,event:l});break;case"button":if(!m.disabled){k=j.fireEvent("buttonClickEvent",{target:m,event:l});}else{k=false;}break;case"td":k=j.fireEvent("cellClickEvent",{target:m,event:l});break;case"tr":k=j.fireEvent("rowClickEvent",{target:m,event:l});break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent("tableClickEvent",{target:(m||j._elContainer),event:l});},_onDropdownChange:function(j,i){var k=g.getTarget(j);i.fireEvent("dropdownChangeEvent",{event:j,target:k});},configs:null,getId:function(){return this._sId;},toString:function(){return"DataTable instance "+this._sId;},getDataSource:function(){return this._oDataSource;},getColumnSet:function(){return this._oColumnSet;},getRecordSet:function(){return this._oRecordSet;},getState:function(){return{totalRecords:this.get("paginator")?this.get("paginator").get("totalRecords"):this._oRecordSet.getLength(),pagination:this.get("paginator")?this.get("paginator").getState():null,sortedBy:this.get("sortedBy"),selectedRows:this.getSelectedRows(),selectedCells:this.getSelectedCells()};},getContainerEl:function(){return this._elContainer;},getTableEl:function(){return this._elTable;},getTheadEl:function(){return this._elThead;},getTbodyEl:function(){return this._elTbody;},getMsgTbodyEl:function(){return this._elMsgTbody;},getMsgTdEl:function(){return this._elMsgTd;},getTrEl:function(k){if(k instanceof YAHOO.widget.Record){return document.getElementById(k.getId());}else{if(h.isNumber(k)){var j=c.getElementsByClassName(d.CLASS_REC,"tr",this._elTbody);return j&&j[k]?j[k]:null;}else{if(k){var i=(h.isString(k))?document.getElementById(k):k;if(i&&i.ownerDocument==document){if(i.nodeName.toLowerCase()!="tr"){i=c.getAncestorByTagName(i,"tr");}return i;}}}}return null;},getFirstTrEl:function(){var k=this._elTbody.rows,j=0;while(k[j]){if(this.getRecord(k[j])){return k[j];}j++;}return null;},getLastTrEl:function(){var k=this._elTbody.rows,j=k.length-1;while(j>-1){if(this.getRecord(k[j])){return k[j];}j--;}return null;},getNextTrEl:function(l,i){var j=this.getTrIndex(l);if(j!==null){var k=this._elTbody.rows;if(i){while(j<k.length-1){l=k[j+1];if(this.getRecord(l)){return l;}j++;}}else{if(j<k.length-1){return k[j+1];}}}return null;},getPreviousTrEl:function(l,i){var j=this.getTrIndex(l);if(j!==null){var k=this._elTbody.rows;if(i){while(j>0){l=k[j-1];if(this.getRecord(l)){return l;}j--;}}else{if(j>0){return k[j-1];}}}return null;},getCellIndex:function(k){k=this.getTdEl(k);if(k){if(b.ie>0){var l=0,n=k.parentNode,m=n.childNodes,j=m.length;for(;l<j;l++){if(m[l]==k){return l;}}}else{return k.cellIndex;}}},getTdLinerEl:function(i){var j=this.getTdEl(i);return j.firstChild||null;},getTdEl:function(i){var n;var l=c.get(i);if(l&&(l.ownerDocument==document)){if(l.nodeName.toLowerCase()!="td"){n=c.getAncestorByTagName(l,"td");}else{n=l;}if(n&&((n.parentNode.parentNode==this._elTbody)||(n.parentNode.parentNode===null)||(n.parentNode.parentNode.nodeType===11))){return n;}}else{if(i){var m,k;if(h.isString(i.columnKey)&&h.isString(i.recordId)){m=this.getRecord(i.recordId);var o=this.getColumn(i.columnKey);if(o){k=o.getKeyIndex();}}if(i.record&&i.column&&i.column.getKeyIndex){m=i.record;k=i.column.getKeyIndex();}var j=this.getTrEl(m);if((k!==null)&&j&&j.cells&&j.cells.length>0){return j.cells[k]||null;}}}return null;},getFirstTdEl:function(j){var i=h.isValue(j)?this.getTrEl(j):this.getFirstTrEl();if(i){if(i.cells&&i.cells.length>0){return i.cells[0];}else{if(i.childNodes&&i.childNodes.length>0){return i.childNodes[0];}}}return null;},getLastTdEl:function(j){var i=h.isValue(j)?this.getTrEl(j):this.getLastTrEl();if(i){if(i.cells&&i.cells.length>0){return i.cells[i.cells.length-1];}else{if(i.childNodes&&i.childNodes.length>0){return i.childNodes[i.childNodes.length-1];}}}return null;},getNextTdEl:function(i){var m=this.getTdEl(i);if(m){var k=this.getCellIndex(m);var j=this.getTrEl(m);if(j.cells&&(j.cells.length)>0&&(k<j.cells.length-1)){return j.cells[k+1];}else{if(j.childNodes&&(j.childNodes.length)>0&&(k<j.childNodes.length-1)){return j.childNodes[k+1];}else{var l=this.getNextTrEl(j);if(l){return l.cells[0];}}}}return null;},getPreviousTdEl:function(i){var m=this.getTdEl(i);if(m){var k=this.getCellIndex(m);var j=this.getTrEl(m);if(k>0){if(j.cells&&j.cells.length>0){return j.cells[k-1];}else{if(j.childNodes&&j.childNodes.length>0){return j.childNodes[k-1];}}}else{var l=this.getPreviousTrEl(j);if(l){return this.getLastTdEl(l);}}}return null;},getAboveTdEl:function(j,i){var m=this.getTdEl(j);if(m){var l=this.getPreviousTrEl(m,i);if(l){var k=this.getCellIndex(m);if(l.cells&&l.cells.length>0){return l.cells[k]?l.cells[k]:null;}else{if(l.childNodes&&l.childNodes.length>0){return l.childNodes[k]?l.childNodes[k]:null;}}}}return null;},getBelowTdEl:function(j,i){var m=this.getTdEl(j);if(m){var l=this.getNextTrEl(m,i);if(l){var k=this.getCellIndex(m);if(l.cells&&l.cells.length>0){return l.cells[k]?l.cells[k]:null;}else{if(l.childNodes&&l.childNodes.length>0){return l.childNodes[k]?l.childNodes[k]:null;}}}}return null;},getThLinerEl:function(j){var i=this.getColumn(j);return(i)?i.getThLinerEl():null;},getThEl:function(k){var l;if(k instanceof YAHOO.widget.Column){var j=k;l=j.getThEl();if(l){return l;}}else{var i=c.get(k);if(i&&(i.ownerDocument==document)){if(i.nodeName.toLowerCase()!="th"){l=c.getAncestorByTagName(i,"th");
-}else{l=i;}return l;}}return null;},getTrIndex:function(m){var i=this.getRecord(m),k=this.getRecordIndex(i),l;if(i){l=this.getTrEl(i);if(l){return l.sectionRowIndex;}else{var j=this.get("paginator");if(j){return j.get("recordOffset")+k;}else{return k;}}}return null;},load:function(i){i=i||{};(i.datasource||this._oDataSource).sendRequest(i.request||this.get("initialRequest"),i.callback||{success:this.onDataReturnInitializeTable,failure:this.onDataReturnInitializeTable,scope:this,argument:this.getState()});},initializeTable:function(){this._bInit=true;this._oRecordSet.reset();var i=this.get("paginator");if(i){i.set("totalRecords",0);}this._unselectAllTrEls();this._unselectAllTdEls();this._aSelections=null;this._oAnchorRecord=null;this._oAnchorCell=null;this.set("sortedBy",null);},_runRenderChain:function(){this._oChainRender.run();},_getViewRecords:function(){var i=this.get("paginator");if(i){return this._oRecordSet.getRecords(i.getStartIndex(),i.getRowsPerPage());}else{return this._oRecordSet.getRecords();}},render:function(){this._oChainRender.stop();this.fireEvent("beforeRenderEvent");var r,p,o,s,l=this._getViewRecords();var m=this._elTbody,q=this.get("renderLoopSize"),t=l.length;if(t>0){m.style.display="none";while(m.lastChild){m.removeChild(m.lastChild);}m.style.display="";this._oChainRender.add({method:function(u){if((this instanceof d)&&this._sId){var k=u.nCurrentRecord,w=((u.nCurrentRecord+u.nLoopLength)>t)?t:(u.nCurrentRecord+u.nLoopLength),j,v;m.style.display="none";for(;k<w;k++){j=c.get(l[k].getId());j=j||this._addTrEl(l[k]);v=m.childNodes[k]||null;m.insertBefore(j,v);}m.style.display="";u.nCurrentRecord=k;}},scope:this,iterations:(q>0)?Math.ceil(t/q):1,argument:{nCurrentRecord:0,nLoopLength:(q>0)?q:t},timeout:(q>0)?0:-1});this._oChainRender.add({method:function(i){if((this instanceof d)&&this._sId){while(m.rows.length>t){m.removeChild(m.lastChild);}this._setFirstRow();this._setLastRow();this._setRowStripes();this._setSelections();}},scope:this,timeout:(q>0)?0:-1});}else{var n=m.rows.length;if(n>0){this._oChainRender.add({method:function(k){if((this instanceof d)&&this._sId){var j=k.nCurrent,v=k.nLoopLength,u=(j-v<0)?0:j-v;m.style.display="none";for(;j>u;j--){m.deleteRow(-1);}m.style.display="";k.nCurrent=j;}},scope:this,iterations:(q>0)?Math.ceil(n/q):1,argument:{nCurrent:n,nLoopLength:(q>0)?q:n},timeout:(q>0)?0:-1});}}this._runRenderChain();},disable:function(){this._disabled=true;var i=this._elTable;var j=this._elMask;j.style.width=i.offsetWidth+"px";j.style.height=i.offsetHeight+"px";j.style.left=i.offsetLeft+"px";j.style.display="";this.fireEvent("disableEvent");},undisable:function(){this._disabled=false;this._elMask.style.display="none";this.fireEvent("undisableEvent");},isDisabled:function(){return this._disabled;},destroy:function(){var k=this.toString();this._oChainRender.stop();this._destroyColumnHelpers();var m;for(var l=0,j=this._oColumnSet.flat.length;l<j;l++){m=this._oColumnSet.flat[l].editor;if(m&&m.destroy){m.destroy();this._oColumnSet.flat[l].editor=null;}}this._destroyPaginator();this._oRecordSet.unsubscribeAll();this.unsubscribeAll();g.removeListener(document,"click",this._onDocumentClick);this._destroyContainerEl(this._elContainer);for(var n in this){if(h.hasOwnProperty(this,n)){this[n]=null;}}d._nCurrentCount--;if(d._nCurrentCount<1){if(d._elDynStyleNode){document.getElementsByTagName("head")[0].removeChild(d._elDynStyleNode);d._elDynStyleNode=null;}}},showTableMessage:function(j,i){var k=this._elMsgTd;if(h.isString(j)){k.firstChild.innerHTML=j;}if(h.isString(i)){k.className=i;}this._elMsgTbody.style.display="";this.fireEvent("tableMsgShowEvent",{html:j,className:i});},hideTableMessage:function(){if(this._elMsgTbody.style.display!="none"){this._elMsgTbody.style.display="none";this._elMsgTbody.parentNode.style.width="";this.fireEvent("tableMsgHideEvent");}},focus:function(){this.focusTbodyEl();},focusTheadEl:function(){this._focusEl(this._elThead);},focusTbodyEl:function(){this._focusEl(this._elTbody);},onShow:function(){this.validateColumnWidths();for(var m=this._oColumnSet.keys,l=0,j=m.length,k;l<j;l++){k=m[l];if(k._ddResizer){k._ddResizer.resetResizerEl();}}},getRecordIndex:function(l){var k;if(!h.isNumber(l)){if(l instanceof YAHOO.widget.Record){return this._oRecordSet.getRecordIndex(l);}else{var j=this.getTrEl(l);if(j){k=j.sectionRowIndex;}}}else{k=l;}if(h.isNumber(k)){var i=this.get("paginator");if(i){return i.get("recordOffset")+k;}else{return k;}}return null;},getRecord:function(k){var j=this._oRecordSet.getRecord(k);if(!j){var i=this.getTrEl(k);if(i){j=this._oRecordSet.getRecord(i.id);}}if(j instanceof YAHOO.widget.Record){return this._oRecordSet.getRecord(j);}else{return null;}},getColumn:function(m){var o=this._oColumnSet.getColumn(m);if(!o){var n=this.getTdEl(m);if(n){o=this._oColumnSet.getColumn(this.getCellIndex(n));}else{n=this.getThEl(m);if(n){var k=this._oColumnSet.flat;for(var l=0,j=k.length;l<j;l++){if(k[l].getThEl().id===n.id){o=k[l];}}}}}if(!o){}return o;},getColumnById:function(i){return this._oColumnSet.getColumnById(i);},getColumnSortDir:function(k,l){if(k.sortOptions&&k.sortOptions.defaultDir){if(k.sortOptions.defaultDir=="asc"){k.sortOptions.defaultDir=d.CLASS_ASC;}else{if(k.sortOptions.defaultDir=="desc"){k.sortOptions.defaultDir=d.CLASS_DESC;}}}var j=(k.sortOptions&&k.sortOptions.defaultDir)?k.sortOptions.defaultDir:d.CLASS_ASC;var i=false;l=l||this.get("sortedBy");if(l&&(l.key===k.key)){i=true;if(l.dir){j=(l.dir===d.CLASS_ASC)?d.CLASS_DESC:d.CLASS_ASC;}else{j=(j===d.CLASS_ASC)?d.CLASS_DESC:d.CLASS_ASC;}}return j;},doBeforeSortColumn:function(j,i){this.showTableMessage(this.get("MSG_LOADING"),d.CLASS_LOADING);return true;},sortColumn:function(m,j){if(m&&(m instanceof YAHOO.widget.Column)){if(!m.sortable){c.addClass(this.getThEl(m),d.CLASS_SORTABLE);}if(j&&(j!==d.CLASS_ASC)&&(j!==d.CLASS_DESC)){j=null;}var n=j||this.getColumnSortDir(m);var l=this.get("sortedBy")||{};var t=(l.key===m.key)?true:false;var p=this.doBeforeSortColumn(m,n);
-if(p){if(this.get("dynamicData")){var s=this.getState();if(s.pagination){s.pagination.recordOffset=0;}s.sortedBy={key:m.key,dir:n};var k=this.get("generateRequest")(s,this);this.unselectAllRows();this.unselectAllCells();var r={success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,argument:s,scope:this};this._oDataSource.sendRequest(k,r);}else{var i=(m.sortOptions&&h.isFunction(m.sortOptions.sortFunction))?m.sortOptions.sortFunction:null;if(!t||j||i){i=i||this.get("sortFunction");var q=(m.sortOptions&&m.sortOptions.field)?m.sortOptions.field:m.field;this._oRecordSet.sortRecords(i,((n==d.CLASS_DESC)?true:false),q);}else{this._oRecordSet.reverseRecords();}var o=this.get("paginator");if(o){o.setPage(1,true);}this.render();this.set("sortedBy",{key:m.key,dir:n,column:m});}this.fireEvent("columnSortEvent",{column:m,dir:n});return;}}},setColumnWidth:function(j,i){if(!(j instanceof YAHOO.widget.Column)){j=this.getColumn(j);}if(j){if(h.isNumber(i)){i=(i>j.minWidth)?i:j.minWidth;j.width=i;this._setColumnWidth(j,i+"px");this.fireEvent("columnSetWidthEvent",{column:j,width:i});}else{if(i===null){j.width=i;this._setColumnWidth(j,"auto");this.validateColumnWidths(j);this.fireEvent("columnUnsetWidthEvent",{column:j});}}this._clearTrTemplateEl();}else{}},_setColumnWidth:function(j,i,k){if(j&&(j.getKeyIndex()!==null)){k=k||(((i==="")||(i==="auto"))?"visible":"hidden");if(!d._bDynStylesFallback){this._setColumnWidthDynStyles(j,i,k);}else{this._setColumnWidthDynFunction(j,i,k);}}else{}},_setColumnWidthDynStyles:function(m,l,n){var j=d._elDynStyleNode,k;if(!j){j=document.createElement("style");j.type="text/css";j=document.getElementsByTagName("head").item(0).appendChild(j);d._elDynStyleNode=j;}if(j){var i="."+this.getId()+"-col-"+m.getSanitizedKey()+" ."+d.CLASS_LINER;if(this._elTbody){this._elTbody.style.display="none";}k=d._oDynStyles[i];if(!k){if(j.styleSheet&&j.styleSheet.addRule){j.styleSheet.addRule(i,"overflow:"+n);j.styleSheet.addRule(i,"width:"+l);k=j.styleSheet.rules[j.styleSheet.rules.length-1];d._oDynStyles[i]=k;}else{if(j.sheet&&j.sheet.insertRule){j.sheet.insertRule(i+" {overflow:"+n+";width:"+l+";}",j.sheet.cssRules.length);k=j.sheet.cssRules[j.sheet.cssRules.length-1];d._oDynStyles[i]=k;}}}else{k.style.overflow=n;k.style.width=l;}if(this._elTbody){this._elTbody.style.display="";}}if(!k){d._bDynStylesFallback=true;this._setColumnWidthDynFunction(m,l);}},_setColumnWidthDynFunction:function(r,m,s){if(m=="auto"){m="";}var l=this._elTbody?this._elTbody.rows.length:0;if(!this._aDynFunctions[l]){var q,p,o;var t=["var colIdx=oColumn.getKeyIndex();","oColumn.getThLinerEl().style.overflow="];for(q=l-1,p=2;q>=0;--q){t[p++]="this._elTbody.rows[";t[p++]=q;t[p++]="].cells[colIdx].firstChild.style.overflow=";}t[p]="sOverflow;";t[p+1]="oColumn.getThLinerEl().style.width=";for(q=l-1,o=p+2;q>=0;--q){t[o++]="this._elTbody.rows[";t[o++]=q;t[o++]="].cells[colIdx].firstChild.style.width=";}t[o]="sWidth;";this._aDynFunctions[l]=new Function("oColumn","sWidth","sOverflow",t.join(""));}var n=this._aDynFunctions[l];if(n){n.call(this,r,m,s);}},validateColumnWidths:function(o){var l=this._elColgroup;var q=l.cloneNode(true);var p=false;var n=this._oColumnSet.keys;var k;if(o&&!o.hidden&&!o.width&&(o.getKeyIndex()!==null)){k=o.getThLinerEl();if((o.minWidth>0)&&(k.offsetWidth<o.minWidth)){q.childNodes[o.getKeyIndex()].style.width=o.minWidth+(parseInt(c.getStyle(k,"paddingLeft"),10)|0)+(parseInt(c.getStyle(k,"paddingRight"),10)|0)+"px";p=true;}else{if((o.maxAutoWidth>0)&&(k.offsetWidth>o.maxAutoWidth)){this._setColumnWidth(o,o.maxAutoWidth+"px","hidden");}}}else{for(var m=0,j=n.length;m<j;m++){o=n[m];if(!o.hidden&&!o.width){k=o.getThLinerEl();if((o.minWidth>0)&&(k.offsetWidth<o.minWidth)){q.childNodes[m].style.width=o.minWidth+(parseInt(c.getStyle(k,"paddingLeft"),10)|0)+(parseInt(c.getStyle(k,"paddingRight"),10)|0)+"px";p=true;}else{if((o.maxAutoWidth>0)&&(k.offsetWidth>o.maxAutoWidth)){this._setColumnWidth(o,o.maxAutoWidth+"px","hidden");}}}}}if(p){l.parentNode.replaceChild(q,l);this._elColgroup=q;}},_clearMinWidth:function(i){if(i.getKeyIndex()!==null){this._elColgroup.childNodes[i.getKeyIndex()].style.width="";}},_restoreMinWidth:function(i){if(i.minWidth&&(i.getKeyIndex()!==null)){this._elColgroup.childNodes[i.getKeyIndex()].style.width=i.minWidth+"px";}},hideColumn:function(r){if(!(r instanceof YAHOO.widget.Column)){r=this.getColumn(r);}if(r&&!r.hidden&&r.getTreeIndex()!==null){var o=this.getTbodyEl().rows;var n=o.length;var m=this._oColumnSet.getDescendants(r);for(var q=0,s=m.length;q<s;q++){var t=m[q];t.hidden=true;c.addClass(t.getThEl(),d.CLASS_HIDDEN);var k=t.getKeyIndex();if(k!==null){this._clearMinWidth(r);for(var p=0;p<n;p++){c.addClass(o[p].cells[k],d.CLASS_HIDDEN);}}this.fireEvent("columnHideEvent",{column:t});}this._repaintOpera();this._clearTrTemplateEl();}else{}},showColumn:function(r){if(!(r instanceof YAHOO.widget.Column)){r=this.getColumn(r);}if(r&&r.hidden&&(r.getTreeIndex()!==null)){var o=this.getTbodyEl().rows;var n=o.length;var m=this._oColumnSet.getDescendants(r);for(var q=0,s=m.length;q<s;q++){var t=m[q];t.hidden=false;c.removeClass(t.getThEl(),d.CLASS_HIDDEN);var k=t.getKeyIndex();if(k!==null){this._restoreMinWidth(r);for(var p=0;p<n;p++){c.removeClass(o[p].cells[k],d.CLASS_HIDDEN);}}this.fireEvent("columnShowEvent",{column:t});}this._clearTrTemplateEl();}else{}},removeColumn:function(p){if(!(p instanceof YAHOO.widget.Column)){p=this.getColumn(p);}if(p){var m=p.getTreeIndex();if(m!==null){var o,r,q=p.getKeyIndex();if(q===null){var u=[];var j=this._oColumnSet.getDescendants(p);for(o=0,r=j.length;o<r;o++){var s=j[o].getKeyIndex();if(s!==null){u[u.length]=s;}}if(u.length>0){q=u;}}else{q=[q];}if(q!==null){q.sort(function(v,i){return YAHOO.util.Sort.compare(v,i);});this._destroyTheadEl();var k=this._oColumnSet.getDefinitions();p=k.splice(m,1)[0];this._initColumnSet(k);this._initTheadEl();for(o=q.length-1;o>-1;o--){this._removeColgroupColEl(q[o]);}var t=this._elTbody.rows;if(t.length>0){var n=this.get("renderLoopSize"),l=t.length;
-this._oChainRender.add({method:function(y){if((this instanceof d)&&this._sId){var x=y.nCurrentRow,v=n>0?Math.min(x+n,t.length):t.length,z=y.aIndexes,w;for(;x<v;++x){for(w=z.length-1;w>-1;w--){t[x].removeChild(t[x].childNodes[z[w]]);}}y.nCurrentRow=x;}},iterations:(n>0)?Math.ceil(l/n):1,argument:{nCurrentRow:0,aIndexes:q},scope:this,timeout:(n>0)?0:-1});this._runRenderChain();}this.fireEvent("columnRemoveEvent",{column:p});return p;}}}},insertColumn:function(r,s){if(r instanceof YAHOO.widget.Column){r=r.getDefinition();}else{if(r.constructor!==Object){return;}}var x=this._oColumnSet;if(!h.isValue(s)||!h.isNumber(s)){s=x.tree[0].length;}this._destroyTheadEl();var z=this._oColumnSet.getDefinitions();z.splice(s,0,r);this._initColumnSet(z);this._initTheadEl();x=this._oColumnSet;var n=x.tree[0][s];var p,t,w=[];var l=x.getDescendants(n);for(p=0,t=l.length;p<t;p++){var u=l[p].getKeyIndex();if(u!==null){w[w.length]=u;}}if(w.length>0){var y=w.sort(function(A,i){return YAHOO.util.Sort.compare(A,i);})[0];for(p=w.length-1;p>-1;p--){this._insertColgroupColEl(w[p]);}var v=this._elTbody.rows;if(v.length>0){var o=this.get("renderLoopSize"),m=v.length;var k=[],q;for(p=0,t=w.length;p<t;p++){var j=w[p];q=this._getTrTemplateEl().childNodes[p].cloneNode(true);q=this._formatTdEl(this._oColumnSet.keys[j],q,j,(j===this._oColumnSet.keys.length-1));k[j]=q;}this._oChainRender.add({method:function(D){if((this instanceof d)&&this._sId){var C=D.nCurrentRow,B,F=D.descKeyIndexes,A=o>0?Math.min(C+o,v.length):v.length,E;for(;C<A;++C){E=v[C].childNodes[y]||null;for(B=F.length-1;B>-1;B--){v[C].insertBefore(D.aTdTemplates[F[B]].cloneNode(true),E);}}D.nCurrentRow=C;}},iterations:(o>0)?Math.ceil(m/o):1,argument:{nCurrentRow:0,aTdTemplates:k,descKeyIndexes:w},scope:this,timeout:(o>0)?0:-1});this._runRenderChain();}this.fireEvent("columnInsertEvent",{column:r,index:s});return n;}},reorderColumn:function(q,r){if(!(q instanceof YAHOO.widget.Column)){q=this.getColumn(q);}if(q&&YAHOO.lang.isNumber(r)){var z=q.getTreeIndex();if((z!==null)&&(z!==r)){var p,s,l=q.getKeyIndex(),k,v=[],t;if(l===null){k=this._oColumnSet.getDescendants(q);for(p=0,s=k.length;p<s;p++){t=k[p].getKeyIndex();if(t!==null){v[v.length]=t;}}if(v.length>0){l=v;}}else{l=[l];}if(l!==null){l.sort(function(A,i){return YAHOO.util.Sort.compare(A,i);});this._destroyTheadEl();var w=this._oColumnSet.getDefinitions();var j=w.splice(z,1)[0];w.splice(r,0,j);this._initColumnSet(w);this._initTheadEl();var n=this._oColumnSet.tree[0][r];var y=n.getKeyIndex();if(y===null){v=[];k=this._oColumnSet.getDescendants(n);for(p=0,s=k.length;p<s;p++){t=k[p].getKeyIndex();if(t!==null){v[v.length]=t;}}if(v.length>0){y=v;}}else{y=[y];}var x=y.sort(function(A,i){return YAHOO.util.Sort.compare(A,i);})[0];this._reorderColgroupColEl(l,x);var u=this._elTbody.rows;if(u.length>0){var o=this.get("renderLoopSize"),m=u.length;this._oChainRender.add({method:function(D){if((this instanceof d)&&this._sId){var C=D.nCurrentRow,B,F,E,A=o>0?Math.min(C+o,u.length):u.length,H=D.aIndexes,G;for(;C<A;++C){F=[];G=u[C];for(B=H.length-1;B>-1;B--){F.push(G.removeChild(G.childNodes[H[B]]));}E=G.childNodes[x]||null;for(B=F.length-1;B>-1;B--){G.insertBefore(F[B],E);}}D.nCurrentRow=C;}},iterations:(o>0)?Math.ceil(m/o):1,argument:{nCurrentRow:0,aIndexes:l},scope:this,timeout:(o>0)?0:-1});this._runRenderChain();}this.fireEvent("columnReorderEvent",{column:n,oldIndex:z});return n;}}}},selectColumn:function(k){k=this.getColumn(k);if(k&&!k.selected){if(k.getKeyIndex()!==null){k.selected=true;var l=k.getThEl();c.addClass(l,d.CLASS_SELECTED);var j=this.getTbodyEl().rows;var i=this._oChainRender;i.add({method:function(m){if((this instanceof d)&&this._sId&&j[m.rowIndex]&&j[m.rowIndex].cells[m.cellIndex]){c.addClass(j[m.rowIndex].cells[m.cellIndex],d.CLASS_SELECTED);}m.rowIndex++;},scope:this,iterations:j.length,argument:{rowIndex:0,cellIndex:k.getKeyIndex()}});this._clearTrTemplateEl();this._elTbody.style.display="none";this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnSelectEvent",{column:k});}else{}}},unselectColumn:function(k){k=this.getColumn(k);if(k&&k.selected){if(k.getKeyIndex()!==null){k.selected=false;var l=k.getThEl();c.removeClass(l,d.CLASS_SELECTED);var j=this.getTbodyEl().rows;var i=this._oChainRender;i.add({method:function(m){if((this instanceof d)&&this._sId&&j[m.rowIndex]&&j[m.rowIndex].cells[m.cellIndex]){c.removeClass(j[m.rowIndex].cells[m.cellIndex],d.CLASS_SELECTED);}m.rowIndex++;},scope:this,iterations:j.length,argument:{rowIndex:0,cellIndex:k.getKeyIndex()}});this._clearTrTemplateEl();this._elTbody.style.display="none";this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnUnselectEvent",{column:k});}else{}}},getSelectedColumns:function(n){var k=[];var l=this._oColumnSet.keys;for(var m=0,j=l.length;m<j;m++){if(l[m].selected){k[k.length]=l[m];}}return k;},highlightColumn:function(i){var l=this.getColumn(i);if(l&&(l.getKeyIndex()!==null)){var m=l.getThEl();c.addClass(m,d.CLASS_HIGHLIGHTED);var k=this.getTbodyEl().rows;var j=this._oChainRender;j.add({method:function(n){if((this instanceof d)&&this._sId&&k[n.rowIndex]&&k[n.rowIndex].cells[n.cellIndex]){c.addClass(k[n.rowIndex].cells[n.cellIndex],d.CLASS_HIGHLIGHTED);}n.rowIndex++;},scope:this,iterations:k.length,argument:{rowIndex:0,cellIndex:l.getKeyIndex()},timeout:-1});this._elTbody.style.display="none";this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnHighlightEvent",{column:l});}else{}},unhighlightColumn:function(i){var l=this.getColumn(i);if(l&&(l.getKeyIndex()!==null)){var m=l.getThEl();c.removeClass(m,d.CLASS_HIGHLIGHTED);var k=this.getTbodyEl().rows;var j=this._oChainRender;j.add({method:function(n){if((this instanceof d)&&this._sId&&k[n.rowIndex]&&k[n.rowIndex].cells[n.cellIndex]){c.removeClass(k[n.rowIndex].cells[n.cellIndex],d.CLASS_HIGHLIGHTED);}n.rowIndex++;},scope:this,iterations:k.length,argument:{rowIndex:0,cellIndex:l.getKeyIndex()},timeout:-1});this._elTbody.style.display="none";
-this._runRenderChain();this._elTbody.style.display="";this.fireEvent("columnUnhighlightEvent",{column:l});}else{}},addRow:function(o,k){if(h.isNumber(k)&&(k<0||k>this._oRecordSet.getLength())){return;}if(o&&h.isObject(o)){var m=this._oRecordSet.addRecord(o,k);if(m){var i;var j=this.get("paginator");if(j){var n=j.get("totalRecords");if(n!==e.Paginator.VALUE_UNLIMITED){j.set("totalRecords",n+1);}i=this.getRecordIndex(m);var l=(j.getPageRecords())[1];if(i<=l){this.render();}this.fireEvent("rowAddEvent",{record:m});return;}else{i=this.getRecordIndex(m);if(h.isNumber(i)){this._oChainRender.add({method:function(r){if((this instanceof d)&&this._sId){var s=r.record;var p=r.recIndex;var t=this._addTrEl(s);if(t){var q=(this._elTbody.rows[p])?this._elTbody.rows[p]:null;this._elTbody.insertBefore(t,q);if(p===0){this._setFirstRow();}if(q===null){this._setLastRow();}this._setRowStripes();this.hideTableMessage();this.fireEvent("rowAddEvent",{record:s});}}},argument:{record:m,recIndex:i},scope:this,timeout:(this.get("renderLoopSize")>0)?0:-1});this._runRenderChain();return;}}}}},addRows:function(k,n){if(h.isNumber(n)&&(n<0||n>this._oRecordSet.getLength())){return;}if(h.isArray(k)){var o=this._oRecordSet.addRecords(k,n);if(o){var s=this.getRecordIndex(o[0]);var r=this.get("paginator");if(r){var p=r.get("totalRecords");if(p!==e.Paginator.VALUE_UNLIMITED){r.set("totalRecords",p+o.length);}var q=(r.getPageRecords())[1];if(s<=q){this.render();}this.fireEvent("rowsAddEvent",{records:o});return;}else{var m=this.get("renderLoopSize");var j=s+k.length;var i=(j-s);var l=(s>=this._elTbody.rows.length);this._oChainRender.add({method:function(x){if((this instanceof d)&&this._sId){var y=x.aRecords,w=x.nCurrentRow,v=x.nCurrentRecord,t=m>0?Math.min(w+m,j):j,z=document.createDocumentFragment(),u=(this._elTbody.rows[w])?this._elTbody.rows[w]:null;for(;w<t;w++,v++){z.appendChild(this._addTrEl(y[v]));}this._elTbody.insertBefore(z,u);x.nCurrentRow=w;x.nCurrentRecord=v;}},iterations:(m>0)?Math.ceil(j/m):1,argument:{nCurrentRow:s,nCurrentRecord:0,aRecords:o},scope:this,timeout:(m>0)?0:-1});this._oChainRender.add({method:function(u){var t=u.recIndex;if(t===0){this._setFirstRow();}if(u.isLast){this._setLastRow();}this._setRowStripes();this.fireEvent("rowsAddEvent",{records:o});},argument:{recIndex:s,isLast:l},scope:this,timeout:-1});this._runRenderChain();this.hideTableMessage();return;}}}},updateRow:function(u,k){var r=u;if(!h.isNumber(r)){r=this.getRecordIndex(u);}if(h.isNumber(r)&&(r>=0)){var s=this._oRecordSet,q=s.getRecord(r);if(q){var o=this._oRecordSet.setRecord(k,r),j=this.getTrEl(q),p=q?q.getData():null;if(o){var t=this._aSelections||[],n=0,l=q.getId(),m=o.getId();for(;n<t.length;n++){if((t[n]===l)){t[n]=m;}else{if(t[n].recordId===l){t[n].recordId=m;}}}if(this._oAnchorRecord&&this._oAnchorRecord.getId()===l){this._oAnchorRecord=o;}if(this._oAnchorCell&&this._oAnchorCell.record.getId()===l){this._oAnchorCell.record=o;}this._oChainRender.add({method:function(){if((this instanceof d)&&this._sId){var v=this.get("paginator");if(v){var i=(v.getPageRecords())[0],w=(v.getPageRecords())[1];if((r>=i)||(r<=w)){this.render();}}else{if(j){this._updateTrEl(j,o);}else{this.getTbodyEl().appendChild(this._addTrEl(o));}}this.fireEvent("rowUpdateEvent",{record:o,oldData:p});}},scope:this,timeout:(this.get("renderLoopSize")>0)?0:-1});this._runRenderChain();return;}}}return;},updateRows:function(A,m){if(h.isArray(m)){var s=A,l=this._oRecordSet,o=l.getLength();if(!h.isNumber(A)){s=this.getRecordIndex(A);}if(h.isNumber(s)&&(s>=0)&&(s<l.getLength())){var E=s+m.length,B=l.getRecords(s,m.length),G=l.setRecords(m,s);if(G){var t=this._aSelections||[],D=0,C,u,x,z,y=this._oAnchorRecord?this._oAnchorRecord.getId():null,n=this._oAnchorCell?this._oAnchorCell.record.getId():null;for(;D<B.length;D++){z=B[D].getId();u=G[D];x=u.getId();for(C=0;C<t.length;C++){if((t[C]===z)){t[C]=x;}else{if(t[C].recordId===z){t[C].recordId=x;}}}if(y&&y===z){this._oAnchorRecord=u;}if(n&&n===z){this._oAnchorCell.record=u;}}var F=this.get("paginator");if(F){var r=(F.getPageRecords())[0],p=(F.getPageRecords())[1];if((s>=r)||(E<=p)){this.render();}this.fireEvent("rowsAddEvent",{newRecords:G,oldRecords:B});return;}else{var k=this.get("renderLoopSize"),v=m.length,w=(E>=o),q=(E>o);this._oChainRender.add({method:function(K){if((this instanceof d)&&this._sId){var L=K.aRecords,J=K.nCurrentRow,I=K.nDataPointer,H=k>0?Math.min(J+k,s+L.length):s+L.length;for(;J<H;J++,I++){if(q&&(J>=o)){this._elTbody.appendChild(this._addTrEl(L[I]));}else{this._updateTrEl(this._elTbody.rows[J],L[I]);}}K.nCurrentRow=J;K.nDataPointer=I;}},iterations:(k>0)?Math.ceil(v/k):1,argument:{nCurrentRow:s,aRecords:G,nDataPointer:0,isAdding:q},scope:this,timeout:(k>0)?0:-1});this._oChainRender.add({method:function(j){var i=j.recIndex;if(i===0){this._setFirstRow();}if(j.isLast){this._setLastRow();}this._setRowStripes();this.fireEvent("rowsAddEvent",{newRecords:G,oldRecords:B});},argument:{recIndex:s,isLast:w},scope:this,timeout:-1});this._runRenderChain();this.hideTableMessage();return;}}}}},deleteRow:function(s){var k=(h.isNumber(s))?s:this.getRecordIndex(s);if(h.isNumber(k)){var t=this.getRecord(k);if(t){var m=this.getTrIndex(k);var p=t.getId();var r=this._aSelections||[];for(var n=r.length-1;n>-1;n--){if((h.isString(r[n])&&(r[n]===p))||(h.isObject(r[n])&&(r[n].recordId===p))){r.splice(n,1);}}var l=this._oRecordSet.deleteRecord(k);if(l){var q=this.get("paginator");if(q){var o=q.get("totalRecords"),i=q.getPageRecords();if(o!==e.Paginator.VALUE_UNLIMITED){q.set("totalRecords",o-1);}if(!i||k<=i[1]){this.render();}this._oChainRender.add({method:function(){if((this instanceof d)&&this._sId){this.fireEvent("rowDeleteEvent",{recordIndex:k,oldData:l,trElIndex:m});}},scope:this,timeout:(this.get("renderLoopSize")>0)?0:-1});this._runRenderChain();}else{if(h.isNumber(m)){this._oChainRender.add({method:function(){if((this instanceof d)&&this._sId){var j=(k===this._oRecordSet.getLength());this._deleteTrEl(m);if(this._elTbody.rows.length>0){if(m===0){this._setFirstRow();
-}if(j){this._setLastRow();}if(m!=this._elTbody.rows.length){this._setRowStripes(m);}}this.fireEvent("rowDeleteEvent",{recordIndex:k,oldData:l,trElIndex:m});}},scope:this,timeout:(this.get("renderLoopSize")>0)?0:-1});this._runRenderChain();return;}}}}}return null;},deleteRows:function(y,s){var l=(h.isNumber(y))?y:this.getRecordIndex(y);if(h.isNumber(l)){var z=this.getRecord(l);if(z){var m=this.getTrIndex(l);var u=z.getId();var x=this._aSelections||[];for(var q=x.length-1;q>-1;q--){if((h.isString(x[q])&&(x[q]===u))||(h.isObject(x[q])&&(x[q].recordId===u))){x.splice(q,1);}}var n=l;var w=l;if(s&&h.isNumber(s)){n=(s>0)?l+s-1:l;w=(s>0)?l:l+s+1;s=(s>0)?s:s*-1;if(w<0){w=0;s=n-w+1;}}else{s=1;}var p=this._oRecordSet.deleteRecords(w,s);if(p){var v=this.get("paginator"),r=this.get("renderLoopSize");if(v){var t=v.get("totalRecords"),k=v.getPageRecords();if(t!==e.Paginator.VALUE_UNLIMITED){v.set("totalRecords",t-p.length);}if(!k||w<=k[1]){this.render();}this._oChainRender.add({method:function(j){if((this instanceof d)&&this._sId){this.fireEvent("rowsDeleteEvent",{recordIndex:w,oldData:p,count:s});}},scope:this,timeout:(r>0)?0:-1});this._runRenderChain();return;}else{if(h.isNumber(m)){var o=w;var i=s;this._oChainRender.add({method:function(B){if((this instanceof d)&&this._sId){var A=B.nCurrentRow,j=(r>0)?(Math.max(A-r,o)-1):o-1;for(;A>j;--A){this._deleteTrEl(A);}B.nCurrentRow=A;}},iterations:(r>0)?Math.ceil(s/r):1,argument:{nCurrentRow:n},scope:this,timeout:(r>0)?0:-1});this._oChainRender.add({method:function(){if(this._elTbody.rows.length>0){this._setFirstRow();this._setLastRow();this._setRowStripes();}this.fireEvent("rowsDeleteEvent",{recordIndex:w,oldData:p,count:s});},scope:this,timeout:-1});this._runRenderChain();return;}}}}}return null;},formatCell:function(j,l,m){if(!l){l=this.getRecord(j);}if(!m){m=this.getColumn(this.getCellIndex(j.parentNode));}if(l&&m){var i=m.field;var n=l.getData(i);var k=typeof m.formatter==="function"?m.formatter:d.Formatter[m.formatter+""]||d.Formatter.defaultFormatter;if(k){k.call(this,j,l,m,n);}else{j.innerHTML=n;}this.fireEvent("cellFormatEvent",{record:l,column:m,key:m.key,el:j});}else{}},updateCell:function(k,m,o,j){m=(m instanceof YAHOO.widget.Column)?m:this.getColumn(m);if(m&&m.getField()&&(k instanceof YAHOO.widget.Record)){var l=m.getField(),n=k.getData(l);this._oRecordSet.updateRecordValue(k,l,o);var i=this.getTdEl({record:k,column:m});if(i){this._oChainRender.add({method:function(){if((this instanceof d)&&this._sId){this.formatCell(i.firstChild,k,m);this.fireEvent("cellUpdateEvent",{record:k,column:m,oldData:n});}},scope:this,timeout:(this.get("renderLoopSize")>0)?0:-1});if(!j){this._runRenderChain();}}else{this.fireEvent("cellUpdateEvent",{record:k,column:m,oldData:n});}}},_updatePaginator:function(j){var i=this.get("paginator");if(i&&j!==i){i.unsubscribe("changeRequest",this.onPaginatorChangeRequest,this,true);}if(j){j.subscribe("changeRequest",this.onPaginatorChangeRequest,this,true);}},_handlePaginatorChange:function(l){if(l.prevValue===l.newValue){return;}var n=l.newValue,m=l.prevValue,k=this._defaultPaginatorContainers();if(m){if(m.getContainerNodes()[0]==k[0]){m.set("containers",[]);}m.destroy();if(k[0]){if(n&&!n.getContainerNodes().length){n.set("containers",k);}else{for(var j=k.length-1;j>=0;--j){if(k[j]){k[j].parentNode.removeChild(k[j]);}}}}}if(!this._bInit){this.render();}if(n){this.renderPaginator();}},_defaultPaginatorContainers:function(l){var j=this._sId+"-paginator0",k=this._sId+"-paginator1",i=c.get(j),m=c.get(k);if(l&&(!i||!m)){if(!i){i=document.createElement("div");i.id=j;c.addClass(i,d.CLASS_PAGINATOR);this._elContainer.insertBefore(i,this._elContainer.firstChild);}if(!m){m=document.createElement("div");m.id=k;c.addClass(m,d.CLASS_PAGINATOR);this._elContainer.appendChild(m);}}return[i,m];},_destroyPaginator:function(){var i=this.get("paginator");if(i){i.destroy();}},renderPaginator:function(){var i=this.get("paginator");if(!i){return;}if(!i.getContainerNodes().length){i.set("containers",this._defaultPaginatorContainers(true));}i.render();},doBeforePaginatorChange:function(i){this.showTableMessage(this.get("MSG_LOADING"),d.CLASS_LOADING);return true;},onPaginatorChangeRequest:function(l){var j=this.doBeforePaginatorChange(l);if(j){if(this.get("dynamicData")){var i=this.getState();i.pagination=l;var k=this.get("generateRequest")(i,this);this.unselectAllRows();this.unselectAllCells();var m={success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,argument:i,scope:this};this._oDataSource.sendRequest(k,m);}else{l.paginator.setStartIndex(l.recordOffset,true);l.paginator.setRowsPerPage(l.rowsPerPage,true);this.render();}}else{}},_elLastHighlightedTd:null,_aSelections:null,_oAnchorRecord:null,_oAnchorCell:null,_unselectAllTrEls:function(){var i=c.getElementsByClassName(d.CLASS_SELECTED,"tr",this._elTbody);c.removeClass(i,d.CLASS_SELECTED);},_getSelectionTrigger:function(){var l=this.get("selectionMode");var k={};var o,i,j,n,m;if((l=="cellblock")||(l=="cellrange")||(l=="singlecell")){o=this.getLastSelectedCell();if(!o){return null;}else{i=this.getRecord(o.recordId);j=this.getRecordIndex(i);n=this.getTrEl(i);m=this.getTrIndex(n);if(m===null){return null;}else{k.record=i;k.recordIndex=j;k.el=this.getTdEl(o);k.trIndex=m;k.column=this.getColumn(o.columnKey);k.colKeyIndex=k.column.getKeyIndex();k.cell=o;return k;}}}else{i=this.getLastSelectedRecord();if(!i){return null;}else{i=this.getRecord(i);j=this.getRecordIndex(i);n=this.getTrEl(i);m=this.getTrIndex(n);if(m===null){return null;}else{k.record=i;k.recordIndex=j;k.el=n;k.trIndex=m;return k;}}}},_getSelectionAnchor:function(k){var j=this.get("selectionMode");var l={};var m,o,i;if((j=="cellblock")||(j=="cellrange")||(j=="singlecell")){var n=this._oAnchorCell;if(!n){if(k){n=this._oAnchorCell=k.cell;}else{return null;}}m=this._oAnchorCell.record;o=this._oRecordSet.getRecordIndex(m);i=this.getTrIndex(m);if(i===null){if(o<this.getRecordIndex(this.getFirstTrEl())){i=0;}else{i=this.getRecordIndex(this.getLastTrEl());
-}}l.record=m;l.recordIndex=o;l.trIndex=i;l.column=this._oAnchorCell.column;l.colKeyIndex=l.column.getKeyIndex();l.cell=n;return l;}else{m=this._oAnchorRecord;if(!m){if(k){m=this._oAnchorRecord=k.record;}else{return null;}}o=this.getRecordIndex(m);i=this.getTrIndex(m);if(i===null){if(o<this.getRecordIndex(this.getFirstTrEl())){i=0;}else{i=this.getRecordIndex(this.getLastTrEl());}}l.record=m;l.recordIndex=o;l.trIndex=i;return l;}},_handleStandardSelectionByMouse:function(k){var j=k.target;var m=this.getTrEl(j);if(m){var p=k.event;var s=p.shiftKey;var o=p.ctrlKey||((navigator.userAgent.toLowerCase().indexOf("mac")!=-1)&&p.metaKey);var r=this.getRecord(m);var l=this._oRecordSet.getRecordIndex(r);var q=this._getSelectionAnchor();var n;if(s&&o){if(q){if(this.isSelected(q.record)){if(q.recordIndex<l){for(n=q.recordIndex+1;n<=l;n++){if(!this.isSelected(n)){this.selectRow(n);}}}else{for(n=q.recordIndex-1;n>=l;n--){if(!this.isSelected(n)){this.selectRow(n);}}}}else{if(q.recordIndex<l){for(n=q.recordIndex+1;n<=l-1;n++){if(this.isSelected(n)){this.unselectRow(n);}}}else{for(n=l+1;n<=q.recordIndex-1;n++){if(this.isSelected(n)){this.unselectRow(n);}}}this.selectRow(r);}}else{this._oAnchorRecord=r;if(this.isSelected(r)){this.unselectRow(r);}else{this.selectRow(r);}}}else{if(s){this.unselectAllRows();if(q){if(q.recordIndex<l){for(n=q.recordIndex;n<=l;n++){this.selectRow(n);}}else{for(n=q.recordIndex;n>=l;n--){this.selectRow(n);}}}else{this._oAnchorRecord=r;this.selectRow(r);}}else{if(o){this._oAnchorRecord=r;if(this.isSelected(r)){this.unselectRow(r);}else{this.selectRow(r);}}else{this._handleSingleSelectionByMouse(k);return;}}}}},_handleStandardSelectionByKey:function(m){var i=g.getCharCode(m);if((i==38)||(i==40)){var k=m.shiftKey;var j=this._getSelectionTrigger();if(!j){return null;}g.stopEvent(m);var l=this._getSelectionAnchor(j);if(k){if((i==40)&&(l.recordIndex<=j.trIndex)){this.selectRow(this.getNextTrEl(j.el));}else{if((i==38)&&(l.recordIndex>=j.trIndex)){this.selectRow(this.getPreviousTrEl(j.el));}else{this.unselectRow(j.el);}}}else{this._handleSingleSelectionByKey(m);}}},_handleSingleSelectionByMouse:function(k){var l=k.target;var j=this.getTrEl(l);if(j){var i=this.getRecord(j);this._oAnchorRecord=i;this.unselectAllRows();this.selectRow(i);}},_handleSingleSelectionByKey:function(l){var i=g.getCharCode(l);if((i==38)||(i==40)){var j=this._getSelectionTrigger();if(!j){return null;}g.stopEvent(l);var k;if(i==38){k=this.getPreviousTrEl(j.el);if(k===null){k=this.getFirstTrEl();}}else{if(i==40){k=this.getNextTrEl(j.el);if(k===null){k=this.getLastTrEl();}}}this.unselectAllRows();this.selectRow(k);this._oAnchorRecord=this.getRecord(k);}},_handleCellBlockSelectionByMouse:function(A){var B=A.target;var l=this.getTdEl(B);if(l){var z=A.event;var q=z.shiftKey;var m=z.ctrlKey||((navigator.userAgent.toLowerCase().indexOf("mac")!=-1)&&z.metaKey);var s=this.getTrEl(l);var r=this.getTrIndex(s);var v=this.getColumn(l);var w=v.getKeyIndex();var u=this.getRecord(s);var D=this._oRecordSet.getRecordIndex(u);var p={record:u,column:v};var t=this._getSelectionAnchor();var o=this.getTbodyEl().rows;var n,k,C,y,x;if(q&&m){if(t){if(this.isSelected(t.cell)){if(t.recordIndex===D){if(t.colKeyIndex<w){for(y=t.colKeyIndex+1;y<=w;y++){this.selectCell(s.cells[y]);}}else{if(w<t.colKeyIndex){for(y=w;y<t.colKeyIndex;y++){this.selectCell(s.cells[y]);}}}}else{if(t.recordIndex<D){n=Math.min(t.colKeyIndex,w);k=Math.max(t.colKeyIndex,w);for(y=t.trIndex;y<=r;y++){for(x=n;x<=k;x++){this.selectCell(o[y].cells[x]);}}}else{n=Math.min(t.trIndex,w);k=Math.max(t.trIndex,w);for(y=t.trIndex;y>=r;y--){for(x=k;x>=n;x--){this.selectCell(o[y].cells[x]);}}}}}else{if(t.recordIndex===D){if(t.colKeyIndex<w){for(y=t.colKeyIndex+1;y<w;y++){this.unselectCell(s.cells[y]);}}else{if(w<t.colKeyIndex){for(y=w+1;y<t.colKeyIndex;y++){this.unselectCell(s.cells[y]);}}}}if(t.recordIndex<D){for(y=t.trIndex;y<=r;y++){C=o[y];for(x=0;x<C.cells.length;x++){if(C.sectionRowIndex===t.trIndex){if(x>t.colKeyIndex){this.unselectCell(C.cells[x]);}}else{if(C.sectionRowIndex===r){if(x<w){this.unselectCell(C.cells[x]);}}else{this.unselectCell(C.cells[x]);}}}}}else{for(y=r;y<=t.trIndex;y++){C=o[y];for(x=0;x<C.cells.length;x++){if(C.sectionRowIndex==r){if(x>w){this.unselectCell(C.cells[x]);}}else{if(C.sectionRowIndex==t.trIndex){if(x<t.colKeyIndex){this.unselectCell(C.cells[x]);}}else{this.unselectCell(C.cells[x]);}}}}}this.selectCell(l);}}else{this._oAnchorCell=p;if(this.isSelected(p)){this.unselectCell(p);}else{this.selectCell(p);}}}else{if(q){this.unselectAllCells();if(t){if(t.recordIndex===D){if(t.colKeyIndex<w){for(y=t.colKeyIndex;y<=w;y++){this.selectCell(s.cells[y]);}}else{if(w<t.colKeyIndex){for(y=w;y<=t.colKeyIndex;y++){this.selectCell(s.cells[y]);}}}}else{if(t.recordIndex<D){n=Math.min(t.colKeyIndex,w);k=Math.max(t.colKeyIndex,w);for(y=t.trIndex;y<=r;y++){for(x=n;x<=k;x++){this.selectCell(o[y].cells[x]);}}}else{n=Math.min(t.colKeyIndex,w);k=Math.max(t.colKeyIndex,w);for(y=r;y<=t.trIndex;y++){for(x=n;x<=k;x++){this.selectCell(o[y].cells[x]);}}}}}else{this._oAnchorCell=p;this.selectCell(p);}}else{if(m){this._oAnchorCell=p;if(this.isSelected(p)){this.unselectCell(p);}else{this.selectCell(p);}}else{this._handleSingleCellSelectionByMouse(A);}}}}},_handleCellBlockSelectionByKey:function(o){var j=g.getCharCode(o);var t=o.shiftKey;if((j==9)||!t){this._handleSingleCellSelectionByKey(o);return;}if((j>36)&&(j<41)){var u=this._getSelectionTrigger();if(!u){return null;}g.stopEvent(o);var r=this._getSelectionAnchor(u);var k,s,l,q,m;var p=this.getTbodyEl().rows;var n=u.el.parentNode;if(j==40){if(r.recordIndex<=u.recordIndex){m=this.getNextTrEl(u.el);if(m){s=r.colKeyIndex;l=u.colKeyIndex;if(s>l){for(k=s;k>=l;k--){q=m.cells[k];this.selectCell(q);}}else{for(k=s;k<=l;k++){q=m.cells[k];this.selectCell(q);}}}}else{s=Math.min(r.colKeyIndex,u.colKeyIndex);l=Math.max(r.colKeyIndex,u.colKeyIndex);for(k=s;k<=l;k++){this.unselectCell(n.cells[k]);}}}else{if(j==38){if(r.recordIndex>=u.recordIndex){m=this.getPreviousTrEl(u.el);
-if(m){s=r.colKeyIndex;l=u.colKeyIndex;if(s>l){for(k=s;k>=l;k--){q=m.cells[k];this.selectCell(q);}}else{for(k=s;k<=l;k++){q=m.cells[k];this.selectCell(q);}}}}else{s=Math.min(r.colKeyIndex,u.colKeyIndex);l=Math.max(r.colKeyIndex,u.colKeyIndex);for(k=s;k<=l;k++){this.unselectCell(n.cells[k]);}}}else{if(j==39){if(r.colKeyIndex<=u.colKeyIndex){if(u.colKeyIndex<n.cells.length-1){s=r.trIndex;l=u.trIndex;if(s>l){for(k=s;k>=l;k--){q=p[k].cells[u.colKeyIndex+1];this.selectCell(q);}}else{for(k=s;k<=l;k++){q=p[k].cells[u.colKeyIndex+1];this.selectCell(q);}}}}else{s=Math.min(r.trIndex,u.trIndex);l=Math.max(r.trIndex,u.trIndex);for(k=s;k<=l;k++){this.unselectCell(p[k].cells[u.colKeyIndex]);}}}else{if(j==37){if(r.colKeyIndex>=u.colKeyIndex){if(u.colKeyIndex>0){s=r.trIndex;l=u.trIndex;if(s>l){for(k=s;k>=l;k--){q=p[k].cells[u.colKeyIndex-1];this.selectCell(q);}}else{for(k=s;k<=l;k++){q=p[k].cells[u.colKeyIndex-1];this.selectCell(q);}}}}else{s=Math.min(r.trIndex,u.trIndex);l=Math.max(r.trIndex,u.trIndex);for(k=s;k<=l;k++){this.unselectCell(p[k].cells[u.colKeyIndex]);}}}}}}}},_handleCellRangeSelectionByMouse:function(y){var z=y.target;var k=this.getTdEl(z);if(k){var x=y.event;var o=x.shiftKey;var l=x.ctrlKey||((navigator.userAgent.toLowerCase().indexOf("mac")!=-1)&&x.metaKey);var q=this.getTrEl(k);var p=this.getTrIndex(q);var t=this.getColumn(k);var u=t.getKeyIndex();var s=this.getRecord(q);var B=this._oRecordSet.getRecordIndex(s);var n={record:s,column:t};var r=this._getSelectionAnchor();var m=this.getTbodyEl().rows;var A,w,v;if(o&&l){if(r){if(this.isSelected(r.cell)){if(r.recordIndex===B){if(r.colKeyIndex<u){for(w=r.colKeyIndex+1;w<=u;w++){this.selectCell(q.cells[w]);}}else{if(u<r.colKeyIndex){for(w=u;w<r.colKeyIndex;w++){this.selectCell(q.cells[w]);}}}}else{if(r.recordIndex<B){for(w=r.colKeyIndex+1;w<q.cells.length;w++){this.selectCell(q.cells[w]);}for(w=r.trIndex+1;w<p;w++){for(v=0;v<m[w].cells.length;v++){this.selectCell(m[w].cells[v]);}}for(w=0;w<=u;w++){this.selectCell(q.cells[w]);}}else{for(w=u;w<q.cells.length;w++){this.selectCell(q.cells[w]);}for(w=p+1;w<r.trIndex;w++){for(v=0;v<m[w].cells.length;v++){this.selectCell(m[w].cells[v]);}}for(w=0;w<r.colKeyIndex;w++){this.selectCell(q.cells[w]);}}}}else{if(r.recordIndex===B){if(r.colKeyIndex<u){for(w=r.colKeyIndex+1;w<u;w++){this.unselectCell(q.cells[w]);}}else{if(u<r.colKeyIndex){for(w=u+1;w<r.colKeyIndex;w++){this.unselectCell(q.cells[w]);}}}}if(r.recordIndex<B){for(w=r.trIndex;w<=p;w++){A=m[w];for(v=0;v<A.cells.length;v++){if(A.sectionRowIndex===r.trIndex){if(v>r.colKeyIndex){this.unselectCell(A.cells[v]);}}else{if(A.sectionRowIndex===p){if(v<u){this.unselectCell(A.cells[v]);}}else{this.unselectCell(A.cells[v]);}}}}}else{for(w=p;w<=r.trIndex;w++){A=m[w];for(v=0;v<A.cells.length;v++){if(A.sectionRowIndex==p){if(v>u){this.unselectCell(A.cells[v]);}}else{if(A.sectionRowIndex==r.trIndex){if(v<r.colKeyIndex){this.unselectCell(A.cells[v]);}}else{this.unselectCell(A.cells[v]);}}}}}this.selectCell(k);}}else{this._oAnchorCell=n;if(this.isSelected(n)){this.unselectCell(n);}else{this.selectCell(n);}}}else{if(o){this.unselectAllCells();if(r){if(r.recordIndex===B){if(r.colKeyIndex<u){for(w=r.colKeyIndex;w<=u;w++){this.selectCell(q.cells[w]);}}else{if(u<r.colKeyIndex){for(w=u;w<=r.colKeyIndex;w++){this.selectCell(q.cells[w]);}}}}else{if(r.recordIndex<B){for(w=r.trIndex;w<=p;w++){A=m[w];for(v=0;v<A.cells.length;v++){if(A.sectionRowIndex==r.trIndex){if(v>=r.colKeyIndex){this.selectCell(A.cells[v]);}}else{if(A.sectionRowIndex==p){if(v<=u){this.selectCell(A.cells[v]);}}else{this.selectCell(A.cells[v]);}}}}}else{for(w=p;w<=r.trIndex;w++){A=m[w];for(v=0;v<A.cells.length;v++){if(A.sectionRowIndex==p){if(v>=u){this.selectCell(A.cells[v]);}}else{if(A.sectionRowIndex==r.trIndex){if(v<=r.colKeyIndex){this.selectCell(A.cells[v]);}}else{this.selectCell(A.cells[v]);}}}}}}}else{this._oAnchorCell=n;this.selectCell(n);}}else{if(l){this._oAnchorCell=n;if(this.isSelected(n)){this.unselectCell(n);}else{this.selectCell(n);}}else{this._handleSingleCellSelectionByMouse(y);}}}}},_handleCellRangeSelectionByKey:function(n){var j=g.getCharCode(n);var r=n.shiftKey;if((j==9)||!r){this._handleSingleCellSelectionByKey(n);return;}if((j>36)&&(j<41)){var s=this._getSelectionTrigger();if(!s){return null;}g.stopEvent(n);var q=this._getSelectionAnchor(s);var k,l,p;var o=this.getTbodyEl().rows;var m=s.el.parentNode;if(j==40){l=this.getNextTrEl(s.el);if(q.recordIndex<=s.recordIndex){for(k=s.colKeyIndex+1;k<m.cells.length;k++){p=m.cells[k];this.selectCell(p);}if(l){for(k=0;k<=s.colKeyIndex;k++){p=l.cells[k];this.selectCell(p);}}}else{for(k=s.colKeyIndex;k<m.cells.length;k++){this.unselectCell(m.cells[k]);}if(l){for(k=0;k<s.colKeyIndex;k++){this.unselectCell(l.cells[k]);}}}}else{if(j==38){l=this.getPreviousTrEl(s.el);if(q.recordIndex>=s.recordIndex){for(k=s.colKeyIndex-1;k>-1;k--){p=m.cells[k];this.selectCell(p);}if(l){for(k=m.cells.length-1;k>=s.colKeyIndex;k--){p=l.cells[k];this.selectCell(p);}}}else{for(k=s.colKeyIndex;k>-1;k--){this.unselectCell(m.cells[k]);}if(l){for(k=m.cells.length-1;k>s.colKeyIndex;k--){this.unselectCell(l.cells[k]);}}}}else{if(j==39){l=this.getNextTrEl(s.el);if(q.recordIndex<s.recordIndex){if(s.colKeyIndex<m.cells.length-1){p=m.cells[s.colKeyIndex+1];this.selectCell(p);}else{if(l){p=l.cells[0];this.selectCell(p);}}}else{if(q.recordIndex>s.recordIndex){this.unselectCell(m.cells[s.colKeyIndex]);if(s.colKeyIndex<m.cells.length-1){}else{}}else{if(q.colKeyIndex<=s.colKeyIndex){if(s.colKeyIndex<m.cells.length-1){p=m.cells[s.colKeyIndex+1];this.selectCell(p);}else{if(s.trIndex<o.length-1){p=l.cells[0];this.selectCell(p);}}}else{this.unselectCell(m.cells[s.colKeyIndex]);}}}}else{if(j==37){l=this.getPreviousTrEl(s.el);if(q.recordIndex<s.recordIndex){this.unselectCell(m.cells[s.colKeyIndex]);if(s.colKeyIndex>0){}else{}}else{if(q.recordIndex>s.recordIndex){if(s.colKeyIndex>0){p=m.cells[s.colKeyIndex-1];this.selectCell(p);}else{if(s.trIndex>0){p=l.cells[l.cells.length-1];this.selectCell(p);
-}}}else{if(q.colKeyIndex>=s.colKeyIndex){if(s.colKeyIndex>0){p=m.cells[s.colKeyIndex-1];this.selectCell(p);}else{if(s.trIndex>0){p=l.cells[l.cells.length-1];this.selectCell(p);}}}else{this.unselectCell(m.cells[s.colKeyIndex]);if(s.colKeyIndex>0){}else{}}}}}}}}}},_handleSingleCellSelectionByMouse:function(n){var o=n.target;var k=this.getTdEl(o);if(k){var j=this.getTrEl(k);var i=this.getRecord(j);var m=this.getColumn(k);var l={record:i,column:m};this._oAnchorCell=l;this.unselectAllCells();this.selectCell(l);}},_handleSingleCellSelectionByKey:function(m){var i=g.getCharCode(m);if((i==9)||((i>36)&&(i<41))){var k=m.shiftKey;var j=this._getSelectionTrigger();if(!j){return null;}var l;if(i==40){l=this.getBelowTdEl(j.el);if(l===null){l=j.el;}}else{if(i==38){l=this.getAboveTdEl(j.el);if(l===null){l=j.el;}}else{if((i==39)||(!k&&(i==9))){l=this.getNextTdEl(j.el);if(l===null){return;}}else{if((i==37)||(k&&(i==9))){l=this.getPreviousTdEl(j.el);if(l===null){return;}}}}}g.stopEvent(m);this.unselectAllCells();this.selectCell(l);this._oAnchorCell={record:this.getRecord(l),column:this.getColumn(l)};}},getSelectedTrEls:function(){return c.getElementsByClassName(d.CLASS_SELECTED,"tr",this._elTbody);},selectRow:function(p){var o,i;if(p instanceof YAHOO.widget.Record){o=this._oRecordSet.getRecord(p);i=this.getTrEl(o);}else{if(h.isNumber(p)){o=this.getRecord(p);i=this.getTrEl(o);}else{i=this.getTrEl(p);o=this.getRecord(i);}}if(o){var n=this._aSelections||[];var m=o.getId();var l=-1;if(n.indexOf){l=n.indexOf(m);}else{for(var k=n.length-1;k>-1;k--){if(n[k]===m){l=k;break;}}}if(l>-1){n.splice(l,1);}n.push(m);this._aSelections=n;if(!this._oAnchorRecord){this._oAnchorRecord=o;}if(i){c.addClass(i,d.CLASS_SELECTED);}this.fireEvent("rowSelectEvent",{record:o,el:i});}else{}},unselectRow:function(p){var i=this.getTrEl(p);var o;if(p instanceof YAHOO.widget.Record){o=this._oRecordSet.getRecord(p);}else{if(h.isNumber(p)){o=this.getRecord(p);}else{o=this.getRecord(i);}}if(o){var n=this._aSelections||[];var m=o.getId();var l=-1;if(n.indexOf){l=n.indexOf(m);}else{for(var k=n.length-1;k>-1;k--){if(n[k]===m){l=k;break;}}}if(l>-1){n.splice(l,1);this._aSelections=n;c.removeClass(i,d.CLASS_SELECTED);this.fireEvent("rowUnselectEvent",{record:o,el:i});return;}}},unselectAllRows:function(){var k=this._aSelections||[],m,l=[];for(var i=k.length-1;i>-1;i--){if(h.isString(k[i])){m=k.splice(i,1);l[l.length]=this.getRecord(h.isArray(m)?m[0]:m);}}this._aSelections=k;this._unselectAllTrEls();this.fireEvent("unselectAllRowsEvent",{records:l});},_unselectAllTdEls:function(){var i=c.getElementsByClassName(d.CLASS_SELECTED,"td",this._elTbody);c.removeClass(i,d.CLASS_SELECTED);},getSelectedTdEls:function(){return c.getElementsByClassName(d.CLASS_SELECTED,"td",this._elTbody);},selectCell:function(i){var p=this.getTdEl(i);if(p){var o=this.getRecord(p);var q=this.getColumn(this.getCellIndex(p));var m=q.getKey();if(o&&m){var n=this._aSelections||[];var l=o.getId();for(var k=n.length-1;k>-1;k--){if((n[k].recordId===l)&&(n[k].columnKey===m)){n.splice(k,1);break;}}n.push({recordId:l,columnKey:m});this._aSelections=n;if(!this._oAnchorCell){this._oAnchorCell={record:o,column:q};}c.addClass(p,d.CLASS_SELECTED);this.fireEvent("cellSelectEvent",{record:o,column:q,key:m,el:p});return;}}},unselectCell:function(i){var o=this.getTdEl(i);if(o){var n=this.getRecord(o);var p=this.getColumn(this.getCellIndex(o));var l=p.getKey();if(n&&l){var m=this._aSelections||[];var q=n.getId();for(var k=m.length-1;k>-1;k--){if((m[k].recordId===q)&&(m[k].columnKey===l)){m.splice(k,1);this._aSelections=m;c.removeClass(o,d.CLASS_SELECTED);this.fireEvent("cellUnselectEvent",{record:n,column:p,key:l,el:o});return;}}}}},unselectAllCells:function(){var k=this._aSelections||[];for(var i=k.length-1;i>-1;i--){if(h.isObject(k[i])){k.splice(i,1);}}this._aSelections=k;this._unselectAllTdEls();this.fireEvent("unselectAllCellsEvent");},isSelected:function(p){if(p&&(p.ownerDocument==document)){return(c.hasClass(this.getTdEl(p),d.CLASS_SELECTED)||c.hasClass(this.getTrEl(p),d.CLASS_SELECTED));}else{var n,k,i;var m=this._aSelections;if(m&&m.length>0){if(p instanceof YAHOO.widget.Record){n=p;}else{if(h.isNumber(p)){n=this.getRecord(p);}}if(n){k=n.getId();if(m.indexOf){if(m.indexOf(k)>-1){return true;}}else{for(i=m.length-1;i>-1;i--){if(m[i]===k){return true;}}}}else{if(p.record&&p.column){k=p.record.getId();var l=p.column.getKey();for(i=m.length-1;i>-1;i--){if((m[i].recordId===k)&&(m[i].columnKey===l)){return true;}}}}}}return false;},getSelectedRows:function(){var i=[];var l=this._aSelections||[];for(var k=0;k<l.length;k++){if(h.isString(l[k])){i.push(l[k]);}}return i;},getSelectedCells:function(){var k=[];var l=this._aSelections||[];for(var i=0;i<l.length;i++){if(l[i]&&h.isObject(l[i])){k.push(l[i]);}}return k;},getLastSelectedRecord:function(){var k=this._aSelections;if(k&&k.length>0){for(var j=k.length-1;j>-1;j--){if(h.isString(k[j])){return k[j];}}}},getLastSelectedCell:function(){var k=this._aSelections;if(k&&k.length>0){for(var j=k.length-1;j>-1;j--){if(k[j].recordId&&k[j].columnKey){return k[j];}}}},highlightRow:function(k){var i=this.getTrEl(k);if(i){var j=this.getRecord(i);c.addClass(i,d.CLASS_HIGHLIGHTED);this.fireEvent("rowHighlightEvent",{record:j,el:i});return;}},unhighlightRow:function(k){var i=this.getTrEl(k);if(i){var j=this.getRecord(i);c.removeClass(i,d.CLASS_HIGHLIGHTED);this.fireEvent("rowUnhighlightEvent",{record:j,el:i});return;}},highlightCell:function(i){var l=this.getTdEl(i);if(l){if(this._elLastHighlightedTd){this.unhighlightCell(this._elLastHighlightedTd);}var k=this.getRecord(l);var m=this.getColumn(this.getCellIndex(l));var j=m.getKey();c.addClass(l,d.CLASS_HIGHLIGHTED);this._elLastHighlightedTd=l;this.fireEvent("cellHighlightEvent",{record:k,column:m,key:j,el:l});return;}},unhighlightCell:function(i){var k=this.getTdEl(i);if(k){var j=this.getRecord(k);c.removeClass(k,d.CLASS_HIGHLIGHTED);this._elLastHighlightedTd=null;this.fireEvent("cellUnhighlightEvent",{record:j,column:this.getColumn(this.getCellIndex(k)),key:this.getColumn(this.getCellIndex(k)).getKey(),el:k});
-return;}},addCellEditor:function(j,i){j.editor=i;j.editor.subscribe("showEvent",this._onEditorShowEvent,this,true);j.editor.subscribe("keydownEvent",this._onEditorKeydownEvent,this,true);j.editor.subscribe("revertEvent",this._onEditorRevertEvent,this,true);j.editor.subscribe("saveEvent",this._onEditorSaveEvent,this,true);j.editor.subscribe("cancelEvent",this._onEditorCancelEvent,this,true);j.editor.subscribe("blurEvent",this._onEditorBlurEvent,this,true);j.editor.subscribe("blockEvent",this._onEditorBlockEvent,this,true);j.editor.subscribe("unblockEvent",this._onEditorUnblockEvent,this,true);},getCellEditor:function(){return this._oCellEditor;},showCellEditor:function(p,q,l){p=this.getTdEl(p);if(p){l=this.getColumn(p);if(l&&l.editor){var j=this._oCellEditor;if(j){if(this._oCellEditor.cancel){this._oCellEditor.cancel();}else{if(j.isActive){this.cancelCellEditor();}}}if(l.editor instanceof YAHOO.widget.BaseCellEditor){j=l.editor;var n=j.attach(this,p);if(n){j.render();j.move();n=this.doBeforeShowCellEditor(j);if(n){j.show();this._oCellEditor=j;}}}else{if(!q||!(q instanceof YAHOO.widget.Record)){q=this.getRecord(p);}if(!l||!(l instanceof YAHOO.widget.Column)){l=this.getColumn(p);}if(q&&l){if(!this._oCellEditor||this._oCellEditor.container){this._initCellEditorEl();}j=this._oCellEditor;j.cell=p;j.record=q;j.column=l;j.validator=(l.editorOptions&&h.isFunction(l.editorOptions.validator))?l.editorOptions.validator:null;j.value=q.getData(l.key);j.defaultValue=null;var k=j.container;var o=c.getX(p);var m=c.getY(p);if(isNaN(o)||isNaN(m)){o=p.offsetLeft+c.getX(this._elTbody.parentNode)-this._elTbody.scrollLeft;m=p.offsetTop+c.getY(this._elTbody.parentNode)-this._elTbody.scrollTop+this._elThead.offsetHeight;}k.style.left=o+"px";k.style.top=m+"px";this.doBeforeShowCellEditor(this._oCellEditor);k.style.display="";g.addListener(k,"keydown",function(s,r){if((s.keyCode==27)){r.cancelCellEditor();r.focusTbodyEl();}else{r.fireEvent("editorKeydownEvent",{editor:r._oCellEditor,event:s});}},this);var i;if(h.isString(l.editor)){switch(l.editor){case"checkbox":i=d.editCheckbox;break;case"date":i=d.editDate;break;case"dropdown":i=d.editDropdown;break;case"radio":i=d.editRadio;break;case"textarea":i=d.editTextarea;break;case"textbox":i=d.editTextbox;break;default:i=null;}}else{if(h.isFunction(l.editor)){i=l.editor;}}if(i){i(this._oCellEditor,this);if(!l.editorOptions||!l.editorOptions.disableBtns){this.showCellEditorBtns(k);}j.isActive=true;this.fireEvent("editorShowEvent",{editor:j});return;}}}}}},_initCellEditorEl:function(){var i=document.createElement("div");i.id=this._sId+"-celleditor";i.style.display="none";i.tabIndex=0;c.addClass(i,d.CLASS_EDITOR);var k=c.getFirstChild(document.body);if(k){i=c.insertBefore(i,k);}else{i=document.body.appendChild(i);}var j={};j.container=i;j.value=null;j.isActive=false;this._oCellEditor=j;},doBeforeShowCellEditor:function(i){return true;},saveCellEditor:function(){if(this._oCellEditor){if(this._oCellEditor.save){this._oCellEditor.save();}else{if(this._oCellEditor.isActive){var i=this._oCellEditor.value;var j=this._oCellEditor.record.getData(this._oCellEditor.column.key);if(this._oCellEditor.validator){i=this._oCellEditor.value=this._oCellEditor.validator.call(this,i,j,this._oCellEditor);if(i===null){this.resetCellEditor();this.fireEvent("editorRevertEvent",{editor:this._oCellEditor,oldData:j,newData:i});return;}}this._oRecordSet.updateRecordValue(this._oCellEditor.record,this._oCellEditor.column.key,this._oCellEditor.value);this.formatCell(this._oCellEditor.cell.firstChild,this._oCellEditor.record,this._oCellEditor.column);this._oChainRender.add({method:function(){this.validateColumnWidths();},scope:this});this._oChainRender.run();this.resetCellEditor();this.fireEvent("editorSaveEvent",{editor:this._oCellEditor,oldData:j,newData:i});}}}},cancelCellEditor:function(){if(this._oCellEditor){if(this._oCellEditor.cancel){this._oCellEditor.cancel();}else{if(this._oCellEditor.isActive){this.resetCellEditor();this.fireEvent("editorCancelEvent",{editor:this._oCellEditor});}}}},destroyCellEditor:function(){if(this._oCellEditor){this._oCellEditor.destroy();this._oCellEditor=null;}},_onEditorShowEvent:function(i){this.fireEvent("editorShowEvent",i);},_onEditorKeydownEvent:function(i){this.fireEvent("editorKeydownEvent",i);},_onEditorRevertEvent:function(i){this.fireEvent("editorRevertEvent",i);},_onEditorSaveEvent:function(i){this.fireEvent("editorSaveEvent",i);},_onEditorCancelEvent:function(i){this.fireEvent("editorCancelEvent",i);},_onEditorBlurEvent:function(i){this.fireEvent("editorBlurEvent",i);},_onEditorBlockEvent:function(i){this.fireEvent("editorBlockEvent",i);},_onEditorUnblockEvent:function(i){this.fireEvent("editorUnblockEvent",i);},onEditorBlurEvent:function(i){if(i.editor.disableBtns){if(i.editor.save){i.editor.save();}}else{if(i.editor.cancel){i.editor.cancel();}}},onEditorBlockEvent:function(i){this.disable();},onEditorUnblockEvent:function(i){this.undisable();},doBeforeLoadData:function(i,j,k){return true;},onEventSortColumn:function(k){var i=k.event;var m=k.target;var j=this.getThEl(m)||this.getTdEl(m);if(j){var l=this.getColumn(j);if(l.sortable){g.stopEvent(i);this.sortColumn(l);}}else{}},onEventSelectColumn:function(i){this.selectColumn(i.target);},onEventHighlightColumn:function(i){this.highlightColumn(i.target);},onEventUnhighlightColumn:function(i){this.unhighlightColumn(i.target);},onEventSelectRow:function(j){var i=this.get("selectionMode");if(i=="single"){this._handleSingleSelectionByMouse(j);}else{this._handleStandardSelectionByMouse(j);}},onEventSelectCell:function(j){var i=this.get("selectionMode");if(i=="cellblock"){this._handleCellBlockSelectionByMouse(j);}else{if(i=="cellrange"){this._handleCellRangeSelectionByMouse(j);}else{this._handleSingleCellSelectionByMouse(j);}}},onEventHighlightRow:function(i){this.highlightRow(i.target);},onEventUnhighlightRow:function(i){this.unhighlightRow(i.target);},onEventHighlightCell:function(i){this.highlightCell(i.target);
-},onEventUnhighlightCell:function(i){this.unhighlightCell(i.target);},onEventFormatCell:function(i){var l=i.target;var j=this.getTdEl(l);if(j){var k=this.getColumn(this.getCellIndex(j));this.formatCell(j.firstChild,this.getRecord(j),k);}else{}},onEventShowCellEditor:function(i){if(!this.isDisabled()){this.showCellEditor(i.target);}},onEventSaveCellEditor:function(i){if(this._oCellEditor){if(this._oCellEditor.save){this._oCellEditor.save();}else{this.saveCellEditor();}}},onEventCancelCellEditor:function(i){if(this._oCellEditor){if(this._oCellEditor.cancel){this._oCellEditor.cancel();}else{this.cancelCellEditor();}}},onDataReturnInitializeTable:function(i,j,k){if((this instanceof d)&&this._sId){this.initializeTable();this.onDataReturnSetRows(i,j,k);}},onDataReturnReplaceRows:function(m,l,n){if((this instanceof d)&&this._sId){this.fireEvent("dataReturnEvent",{request:m,response:l,payload:n});var j=this.doBeforeLoadData(m,l,n),k=this.get("paginator"),i=0;if(j&&l&&!l.error&&h.isArray(l.results)){this._oRecordSet.reset();if(this.get("dynamicData")){if(n&&n.pagination&&h.isNumber(n.pagination.recordOffset)){i=n.pagination.recordOffset;}else{if(k){i=k.getStartIndex();}}}this._oRecordSet.setRecords(l.results,i|0);this._handleDataReturnPayload(m,l,n);this.render();}else{if(j&&l.error){this.showTableMessage(this.get("MSG_ERROR"),d.CLASS_ERROR);}}}},onDataReturnAppendRows:function(j,k,l){if((this instanceof d)&&this._sId){this.fireEvent("dataReturnEvent",{request:j,response:k,payload:l});var i=this.doBeforeLoadData(j,k,l);if(i&&k&&!k.error&&h.isArray(k.results)){this.addRows(k.results);this._handleDataReturnPayload(j,k,l);}else{if(i&&k.error){this.showTableMessage(this.get("MSG_ERROR"),d.CLASS_ERROR);}}}},onDataReturnInsertRows:function(j,k,l){if((this instanceof d)&&this._sId){this.fireEvent("dataReturnEvent",{request:j,response:k,payload:l});var i=this.doBeforeLoadData(j,k,l);if(i&&k&&!k.error&&h.isArray(k.results)){this.addRows(k.results,(l?l.insertIndex:0));this._handleDataReturnPayload(j,k,l);}else{if(i&&k.error){this.showTableMessage(this.get("MSG_ERROR"),d.CLASS_ERROR);}}}},onDataReturnUpdateRows:function(j,k,l){if((this instanceof d)&&this._sId){this.fireEvent("dataReturnEvent",{request:j,response:k,payload:l});var i=this.doBeforeLoadData(j,k,l);if(i&&k&&!k.error&&h.isArray(k.results)){this.updateRows((l?l.updateIndex:0),k.results);this._handleDataReturnPayload(j,k,l);}else{if(i&&k.error){this.showTableMessage(this.get("MSG_ERROR"),d.CLASS_ERROR);}}}},onDataReturnSetRows:function(m,l,n){if((this instanceof d)&&this._sId){this.fireEvent("dataReturnEvent",{request:m,response:l,payload:n});var j=this.doBeforeLoadData(m,l,n),k=this.get("paginator"),i=0;if(j&&l&&!l.error&&h.isArray(l.results)){if(this.get("dynamicData")){if(n&&n.pagination&&h.isNumber(n.pagination.recordOffset)){i=n.pagination.recordOffset;}else{if(k){i=k.getStartIndex();}}this._oRecordSet.reset();}this._oRecordSet.setRecords(l.results,i|0);this._handleDataReturnPayload(m,l,n);this.render();}else{if(j&&l.error){this.showTableMessage(this.get("MSG_ERROR"),d.CLASS_ERROR);}}}else{}},handleDataReturnPayload:function(j,i,k){return k||{};},_handleDataReturnPayload:function(k,j,l){l=this.handleDataReturnPayload(k,j,l);if(l){var i=this.get("paginator");if(i){if(this.get("dynamicData")){if(e.Paginator.isNumeric(l.totalRecords)){i.set("totalRecords",l.totalRecords);}}else{i.set("totalRecords",this._oRecordSet.getLength());}if(h.isObject(l.pagination)){i.set("rowsPerPage",l.pagination.rowsPerPage);i.set("recordOffset",l.pagination.recordOffset);}}if(l.sortedBy){this.set("sortedBy",l.sortedBy);}else{if(l.sorting){this.set("sortedBy",l.sorting);}}}},showCellEditorBtns:function(k){var l=k.appendChild(document.createElement("div"));c.addClass(l,d.CLASS_BUTTON);var j=l.appendChild(document.createElement("button"));c.addClass(j,d.CLASS_DEFAULT);j.innerHTML="OK";g.addListener(j,"click",function(n,m){m.onEventSaveCellEditor(n,m);m.focusTbodyEl();},this,true);var i=l.appendChild(document.createElement("button"));i.innerHTML="Cancel";g.addListener(i,"click",function(n,m){m.onEventCancelCellEditor(n,m);m.focusTbodyEl();},this,true);},resetCellEditor:function(){var i=this._oCellEditor.container;i.style.display="none";g.purgeElement(i,true);i.innerHTML="";this._oCellEditor.value=null;this._oCellEditor.isActive=false;},getBody:function(){return this.getTbodyEl();},getCell:function(i){return this.getTdEl(i);},getRow:function(i){return this.getTrEl(i);},refreshView:function(){this.render();},select:function(k){if(!h.isArray(k)){k=[k];}for(var j=0;j<k.length;j++){this.selectRow(k[j]);}},onEventEditCell:function(i){this.onEventShowCellEditor(i);},_syncColWidths:function(){this.validateColumnWidths();}});d.prototype.onDataReturnSetRecords=d.prototype.onDataReturnSetRows;d.prototype.onPaginatorChange=d.prototype.onPaginatorChangeRequest;d.editCheckbox=function(){};d.editDate=function(){};d.editDropdown=function(){};d.editRadio=function(){};d.editTextarea=function(){};d.editTextbox=function(){};})();(function(){var c=YAHOO.lang,f=YAHOO.util,e=YAHOO.widget,a=YAHOO.env.ua,d=f.Dom,j=f.Event,i=f.DataSourceBase,g=e.DataTable,b=e.Paginator;e.ScrollingDataTable=function(n,m,k,l){l=l||{};if(l.scrollable){l.scrollable=false;}this._init();e.ScrollingDataTable.superclass.constructor.call(this,n,m,k,l);this.subscribe("columnShowEvent",this._onColumnChange);};var h=e.ScrollingDataTable;c.augmentObject(h,{CLASS_HEADER:"yui-dt-hd",CLASS_BODY:"yui-dt-bd"});c.extend(h,g,{_elHdContainer:null,_elHdTable:null,_elBdContainer:null,_elBdThead:null,_elTmpContainer:null,_elTmpTable:null,_bScrollbarX:null,initAttributes:function(k){k=k||{};h.superclass.initAttributes.call(this,k);this.setAttributeConfig("width",{value:null,validator:c.isString,method:function(l){if(this._elHdContainer&&this._elBdContainer){this._elHdContainer.style.width=l;this._elBdContainer.style.width=l;this._syncScrollX();this._syncScrollOverhang();}}});this.setAttributeConfig("height",{value:null,validator:c.isString,method:function(l){if(this._elHdContainer&&this._elBdContainer){this._elBdContainer.style.height=l;
-this._syncScrollX();this._syncScrollY();this._syncScrollOverhang();}}});this.setAttributeConfig("COLOR_COLUMNFILLER",{value:"#F2F2F2",validator:c.isString,method:function(l){if(this._elHdContainer){this._elHdContainer.style.backgroundColor=l;}}});},_init:function(){this._elHdContainer=null;this._elHdTable=null;this._elBdContainer=null;this._elBdThead=null;this._elTmpContainer=null;this._elTmpTable=null;},_initDomElements:function(k){this._initContainerEl(k);if(this._elContainer&&this._elHdContainer&&this._elBdContainer){this._initTableEl();if(this._elHdTable&&this._elTable){this._initColgroupEl(this._elHdTable);this._initTheadEl(this._elHdTable,this._elTable);this._initTbodyEl(this._elTable);this._initMsgTbodyEl(this._elTable);}}if(!this._elContainer||!this._elTable||!this._elColgroup||!this._elThead||!this._elTbody||!this._elMsgTbody||!this._elHdTable||!this._elBdThead){return false;}else{return true;}},_destroyContainerEl:function(k){d.removeClass(k,g.CLASS_SCROLLABLE);h.superclass._destroyContainerEl.call(this,k);this._elHdContainer=null;this._elBdContainer=null;},_initContainerEl:function(l){h.superclass._initContainerEl.call(this,l);if(this._elContainer){l=this._elContainer;d.addClass(l,g.CLASS_SCROLLABLE);var k=document.createElement("div");k.style.width=this.get("width")||"";k.style.backgroundColor=this.get("COLOR_COLUMNFILLER");d.addClass(k,h.CLASS_HEADER);this._elHdContainer=k;l.appendChild(k);var m=document.createElement("div");m.style.width=this.get("width")||"";m.style.height=this.get("height")||"";d.addClass(m,h.CLASS_BODY);j.addListener(m,"scroll",this._onScroll,this);this._elBdContainer=m;l.appendChild(m);}},_initCaptionEl:function(k){},_destroyHdTableEl:function(){var k=this._elHdTable;if(k){j.purgeElement(k,true);k.parentNode.removeChild(k);this._elBdThead=null;}},_initTableEl:function(){if(this._elHdContainer){this._destroyHdTableEl();this._elHdTable=this._elHdContainer.appendChild(document.createElement("table"));j.delegate(this._elHdTable,"mouseenter",this._onTableMouseover,"thead ."+g.CLASS_LABEL,this);j.delegate(this._elHdTable,"mouseleave",this._onTableMouseout,"thead ."+g.CLASS_LABEL,this);}h.superclass._initTableEl.call(this,this._elBdContainer);},_initTheadEl:function(l,k){l=l||this._elHdTable;k=k||this._elTable;this._initBdTheadEl(k);h.superclass._initTheadEl.call(this,l);},_initThEl:function(l,k){h.superclass._initThEl.call(this,l,k);l.id=this.getId()+"-fixedth-"+k.getSanitizedKey();},_destroyBdTheadEl:function(){var k=this._elBdThead;if(k){var l=k.parentNode;j.purgeElement(k,true);l.removeChild(k);this._elBdThead=null;this._destroyColumnHelpers();}},_initBdTheadEl:function(t){if(t){this._destroyBdTheadEl();var p=t.insertBefore(document.createElement("thead"),t.firstChild);var v=this._oColumnSet,u=v.tree,o,l,s,q,n,m,r;for(q=0,m=u.length;q<m;q++){l=p.appendChild(document.createElement("tr"));for(n=0,r=u[q].length;n<r;n++){s=u[q][n];o=l.appendChild(document.createElement("th"));this._initBdThEl(o,s,q,n);}}this._elBdThead=p;}},_initBdThEl:function(n,m){n.id=this.getId()+"-th-"+m.getSanitizedKey();n.rowSpan=m.getRowspan();n.colSpan=m.getColspan();if(m.abbr){n.abbr=m.abbr;}var l=m.getKey();var k=c.isValue(m.label)?m.label:l;n.innerHTML=k;},_initTbodyEl:function(k){h.superclass._initTbodyEl.call(this,k);k.style.marginTop=(this._elTbody.offsetTop>0)?"-"+this._elTbody.offsetTop+"px":0;},_focusEl:function(l){l=l||this._elTbody;var k=this;this._storeScrollPositions();setTimeout(function(){setTimeout(function(){try{l.focus();k._restoreScrollPositions();}catch(m){}},0);},0);},_runRenderChain:function(){this._storeScrollPositions();this._oChainRender.run();},_storeScrollPositions:function(){this._nScrollTop=this._elBdContainer.scrollTop;this._nScrollLeft=this._elBdContainer.scrollLeft;},clearScrollPositions:function(){this._nScrollTop=0;this._nScrollLeft=0;},_restoreScrollPositions:function(){if(this._nScrollTop){this._elBdContainer.scrollTop=this._nScrollTop;this._nScrollTop=null;}if(this._nScrollLeft){this._elBdContainer.scrollLeft=this._nScrollLeft;this._elHdContainer.scrollLeft=this._nScrollLeft;this._nScrollLeft=null;}},_validateColumnWidth:function(n,k){if(!n.width&&!n.hidden){var p=n.getThEl();if(n._calculatedWidth){this._setColumnWidth(n,"auto","visible");}if(p.offsetWidth!==k.offsetWidth){var m=(p.offsetWidth>k.offsetWidth)?n.getThLinerEl():k.firstChild;var l=Math.max(0,(m.offsetWidth-(parseInt(d.getStyle(m,"paddingLeft"),10)|0)-(parseInt(d.getStyle(m,"paddingRight"),10)|0)),n.minWidth);var o="visible";if((n.maxAutoWidth>0)&&(l>n.maxAutoWidth)){l=n.maxAutoWidth;o="hidden";}this._elTbody.style.display="none";this._setColumnWidth(n,l+"px",o);n._calculatedWidth=l;this._elTbody.style.display="";}}},validateColumnWidths:function(s){var u=this._oColumnSet.keys,w=u.length,l=this.getFirstTrEl();if(a.ie){this._setOverhangValue(1);}if(u&&l&&(l.childNodes.length===w)){var m=this.get("width");if(m){this._elHdContainer.style.width="";this._elBdContainer.style.width="";}this._elContainer.style.width="";if(s&&c.isNumber(s.getKeyIndex())){this._validateColumnWidth(s,l.childNodes[s.getKeyIndex()]);}else{var t,k=[],o,q,r;for(q=0;q<w;q++){s=u[q];if(!s.width&&!s.hidden&&s._calculatedWidth){k[k.length]=s;}}this._elTbody.style.display="none";for(q=0,r=k.length;q<r;q++){this._setColumnWidth(k[q],"auto","visible");}this._elTbody.style.display="";k=[];for(q=0;q<w;q++){s=u[q];t=l.childNodes[q];if(!s.width&&!s.hidden){var n=s.getThEl();if(n.offsetWidth!==t.offsetWidth){var v=(n.offsetWidth>t.offsetWidth)?s.getThLinerEl():t.firstChild;var p=Math.max(0,(v.offsetWidth-(parseInt(d.getStyle(v,"paddingLeft"),10)|0)-(parseInt(d.getStyle(v,"paddingRight"),10)|0)),s.minWidth);var x="visible";if((s.maxAutoWidth>0)&&(p>s.maxAutoWidth)){p=s.maxAutoWidth;x="hidden";}k[k.length]=[s,p,x];}}}this._elTbody.style.display="none";for(q=0,r=k.length;q<r;q++){o=k[q];this._setColumnWidth(o[0],o[1]+"px",o[2]);o[0]._calculatedWidth=o[1];}this._elTbody.style.display="";}if(m){this._elHdContainer.style.width=m;this._elBdContainer.style.width=m;
-}}this._syncScroll();this._restoreScrollPositions();},_syncScroll:function(){this._syncScrollX();this._syncScrollY();this._syncScrollOverhang();if(a.opera){this._elHdContainer.scrollLeft=this._elBdContainer.scrollLeft;if(!this.get("width")){document.body.style+="";}}},_syncScrollY:function(){var k=this._elTbody,l=this._elBdContainer;if(!this.get("width")){this._elContainer.style.width=(l.scrollHeight>l.clientHeight)?(k.parentNode.clientWidth+19)+"px":(k.parentNode.clientWidth+2)+"px";}},_syncScrollX:function(){var k=this._elTbody,l=this._elBdContainer;if(!this.get("height")&&(a.ie)){l.style.height=(l.scrollWidth>l.offsetWidth)?(k.parentNode.offsetHeight+18)+"px":k.parentNode.offsetHeight+"px";}if(this._elTbody.rows.length===0){this._elMsgTbody.parentNode.style.width=this.getTheadEl().parentNode.offsetWidth+"px";}else{this._elMsgTbody.parentNode.style.width="";}},_syncScrollOverhang:function(){var l=this._elBdContainer,k=1;if((l.scrollHeight>l.clientHeight)&&(l.scrollWidth>l.clientWidth)){k=18;}this._setOverhangValue(k);},_setOverhangValue:function(n){var p=this._oColumnSet.headers[this._oColumnSet.headers.length-1]||[],l=p.length,k=this._sId+"-fixedth-",o=n+"px solid "+this.get("COLOR_COLUMNFILLER");this._elThead.style.display="none";for(var m=0;m<l;m++){d.get(k+p[m]).style.borderRight=o;}this._elThead.style.display="";},getHdContainerEl:function(){return this._elHdContainer;},getBdContainerEl:function(){return this._elBdContainer;},getHdTableEl:function(){return this._elHdTable;},getBdTableEl:function(){return this._elTable;},disable:function(){var k=this._elMask;k.style.width=this._elBdContainer.offsetWidth+"px";k.style.height=this._elHdContainer.offsetHeight+this._elBdContainer.offsetHeight+"px";k.style.display="";this.fireEvent("disableEvent");},removeColumn:function(m){var k=this._elHdContainer.scrollLeft;var l=this._elBdContainer.scrollLeft;m=h.superclass.removeColumn.call(this,m);this._elHdContainer.scrollLeft=k;this._elBdContainer.scrollLeft=l;return m;},insertColumn:function(n,l){var k=this._elHdContainer.scrollLeft;var m=this._elBdContainer.scrollLeft;var o=h.superclass.insertColumn.call(this,n,l);this._elHdContainer.scrollLeft=k;this._elBdContainer.scrollLeft=m;return o;},reorderColumn:function(n,l){var k=this._elHdContainer.scrollLeft;var m=this._elBdContainer.scrollLeft;var o=h.superclass.reorderColumn.call(this,n,l);this._elHdContainer.scrollLeft=k;this._elBdContainer.scrollLeft=m;return o;},setColumnWidth:function(l,k){l=this.getColumn(l);if(l){this._storeScrollPositions();if(c.isNumber(k)){k=(k>l.minWidth)?k:l.minWidth;l.width=k;this._setColumnWidth(l,k+"px");this._syncScroll();this.fireEvent("columnSetWidthEvent",{column:l,width:k});}else{if(k===null){l.width=k;this._setColumnWidth(l,"auto");this.validateColumnWidths(l);this.fireEvent("columnUnsetWidthEvent",{column:l});}}this._clearTrTemplateEl();}else{}},scrollTo:function(m){var l=this.getTdEl(m);if(l){this.clearScrollPositions();this.getBdContainerEl().scrollLeft=l.offsetLeft;this.getBdContainerEl().scrollTop=l.parentNode.offsetTop;}else{var k=this.getTrEl(m);if(k){this.clearScrollPositions();this.getBdContainerEl().scrollTop=k.offsetTop;}}},showTableMessage:function(o,k){var p=this._elMsgTd;if(c.isString(o)){p.firstChild.innerHTML=o;}if(c.isString(k)){d.addClass(p.firstChild,k);}var n=this.getTheadEl();var l=n.parentNode;var m=l.offsetWidth;this._elMsgTbody.parentNode.style.width=this.getTheadEl().parentNode.offsetWidth+"px";this._elMsgTbody.style.display="";this.fireEvent("tableMsgShowEvent",{html:o,className:k});},_onColumnChange:function(k){var l=(k.column)?k.column:(k.editor)?k.editor.column:null;this._storeScrollPositions();this.validateColumnWidths(l);},_onScroll:function(m,l){l._elHdContainer.scrollLeft=l._elBdContainer.scrollLeft;if(l._oCellEditor&&l._oCellEditor.isActive){l.fireEvent("editorBlurEvent",{editor:l._oCellEditor});l.cancelCellEditor();}var n=j.getTarget(m);var k=n.nodeName.toLowerCase();l.fireEvent("tableScrollEvent",{event:m,target:n});},_onTheadKeydown:function(n,l){if(j.getCharCode(n)===9){setTimeout(function(){if((l instanceof h)&&l._sId){l._elBdContainer.scrollLeft=l._elHdContainer.scrollLeft;}},0);}var o=j.getTarget(n);var k=o.nodeName.toLowerCase();var m=true;while(o&&(k!="table")){switch(k){case"body":return;case"input":case"textarea":break;case"thead":m=l.fireEvent("theadKeyEvent",{target:o,event:n});break;default:break;}if(m===false){return;}else{o=o.parentNode;if(o){k=o.nodeName.toLowerCase();}}}l.fireEvent("tableKeyEvent",{target:(o||l._elContainer),event:n});}});})();(function(){var c=YAHOO.lang,f=YAHOO.util,e=YAHOO.widget,b=YAHOO.env.ua,d=f.Dom,i=f.Event,h=e.DataTable;e.BaseCellEditor=function(k,j){this._sId=this._sId||d.generateId(null,"yui-ceditor");YAHOO.widget.BaseCellEditor._nCount++;this._sType=k;this._initConfigs(j);this._initEvents();this._needsRender=true;};var a=e.BaseCellEditor;c.augmentObject(a,{_nCount:0,CLASS_CELLEDITOR:"yui-ceditor"});a.prototype={_sId:null,_sType:null,_oDataTable:null,_oColumn:null,_oRecord:null,_elTd:null,_elContainer:null,_elCancelBtn:null,_elSaveBtn:null,_initConfigs:function(k){if(k&&YAHOO.lang.isObject(k)){for(var j in k){if(j){this[j]=k[j];}}}},_initEvents:function(){this.createEvent("showEvent");this.createEvent("keydownEvent");this.createEvent("invalidDataEvent");this.createEvent("revertEvent");this.createEvent("saveEvent");this.createEvent("cancelEvent");this.createEvent("blurEvent");this.createEvent("blockEvent");this.createEvent("unblockEvent");},_initContainerEl:function(){if(this._elContainer){YAHOO.util.Event.purgeElement(this._elContainer,true);this._elContainer.innerHTML="";}var j=document.createElement("div");j.id=this.getId()+"-container";j.style.display="none";j.tabIndex=0;this.className=c.isArray(this.className)?this.className:this.className?[this.className]:[];this.className[this.className.length]=h.CLASS_EDITOR;j.className=this.className.join(" ");document.body.insertBefore(j,document.body.firstChild);this._elContainer=j;},_initShimEl:function(){if(this.useIFrame){if(!this._elIFrame){var j=document.createElement("iframe");
-j.src="javascript:false";j.frameBorder=0;j.scrolling="no";j.style.display="none";j.className=h.CLASS_EDITOR_SHIM;j.tabIndex=-1;j.role="presentation";j.title="Presentational iframe shim";document.body.insertBefore(j,document.body.firstChild);this._elIFrame=j;}}},_hide:function(){this.getContainerEl().style.display="none";if(this._elIFrame){this._elIFrame.style.display="none";}this.isActive=false;this.getDataTable()._oCellEditor=null;},asyncSubmitter:null,value:null,defaultValue:null,validator:null,resetInvalidData:true,isActive:false,LABEL_SAVE:"Save",LABEL_CANCEL:"Cancel",disableBtns:false,useIFrame:false,className:null,toString:function(){return"CellEditor instance "+this._sId;},getId:function(){return this._sId;},getDataTable:function(){return this._oDataTable;},getColumn:function(){return this._oColumn;},getRecord:function(){return this._oRecord;},getTdEl:function(){return this._elTd;},getContainerEl:function(){return this._elContainer;},destroy:function(){this.unsubscribeAll();var k=this.getColumn();if(k){k.editor=null;}var j=this.getContainerEl();if(j){i.purgeElement(j,true);j.parentNode.removeChild(j);}},render:function(){if(!this._needsRender){return;}this._initContainerEl();this._initShimEl();i.addListener(this.getContainerEl(),"keydown",function(l,j){if((l.keyCode==27)){var k=i.getTarget(l);if(k.nodeName&&k.nodeName.toLowerCase()==="select"){k.blur();}j.cancel();}j.fireEvent("keydownEvent",{editor:j,event:l});},this);this.renderForm();if(!this.disableBtns){this.renderBtns();}this.doAfterRender();this._needsRender=false;},renderBtns:function(){var l=this.getContainerEl().appendChild(document.createElement("div"));l.className=h.CLASS_BUTTON;var k=l.appendChild(document.createElement("button"));k.className=h.CLASS_DEFAULT;k.innerHTML=this.LABEL_SAVE;i.addListener(k,"click",function(m){this.save();},this,true);this._elSaveBtn=k;var j=l.appendChild(document.createElement("button"));j.innerHTML=this.LABEL_CANCEL;i.addListener(j,"click",function(m){this.cancel();},this,true);this._elCancelBtn=j;},attach:function(n,l){if(n instanceof YAHOO.widget.DataTable){this._oDataTable=n;l=n.getTdEl(l);if(l){this._elTd=l;var m=n.getColumn(l);if(m){this._oColumn=m;var j=n.getRecord(l);if(j){this._oRecord=j;var k=j.getData(this.getColumn().getField());this.value=(k!==undefined)?k:this.defaultValue;return true;}}}}return false;},move:function(){var m=this.getContainerEl(),l=this.getTdEl(),j=d.getX(l),n=d.getY(l);if(isNaN(j)||isNaN(n)){var k=this.getDataTable().getTbodyEl();j=l.offsetLeft+d.getX(k.parentNode)-k.scrollLeft;n=l.offsetTop+d.getY(k.parentNode)-k.scrollTop+this.getDataTable().getTheadEl().offsetHeight;}m.style.left=j+"px";m.style.top=n+"px";if(this._elIFrame){this._elIFrame.style.left=j+"px";this._elIFrame.style.top=n+"px";}},show:function(){var k=this.getContainerEl(),j=this._elIFrame;this.resetForm();this.isActive=true;k.style.display="";if(j){j.style.width=k.offsetWidth+"px";j.style.height=k.offsetHeight+"px";j.style.display="";}this.focus();this.fireEvent("showEvent",{editor:this});},block:function(){this.fireEvent("blockEvent",{editor:this});},unblock:function(){this.fireEvent("unblockEvent",{editor:this});},save:function(){var k=this.getInputValue();var l=k;if(this.validator){l=this.validator.call(this.getDataTable(),k,this.value,this);if(l===undefined){if(this.resetInvalidData){this.resetForm();}this.fireEvent("invalidDataEvent",{editor:this,oldData:this.value,newData:k});return;}}var m=this;var j=function(o,n){var p=m.value;if(o){m.value=n;m.getDataTable().updateCell(m.getRecord(),m.getColumn(),n);m._hide();m.fireEvent("saveEvent",{editor:m,oldData:p,newData:m.value});}else{m.resetForm();m.fireEvent("revertEvent",{editor:m,oldData:p,newData:n});}m.unblock();};this.block();if(c.isFunction(this.asyncSubmitter)){this.asyncSubmitter.call(this,j,l);}else{j(true,l);}},cancel:function(){if(this.isActive){this._hide();this.fireEvent("cancelEvent",{editor:this});}else{}},renderForm:function(){},doAfterRender:function(){},handleDisabledBtns:function(){},resetForm:function(){},focus:function(){},getInputValue:function(){}};c.augmentProto(a,f.EventProvider);e.CheckboxCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,"yui-checkboxceditor");YAHOO.widget.BaseCellEditor._nCount++;e.CheckboxCellEditor.superclass.constructor.call(this,j.type||"checkbox",j);};c.extend(e.CheckboxCellEditor,a,{checkboxOptions:null,checkboxes:null,value:null,renderForm:function(){if(c.isArray(this.checkboxOptions)){var n,o,q,l,m,k;for(m=0,k=this.checkboxOptions.length;m<k;m++){n=this.checkboxOptions[m];o=c.isValue(n.value)?n.value:n;q=this.getId()+"-chk"+m;this.getContainerEl().innerHTML+='<input type="checkbox"'+' id="'+q+'"'+' value="'+o+'" />';l=this.getContainerEl().appendChild(document.createElement("label"));l.htmlFor=q;l.innerHTML=c.isValue(n.label)?n.label:n;}var p=[];for(m=0;m<k;m++){p[p.length]=this.getContainerEl().childNodes[m*2];}this.checkboxes=p;if(this.disableBtns){this.handleDisabledBtns();}}else{}},handleDisabledBtns:function(){i.addListener(this.getContainerEl(),"click",function(j){if(i.getTarget(j).tagName.toLowerCase()==="input"){this.save();}},this,true);},resetForm:function(){var p=c.isArray(this.value)?this.value:[this.value];for(var o=0,n=this.checkboxes.length;o<n;o++){this.checkboxes[o].checked=false;for(var m=0,l=p.length;m<l;m++){if(this.checkboxes[o].value==p[m]){this.checkboxes[o].checked=true;}}}},focus:function(){this.checkboxes[0].focus();},getInputValue:function(){var k=[];for(var m=0,l=this.checkboxes.length;m<l;m++){if(this.checkboxes[m].checked){k[k.length]=this.checkboxes[m].value;}}return k;}});c.augmentObject(e.CheckboxCellEditor,a);e.DateCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,"yui-dateceditor");YAHOO.widget.BaseCellEditor._nCount++;e.DateCellEditor.superclass.constructor.call(this,j.type||"date",j);};c.extend(e.DateCellEditor,a,{calendar:null,calendarOptions:null,defaultValue:new Date(),renderForm:function(){if(YAHOO.widget.Calendar){var k=this.getContainerEl().appendChild(document.createElement("div"));
-k.id=this.getId()+"-dateContainer";var l=new YAHOO.widget.Calendar(this.getId()+"-date",k.id,this.calendarOptions);l.render();k.style.cssFloat="none";l.hideEvent.subscribe(function(){this.cancel();},this,true);if(b.ie){var j=this.getContainerEl().appendChild(document.createElement("div"));j.style.clear="both";}this.calendar=l;if(this.disableBtns){this.handleDisabledBtns();}}else{}},handleDisabledBtns:function(){this.calendar.selectEvent.subscribe(function(j){this.save();},this,true);},resetForm:function(){var j=this.value||(new Date());this.calendar.select(j);this.calendar.cfg.setProperty("pagedate",j,false);this.calendar.render();this.calendar.show();},focus:function(){},getInputValue:function(){return this.calendar.getSelectedDates()[0];}});c.augmentObject(e.DateCellEditor,a);e.DropdownCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,"yui-dropdownceditor");YAHOO.widget.BaseCellEditor._nCount++;e.DropdownCellEditor.superclass.constructor.call(this,j.type||"dropdown",j);};c.extend(e.DropdownCellEditor,a,{dropdownOptions:null,dropdown:null,multiple:false,size:null,renderForm:function(){var n=this.getContainerEl().appendChild(document.createElement("select"));n.style.zoom=1;if(this.multiple){n.multiple="multiple";}if(c.isNumber(this.size)){n.size=this.size;}this.dropdown=n;if(c.isArray(this.dropdownOptions)){var o,m;for(var l=0,k=this.dropdownOptions.length;l<k;l++){o=this.dropdownOptions[l];m=document.createElement("option");m.value=(c.isValue(o.value))?o.value:o;m.innerHTML=(c.isValue(o.label))?o.label:o;m=n.appendChild(m);}if(this.disableBtns){this.handleDisabledBtns();}}},handleDisabledBtns:function(){if(this.multiple){i.addListener(this.dropdown,"blur",function(j){this.save();},this,true);}else{if(!b.ie){i.addListener(this.dropdown,"change",function(j){this.save();},this,true);}else{i.addListener(this.dropdown,"blur",function(j){this.save();},this,true);i.addListener(this.dropdown,"click",function(j){this.save();},this,true);}}},resetForm:function(){var s=this.dropdown.options,p=0,o=s.length;if(c.isArray(this.value)){var l=this.value,k=0,r=l.length,q={};for(;p<o;p++){s[p].selected=false;q[s[p].value]=s[p];}for(;k<r;k++){if(q[l[k]]){q[l[k]].selected=true;}}}else{for(;p<o;p++){if(this.value==s[p].value){s[p].selected=true;}}}},focus:function(){this.getDataTable()._focusEl(this.dropdown);},getInputValue:function(){var n=this.dropdown.options;if(this.multiple){var k=[],m=0,l=n.length;for(;m<l;m++){if(n[m].selected){k.push(n[m].value);}}return k;}else{return n[n.selectedIndex].value;}}});c.augmentObject(e.DropdownCellEditor,a);e.RadioCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,"yui-radioceditor");YAHOO.widget.BaseCellEditor._nCount++;e.RadioCellEditor.superclass.constructor.call(this,j.type||"radio",j);};c.extend(e.RadioCellEditor,a,{radios:null,radioOptions:null,renderForm:function(){if(c.isArray(this.radioOptions)){var k,l,r,o;for(var n=0,p=this.radioOptions.length;n<p;n++){k=this.radioOptions[n];l=c.isValue(k.value)?k.value:k;r=this.getId()+"-radio"+n;this.getContainerEl().innerHTML+='<input type="radio"'+' name="'+this.getId()+'"'+' value="'+l+'"'+' id="'+r+'" />';o=this.getContainerEl().appendChild(document.createElement("label"));o.htmlFor=r;o.innerHTML=(c.isValue(k.label))?k.label:k;}var q=[],s;for(var m=0;m<p;m++){s=this.getContainerEl().childNodes[m*2];q[q.length]=s;}this.radios=q;if(this.disableBtns){this.handleDisabledBtns();}}else{}},handleDisabledBtns:function(){i.addListener(this.getContainerEl(),"click",function(j){if(i.getTarget(j).tagName.toLowerCase()==="input"){this.save();}},this,true);},resetForm:function(){for(var m=0,l=this.radios.length;m<l;m++){var k=this.radios[m];if(this.value==k.value){k.checked=true;return;}}},focus:function(){for(var l=0,k=this.radios.length;l<k;l++){if(this.radios[l].checked){this.radios[l].focus();return;}}},getInputValue:function(){for(var l=0,k=this.radios.length;l<k;l++){if(this.radios[l].checked){return this.radios[l].value;}}}});c.augmentObject(e.RadioCellEditor,a);e.TextareaCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,"yui-textareaceditor");YAHOO.widget.BaseCellEditor._nCount++;e.TextareaCellEditor.superclass.constructor.call(this,j.type||"textarea",j);};c.extend(e.TextareaCellEditor,a,{textarea:null,renderForm:function(){var j=this.getContainerEl().appendChild(document.createElement("textarea"));this.textarea=j;if(this.disableBtns){this.handleDisabledBtns();}},handleDisabledBtns:function(){i.addListener(this.textarea,"blur",function(j){this.save();},this,true);},move:function(){this.textarea.style.width=this.getTdEl().offsetWidth+"px";this.textarea.style.height="3em";YAHOO.widget.TextareaCellEditor.superclass.move.call(this);},resetForm:function(){this.textarea.value=this.value;},focus:function(){this.getDataTable()._focusEl(this.textarea);this.textarea.select();},getInputValue:function(){return this.textarea.value;}});c.augmentObject(e.TextareaCellEditor,a);e.TextboxCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,"yui-textboxceditor");YAHOO.widget.BaseCellEditor._nCount++;e.TextboxCellEditor.superclass.constructor.call(this,j.type||"textbox",j);};c.extend(e.TextboxCellEditor,a,{textbox:null,renderForm:function(){var j;if(b.webkit>420){j=this.getContainerEl().appendChild(document.createElement("form")).appendChild(document.createElement("input"));}else{j=this.getContainerEl().appendChild(document.createElement("input"));}j.type="text";this.textbox=j;i.addListener(j,"keypress",function(k){if((k.keyCode===13)){YAHOO.util.Event.preventDefault(k);this.save();}},this,true);if(this.disableBtns){this.handleDisabledBtns();}},move:function(){this.textbox.style.width=this.getTdEl().offsetWidth+"px";e.TextboxCellEditor.superclass.move.call(this);},resetForm:function(){this.textbox.value=c.isValue(this.value)?this.value.toString():"";},focus:function(){this.getDataTable()._focusEl(this.textbox);this.textbox.select();},getInputValue:function(){return this.textbox.value;
-}});c.augmentObject(e.TextboxCellEditor,a);h.Editors={checkbox:e.CheckboxCellEditor,"date":e.DateCellEditor,dropdown:e.DropdownCellEditor,radio:e.RadioCellEditor,textarea:e.TextareaCellEditor,textbox:e.TextboxCellEditor};e.CellEditor=function(k,j){if(k&&h.Editors[k]){c.augmentObject(a,h.Editors[k]);return new h.Editors[k](j);}else{return new a(null,j);}};var g=e.CellEditor;c.augmentObject(g,a);})();YAHOO.register("datatable",YAHOO.widget.DataTable,{version:"2.9.0",build:"2800"});
-
-
+(function(){var d=YAHOO.util.Dom,f=YAHOO.lang,b=f.isObject,e=f.isFunction,c=f.isArray,a=f.isString;function g(k){var n=g.VALUE_UNLIMITED,l,h,i,j,m;k=b(k)?k:{};this.initConfig();this.initEvents();this.set("rowsPerPage",k.rowsPerPage,true);if(g.isNumeric(k.totalRecords)){this.set("totalRecords",k.totalRecords,true);}this.initUIComponents();for(l in k){if(k.hasOwnProperty(l)){this.set(l,k[l],true);}}h=this.get("initialPage");i=this.get("totalRecords");j=this.get("rowsPerPage");if(h>1&&j!==n){m=(h-1)*j;if(i===n||m<i){this.set("recordOffset",m,true);}}}f.augmentObject(g,{id:0,ID_BASE:"yui-pg",VALUE_UNLIMITED:-1,TEMPLATE_DEFAULT:"{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}",TEMPLATE_ROWS_PER_PAGE:"{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}",ui:{},isNumeric:function(h){return isFinite(+h);},toNumber:function(h){return isFinite(+h)?+h:null;}},true);g.prototype={_containers:[],_batch:false,_pageChanged:false,_state:null,initConfig:function(){var h=g.VALUE_UNLIMITED;this.setAttributeConfig("rowsPerPage",{value:0,validator:g.isNumeric,setter:g.toNumber});this.setAttributeConfig("containers",{value:null,validator:function(l){if(!c(l)){l=[l];}for(var k=0,j=l.length;k<j;++k){if(a(l[k])||(b(l[k])&&l[k].nodeType===1)){continue;}return false;}return true;},method:function(i){i=d.get(i);if(!c(i)){i=[i];}this._containers=i;}});this.setAttributeConfig("totalRecords",{value:0,validator:g.isNumeric,setter:g.toNumber});this.setAttributeConfig("recordOffset",{value:0,validator:function(j){var i=this.get("totalRecords");if(g.isNumeric(j)){j=+j;return i===h||i>j||(i===0&&j===0);}return false;},setter:g.toNumber});this.setAttributeConfig("initialPage",{value:1,validator:g.isNumeric,setter:g.toNumber});this.setAttributeConfig("template",{value:g.TEMPLATE_DEFAULT,validator:a});this.setAttributeConfig("containerClass",{value:"yui-pg-container",validator:a});this.setAttributeConfig("alwaysVisible",{value:true,validator:f.isBoolean});this.setAttributeConfig("updateOnChange",{value:false,validator:f.isBoolean});this.setAttributeConfig("id",{value:g.id++,readOnly:true});this.setAttributeConfig("rendered",{value:false,readOnly:true});},initUIComponents:function(){var j=g.ui,i,h;for(i in j){if(j.hasOwnProperty(i)){h=j[i];if(b(h)&&e(h.init)){h.init(this);}}}},initEvents:function(){this.createEvent("render");this.createEvent("rendered");this.createEvent("changeRequest");this.createEvent("pageChange");this.createEvent("beforeDestroy");this.createEvent("destroy");this._selfSubscribe();},_selfSubscribe:function(){this.subscribe("totalRecordsChange",this.updateVisibility,this,true);this.subscribe("alwaysVisibleChange",this.updateVisibility,this,true);this.subscribe("totalRecordsChange",this._handleStateChange,this,true);this.subscribe("recordOffsetChange",this._handleStateChange,this,true);this.subscribe("rowsPerPageChange",this._handleStateChange,this,true);this.subscribe("totalRecordsChange",this._syncRecordOffset,this,true);},_syncRecordOffset:function(k){var h=k.newValue,j,i;if(k.prevValue!==h){if(h!==g.VALUE_UNLIMITED){j=this.get("rowsPerPage");if(j&&this.get("recordOffset")>=h){i=this.getState({totalRecords:k.prevValue,recordOffset:this.get("recordOffset")});this.set("recordOffset",i.before.recordOffset);this._firePageChange(i);}}}},_handleStateChange:function(i){if(i.prevValue!==i.newValue){var j=this._state||{},h;j[i.type.replace(/Change$/,"")]=i.prevValue;h=this.getState(j);if(h.page!==h.before.page){if(this._batch){this._pageChanged=true;}else{this._firePageChange(h);}}}},_firePageChange:function(h){if(b(h)){var i=h.before;delete h.before;this.fireEvent("pageChange",{type:"pageChange",prevValue:h.page,newValue:i.page,prevState:h,newState:i});}},render:function(){if(this.get("rendered")){return this;}var l=this.get("template"),m=this.getState(),k=g.ID_BASE+this.get("id")+"-",j,h;for(j=0,h=this._containers.length;j<h;++j){this._renderTemplate(this._containers[j],l,k+j,true);}this.updateVisibility();if(this._containers.length){this.setAttributeConfig("rendered",{value:true});this.fireEvent("render",m);this.fireEvent("rendered",m);}return this;},_renderTemplate:function(j,n,m,l){var p=this.get("containerClass"),o,k,h;if(!j){return;}d.setStyle(j,"display","none");d.addClass(j,p);j.innerHTML=n.replace(/\{([a-z0-9_ \-]+)\}/gi,'<span class="yui-pg-ui yui-pg-ui-$1"></span>');o=d.getElementsByClassName("yui-pg-ui","span",j);for(k=0,h=o.length;k<h;++k){this.renderUIComponent(o[k],m);}if(!l){d.setStyle(j,"display","");}},renderUIComponent:function(h,m){var l=h.parentNode,k=/yui-pg-ui-(\w+)/.exec(h.className),j=k&&g.ui[k[1]],i;if(e(j)){i=new j(this);if(e(i.render)){l.replaceChild(i.render(m),h);}}return this;},destroy:function(){this.fireEvent("beforeDestroy");this.fireEvent("destroy");this.setAttributeConfig("rendered",{value:false});this.unsubscribeAll();},updateVisibility:function(m){var p=this.get("alwaysVisible"),n,j,q,o,k,l,h;if(!m||m.type==="alwaysVisibleChange"||!p){n=this.get("totalRecords");j=true;q=this.get("rowsPerPage");o=this.get("rowsPerPageOptions");if(c(o)){for(k=0,l=o.length;k<l;++k){h=o[k];if(f.isNumber(h||h.value)){q=Math.min(q,(h.value||h));}}}if(n!==g.VALUE_UNLIMITED&&n<=q){j=false;}j=j||p;for(k=0,l=this._containers.length;k<l;++k){d.setStyle(this._containers[k],"display",j?"":"none");}}},getContainerNodes:function(){return this._containers;},getTotalPages:function(){var h=this.get("totalRecords"),i=this.get("rowsPerPage");if(!i){return null;}if(h===g.VALUE_UNLIMITED){return g.VALUE_UNLIMITED;}return Math.ceil(h/i);},hasPage:function(i){if(!f.isNumber(i)||i<1){return false;}var h=this.getTotalPages();return(h===g.VALUE_UNLIMITED||h>=i);},getCurrentPage:function(){var h=this.get("rowsPerPage");if(!h||!this.get("totalRecords")){return 0;}return Math.floor(this.get("recordOffset")/h)+1;},hasNextPage:function(){var h=this.getCurrentPage(),i=this.getTotalPages();return h&&(i===g.VALUE_UNLIMITED||h<i);},getNextPage:function(){return this.hasNextPage()?this.getCurrentPage()+1:null;
+},hasPreviousPage:function(){return(this.getCurrentPage()>1);},getPreviousPage:function(){return(this.hasPreviousPage()?this.getCurrentPage()-1:1);},getPageRecords:function(k){if(!f.isNumber(k)){k=this.getCurrentPage();}var j=this.get("rowsPerPage"),i=this.get("totalRecords"),l,h;if(!k||!j){return null;}l=(k-1)*j;if(i!==g.VALUE_UNLIMITED){if(l>=i){return null;}h=Math.min(l+j,i)-1;}else{h=l+j-1;}return[l,h];},setPage:function(i,h){if(this.hasPage(i)&&i!==this.getCurrentPage()){if(this.get("updateOnChange")||h){this.set("recordOffset",(i-1)*this.get("rowsPerPage"));}else{this.fireEvent("changeRequest",this.getState({"page":i}));}}},getRowsPerPage:function(){return this.get("rowsPerPage");},setRowsPerPage:function(i,h){if(g.isNumeric(i)&&+i>0&&+i!==this.get("rowsPerPage")){if(this.get("updateOnChange")||h){this.set("rowsPerPage",i);}else{this.fireEvent("changeRequest",this.getState({"rowsPerPage":+i}));}}},getTotalRecords:function(){return this.get("totalRecords");},setTotalRecords:function(i,h){if(g.isNumeric(i)&&+i>=0&&+i!==this.get("totalRecords")){if(this.get("updateOnChange")||h){this.set("totalRecords",i);}else{this.fireEvent("changeRequest",this.getState({"totalRecords":+i}));}}},getStartIndex:function(){return this.get("recordOffset");},setStartIndex:function(i,h){if(g.isNumeric(i)&&+i>=0&&+i!==this.get("recordOffset")){if(this.get("updateOnChange")||h){this.set("recordOffset",i);}else{this.fireEvent("changeRequest",this.getState({"recordOffset":+i}));}}},getState:function(n){var p=g.VALUE_UNLIMITED,l=Math,m=l.max,o=l.ceil,j,h,k;function i(s,q,r){if(s<=0||q===0){return 0;}if(q===p||q>s){return s-(s%r);}return q-(q%r||r);}j={paginator:this,totalRecords:this.get("totalRecords"),rowsPerPage:this.get("rowsPerPage"),records:this.getPageRecords()};j.recordOffset=i(this.get("recordOffset"),j.totalRecords,j.rowsPerPage);j.page=o(j.recordOffset/j.rowsPerPage)+1;if(!n){return j;}h={paginator:this,before:j,rowsPerPage:n.rowsPerPage||j.rowsPerPage,totalRecords:(g.isNumeric(n.totalRecords)?m(n.totalRecords,p):+j.totalRecords)};if(h.totalRecords===0){h.recordOffset=h.page=0;}else{k=g.isNumeric(n.page)?(n.page-1)*h.rowsPerPage:g.isNumeric(n.recordOffset)?+n.recordOffset:j.recordOffset;h.recordOffset=i(k,h.totalRecords,h.rowsPerPage);h.page=o(h.recordOffset/h.rowsPerPage)+1;}h.records=[h.recordOffset,h.recordOffset+h.rowsPerPage-1];if(h.totalRecords!==p&&h.recordOffset<h.totalRecords&&h.records&&h.records[1]>h.totalRecords-1){h.records[1]=h.totalRecords-1;}return h;},setState:function(i){if(b(i)){this._state=this.getState({});i={page:i.page,rowsPerPage:i.rowsPerPage,totalRecords:i.totalRecords,recordOffset:i.recordOffset};if(i.page&&i.recordOffset===undefined){i.recordOffset=(i.page-1)*(i.rowsPerPage||this.get("rowsPerPage"));}this._batch=true;this._pageChanged=false;for(var h in i){if(i.hasOwnProperty(h)&&this._configs.hasOwnProperty(h)){this.set(h,i[h]);}}this._batch=false;if(this._pageChanged){this._pageChanged=false;this._firePageChange(this.getState(this._state));}}}};f.augmentProto(g,YAHOO.util.AttributeProvider);YAHOO.widget.Paginator=g;})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.CurrentPageReport=function(d){this.paginator=d;d.subscribe("recordOffsetChange",this.update,this,true);d.subscribe("rowsPerPageChange",this.update,this,true);d.subscribe("totalRecordsChange",this.update,this,true);d.subscribe("pageReportTemplateChange",this.update,this,true);d.subscribe("destroy",this.destroy,this,true);d.subscribe("pageReportClassChange",this.update,this,true);};c.ui.CurrentPageReport.init=function(d){d.setAttributeConfig("pageReportClass",{value:"yui-pg-current",validator:b.isString});d.setAttributeConfig("pageReportTemplate",{value:"({currentPage} of {totalPages})",validator:b.isString});d.setAttributeConfig("pageReportValueGenerator",{value:function(g){var f=g.getCurrentPage(),e=g.getPageRecords();return{"currentPage":e?f:0,"totalPages":g.getTotalPages(),"startIndex":e?e[0]:0,"endIndex":e?e[1]:0,"startRecord":e?e[0]+1:0,"endRecord":e?e[1]+1:0,"totalRecords":g.get("totalRecords")};},validator:b.isFunction});};c.ui.CurrentPageReport.sprintf=function(e,d){return e.replace(/\{([\w\s\-]+)\}/g,function(f,g){return(g in d)?d[g]:"";});};c.ui.CurrentPageReport.prototype={span:null,render:function(d){this.span=document.createElement("span");this.span.className=this.paginator.get("pageReportClass");a(this.span,d+"-page-report");this.update();return this.span;},update:function(d){if(d&&d.prevValue===d.newValue){return;}this.span.innerHTML=c.ui.CurrentPageReport.sprintf(this.paginator.get("pageReportTemplate"),this.paginator.get("pageReportValueGenerator")(this.paginator));},destroy:function(){this.span.parentNode.removeChild(this.span);this.span=null;}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.PageLinks=function(d){this.paginator=d;d.subscribe("recordOffsetChange",this.update,this,true);d.subscribe("rowsPerPageChange",this.update,this,true);d.subscribe("totalRecordsChange",this.update,this,true);d.subscribe("pageLinksChange",this.rebuild,this,true);d.subscribe("pageLinkClassChange",this.rebuild,this,true);d.subscribe("currentPageClassChange",this.rebuild,this,true);d.subscribe("destroy",this.destroy,this,true);d.subscribe("pageLinksContainerClassChange",this.rebuild,this,true);};c.ui.PageLinks.init=function(d){d.setAttributeConfig("pageLinkClass",{value:"yui-pg-page",validator:b.isString});d.setAttributeConfig("currentPageClass",{value:"yui-pg-current-page",validator:b.isString});d.setAttributeConfig("pageLinksContainerClass",{value:"yui-pg-pages",validator:b.isString});d.setAttributeConfig("pageLinks",{value:10,validator:c.isNumeric});d.setAttributeConfig("pageLabelBuilder",{value:function(e,f){return e;},validator:b.isFunction});d.setAttributeConfig("pageTitleBuilder",{value:function(e,f){return"Page "+e;},validator:b.isFunction});};c.ui.PageLinks.calculateRange=function(f,g,e){var j=c.VALUE_UNLIMITED,i,d,h;if(!f||e===0||g===0||(g===j&&e===j)){return[0,-1];
+}if(g!==j){e=e===j?g:Math.min(e,g);}i=Math.max(1,Math.ceil(f-(e/2)));if(g===j){d=i+e-1;}else{d=Math.min(g,i+e-1);}h=e-(d-i+1);i=Math.max(1,i-h);return[i,d];};c.ui.PageLinks.prototype={current:0,container:null,render:function(d){var e=this.paginator;this.container=document.createElement("span");a(this.container,d+"-pages");this.container.className=e.get("pageLinksContainerClass");YAHOO.util.Event.on(this.container,"click",this.onClick,this,true);this.update({newValue:null,rebuild:true});return this.container;},update:function(q){if(q&&q.prevValue===q.newValue){return;}var g=this.paginator,m=g.getCurrentPage();if(this.current!==m||!m||q.rebuild){var r=g.get("pageLabelBuilder"),l=g.get("pageTitleBuilder"),k=c.ui.PageLinks.calculateRange(m,g.getTotalPages(),g.get("pageLinks")),f=k[0],h=k[1],o="",d,j,n;d='<a href="#" class="{class}" page="{page}" title="{title}">{label}</a>';n='<span class="{class}">{label}</span>';for(j=f;j<=h;++j){if(j===m){o+=b.substitute(n,{"class":g.get("currentPageClass")+" "+g.get("pageLinkClass"),"label":r(j,g)});}else{o+=b.substitute(d,{"class":g.get("pageLinkClass"),"page":j,"label":r(j,g),"title":l(j,g)});}}this.container.innerHTML=o;}},rebuild:function(d){d.rebuild=true;this.update(d);},destroy:function(){YAHOO.util.Event.purgeElement(this.container,true);this.container.parentNode.removeChild(this.container);this.container=null;},onClick:function(f){var d=YAHOO.util.Event.getTarget(f);if(d&&YAHOO.util.Dom.hasClass(d,this.paginator.get("pageLinkClass"))){YAHOO.util.Event.stopEvent(f);this.paginator.setPage(parseInt(d.getAttribute("page"),10));}}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.FirstPageLink=function(d){this.paginator=d;d.subscribe("recordOffsetChange",this.update,this,true);d.subscribe("rowsPerPageChange",this.update,this,true);d.subscribe("totalRecordsChange",this.update,this,true);d.subscribe("destroy",this.destroy,this,true);d.subscribe("firstPageLinkLabelChange",this.update,this,true);d.subscribe("firstPageLinkClassChange",this.update,this,true);};c.ui.FirstPageLink.init=function(d){d.setAttributeConfig("firstPageLinkLabel",{value:"&lt;&lt; first",validator:b.isString});d.setAttributeConfig("firstPageLinkClass",{value:"yui-pg-first",validator:b.isString});d.setAttributeConfig("firstPageLinkTitle",{value:"First Page",validator:b.isString});};c.ui.FirstPageLink.prototype={current:null,link:null,span:null,render:function(e){var f=this.paginator,h=f.get("firstPageLinkClass"),d=f.get("firstPageLinkLabel"),g=f.get("firstPageLinkTitle");this.link=document.createElement("a");this.span=document.createElement("span");a(this.link,e+"-first-link");this.link.href="#";this.link.className=h;this.link.innerHTML=d;this.link.title=g;YAHOO.util.Event.on(this.link,"click",this.onClick,this,true);a(this.span,e+"-first-span");this.span.className=h;this.span.innerHTML=d;this.current=f.getCurrentPage()>1?this.link:this.span;return this.current;},update:function(f){if(f&&f.prevValue===f.newValue){return;}var d=this.current?this.current.parentNode:null;if(this.paginator.getCurrentPage()>1){if(d&&this.current===this.span){d.replaceChild(this.link,this.current);this.current=this.link;}}else{if(d&&this.current===this.link){d.replaceChild(this.span,this.current);this.current=this.span;}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current);this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.setPage(1);}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.LastPageLink=function(d){this.paginator=d;d.subscribe("recordOffsetChange",this.update,this,true);d.subscribe("rowsPerPageChange",this.update,this,true);d.subscribe("totalRecordsChange",this.update,this,true);d.subscribe("destroy",this.destroy,this,true);d.subscribe("lastPageLinkLabelChange",this.update,this,true);d.subscribe("lastPageLinkClassChange",this.update,this,true);};c.ui.LastPageLink.init=function(d){d.setAttributeConfig("lastPageLinkLabel",{value:"last &gt;&gt;",validator:b.isString});d.setAttributeConfig("lastPageLinkClass",{value:"yui-pg-last",validator:b.isString});d.setAttributeConfig("lastPageLinkTitle",{value:"Last Page",validator:b.isString});};c.ui.LastPageLink.prototype={current:null,link:null,span:null,na:null,render:function(e){var g=this.paginator,i=g.get("lastPageLinkClass"),d=g.get("lastPageLinkLabel"),f=g.getTotalPages(),h=g.get("lastPageLinkTitle");this.link=document.createElement("a");this.span=document.createElement("span");this.na=this.span.cloneNode(false);a(this.link,e+"-last-link");this.link.href="#";this.link.className=i;this.link.innerHTML=d;this.link.title=h;YAHOO.util.Event.on(this.link,"click",this.onClick,this,true);a(this.span,e+"-last-span");this.span.className=i;this.span.innerHTML=d;a(this.na,e+"-last-na");switch(f){case c.VALUE_UNLIMITED:this.current=this.na;break;case g.getCurrentPage():this.current=this.span;break;default:this.current=this.link;}return this.current;},update:function(f){if(f&&f.prevValue===f.newValue){return;}var d=this.current?this.current.parentNode:null,g=this.link;if(d){switch(this.paginator.getTotalPages()){case c.VALUE_UNLIMITED:g=this.na;break;case this.paginator.getCurrentPage():g=this.span;break;}if(this.current!==g){d.replaceChild(g,this.current);this.current=g;}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current);this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.setPage(this.paginator.getTotalPages());}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.NextPageLink=function(d){this.paginator=d;d.subscribe("recordOffsetChange",this.update,this,true);d.subscribe("rowsPerPageChange",this.update,this,true);d.subscribe("totalRecordsChange",this.update,this,true);d.subscribe("destroy",this.destroy,this,true);d.subscribe("nextPageLinkLabelChange",this.update,this,true);
+d.subscribe("nextPageLinkClassChange",this.update,this,true);};c.ui.NextPageLink.init=function(d){d.setAttributeConfig("nextPageLinkLabel",{value:"next &gt;",validator:b.isString});d.setAttributeConfig("nextPageLinkClass",{value:"yui-pg-next",validator:b.isString});d.setAttributeConfig("nextPageLinkTitle",{value:"Next Page",validator:b.isString});};c.ui.NextPageLink.prototype={current:null,link:null,span:null,render:function(e){var g=this.paginator,i=g.get("nextPageLinkClass"),d=g.get("nextPageLinkLabel"),f=g.getTotalPages(),h=g.get("nextPageLinkTitle");this.link=document.createElement("a");this.span=document.createElement("span");a(this.link,e+"-next-link");this.link.href="#";this.link.className=i;this.link.innerHTML=d;this.link.title=h;YAHOO.util.Event.on(this.link,"click",this.onClick,this,true);a(this.span,e+"-next-span");this.span.className=i;this.span.innerHTML=d;this.current=g.getCurrentPage()===f?this.span:this.link;return this.current;},update:function(g){if(g&&g.prevValue===g.newValue){return;}var f=this.paginator.getTotalPages(),d=this.current?this.current.parentNode:null;if(this.paginator.getCurrentPage()!==f){if(d&&this.current===this.span){d.replaceChild(this.link,this.current);this.current=this.link;}}else{if(this.current===this.link){if(d){d.replaceChild(this.span,this.current);this.current=this.span;}}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current);this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.setPage(this.paginator.getNextPage());}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.PreviousPageLink=function(d){this.paginator=d;d.subscribe("recordOffsetChange",this.update,this,true);d.subscribe("rowsPerPageChange",this.update,this,true);d.subscribe("totalRecordsChange",this.update,this,true);d.subscribe("destroy",this.destroy,this,true);d.subscribe("previousPageLinkLabelChange",this.update,this,true);d.subscribe("previousPageLinkClassChange",this.update,this,true);};c.ui.PreviousPageLink.init=function(d){d.setAttributeConfig("previousPageLinkLabel",{value:"&lt; prev",validator:b.isString});d.setAttributeConfig("previousPageLinkClass",{value:"yui-pg-previous",validator:b.isString});d.setAttributeConfig("previousPageLinkTitle",{value:"Previous Page",validator:b.isString});};c.ui.PreviousPageLink.prototype={current:null,link:null,span:null,render:function(e){var f=this.paginator,h=f.get("previousPageLinkClass"),d=f.get("previousPageLinkLabel"),g=f.get("previousPageLinkTitle");this.link=document.createElement("a");this.span=document.createElement("span");a(this.link,e+"-prev-link");this.link.href="#";this.link.className=h;this.link.innerHTML=d;this.link.title=g;YAHOO.util.Event.on(this.link,"click",this.onClick,this,true);a(this.span,e+"-prev-span");this.span.className=h;this.span.innerHTML=d;this.current=f.getCurrentPage()>1?this.link:this.span;return this.current;},update:function(f){if(f&&f.prevValue===f.newValue){return;}var d=this.current?this.current.parentNode:null;if(this.paginator.getCurrentPage()>1){if(d&&this.current===this.span){d.replaceChild(this.link,this.current);this.current=this.link;}}else{if(d&&this.current===this.link){d.replaceChild(this.span,this.current);this.current=this.span;}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current);this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.setPage(this.paginator.getPreviousPage());}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.RowsPerPageDropdown=function(d){this.paginator=d;d.subscribe("rowsPerPageChange",this.update,this,true);d.subscribe("rowsPerPageOptionsChange",this.rebuild,this,true);d.subscribe("totalRecordsChange",this._handleTotalRecordsChange,this,true);d.subscribe("destroy",this.destroy,this,true);d.subscribe("rowsPerPageDropdownClassChange",this.rebuild,this,true);};c.ui.RowsPerPageDropdown.init=function(d){d.setAttributeConfig("rowsPerPageOptions",{value:[],validator:b.isArray});d.setAttributeConfig("rowsPerPageDropdownClass",{value:"yui-pg-rpp-options",validator:b.isString});};c.ui.RowsPerPageDropdown.prototype={select:null,all:null,render:function(d){this.select=document.createElement("select");a(this.select,d+"-rpp");this.select.className=this.paginator.get("rowsPerPageDropdownClass");this.select.title="Rows per page";YAHOO.util.Event.on(this.select,"change",this.onChange,this,true);this.rebuild();return this.select;},rebuild:function(m){var d=this.paginator,g=this.select,n=d.get("rowsPerPageOptions"),f,l,h,j,k;this.all=null;for(j=0,k=n.length;j<k;++j){l=n[j];f=g.options[j]||g.appendChild(document.createElement("option"));h=b.isValue(l.value)?l.value:l;f.text=b.isValue(l.text)?l.text:l;if(b.isString(h)&&h.toLowerCase()==="all"){this.all=f;f.value=d.get("totalRecords");}else{f.value=h;}}while(g.options.length>n.length){g.removeChild(g.firstChild);}this.update();},update:function(j){if(j&&j.prevValue===j.newValue){return;}var h=this.paginator.get("rowsPerPage")+"",f=this.select.options,g,d;for(g=0,d=f.length;g<d;++g){if(f[g].value===h){f[g].selected=true;break;}}},onChange:function(d){this.paginator.setRowsPerPage(parseInt(this.select.options[this.select.selectedIndex].value,10));},_handleTotalRecordsChange:function(d){if(!this.all||(d&&d.prevValue===d.newValue)){return;}this.all.value=d.newValue;if(this.all.selected){this.paginator.set("rowsPerPage",d.newValue);}},destroy:function(){YAHOO.util.Event.purgeElement(this.select);this.select.parentNode.removeChild(this.select);this.select=null;}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.JumpToPageDropdown=function(d){this.paginator=d;d.subscribe("rowsPerPageChange",this.rebuild,this,true);d.subscribe("rowsPerPageOptionsChange",this.rebuild,this,true);d.subscribe("pageChange",this.update,this,true);d.subscribe("totalRecordsChange",this.rebuild,this,true);
+d.subscribe("destroy",this.destroy,this,true);};c.ui.JumpToPageDropdown.init=function(d){d.setAttributeConfig("jumpToPageDropdownClass",{value:"yui-pg-jtp-options",validator:b.isString});};c.ui.JumpToPageDropdown.prototype={select:null,render:function(d){this.select=document.createElement("select");a(this.select,d+"-jtp");this.select.className=this.paginator.get("jumpToPageDropdownClass");this.select.title="Jump to page";YAHOO.util.Event.on(this.select,"change",this.onChange,this,true);this.rebuild();return this.select;},rebuild:function(l){var k=this.paginator,j=this.select,f=k.getTotalPages(),h,g,d;this.all=null;for(g=0,d=f;g<d;++g){h=j.options[g]||j.appendChild(document.createElement("option"));h.innerHTML=g+1;h.value=g+1;}for(g=f,d=j.options.length;g<d;g++){j.removeChild(j.lastChild);}this.update();},update:function(j){if(j&&j.prevValue===j.newValue){return;}var h=this.paginator.getCurrentPage()+"",f=this.select.options,g,d;for(g=0,d=f.length;g<d;++g){if(f[g].value===h){f[g].selected=true;break;}}},onChange:function(d){this.paginator.setPage(parseInt(this.select.options[this.select.selectedIndex].value,false));},destroy:function(){YAHOO.util.Event.purgeElement(this.select);this.select.parentNode.removeChild(this.select);this.select=null;}};})();YAHOO.register("paginator",YAHOO.widget.Paginator,{version:"2.9.0",build:"2800"});
--- a/rhodecode/templates/_data_table/_dt_elements.html	Sat May 19 14:54:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-## DATA TABLE RE USABLE ELEMENTS
-## usage:
-## <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
-
-<%def name="quick_menu(repo_name)">
-  <ul class="menu_items hidden">
-    <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
-    <li>
-       <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
-       <span class="icon">
-           <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
-       </span>
-       <span>${_('Summary')}</span>
-       </a>
-    </li>
-    <li>
-       <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
-       <span class="icon">
-           <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
-       </span>
-       <span>${_('Changelog')}</span>
-       </a>
-    </li>
-    <li>
-       <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
-       <span class="icon">
-           <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
-       </span>
-       <span>${_('Files')}</span>
-       </a>
-    </li>
-    <li>
-       <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
-       <span class="icon">
-           <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
-       </span>
-       <span>${_('Fork')}</span>
-       </a>
-    </li>
-  </ul>
-</%def>
-
-<%def name="repo_name(name,rtype,private,fork_of,short_name=False, admin=False)">
-    <%
-    def get_name(name,short_name=short_name):
-      if short_name:
-        return name.split('/')[-1]
-      else:
-        return name
-    %>
-  <div style="white-space: nowrap">
-   ##TYPE OF REPO
-   %if h.is_hg(rtype):
-     <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
-   %elif h.is_git(rtype):
-     <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
-   %endif
-
-   ##PRIVATE/PUBLIC
-   %if private:
-      <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
-   %else:
-      <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
-   %endif
-
-   ##NAME
-   %if admin:
-    ${h.link_to(get_name(name),h.url('edit_repo',repo_name=name),class_="repo_name")}
-   %else:
-    ${h.link_to(get_name(name),h.url('summary_home',repo_name=name),class_="repo_name")}
-   %endif
-   %if fork_of:
-        <a href="${h.url('summary_home',repo_name=fork_of)}">
-        <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
-   %endif
-  </div>
-</%def>
-
-
-
-<%def name="revision(name,rev,tip,author,last_msg)">
-  <div>
-  %if rev >= 0:
-      <pre><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></pre>
-  %else:
-      ${_('No changesets yet')}
-  %endif
-  </div>
-</%def>
--- a/rhodecode/templates/admin/admin_log.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/admin_log.html	Sun Sep 02 21:19:54 2012 +0200
@@ -12,19 +12,20 @@
 	%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)[0]}
+		<td>${h.action_parser(l)[0]()}
 		  <div class="journal_action_params">
-		  ${h.literal(h.action_parser(l)[1]())}</div>
+            ${h.literal(h.action_parser(l)[1]())}
+          </div>
 		</td>
 		<td>
-		%if l.repository:
+		%if l.repository is not None:
 		  ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
 		%else:
 		  ${l.repository_name}
 		%endif
 		</td>
 
-		<td>${l.action_date}</td>
+		<td>${h.fmt_date(l.action_date)}</td>
 		<td>${l.user_ip}</td>
 	</tr>
 	%endfor
--- a/rhodecode/templates/admin/ldap/ldap.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/ldap/ldap.html	Sun Sep 02 21:19:54 2012 +0200
@@ -86,7 +86,7 @@
             </div>
 
             <div class="buttons">
-            ${h.submit('save',_('Save'),class_="ui-button")}
+            ${h.submit('save',_('Save'),class_="ui-btn large")}
             </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/notifications/notifications.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/notifications/notifications.html	Sun Sep 02 21:19:54 2012 +0200
@@ -24,33 +24,42 @@
         ##    </li>
         ##</ul>
     </div>
-    %if c.notifications:
+
+      <div style="padding:14px 18px;text-align: right;float:left">
+      <span id='all' class="ui-btn"><a href="${h.url.current()}">${_('All')}</a></span>
+      <span id='comment' class="ui-btn"><a href="${h.url.current(type=c.comment_type)}">${_('Comments')}</a></span>
+      <span id='pull_request' class="ui-btn"><a href="${h.url.current(type=c.pull_request_type)}">${_('Pull requests')}</a></span>
+      </div>
+      %if c.notifications:
       <div style="padding:14px 18px;text-align: right;float:right">
       <span id='mark_all_read' class="ui-btn">${_('Mark all read')}</span>
       </div>
-    %endif
+      %endif
   <div id='notification_data'>
     <%include file='notifications_data.html'/>
   </div>
 </div>
 <script type="text/javascript">
-var url_del = "${url('notification', notification_id='__NOTIFICATION_ID__')}";
-YUE.on(YUQ('.delete-notification'),'click',function(e){
- var notification_id = e.currentTarget.id;
- deleteNotification(url_del,notification_id)
-})
+var url_action = "${url('notification', notification_id='__NOTIFICATION_ID__')}";
+var run = function(){
+  YUE.on(YUQ('.delete-notification'),'click',function(e){
+   var notification_id = e.currentTarget.id;
+   deleteNotification(url_action,notification_id)
+  })
+  YUE.on(YUQ('.read-notification'),'click',function(e){
+     var notification_id = e.currentTarget.id;
+     readNotification(url_action,notification_id)
+  })
+}
+run()
 YUE.on('mark_all_read','click',function(e){
-    var url = "${h.url('notifications_mark_all_read')}";
-    ypjax(url,'notification_data',function(){
-    	var notification_counter = YUD.get('notification_counter');
-    	if(notification_counter){
-    		notification_counter.innerHTML=0;
-    	}
-    	YUE.on(YUQ('.delete-notification'),'click',function(e){
-    		 var notification_id = e.currentTarget.id;
-    		 deleteNotification(url_del,notification_id)
-    	})
-    });
+    var url = "${h.url('notifications_mark_all_read', **request.GET.mixed())}";
+    ypjax(url,'notification_data',function(){run()});
 })
+
+var current_filter = "${c.current_filter}";
+if (YUD.get(current_filter)){
+	YUD.addClass(current_filter, 'active');
+}
 </script>
 </%def>
--- a/rhodecode/templates/admin/notifications/notifications_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/notifications/notifications_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -3,18 +3,14 @@
 <%
 unread = lambda n:{False:'unread'}.get(n)
 %>
-<div class="notification-paginator">
-  <div class="pagination-wh pagination-left">
-  ${c.notifications.pager('$link_previous ~2~ $link_next')}
-  </div>
-</div>
+
 
 <div class="notification-list  notification-table">
 %for notification in c.notifications:
   <div id="notification_${notification.notification.notification_id}" class="container ${unread(notification.read)}">
     <div class="notification-header">
       <div class="gravatar">
-          <img alt="gravatar" src="${h.gravatar_url(h.email(notification.notification.created_by_user.email),24)}"/>
+          <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(notification.notification.created_by_user.email),24)}"/>
       </div>
       <div class="desc ${unread(notification.read)}">
       <a href="${url('notification', notification_id=notification.notification.notification_id)}">${notification.notification.description}</a>
@@ -22,6 +18,11 @@
       <div class="delete-notifications">
         <span id="${notification.notification.notification_id}" class="delete-notification delete_icon action"></span>
       </div>
+      %if not notification.read:
+      <div class="read-notifications">
+        <span id="${notification.notification.notification_id}" class="read-notification accept_icon action"></span>
+      </div>
+      %endif
     </div>
     <div class="notification-subject">${h.literal(notification.notification.subject)}</div>
   </div>
@@ -30,7 +31,7 @@
 
 <div class="notification-paginator">
   <div class="pagination-wh pagination-left">
-  ${c.notifications.pager('$link_previous ~2~ $link_next')}
+  ${c.notifications.pager('$link_previous ~2~ $link_next',**request.GET.mixed())}
   </div>
 </div>
 
--- a/rhodecode/templates/admin/notifications/show_notification.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/notifications/show_notification.html	Sun Sep 02 21:19:54 2012 +0200
@@ -30,7 +30,7 @@
       <div id="notification_${c.notification.notification_id}">
         <div class="notification-header">
           <div class="gravatar">
-              <img alt="gravatar" src="${h.gravatar_url(h.email(c.notification.created_by_user.email),24)}"/>
+              <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(c.notification.created_by_user.email),24)}"/>
           </div>
           <div class="desc">
               ${c.notification.description}
--- a/rhodecode/templates/admin/permissions/permissions.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/permissions/permissions.html	Sun Sep 02 21:19:54 2012 +0200
@@ -37,7 +37,7 @@
                 </div>
             </div>
 			<div class="field">
-				<div class="label label-select">
+				<div class="label">
 					<label for="default_perm">${_('Repository permission')}:</label>
 				</div>
 				<div class="select">
@@ -66,9 +66,16 @@
 					${h.select('default_create','',c.create_choices)}
 				</div>
              </div>
-
+             <div class="field">
+                <div class="label">
+                    <label for="default_fork">${_('Repository forking')}:</label>
+                </div>
+                <div class="select">
+                    ${h.select('default_fork','',c.fork_choices)}
+                </div>
+             </div>
 	        <div class="buttons">
-	        ${h.submit('set',_('set'),class_="ui-button")}
+	        ${h.submit('set',_('set'),class_="ui-btn large")}
 	        </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/repos/repo_add_base.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos/repo_add_base.html	Sun Sep 02 21:19:54 2012 +0200
@@ -30,7 +30,7 @@
              </div>
              <div class="input">
                  ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
-                 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
+                 <span class="help-block">${_('Optionaly select a group to put this repository into.')}</span>
              </div>
          </div>
         <div class="field">
@@ -42,6 +42,15 @@
                 <span class="help-block">${_('Type of repository to create.')}</span>
             </div>
          </div>
+         <div class="field">
+            <div class="label">
+                <label for="landing_rev">${_('Landing revision')}:</label>
+            </div>
+            <div class="input">
+                ${h.select('landing_rev','',c.landing_revs,class_="medium")}
+                <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
+            </div>
+        </div>
         <div class="field">
             <div class="label label-textarea">
                 <label for="description">${_('Description')}:</label>
@@ -61,7 +70,7 @@
             </div>
          </div>
         <div class="buttons">
-          ${h.submit('add',_('add'),class_="ui-button")}
+          ${h.submit('add',_('add'),class_="ui-btn large")}
         </div>
     </div>
 </div>
--- a/rhodecode/templates/admin/repos/repo_edit.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos/repo_edit.html	Sun Sep 02 21:19:54 2012 +0200
@@ -62,6 +62,15 @@
                 </div>
             </div>
             <div class="field">
+                <div class="label">
+                    <label for="landing_rev">${_('Landing revision')}:</label>
+                </div>
+                <div class="input">
+                    ${h.select('landing_rev','',c.landing_revs,class_="medium")}
+                    <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
+                </div>
+            </div>
+            <div class="field">
                 <div class="label label-textarea">
                     <label for="description">${_('Description')}:</label>
                 </div>
@@ -99,6 +108,15 @@
                 </div>
             </div>
             <div class="field">
+                <div class="label label-checkbox">
+                    <label for="enable_locking">${_('Enable locking')}:</label>
+                </div>
+                <div class="checkboxes">
+                    ${h.checkbox('enable_locking',value="True")}
+                    <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
+                </div>
+            </div>            
+            <div class="field">
                 <div class="label">
                     <label for="user">${_('Owner')}:</label>
                 </div>
@@ -120,8 +138,8 @@
                 </div>
 
                 <div class="buttons">
-                  ${h.submit('save','Save',class_="ui-button")}
-                  ${h.reset('reset','Reset',class_="ui-button")}
+                  ${h.submit('save',_('Save'),class_="ui-btn large")}
+                  ${h.reset('reset',_('Reset'),class_="ui-btn large")}
                 </div>
             </div>
     </div>
@@ -187,13 +205,49 @@
                 </div>
                <div class="field" style="border:none;color:#888">
                <ul>
-                    <li>${_('''All actions made on this repository will be accessible to everyone in public journal''')}
+                    <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
                     </li>
                </ul>
                </div>
         </div>
         ${h.end_form()}
 
+        <h3>${_('Locking')}</h3>
+        ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
+        <div class="form">
+           <div class="fields">
+              %if c.repo_info.locked[0]:
+               ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
+               ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
+              %else:
+                ${h.submit('set_lock',_('lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
+                ${_('Repository is not locked')}
+              %endif
+           </div>
+           <div class="field" style="border:none;color:#888">
+           <ul>
+                <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
+                </li>
+           </ul>
+           </div>           
+        </div>
+        ${h.end_form()}
+
+        <h3>${_('Set as fork of')}</h3>
+        ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
+        <div class="form">
+           <div class="fields">
+               ${h.select('id_fork_of','',c.repos_list,class_="medium")}
+               ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
+           </div>
+               <div class="field" style="border:none;color:#888">
+               <ul>
+                    <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
+               </ul>
+               </div>
+        </div>        
+        ${h.end_form()}
+        
         <h3>${_('Delete')}</h3>
         ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
         <div class="form">
@@ -208,24 +262,7 @@
            </ul>
            </div>
         </div>
-        ${h.end_form()}
-
-        <h3>${_('Set as fork')}</h3>
-        ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
-        <div class="form">
-           <div class="fields">
-               ${h.select('id_fork_of','',c.repos_list,class_="medium")}
-               ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
-           </div>
-               <div class="field" style="border:none;color:#888">
-               <ul>
-                    <li>${_('''Manually set this repository as a fork of another''')}</li>
-               </ul>
-               </div>
-        </div>
-        ${h.end_form()}
-
+        ${h.end_form()}        
 </div>
 
-
 </%def>
--- a/rhodecode/templates/admin/repos/repo_edit_perms.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos/repo_edit_perms.html	Sun Sep 02 21:19:54 2012 +0200
@@ -16,7 +16,7 @@
                     ${_('private repository')}
                     </span>
                 </td>
-                <td class="private_repo_msg"><img style="vertical-align:bottom" src="${h.url('/images/icons/user.png')}"/>${r2p.user.username}</td>
+                <td class="private_repo_msg"><img style="vertical-align:bottom" src="${h.url('/images/icons/user.png')}"/>${_('default')}</td>
             </tr>
         %else:
         <tr id="id${id(r2p.user.username)}">
@@ -25,7 +25,7 @@
             <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.write')}</td>
             <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.admin')}</td>
             <td style="white-space: nowrap;">
-                <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username}
+                <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')}
             </td>
             <td>
               %if r2p.user.username !='default':
@@ -46,7 +46,12 @@
             <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.write')}</td>
             <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.admin')}</td>
             <td style="white-space: nowrap;">
-                <img class="perm-gravatar" src="${h.url('/images/icons/group.png')}"/>${g2p.users_group.users_group_name}
+                <img class="perm-gravatar" src="${h.url('/images/icons/group.png')}"/>
+                %if h.HasPermissionAny('hg.admin')():
+                 <a href="${h.url('edit_users_group',id=g2p.users_group.users_group_id)}">${g2p.users_group.users_group_name}</a>
+                %else:
+                 ${g2p.users_group.users_group_name}
+                %endif
             </td>
             <td>
                 <span class="delete_icon action_button" onclick="ajaxActionUsersGroup(${g2p.users_group.users_group_id},'${'id%s'%id(g2p.users_group.users_group_name)}')">
@@ -55,20 +60,23 @@
             </td>
         </tr>
     %endfor
-    <tr id="add_perm_input">
-        <td>${h.radio('perm_new_member','repository.none')}</td>
-        <td>${h.radio('perm_new_member','repository.read')}</td>
-        <td>${h.radio('perm_new_member','repository.write')}</td>
-        <td>${h.radio('perm_new_member','repository.admin')}</td>
-        <td class='ac'>
-            <div class="perm_ac" id="perm_ac">
-                ${h.text('perm_new_member_name',class_='yui-ac-input')}
-                ${h.hidden('perm_new_member_type')}
-                <div id="perm_container"></div>
-            </div>
-        </td>
-        <td></td>
-    </tr>
+    <%
+    _tmpl = h.literal("""' \
+        <td><input type="radio" value="repository.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="repository.read" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="repository.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="repository.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td class="ac"> \
+            <div class="perm_ac" id="perm_ac_{0}"> \
+                <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
+                <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden">  \
+                <div id="perm_container_{0}"></div> \
+            </div> \
+        </td> \
+        <td></td>'""")
+    %>    
+    ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'    
+    <tr class="new_members last_new_member" id="add_perm_input"></tr>
     <tr>
         <td colspan="6">
             <span id="add_perm" class="add_icon" style="cursor: pointer;">
@@ -113,16 +121,8 @@
         YUD.setStyle('add_perm_input', 'display', 'none');
     }
     YAHOO.util.Event.addListener('add_perm', 'click', function () {
-        YUD.setStyle('add_perm_input', 'display', '');
-        YUD.setStyle('add_perm', 'opacity', '0.6');
-        YUD.setStyle('add_perm', 'cursor', 'default');
+        addPermAction(${_tmpl}, ${c.users_array|n}, ${c.users_groups_array|n});
     });
-    MembersAutoComplete(
-    		  ${c.users_array|n},
-    		  ${c.users_groups_array|n},
-    		  "${_('Group')}",
-    		  "${_('members')}"
-    		);
 });
 
 </script>
--- a/rhodecode/templates/admin/repos/repos.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos/repos.html	Sun Sep 02 21:19:54 2012 +0200
@@ -5,9 +5,8 @@
     ${_('Repositories administration')} - ${c.rhodecode_name}
 </%def>
 
-
 <%def name="breadcrumbs_links()">
-    ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Repositories')}
+    <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="repo_count">0</span> ${_('repositories')}
 </%def>
 <%def name="page_nav()">
 	${self.menu('admin')}
@@ -23,102 +22,114 @@
           </li>
         </ul>
     </div>
-
-    <div class="table">
-        <div id='repos_list_wrap' class="yui-skin-sam">
-        <%cnt=0%>
-        <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
-
-        <table id="repos_list">
-         <thead>
-          <tr>
-            <th class="left"></th>
-  	        <th class="left">${_('Name')}</th>
-  	        <th class="left">${_('Description')}</th>
-  	        <th class="left">${_('Last change')}</th>
-  	        <th class="left">${_('Tip')}</th>
-  	        <th class="left">${_('Contact')}</th>
-            <th class="left">${_('Action')}</th>
-          </tr>
-         </thead>
+    <div class="table yui-skin-sam" id="repos_list_wrap"></div>
+    <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
 
-          %for cnt,repo in enumerate(c.repos_list):
-          <tr class="parity${(cnt+1)%2}">
-              <td class="quick_repo_menu">
-                ${dt.quick_menu(repo['name'])}
-              </td>
-              <td class="reponame">
-                ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'), admin=True)}
-              </td>
-              ##DESCRIPTION
-              <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
-                 ${h.truncate(repo['description'],60)}</span>
-              </td>
-              ##LAST CHANGE
-              <td>
-                <span class="tooltip" title="${repo['last_change']}">${h.age(repo['last_change'])}</span>
-              </td>
-              ##LAST REVISION
-              <td>
-                  ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
-              </td>
-            <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
-              <td>
-                ${h.form(url('repo', 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: %s') % repo['name']+"');")}
-                ${h.end_form()}
-              </td>
-          </tr>
-          %endfor
-        </table>
-        </div>
-    </div>
+
 </div>
 <script>
+  var url = "${h.url('formatted_users', format='json')}";
+  var data = ${c.data|n};
+  var myDataSource = new YAHOO.util.DataSource(data);
+  myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
+
+  myDataSource.responseSchema = {
+      resultsList: "records",
+      fields: [
+         {key:"menu"},
+         {key:"raw_name"},
+         {key:"name"},
+         {key:"desc"},
+         {key:"owner"},
+         {key:"action"},
+      ]
+   };
+  myDataSource.doBeforeCallback = function(req,raw,res,cb) {
+      // This is the filter function
+      var data     = res.results || [],
+          filtered = [],
+          i,l;
+
+      if (req) {
+          req = req.toLowerCase();
+          for (i = 0; i<data.length; i++) {
+              var pos = data[i].raw_name.toLowerCase().indexOf(req)
+              if (pos != -1) {
+                  filtered.push(data[i]);
+              }
+          }
+          res.results = filtered;
+      }
+      YUD.get('repo_count').innerHTML = res.results.length;
+      return res;
+  }
 
   // main table sorting
   var myColumnDefs = [
       {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
       {key:"name",label:"${_('Name')}",sortable:true,
-          sortOptions: { sortFunction: nameSort }},
+    	  sortOptions: { sortFunction: nameSort }},
       {key:"desc",label:"${_('Description')}",sortable:true},
-      {key:"last_change",label:"${_('Last Change')}",sortable:true,
-          sortOptions: { sortFunction: ageSort }},
-      {key:"tip",label:"${_('Tip')}",sortable:true,
-          sortOptions: { sortFunction: revisionSort }},
       {key:"owner",label:"${_('Owner')}",sortable:true},
       {key:"action",label:"${_('Action')}",sortable:false},
   ];
 
-  var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
-
-  myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
+  var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
+    sortedBy:{key:"name",dir:"asc"},
+    paginator: new YAHOO.widget.Paginator({
+        rowsPerPage: 15,
+        alwaysVisible: false,
+        template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
+        pageLinks: 5,
+        containerClass: 'pagination-wh',
+        currentPageClass: 'pager_curpage',
+        pageLinkClass: 'pager_link',
+        nextPageLinkLabel: '&gt;',
+        previousPageLinkLabel: '&lt;',
+        firstPageLinkLabel: '&lt;&lt;',
+        lastPageLinkLabel: '&gt;&gt;',
+        containers:['user-paginator']
+    }),
 
-  myDataSource.responseSchema = {
-      fields: [
-          {key:"menu"},
-          {key:"name"},
-          {key:"desc"},
-          {key:"last_change"},
-          {key:"tip"},
-          {key:"owner"},
-          {key:"action"},
-      ]
-  };
-
-  var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
-          {
-            sortedBy:{key:"name",dir:"asc"},
-            MSG_SORTASC:"${_('Click to sort ascending')}",
-            MSG_SORTDESC:"${_('Click to sort descending')}",
-            MSG_EMPTY:"${_('No records found.')}",
-            MSG_ERROR:"${_('Data error.')}",
-            MSG_LOADING:"${_('Loading...')}",
-          }
+    MSG_SORTASC:"${_('Click to sort ascending')}",
+    MSG_SORTDESC:"${_('Click to sort descending')}",
+    MSG_EMPTY:"${_('No records found.')}",
+    MSG_ERROR:"${_('Data error.')}",
+    MSG_LOADING:"${_('Loading...')}",
+  }
   );
   myDataTable.subscribe('postRenderEvent',function(oArgs) {
       tooltip_activate();
       quick_repo_menu();
   });
+
+  var filterTimeout = null;
+
+  updateFilter  = function () {
+      // Reset timeout
+      filterTimeout = null;
+
+      // Reset sort
+      var state = myDataTable.getState();
+          state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
+
+      // Get filtered data
+      myDataSource.sendRequest(YUD.get('q_filter').value,{
+          success : myDataTable.onDataReturnInitializeTable,
+          failure : myDataTable.onDataReturnInitializeTable,
+          scope   : myDataTable,
+          argument: state
+      });
+
+  };
+  YUE.on('q_filter','click',function(){
+      YUD.get('q_filter').value = '';
+   });
+
+  YUE.on('q_filter','keyup',function (e) {
+      clearTimeout(filterTimeout);
+      filterTimeout = setTimeout(updateFilter,600);
+  });
 </script>
+
 </%def>
--- a/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html	Sun Sep 02 21:19:54 2012 +0200
@@ -15,7 +15,7 @@
             <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write')}</td>
             <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin')}</td>
             <td style="white-space: nowrap;">
-                <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username}
+                <img class="perm-gravatar" src="${h.gravatar_url(r2p.user.email,14)}"/>${r2p.user.username if r2p.user.username != 'default' else _('default')}
             </td>
             <td>
               %if r2p.user.username !='default':
@@ -44,20 +44,23 @@
             </td>
         </tr>
     %endfor
-    <tr id="add_perm_input">
-        <td>${h.radio('perm_new_member','group.none')}</td>
-        <td>${h.radio('perm_new_member','group.read')}</td>
-        <td>${h.radio('perm_new_member','group.write')}</td>
-        <td>${h.radio('perm_new_member','group.admin')}</td>
-        <td class='ac'>
-            <div class="perm_ac" id="perm_ac">
-                ${h.text('perm_new_member_name',class_='yui-ac-input')}
-                ${h.hidden('perm_new_member_type')}
-                <div id="perm_container"></div>
-            </div>
-        </td>
-        <td></td>
-    </tr>
+<%
+    _tmpl = h.literal("""' \
+        <td><input type="radio" value="group.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="group.read" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="group.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td><input type="radio" value="group.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
+        <td class="ac"> \
+            <div class="perm_ac" id="perm_ac_{0}"> \
+                <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
+                <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden">  \
+                <div id="perm_container_{0}"></div> \
+            </div> \
+        </td> \
+        <td></td>'""")
+    %>    
+    ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'    
+    <tr class="new_members last_new_member" id="add_perm_input"></tr>
     <tr>
         <td colspan="6">
             <span id="add_perm" class="add_icon" style="cursor: pointer;">
@@ -102,16 +105,8 @@
         YUD.setStyle('add_perm_input', 'display', 'none');
     }
     YAHOO.util.Event.addListener('add_perm', 'click', function () {
-        YUD.setStyle('add_perm_input', 'display', '');
-        YUD.setStyle('add_perm', 'opacity', '0.6');
-        YUD.setStyle('add_perm', 'cursor', 'default');
+    	addPermAction(${_tmpl}, ${c.users_array|n}, ${c.users_groups_array|n});
     });
-    MembersAutoComplete(
-            ${c.users_array|n},
-            ${c.users_groups_array|n},
-            "${_('Group')}",
-            "${_('members')}"
-          );
 });
 
 </script>
--- a/rhodecode/templates/admin/repos_groups/repos_groups_add.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_add.html	Sun Sep 02 21:19:54 2012 +0200
@@ -55,7 +55,7 @@
              </div>
 
             <div class="buttons">
-              ${h.submit('save',_('save'),class_="ui-button")}
+              ${h.submit('save',_('save'),class_="ui-btn large")}
             </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/repos_groups/repos_groups_edit.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_edit.html	Sun Sep 02 21:19:54 2012 +0200
@@ -60,11 +60,19 @@
                 <div class="input">
                     <%include file="repos_group_edit_perms.html"/>
                 </div>
-
             </div>
+            <div class="field">
+                <div class="label label-checkbox">
+                    <label for="enable_locking">${_('Enable locking')}:</label>
+                </div>
+                <div class="checkboxes">
+                    ${h.checkbox('enable_locking',value="True")}
+                    <span class="help-block">${_('Enable lock-by-pulling on group. This option will be applied to all other groups and repositories inside')}</span>
+                </div>
+            </div>    
             <div class="buttons">
-              ${h.submit('save',_('Save'),class_="ui-button")}
-              ${h.reset('reset',_('Reset'),class_="ui-button")}
+              ${h.submit('save',_('Save'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
             </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/repos_groups/repos_groups_show.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/repos_groups/repos_groups_show.html	Sun Sep 02 21:19:54 2012 +0200
@@ -51,7 +51,7 @@
                       <td><b>${gr.repositories.count()}</b></td>
 		               <td>
 		                 ${h.form(url('repos_group', id=gr.group_id),method='delete')}
-		                   ${h.submit('remove_%s' % gr.name,'delete',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this group: %s') % gr.name+"');")}
+		                   ${h.submit('remove_%s' % gr.name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this group: %s') % gr.name+"');")}
 		                 ${h.end_form()}
 		               </td>
                   </tr>
--- a/rhodecode/templates/admin/settings/hooks.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/settings/hooks.html	Sun Sep 02 21:19:54 2012 +0200
@@ -70,7 +70,7 @@
             </div>
           </div>
           <div class="buttons" style="margin-left:280px">
-             ${h.submit('save',_('Save'),class_="ui-button")}
+             ${h.submit('save',_('Save'),class_="ui-btn large")}
           </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/settings/settings.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/settings/settings.html	Sun Sep 02 21:19:54 2012 +0200
@@ -38,11 +38,12 @@
 		                <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
 		                ${_('destroy old data')}</span> </label>
 		            </div>
+                    <span class="help-block">${_('Rescan repositories location for new repositories. Also deletes obsolete if `destroy` flag is checked ')}</span>
 		        </div>
 			</div>
 
             <div class="buttons">
-            ${h.submit('rescan',_('Rescan repositories'),class_="ui-button")}
+            ${h.submit('rescan',_('Rescan repositories'),class_="ui-btn large")}
             </div>
         </div>
     </div>
@@ -67,7 +68,7 @@
             </div>
 
             <div class="buttons">
-            ${h.submit('reindex',_('Reindex'),class_="ui-button")}
+            ${h.submit('reindex',_('Reindex'),class_="ui-btn large")}
             </div>
         </div>
     </div>
@@ -108,15 +109,72 @@
             </div>
 
             <div class="buttons">
-                ${h.submit('save',_('Save settings'),class_="ui-button")}
-                ${h.reset('reset',_('Reset'),class_="ui-button")}
+                ${h.submit('save',_('Save settings'),class_="ui-btn large")}
+                ${h.reset('reset',_('Reset'),class_="ui-btn large")}
            </div>
         </div>
     </div>
     ${h.end_form()}
 
-    <h3>${_('Mercurial settings')}</h3>
-    ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
+    <h3>${_('Visualisation settings')}</h3>
+    ${h.form(url('admin_setting', setting_id='visual'),method='put')}
+    <div class="form">
+        <!-- fields -->
+
+        <div class="fields">
+
+             <div class="field">
+                <div class="label label-checkbox">
+                    <label>${_('Icons')}:</label>
+                </div>
+                <div class="checkboxes">
+                    <div class="checkbox">
+                        ${h.checkbox('rhodecode_show_public_icon','True')}
+                        <label for="rhodecode_show_public_icon">${_('Show public repo icon on repositories')}</label>
+                    </div>
+                    <div class="checkbox">
+                        ${h.checkbox('rhodecode_show_private_icon','True')}
+                        <label for="rhodecode_show_private_icon">${_('Show private repo icon on repositories')}</label>
+                    </div>
+                 </div>
+             </div>
+
+             <div class="field">
+                <div class="label label-checkbox">
+                    <label>${_('Meta-Tagging')}:</label>
+                </div>
+                <div class="checkboxes">
+                    <div class="checkbox">
+                        ${h.checkbox('rhodecode_stylify_metatags','True')}
+                        <label for="rhodecode_stylify_metatags">${_('Stylify recognised metatags:')}</label>
+                    </div>
+                    <div style="padding-left: 20px;">
+                        <ul> <!-- Fix style here -->
+                            <li>[featured] <span class="metatag" tag="featured">featured</span></li>
+                            <li>[stale] <span class="metatag" tag="stale">stale</span></li>
+                            <li>[dead] <span class="metatag" tag="dead">dead</span></li>
+                            <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
+                            <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>                            
+                            <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
+                            <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
+                            <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
+                        </ul>
+                    </div>
+                 </div>
+             </div>
+
+             <div class="buttons">
+                 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
+                 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
+             </div>
+
+        </div>
+    </div>
+    ${h.end_form()}
+
+
+    <h3>${_('VCS settings')}</h3>
+    ${h.form(url('admin_setting', setting_id='vcs'),method='put')}
     <div class="form">
         <!-- fields -->
 
@@ -129,8 +187,9 @@
                 <div class="checkboxes">
 					<div class="checkbox">
 						${h.checkbox('web_push_ssl','true')}
-						<label for="web_push_ssl">${_('require ssl for pushing')}</label>
+						<label for="web_push_ssl">${_('require ssl for vcs operations')}</label>
 					</div>
+                    <span class="help-block">${_('RhodeCode will require SSL for pushing or pulling. If SSL is missing it will return HTTP Error 406: Not Acceptable')}</span>
 				</div>
              </div>
 
@@ -148,18 +207,39 @@
 						<label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
 					</div>
                     <div class="checkbox">
-                        ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
-                        <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
+                        ${h.checkbox('hooks_changegroup_push_logger','True')}
+                        <label for="hooks_changegroup_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>
+                        ${h.checkbox('hooks_outgoing_pull_logger','True')}
+                        <label for="hooks_outgoing_pull_logger">${_('Log user pull commands')}</label>
                     </div>
 				</div>
                 <div class="input" style="margin-top:10px">
                     ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'),class_="ui-btn")}
                 </div>
              </div>
+             <div class="field">
+                <div class="label label-checkbox">
+                    <label>${_('Mercurial Extensions')}:</label>
+                </div>
+                <div class="checkboxes">
+                    <div class="checkbox">
+                        ${h.checkbox('extensions_largefiles','True')}
+                        <label for="extensions_hgsubversion">${_('largefiles extensions')}</label>
+                    </div>
+                    <div class="checkbox">
+                        ${h.checkbox('extensions_hgsubversion','True')}
+                        <label for="extensions_hgsubversion">${_('hgsubversion extensions')}</label>
+                    </div>
+                    <span class="help-block">${_('Requires hgsubversion library installed. Allows clonning from svn remote locations')}</span>
+                    ##<div class="checkbox">
+                    ##    ${h.checkbox('extensions_hggit','True')}
+                    ##    <label for="extensions_hggit">${_('hg-git extensions')}</label>
+                    ##</div>
+                    ##<span class="help-block">${_('Requires hg-git library installed. Allows clonning from git remote locations')}</span>                    
+                </div>
+             </div>             
             <div class="field">
                 <div class="label">
                     <label for="paths_root_path">${_('Repositories location')}:</label>
@@ -169,12 +249,13 @@
 					<span id="path_unlock" class="tooltip"
 						title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
 		                ${_('unlock')}</span>
+                    <span class="help-block">${_('Location where repositories are stored. After changing this value a restart, and rescan is required')}</span>
                 </div>
             </div>
 
             <div class="buttons">
-                ${h.submit('save',_('Save settings'),class_="ui-button")}
-                ${h.reset('reset',_('Reset'),class_="ui-button")}
+                ${h.submit('save',_('Save settings'),class_="ui-btn large")}
+                ${h.reset('reset',_('Reset'),class_="ui-btn large")}
            </div>
         </div>
     </div>
@@ -204,7 +285,7 @@
             </div>
 
             <div class="buttons">
-            ${h.submit('send',_('Send'),class_="ui-button")}
+            ${h.submit('send',_('Send'),class_="ui-btn large")}
             </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/users/user_add.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/users/user_add.html	Sun Sep 02 21:19:54 2012 +0200
@@ -56,10 +56,10 @@
 
              <div class="field">
                 <div class="label">
-                    <label for="name">${_('First Name')}:</label>
+                    <label for="firstname">${_('First Name')}:</label>
                 </div>
                 <div class="input">
-                    ${h.text('name',class_='small')}
+                    ${h.text('firstname',class_='small')}
                 </div>
              </div>
 
@@ -91,7 +91,7 @@
              </div>
 
             <div class="buttons">
-              ${h.submit('save',_('save'),class_="ui-button")}
+              ${h.submit('save',_('save'),class_="ui-btn large")}
             </div>
     	</div>
     </div>
--- a/rhodecode/templates/admin/users/user_edit.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/users/user_edit.html	Sun Sep 02 21:19:54 2012 +0200
@@ -83,10 +83,10 @@
 
              <div class="field">
                 <div class="label">
-                    <label for="name">${_('First Name')}:</label>
+                    <label for="firstname">${_('First Name')}:</label>
                 </div>
                 <div class="input">
-                    ${h.text('name',class_='medium')}
+                    ${h.text('firstname',class_='medium')}
                 </div>
              </div>
 
@@ -126,14 +126,14 @@
                 </div>
              </div>
             <div class="buttons">
-              ${h.submit('save',_('Save'),class_="ui-button")}
-              ${h.reset('reset',_('Reset'),class_="ui-button")}
+              ${h.submit('save',_('Save'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
             </div>
     	</div>
     </div>
     ${h.end_form()}
 </div>
-<div class="box box-right">
+<div style="min-height:780px" class="box box-right">
     <!-- box / title -->
     <div class="title">
         <h5>${_('Permissions')}</h5>
@@ -144,15 +144,138 @@
         <div class="fields">
              <div class="field">
                 <div class="label label-checkbox">
+                    <label for="inherit_permissions">${_('Inherit default permissions')}:</label>
+                </div>
+                <div class="checkboxes">
+                    ${h.checkbox('inherit_default_permissions',value=True)}
+                </div>
+                <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. '
+                                             'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span>
+             </div>
+             <div id="inherit_overlay" style="${'opacity:0.3' if c.user.inherit_default_permissions else ''}" >        
+             <div class="field">
+                <div class="label label-checkbox">
                     <label for="create_repo_perm">${_('Create repositories')}:</label>
                 </div>
                 <div class="checkboxes">
                     ${h.checkbox('create_repo_perm',value=True)}
                 </div>
              </div>
+             <div class="field">
+                <div class="label label-checkbox">
+                    <label for="fork_repo_perm">${_('Fork repositories')}:</label>
+                </div>
+                <div class="checkboxes">
+                    ${h.checkbox('fork_repo_perm',value=True)}
+                </div>
+             </div>
+             </div>             
             <div class="buttons">
-              ${h.submit('save',_('Save'),class_="ui-button")}
-              ${h.reset('reset',_('Reset'),class_="ui-button")}
+              ${h.submit('save',_('Save'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
+            </div>
+        </div>
+    </div>
+    ${h.end_form()}
+
+    ## permissions overview
+    <div id="perms" class="table">
+           %for section in sorted(c.perm_user.permissions.keys()):
+              <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
+              %if not c.perm_user.permissions[section]:
+                  <span class="empty_data">${_('Nothing here yet')}</span>
+              %else:
+              <div id='tbl_list_wrap_${section}' class="yui-skin-sam">
+               <table id="tbl_list_${section}">
+                <thead>
+                    <tr>
+                    <th class="left">${_('Name')}</th>
+                    <th class="left">${_('Permission')}</th>
+                    <th class="left">${_('Edit Permission')}</th>
+                </thead>
+                <tbody>
+                %for k in c.perm_user.permissions[section]:
+                     <%
+                     if section != 'global':
+                         section_perm = c.perm_user.permissions[section].get(k)
+                         _perm = section_perm.split('.')[-1]
+                     else:
+                         _perm = section_perm = None
+                     %>
+                    <tr>
+                        <td>
+                            %if section == 'repositories':
+                                <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
+                            %elif section == 'repositories_groups':
+                                <a href="${h.url('repos_group_home',group_name=k)}">${k}</a>
+                            %else:
+                                ${h.get_permission_name(k)}
+                            %endif
+                        </td>
+                        <td>
+                            %if section == 'global':
+                             ${h.bool2icon(k.split('.')[-1] != 'none')}
+                            %else:
+                             <span class="perm_tag ${_perm}">${section_perm}</span>
+                            %endif
+                        </td>
+                        <td>
+                            %if section == 'repositories':
+                                <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a>
+                            %elif section == 'repositories_groups':
+                                <a href="${h.url('edit_repos_group',id=k,anchor='permissions_manage')}">${_('edit')}</a>
+                            %else:
+                                --
+                            %endif
+                        </td>
+                    </tr>
+                %endfor
+                </tbody>
+               </table>
+              </div>
+              %endif
+           %endfor
+    </div>
+</div>
+<div class="box box-left">
+    <!-- box / title -->
+    <div class="title">
+        <h5>${_('Email addresses')}</h5>
+    </div>
+
+    <div class="emails_wrap">
+      <table class="noborder">
+      %for em in c.user_email_map:
+        <tr>
+            <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.user.email,16)}"/> </div></td>
+            <td><div class="email">${em.email}</div></td>
+            <td>
+              ${h.form(url('user_emails_delete', id=c.user.user_id),method='delete')}
+                  ${h.hidden('del_email',em.email_id)}
+                  ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
+                  class_="delete_icon action_button", onclick="return  confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
+              ${h.end_form()}
+            </td>
+        </tr>
+      %endfor
+      </table>
+    </div>
+
+    ${h.form(url('user_emails', id=c.user.user_id),method='put')}
+    <div class="form">
+        <!-- fields -->
+        <div class="fields">
+             <div class="field">
+                <div class="label">
+                    <label for="email">${_('New email address')}:</label>
+                </div>
+                <div class="input">
+                    ${h.text('new_email', class_='medium')}
+                </div>
+             </div>
+            <div class="buttons">
+              ${h.submit('save',_('Add'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
             </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/users/user_edit_my_account.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/users/user_edit_my_account.html	Sun Sep 02 21:19:54 2012 +0200
@@ -21,158 +21,34 @@
         ${self.breadcrumbs()}
     </div>
     <!-- end box / title -->
-    <div>
-    ${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>
-                    %if c.use_gravatar:
-                    <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
-                    <br/>${_('Using')} ${c.user.email}
-                    %else:
-                    <br/>${c.user.email}
-                    %endif
-                    </p>
-                </div>
-             </div>
-	        <div class="field">
-	            <div class="label">
-	                <label>${_('API key')}</label> ${c.user.api_key}
-	            </div>
-	        </div>
-	        <div class="fields">
-	             <div class="field">
-	                <div class="label">
-	                    <label for="username">${_('Username')}:</label>
-	                </div>
-	                <div class="input">
-	                    ${h.text('username',class_="medium")}
-	                </div>
-	             </div>
-
-	             <div class="field">
-	                <div class="label">
-	                    <label for="new_password">${_('New password')}:</label>
-	                </div>
-	                <div class="input">
-	                    ${h.password('new_password',class_="medium",autocomplete="off")}
-	                </div>
-	             </div>
-
-                 <div class="field">
-                    <div class="label">
-                        <label for="password_confirmation">${_('New password confirmation')}:</label>
-                    </div>
-                    <div class="input">
-                        ${h.password('password_confirmation',class_="medium",autocomplete="off")}
-                    </div>
-                 </div>
-
-	             <div class="field">
-	                <div class="label">
-	                    <label for="name">${_('First Name')}:</label>
-	                </div>
-	                <div class="input">
-	                    ${h.text('name',class_="medium")}
-	                </div>
-	             </div>
-
-	             <div class="field">
-	                <div class="label">
-	                    <label for="lastname">${_('Last Name')}:</label>
-	                </div>
-	                <div class="input">
-	                    ${h.text('lastname',class_="medium")}
-	                </div>
-	             </div>
-
-	             <div class="field">
-	                <div class="label">
-	                    <label for="email">${_('Email')}:</label>
-	                </div>
-	                <div class="input">
-	                    ${h.text('email',class_="medium")}
-	                </div>
-	             </div>
-
-	            <div class="buttons">
-	              ${h.submit('save',_('Save'),class_="ui-button")}
-	              ${h.reset('reset',_('Reset'),class_="ui-button")}
-	            </div>
-	    	</div>
-	    </div>
-    ${h.end_form()}
-    </div>
+    ${c.form|n}
 </div>
 
 <div class="box box-right">
     <!-- box / title -->
     <div class="title">
         <h5>
-        <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
-        <a id="show_my" class="link-white" href="#my">${_('My repos')}</a> / <a id="show_perms" class="link-white" href="#perms">${_('My permissions')}</a>
+        <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}" style="display: none"/>
         </h5>
-         %if h.HasPermissionAny('hg.admin','hg.create.repository')():
-         <ul class="links">
+         <ul class="links" style="color:#DADADA">
+           <li>
+             <span><a id="show_perms" class="link-white current" href="#perms">${_('My permissions')}</a> </span>
+           </li>
+           <li>
+             <span><a id="show_my" class="link-white" href="#my">${_('My repos')}</a> </span>
+           </li>
            <li>
-             <span>${h.link_to(_('ADD'),h.url('admin_settings_create_repository'))}</span>
+             <span><a id="show_pullrequests" class="link-white" href="#perms">${_('My pull requests')}</a> </span>
            </li>
+           %if h.HasPermissionAny('hg.admin','hg.create.repository')():
+             <li>
+               <span>${h.link_to(_('Add repo'),h.url('admin_settings_create_repository'))}</span>
+             </li>
+           %endif
          </ul>
-         %endif
     </div>
     <!-- end box / title -->
-    <div id="my" class="table">
-        <div id='repos_list_wrap' class="yui-skin-sam">
-        <table id="repos_list">
-	    <thead>
-            <tr>
-            <th></th>
-            <th class="left">${_('Name')}</th>
-            <th class="left">${_('Revision')}</th>
-            <th class="left">${_('Action')}</th>
-            <th class="left">${_('Action')}</th>
-	    </thead>
-	     <tbody>
-         <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
-	     %if c.user_repos:
-		     %for repo in c.user_repos:
-		        <tr>
-                    ##QUICK MENU
-                    <td class="quick_repo_menu">
-                      ${dt.quick_menu(repo['name'])}
-                    </td>
-                    ##REPO NAME AND ICONS
-                    <td class="reponame">
-                      ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'))}
-                    </td>
-                    ##LAST REVISION
-                    <td>
-                        ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
-                    </td>
-		            <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/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'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")}
-	                  ${h.end_form()}
-		            </td>
-		        </tr>
-		     %endfor
-	     %else:
-            <div style="padding:5px 0px 10px 0px;">
-	     	${_('No repositories yet')}
-	     	%if h.HasPermissionAny('hg.admin','hg.create.repository')():
-	     		${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")}
-	     	%endif
-            </div>
-	     %endif
-	     </tbody>
-	     </table>
-       </div>
-    </div>
-    <div id="perms" class="table" style="display:none">
+    <div id="perms" class="table">
            %for section in sorted(c.rhodecode_user.permissions.keys()):
             <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
 
@@ -218,7 +94,13 @@
             </div>
            %endfor
     </div>
+    <div id="my" class="table" style="display:none">
+    </div>
+    <div id="pullrequests" class="table" style="display:none"></div>
 </div>
+
+
+
 <script type="text/javascript">
 var filter_activate = function(){
     var nodes = YUQ('#my tr td a.repo_name');
@@ -227,22 +109,48 @@
     }
     q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
 }
+YUE.on('show_perms','click',function(e){
+	YUD.addClass('show_perms', 'current');
+	YUD.removeClass('show_my','current');
+	YUD.removeClass('show_pullrequests','current');
 
-YUE.on('show_my','click',function(e){
-    YUD.setStyle('perms','display','none');
-    YUD.setStyle('my','display','');
-    YUD.get('q_filter').removeAttribute('disabled');
-    filter_activate();
+    YUD.setStyle('my','display','none');
+    YUD.setStyle('pullrequests','display','none');
+    YUD.setStyle('perms','display','');
+    YUD.setStyle('q_filter','display','none');
     YUE.preventDefault(e);
 })
-YUE.on('show_perms','click',function(e){
+YUE.on('show_my','click',function(e){
+    YUD.addClass('show_my', 'current');
+    YUD.removeClass('show_perms','current');
+    YUD.removeClass('show_pullrequests','current');
+
+    YUD.setStyle('perms','display','none');
+    YUD.setStyle('pullrequests','display','none');
+    YUD.setStyle('my','display','');
+    YUD.setStyle('q_filter','display','');
+
+    YUE.preventDefault(e);
+    var url = "${h.url('admin_settings_my_repos')}";
+    ypjax(url, 'my', function(){
+    	table_sort();
+    	filter_activate();
+    });
+})
+YUE.on('show_pullrequests','click',function(e){
+    YUD.addClass('show_pullrequests', 'current');
+    YUD.removeClass('show_my','current');
+    YUD.removeClass('show_perms','current');
+
     YUD.setStyle('my','display','none');
-    YUD.setStyle('perms','display','');
-    YUD.setAttribute('q_filter','disabled','disabled');
+    YUD.setStyle('perms','display','none');
+    YUD.setStyle('pullrequests','display','');
+    YUD.setStyle('q_filter','display','none');
     YUE.preventDefault(e);
+    var url = "${h.url('admin_settings_my_pullrequests')}";
+    ypjax(url, 'pullrequests');
 })
 
-
 // main table sorting
 var myColumnDefs = [
     {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
@@ -254,6 +162,7 @@
     {key:"action2",label:"",sortable:false},
 ];
 
+function table_sort(){
 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
 myDataSource.responseSchema = {
@@ -308,6 +217,6 @@
 };
 
 new YAHOO.widget.DataTable("tbl_list_wrap_repositories_groups", permsColumnDefs, myDataSource3, trans_defs);
-
+}
 </script>
 </%def>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/admin/users/user_edit_my_account_form.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,85 @@
+<div>
+    ${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>
+                    %if c.use_gravatar:
+                    <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
+                    <br/>${_('Using')} ${c.user.email}
+                    %else:
+                    <br/>${c.user.email}
+                    %endif
+                    </p>
+                </div>
+             </div>
+            <div class="field">
+                <div class="label">
+                    <label>${_('API key')}</label> ${c.user.api_key}
+                </div>
+            </div>
+            <div class="fields">
+                 <div class="field">
+                    <div class="label">
+                        <label for="username">${_('Username')}:</label>
+                    </div>
+                    <div class="input">
+                        ${h.text('username',class_="medium")}
+                    </div>
+                 </div>
+
+                 <div class="field">
+                    <div class="label">
+                        <label for="new_password">${_('New password')}:</label>
+                    </div>
+                    <div class="input">
+                        ${h.password('new_password',class_="medium",autocomplete="off")}
+                    </div>
+                 </div>
+
+                 <div class="field">
+                    <div class="label">
+                        <label for="password_confirmation">${_('New password confirmation')}:</label>
+                    </div>
+                    <div class="input">
+                        ${h.password('password_confirmation',class_="medium",autocomplete="off")}
+                    </div>
+                 </div>
+
+                 <div class="field">
+                    <div class="label">
+                        <label for="name">${_('First Name')}:</label>
+                    </div>
+                    <div class="input">
+                        ${h.text('firstname',class_="medium")}
+                    </div>
+                 </div>
+
+                 <div class="field">
+                    <div class="label">
+                        <label for="lastname">${_('Last Name')}:</label>
+                    </div>
+                    <div class="input">
+                        ${h.text('lastname',class_="medium")}
+                    </div>
+                 </div>
+
+                 <div class="field">
+                    <div class="label">
+                        <label for="email">${_('Email')}:</label>
+                    </div>
+                    <div class="input">
+                        ${h.text('email',class_="medium")}
+                    </div>
+                 </div>
+
+                <div class="buttons">
+                  ${h.submit('save',_('Save'),class_="ui-btn large")}
+                  ${h.reset('reset',_('Reset'),class_="ui-btn large")}
+                </div>
+            </div>
+        </div>
+    ${h.end_form()}
+    </div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/admin/users/user_edit_my_account_pullrequests.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,41 @@
+
+<div class="pullrequests_section_head">${_('Opened by me')}</div>
+<ul>
+    %if c.my_pull_requests:
+      %for pull_request in c.my_pull_requests:
+      <li>
+        <div style="height: 12px">
+          <div style="float:left">
+          <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
+          ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.fmt_date(pull_request.created_on))}
+          </a>
+          </div>
+          <div style="float:left;margin-top: -5px">
+            ${h.form(url('pullrequest_delete', repo_name=pull_request.other_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')}
+              ${h.submit('remove_%s' % pull_request.pull_request_id,'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
+            ${h.end_form()}
+          </div>
+        </div>
+      </li>
+      %endfor
+   %else:
+    <li><span class="empty_data">${_('Nothing here yet')}</span></li>
+   %endif
+</ul>
+
+<div class="pullrequests_section_head" style="clear:both">${_('I participate in')}</div>
+<ul>
+    %if c.my_pull_requests:
+      %for pull_request in c.participate_in_pull_requests:
+      <li>
+        <div style="height: 12px">
+        <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
+        ${_('Pull request #%s opened by %s on %s') % (pull_request.pull_request_id, pull_request.author.full_name, h.fmt_date(pull_request.created_on))}
+        </a>
+      </div>
+      </li>
+      %endfor
+    %else:
+     <li><span class="empty_data">${_('Nothing here yet')}</span></li>
+    %endif
+</ul>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/admin/users/user_edit_my_account_repos.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,46 @@
+<div id='repos_list_wrap' class="yui-skin-sam">
+  <table id="repos_list">
+  <thead>
+      <tr>
+      <th></th>
+      <th class="left">${_('Name')}</th>
+      <th class="left">${_('Revision')}</th>
+      <th class="left">${_('Action')}</th>
+      <th class="left">${_('Action')}</th>
+  </thead>
+   <tbody>
+   <%namespace name="dt" file="/data_table/_dt_elements.html"/>
+   %if c.user_repos:
+       %for repo in c.user_repos:
+          <tr>
+              ##QUICK MENU
+              <td class="quick_repo_menu">
+                ${dt.quick_menu(repo['name'])}
+              </td>
+              ##REPO NAME AND ICONS
+              <td class="reponame">
+                ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'))}
+              </td>
+              ##LAST REVISION
+              <td>
+                  ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
+              </td>
+              <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/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'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")}
+                ${h.end_form()}
+              </td>
+          </tr>
+       %endfor
+   %else:
+      <div style="padding:5px 0px 10px 0px;">
+      ${_('No repositories yet')}
+      %if h.HasPermissionAny('hg.admin','hg.create.repository')():
+          ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")}
+      %endif
+      </div>
+   %endif
+   </tbody>
+   </table>
+</div>
--- a/rhodecode/templates/admin/users/users.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/users/users.html	Sun Sep 02 21:19:54 2012 +0200
@@ -6,7 +6,7 @@
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Users')}
+    <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="user_count">0</span> ${_('users')}
 </%def>
 
 <%def name="page_nav()">
@@ -22,44 +22,126 @@
           <li>
             <span>${h.link_to(_(u'ADD NEW USER'),h.url('new_user'))}</span>
           </li>
-
         </ul>
     </div>
     <!-- end box / title -->
-    <div class="table">
-        <table class="table_disp">
-        <tr class="header">
-        	<th></th>
-            <th class="left">${_('username')}</th>
-            <th class="left">${_('name')}</th>
-            <th class="left">${_('lastname')}</th>
-            <th class="left">${_('last login')}</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>${h.link_to(user.username,h.url('edit_user', id=user.user_id))}</td>
-                    <td>${user.name}</td>
-                    <td>${user.lastname}</td>
-                    <td>${user.last_login}</td>
-                    <td>${h.bool2icon(user.active)}</td>
-                    <td>${h.bool2icon(user.admin)}</td>
-                    <td>${h.bool2icon(bool(user.ldap_dn))}</td>
-                    <td>
-                        ${h.form(url('delete_user', id=user.user_id),method='delete')}
-                            ${h.submit('remove_',_('delete'),id="remove_user_%s" % user.user_id,
-                            class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % user.username+"');")}
-                        ${h.end_form()}
-                    </td>
-                </tr>
-             %endif
-            %endfor
-        </table>
-    </div>
+    <div class="table yui-skin-sam" id="users_list_wrap"></div>
+    <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
 </div>
+
+<script>
+  var url = "${h.url('formatted_users', format='json')}";
+  var data = ${c.data|n};
+  var myDataSource = new YAHOO.util.DataSource(data);
+  myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
+
+  myDataSource.responseSchema = {
+	  resultsList: "records",
+      fields: [
+          {key: "gravatar"},
+          {key: "raw_username"},
+          {key: "username"},
+          {key: "firstname"},
+          {key: "lastname"},
+          {key: "last_login"},
+          {key: "last_login_raw"},
+          {key: "active"},
+          {key: "admin"},
+          {key: "ldap"},
+          {key: "action"},
+      ]
+   };
+  myDataSource.doBeforeCallback = function(req,raw,res,cb) {
+      // This is the filter function
+      var data     = res.results || [],
+          filtered = [],
+          i,l;
+
+      if (req) {
+          req = req.toLowerCase();
+          for (i = 0; i<data.length; i++) {
+        	  var pos = data[i].raw_username.toLowerCase().indexOf(req)
+              if (pos != -1) {
+                  filtered.push(data[i]);
+              }
+          }
+          res.results = filtered;
+      }
+      YUD.get('user_count').innerHTML = res.results.length;
+      return res;
+  }
+
+  // main table sorting
+  var myColumnDefs = [
+      {key:"gravatar",label:"",sortable:false,},
+      {key:"username",label:"${_('username')}",sortable:true,
+    	  sortOptions: { sortFunction: linkSort }
+      },
+      {key:"firstname",label:"${_('firstname')}",sortable:true,},
+      {key:"lastname",label:"${_('lastname')}",sortable:true,},
+      {key:"last_login",label:"${_('last login')}",sortable:true,
+    	  sortOptions: { sortFunction: lastLoginSort }},
+      {key:"active",label:"${_('active')}",sortable:true,},
+      {key:"admin",label:"${_('admin')}",sortable:true,},
+      {key:"ldap",label:"${_('ldap')}",sortable:true,},
+      {key:"action",label:"${_('action')}",sortable:false},
+  ];
+
+  var myDataTable = new YAHOO.widget.DataTable("users_list_wrap", myColumnDefs, myDataSource,{
+    sortedBy:{key:"username",dir:"asc"},
+    paginator: new YAHOO.widget.Paginator({
+        rowsPerPage: 15,
+        alwaysVisible: false,
+        template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
+        pageLinks: 5,
+        containerClass: 'pagination-wh',
+        currentPageClass: 'pager_curpage',
+        pageLinkClass: 'pager_link',
+        nextPageLinkLabel: '&gt;',
+        previousPageLinkLabel: '&lt;',
+        firstPageLinkLabel: '&lt;&lt;',
+        lastPageLinkLabel: '&gt;&gt;',
+        containers:['user-paginator']
+    }),
+
+    MSG_SORTASC:"${_('Click to sort ascending')}",
+    MSG_SORTDESC:"${_('Click to sort descending')}",
+    MSG_EMPTY:"${_('No records found.')}",
+    MSG_ERROR:"${_('Data error.')}",
+    MSG_LOADING:"${_('Loading...')}",
+  }
+  );
+  myDataTable.subscribe('postRenderEvent',function(oArgs) {
+
+  });
+
+  var filterTimeout = null;
+
+  updateFilter  = function () {
+      // Reset timeout
+      filterTimeout = null;
+
+      // Reset sort
+      var state = myDataTable.getState();
+          state.sortedBy = {key:'username', dir:YAHOO.widget.DataTable.CLASS_ASC};
+
+      // Get filtered data
+      myDataSource.sendRequest(YUD.get('q_filter').value,{
+          success : myDataTable.onDataReturnInitializeTable,
+          failure : myDataTable.onDataReturnInitializeTable,
+          scope   : myDataTable,
+          argument: state
+      });
+
+  };
+  YUE.on('q_filter','click',function(){
+      YUD.get('q_filter').value = '';
+   });
+
+  YUE.on('q_filter','keyup',function (e) {
+      clearTimeout(filterTimeout);
+      filterTimeout = setTimeout(updateFilter,600);
+  });
+</script>
+
 </%def>
--- a/rhodecode/templates/admin/users_groups/users_group_add.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/users_groups/users_group_add.html	Sun Sep 02 21:19:54 2012 +0200
@@ -46,7 +46,7 @@
              </div>
 
             <div class="buttons">
-              ${h.submit('save',_('save'),class_="ui-button")}
+              ${h.submit('save',_('save'),class_="ui-btn large")}
             </div>
         </div>
     </div>
--- a/rhodecode/templates/admin/users_groups/users_group_edit.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/users_groups/users_group_edit.html	Sun Sep 02 21:19:54 2012 +0200
@@ -87,7 +87,7 @@
 
                 </div>
                 <div class="buttons">
-                  ${h.submit('save',_('save'),class_="ui-button")}
+                  ${h.submit('save',_('save'),class_="ui-btn large")}
                 </div>
             </div>
     </div>
@@ -105,15 +105,35 @@
         <div class="fields">
              <div class="field">
                 <div class="label label-checkbox">
+                    <label for="inherit_permissions">${_('Inherit default permissions')}:</label>
+                </div>
+                <div class="checkboxes">
+                    ${h.checkbox('inherit_default_permissions',value=True)}
+                </div>
+                <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. '
+                                             'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span>
+             </div>        
+             <div id="inherit_overlay" style="${'opacity:0.3' if c.users_group.inherit_default_permissions else ''}" >
+             <div class="field">
+                <div class="label label-checkbox">
                     <label for="create_repo_perm">${_('Create repositories')}:</label>
                 </div>
                 <div class="checkboxes">
                     ${h.checkbox('create_repo_perm',value=True)}
                 </div>
              </div>
+             <div class="field">
+                <div class="label label-checkbox">
+                    <label for="fork_repo_perm">${_('Fork repositories')}:</label>
+                </div>
+                <div class="checkboxes">
+                    ${h.checkbox('fork_repo_perm',value=True)}
+                </div>
+             </div>
+             </div>          
             <div class="buttons">
-              ${h.submit('save',_('Save'),class_="ui-button")}
-              ${h.reset('reset',_('Reset'),class_="ui-button")}
+              ${h.submit('save',_('Save'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
             </div>
         </div>
     </div>
@@ -140,141 +160,6 @@
     </div>
 </div>
 <script type="text/javascript">
-YAHOO.util.Event.onDOMReady(function(){
-  var D = YAHOO.util.Dom;
-  var E = YAHOO.util.Event;
-
-  //definition of containers ID's
-  var available_container = 'available_members';
-  var selected_container = 'users_group_members';
-
-  //form containing containers id
-  var form_id = 'edit_users_group';
-
-  //temp container for selected storage.
-  var cache = new Array();
-  var av_cache = new Array();
-  var c =  D.get(selected_container);
-  var ac = D.get(available_container);
-
-  //get only selected options for further fullfilment
-  for(var i = 0;node =c.options[i];i++){
-      if(node.selected){
-          //push selected to my temp storage left overs :)
-          cache.push(node);
-      }
-  }
-
-  //get all available options to cache
-  for(var i = 0;node =ac.options[i];i++){
-          //push selected to my temp storage left overs :)
-          av_cache.push(node);
-  }
-
-  //fill available only with those not in choosen
-  ac.options.length=0;
-  tmp_cache = new Array();
-
-  for(var i = 0;node = av_cache[i];i++){
-      var add = true;
-      for(var i2 = 0;node_2 = cache[i2];i2++){
-          if(node.value == node_2.value){
-              add=false;
-              break;
-          }
-      }
-      if(add){
-          tmp_cache.push(new Option(node.text, node.value, false, false));
-      }
-  }
-
-  for(var i = 0;node = tmp_cache[i];i++){
-      ac.options[i] = node;
-  }
-
-  function prompts_action_callback(e){
-
-      var choosen = D.get(selected_container);
-      var available = D.get(available_container);
-
-      //get checked and unchecked options from field
-      function get_checked(from_field){
-          //temp container for storage.
-          var sel_cache = new Array();
-          var oth_cache = new Array();
-
-          for(var i = 0;node = from_field.options[i];i++){
-              if(node.selected){
-                  //push selected fields :)
-                  sel_cache.push(node);
-              }
-              else{
-                  oth_cache.push(node)
-              }
-          }
-
-          return [sel_cache,oth_cache]
-      }
-
-      //fill the field with given options
-      function fill_with(field,options){
-          //clear firtst
-          field.options.length=0;
-          for(var i = 0;node = options[i];i++){
-                  field.options[i]=new Option(node.text, node.value,
-                          false, false);
-          }
-
-      }
-      //adds to current field
-      function add_to(field,options){
-          for(var i = 0;node = options[i];i++){
-                  field.appendChild(new Option(node.text, node.value,
-                          false, false));
-          }
-      }
-
-      // add action
-      if (this.id=='add_element'){
-          var c = get_checked(available);
-          add_to(choosen,c[0]);
-          fill_with(available,c[1]);
-      }
-      // remove action
-      if (this.id=='remove_element'){
-          var c = get_checked(choosen);
-          add_to(available,c[0]);
-          fill_with(choosen,c[1]);
-      }
-      // add all elements
-      if(this.id=='add_all_elements'){
-          for(var i=0; node = available.options[i];i++){
-                  choosen.appendChild(new Option(node.text,
-                          node.value, false, false));
-          }
-          available.options.length = 0;
-      }
-      //remove all elements
-      if(this.id=='remove_all_elements'){
-          for(var i=0; node = choosen.options[i];i++){
-              available.appendChild(new Option(node.text,
-                      node.value, false, false));
-          }
-          choosen.options.length = 0;
-      }
-
-  }
-
-  E.addListener(['add_element','remove_element',
-                 'add_all_elements','remove_all_elements'],'click',
-                 prompts_action_callback)
-
-  E.addListener(form_id,'submit',function(){
-      var choosen = D.get(selected_container);
-      for (var i = 0; i < choosen.options.length; i++) {
-          choosen.options[i].selected = 'selected';
-      }
-  });
-});
+  MultiSelectWidget('users_group_members','available_members','edit_users_group');
 </script>
 </%def>
--- a/rhodecode/templates/admin/users_groups/users_groups.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/admin/users_groups/users_groups.html	Sun Sep 02 21:19:54 2012 +0200
@@ -37,11 +37,11 @@
             %for cnt,u_group in enumerate(c.users_groups_list):
                 <tr class="parity${cnt%2}">
                     <td>${h.link_to(u_group.users_group_name,h.url('edit_users_group', id=u_group.users_group_id))}</td>
-                    <td><span class="tooltip" title="${', '.join(map(h.safe_unicode,[x.user.username for x in u_group.members[:50]]))}">${len(u_group.members)}</span></td>
+                    <td><span class="tooltip" title="${h.tooltip(', '.join(map(h.safe_unicode,[x.user.username for x in u_group.members[:50]])))}">${len(u_group.members)}</span></td>
                     <td>${h.bool2icon(u_group.users_group_active)}</td>
                     <td>
                         ${h.form(url('users_group', id=u_group.users_group_id),method='delete')}
-                            ${h.submit('remove_','delete',id="remove_group_%s" % u_group.users_group_id,
+                            ${h.submit('remove_',_('delete'),id="remove_group_%s" % u_group.users_group_id,
                             class_="delete_icon action_button",onclick="return  confirm('"+_('Confirm to delete this users group: %s') % u_group.users_group_name+"');")}
                         ${h.end_form()}
                     </td>
--- a/rhodecode/templates/base/base.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/base/base.html	Sun Sep 02 21:19:54 2012 +0200
@@ -207,6 +207,9 @@
                      %endif
                    %endif
                    	<li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
+                    %if h.is_hg(c.rhodecode_repo):
+                     <li>${h.link_to(_('Open new pull request'),h.url('pullrequest_home',repo_name=c.repo_name),class_='pull_request')}</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'):
@@ -247,6 +250,14 @@
                     <span class="short">${c.repository_forks}</span>
                     </a>
                 </li>
+                <li>
+                    <a class="menu_link" title="${_('Pull requests')}" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}">
+                    <span class="icon_short">
+                        <img src="${h.url('/images/icons/arrow_join.png')}" alt="${_('Pull requests')}" />
+                    </span>
+                    <span class="short">${c.repository_pull_requests}</span>
+                    </a>
+                </li>
                 ${usermenu()}
 	        </ul>
             <script type="text/javascript">
--- a/rhodecode/templates/base/root.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/base/root.html	Sun Sep 02 21:19:54 2012 +0200
@@ -36,24 +36,42 @@
 
         ## JAVASCRIPT ##
         <%def name="js()">
+            <script type="text/javascript">
+            //JS translations map
+            var TRANSLATION_MAP = {
+                'add another comment':'${_("add another comment")}',
+                'Stop following this repository':"${_('Stop following this repository')}",
+                'Start following this repository':"${_('Start following this repository')}",
+                'Group':"${_('Group')}",
+                'members':"${_('members')}",
+                'search truncated': "${_('search truncated')}",
+                'no matching files': "${_('no matching files')}"
+
+            };
+            var _TM = TRANSLATION_MAP;
+            </script>
             <script type="text/javascript" src="${h.url('/js/yui.2.9.js')}"></script>
             <!--[if lt IE 9]>
                <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
             <![endif]-->
             <script type="text/javascript" src="${h.url('/js/yui.flot.js')}"></script>
+            <script type="text/javascript" src="${h.url('/js/native.history.js')}"></script>
             <script type="text/javascript" src="${h.url('/js/rhodecode.js')}"></script>
            ## EXTRA FOR JS
            ${self.js_extra()}
 
             <script type="text/javascript">
-            var follow_base_url  = "${h.url('toggle_following')}";
+            (function(window,undefined){
 
-            //JS translations map
-            var TRANSLATION_MAP = {
-            	'add another comment':'${_("add another comment")}',
-                'Stop following this repository':"${_('Stop following this repository')}",
-                'Start following this repository':"${_('Start following this repository')}",
-            };
+                // Prepare
+                var History = window.History; // Note: We are using a capital H instead of a lower h
+                if ( !History.enabled ) {
+                     // History.js is disabled for this browser.
+                     // This is because we can optionally choose to support HTML4 browsers or not.
+                    return false;
+                }
+            })(window);
+            var follow_base_url  = "${h.url('toggle_following')}";
 
             var onSuccessFollow = function(target){
                 var f = YUD.get(target.id);
@@ -61,7 +79,7 @@
 
                 if(f.getAttribute('class')=='follow'){
                     f.setAttribute('class','following');
-                    f.setAttribute('title',TRANSLATION_MAP['Stop following this repository']);
+                    f.setAttribute('title',_TM['Stop following this repository']);
 
                     if(f_cnt){
                         var cnt = Number(f_cnt.innerHTML)+1;
@@ -70,7 +88,7 @@
                 }
                 else{
                     f.setAttribute('class','follow');
-                    f.setAttribute('title',TRANSLATION_MAP['Start following this repository']);
+                    f.setAttribute('title',_TM['Start following this repository']);
                     if(f_cnt){
                         var cnt = Number(f_cnt.innerHTML)+1;
                         f_cnt.innerHTML = cnt;
@@ -132,6 +150,8 @@
         </%def>
         <%def name="js_extra()"></%def>
         ${self.js()}
+        <%def name="head_extra()"></%def>
+        ${self.head_extra()}
     </head>
     <body id="body">
      ## IE hacks
--- a/rhodecode/templates/bookmarks/bookmarks.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/bookmarks/bookmarks.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,13 +2,13 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Bookmarks')} - ${c.rhodecode_name}
+    ${_('%s Bookmarks') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 
 <%def name="breadcrumbs_links()">
     <input class="q_filter_box" id="q_filter_bookmarks" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/bookmarks/bookmarks_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/bookmarks/bookmarks_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -17,7 +17,7 @@
                     h.url('files_home',repo_name=c.repo_name,revision=book[1].raw_id))}</span>
                 </span>
             </td>
-            <td><span class="tooltip" title="${h.age(book[1].date)}">${book[1].date}</span></td>
+            <td><span class="tooltip" title="${h.tooltip(h.age(book[1].date))}">${h.fmt_date(book[1].date)}</span></td>
 	        <td title="${book[1].author}">${h.person(book[1].author)}</td>
 	        <td>
               <div>
--- a/rhodecode/templates/branches/branches.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/branches/branches.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,12 +2,12 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Branches')} - ${c.rhodecode_name}
+    ${_('%s Branches') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
     <input class="q_filter_box" id="q_filter_branches" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
@@ -25,12 +25,27 @@
         ${self.breadcrumbs()}
     </div>
     <!-- end box / title -->
+    %if c.repo_branches:
+    <div class="info_box" id="compare_branches" style="clear: both;padding: 10px 19px;vertical-align: right;text-align: right;"><a href="#" class="ui-btn small">${_('Compare branches')}</a></div>
+    %endif
     <div class="table">
         <%include file='branches_data.html'/>
     </div>
 </div>
 <script type="text/javascript">
+YUE.on('compare_branches','click',function(e){
+	YUE.preventDefault(e);
+	var org = YUQ('input[name=compare_org]:checked')[0];
+	var other = YUQ('input[name=compare_other]:checked')[0];
 
+	if(org && other){
+	    var compare_url = "${h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref='__ORG__',other_ref_type='branch',other_ref='__OTHER__')}";
+		var u = compare_url.replace('__ORG__',org.value)
+		                   .replace('__OTHER__',other.value);
+		window.location=u;
+	}
+
+})
 // main table sorting
 var myColumnDefs = [
     {key:"name",label:"${_('Name')}",sortable:true},
@@ -39,6 +54,7 @@
     {key:"author",label:"${_('Author')}",sortable:true},
     {key:"revision",label:"${_('Revision')}",sortable:true,
         sortOptions: { sortFunction: revisionSort }},
+    {key:"compare",label:"${_('Compare')}",sortable:false,},
 ];
 
 var myDataSource = new YAHOO.util.DataSource(YUD.get("branches_data"));
@@ -51,6 +67,7 @@
         {key:"date"},
         {key:"author"},
         {key:"revision"},
+        {key:"compare"},
     ]
 };
 
--- a/rhodecode/templates/branches/branches_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/branches/branches_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -7,6 +7,7 @@
             <th class="left">${_('date')}</th>
             <th class="left">${_('author')}</th>
             <th class="left">${_('revision')}</th>
+            <th class="left">${_('compare')}</th>
         </tr>
       </thead>
 		%for cnt,branch in enumerate(c.repo_branches.items()):
@@ -17,13 +18,17 @@
                     h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
                 </span>
             </td>
-            <td><span class="tooltip" title="${h.age(branch[1].date)}">${branch[1].date}</span></td>
+            <td><span class="tooltip" title="${h.tooltip(h.age(branch[1].date))}">${h.fmt_date(branch[1].date)}</span></td>
             <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
             <td>
                 <div>
                     <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id)}">r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</a></pre>
                 </div>
             </td>
+            <td>
+                <input class="branch-compare" type="radio" name="compare_org" value="${branch[0]}"/>
+                <input class="branch-compare" type="radio" name="compare_other" value="${branch[0]}"/>
+            </td>
 		</tr>
 		%endfor
         % if hasattr(c,'repo_closed_branches') and c.repo_closed_branches:
@@ -35,13 +40,14 @@
                       h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
                   </span>
               </td>
-              <td><span class="tooltip" title="${h.age(branch[1].date)}">${branch[1].date}</span></td>
+              <td><span class="tooltip" title="${h.tooltip(h.age(branch[1].date))}">${h.fmt_date(branch[1].date)}</span></td>
               <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
               <td>
                 <div>
                     <pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id)}">r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</a></pre>
                 </div>
               </td>
+              <td></td>
           </tr>
           %endfor
         %endif
--- a/rhodecode/templates/changelog/changelog.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/changelog/changelog.html	Sun Sep 02 21:19:54 2012 +0200
@@ -3,15 +3,16 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-${c.repo_name} ${_('Changelog')} - ${c.rhodecode_name}
+${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
-    ${_('Changelog')} - ${_('showing ')} ${c.size if c.size <= c.total_cs else c.total_cs} ${_('out of')} ${c.total_cs} ${_('revisions')}
+    <% size = c.size if c.size <= c.total_cs else c.total_cs %>
+    ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
 </%def>
 
 <%def name="page_nav()">
@@ -31,6 +32,14 @@
 					<canvas id="graph_canvas"></canvas>
 				</div>
 				<div id="graph_content">
+                    <div class="info_box" style="clear: both;padding: 10px 6px;vertical-align: right;text-align: right;">
+                    %if c.rhodecode_db_repo.fork:
+                        <a title="${_('compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref='default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name)}" class="ui-btn small">${_('Compare fork')}</a>
+                    %endif
+                    %if h.is_hg(c.rhodecode_repo):
+                    <a href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
+                    %endif
+                    </div>
 					<div class="container_header">
 				        ${h.form(h.url.current(),method='get')}
 				        <div class="info_box" style="float:left">
@@ -47,24 +56,24 @@
 					<div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
 						<div class="left">
 							<div>
-							${h.checkbox(cs.short_id,class_="changeset_range")}
-							<span class="tooltip" title="${h.age(cs.date)}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
+							${h.checkbox(cs.raw_id,class_="changeset_range")}
+							<span class="tooltip" title="${h.tooltip(h.age(cs.date))}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
 							</div>
 							<div class="author">
 								<div class="gravatar">
-									<img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),16)}"/>
+									<img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
 								</div>
-								<div title="${cs.author}" class="user">${h.person(cs.author)}</div>
+								<div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div>
 							</div>
-                            <div class="date">${cs.date}</div>
+                            <div class="date">${h.fmt_date(cs.date)}</div>
 						</div>
 						<div class="mid">
-                            <div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
+                            <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
                             <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
 						</div>
 						<div class="right">
 									<div class="changes">
-                                        <div id="${cs.raw_id}"  style="float:right;" class="changed_total tooltip" title="${_('Affected number of files, click to show more details')}">${len(cs.affected_files)}</div>
+                                        <div id="changed_total_${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${h.tooltip(_('Affected number of files, click to show more details'))}">${len(cs.affected_files)}</div>
                                         <div class="comments-container">
                                         %if len(c.comments.get(cs.raw_id,[])) > 0:
                                             <div class="comments-cnt" title="${('comments')}">
@@ -75,6 +84,18 @@
                                             </div>
                                         %endif
                                         </div>
+                                        <div class="changeset-status-container">
+                                            %if c.statuses.get(cs.raw_id):
+                                              <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
+                                              <div class="changeset-status-ico">
+                                              %if c.statuses.get(cs.raw_id)[2]:
+                                                <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a>
+                                              %else:
+                                                <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
+                                              %endif
+                                              </div>
+                                            %endif
+                                        </div>
 									</div>
 								   %if cs.parents:
 									%for p_cs in reversed(cs.parents):
@@ -141,8 +162,8 @@
                             		rev_start+'...'+rev_end);
 
                         var link = "<a href="+url+">${_('Show selected changes __S -> __E')}</a>"
-                        link = link.replace('__S',rev_start);
-                        link = link.replace('__E',rev_end);
+                        link = link.replace('__S',rev_start.substr(0,6));
+                        link = link.replace('__E',rev_end.substr(0,6));
                         YUD.get('rev_range_container').innerHTML = link;
                         YUD.setStyle('rev_range_container','display','');
                         }
@@ -182,9 +203,9 @@
 
                     // Fetch changeset details
                     YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
-                    	var id = e.currentTarget.id
-                    	var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}"
-                    	var url = url.replace('__CS__',id);
+                    	var id = e.currentTarget.id;
+                    	var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}";
+                    	var url = url.replace('__CS__',id.replace('changed_total_',''));
                     	ypjax(url,id,function(){tooltip_activate()});
                     });
 
--- a/rhodecode/templates/changelog/changelog_details.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/changelog/changelog_details.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,9 +1,11 @@
+## small box that displays changed/added/removed details fetched by AJAX
+
 % if len(c.cs.affected_files) <= c.affected_files_cut_off:
-<span class="removed tooltip" title="<b>${_('removed')}</b>${h.changed_tooltip(c.cs.removed)}">${len(c.cs.removed)}</span>
-<span class="changed tooltip" title="<b>${_('changed')}</b>${h.changed_tooltip(c.cs.changed)}">${len(c.cs.changed)}</span>
-<span class="added tooltip" title="<b>${_('added')}</b>${h.changed_tooltip(c.cs.added)}">${len(c.cs.added)}</span>
+<span class="removed tooltip" title="<b>${h.tooltip(_('removed'))}</b>${h.changed_tooltip(c.cs.removed)}">${len(c.cs.removed)}</span>
+<span class="changed tooltip" title="<b>${h.tooltip(_('changed'))}</b>${h.changed_tooltip(c.cs.changed)}">${len(c.cs.changed)}</span>
+<span class="added tooltip"   title="<b>${h.tooltip(_('added'))}</b>${h.changed_tooltip(c.cs.added)}">${len(c.cs.added)}</span>
 % else:
- <span class="removed tooltip" title="${_('affected %s files') % len(c.cs.affected_files)}">!</span>
- <span class="changed tooltip" title="${_('affected %s files') % len(c.cs.affected_files)}">!</span>
- <span class="added tooltip"   title="${_('affected %s files') % len(c.cs.affected_files)}">!</span>
+ <span class="removed tooltip" title="${h.tooltip(_('affected %s files') % len(c.cs.affected_files))}">!</span>
+ <span class="changed tooltip" title="${h.tooltip(_('affected %s files') % len(c.cs.affected_files))}">!</span>
+ <span class="added tooltip"   title="${h.tooltip(_('affected %s files') % len(c.cs.affected_files))}">!</span>
 % endif
--- a/rhodecode/templates/changeset/changeset.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/changeset/changeset.html	Sun Sep 02 21:19:54 2012 +0200
@@ -3,11 +3,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
+    ${_('%s Changeset') % c.repo_name} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
@@ -31,15 +31,21 @@
                  r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
                 </div>
                 <div class="date">
-                  ${c.changeset.date}
+                  ${h.fmt_date(c.changeset.date)}
+                </div>
+                <div class="changeset-status-container">
+                    %if c.statuses:
+                      <div title="${_('Changeset status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.statuses[0])}]</div>
+                      <div class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[0])}" /></div>
+                    %endif
                 </div>
                 <div class="diff-actions">
-                  <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show')}" title="${_('raw diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
-                  <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download')}" title="${_('download diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
+                  <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show')}"  class="tooltip" title="${h.tooltip(_('raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
+                  <a href="${h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download')}"  class="tooltip" title="${h.tooltip(_('download diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
                   ${c.ignorews_url(request.GET)}
                   ${c.context_url(request.GET)}
                 </div>
-                <div class="comments-number" style="float:right;padding-right:5px">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
+                <div class="comments-number" style="float:right;padding-right:5px">${ungettext("%d comment", "%d comments", len(c.comments)) % len(c.comments)} ${ungettext("(%d inline)", "(%d inline)", c.inline_cnt) % c.inline_cnt}</div>
 			</div>
 		</div>
 	    <div id="changeset_content">
@@ -47,12 +53,12 @@
 	             <div class="left">
 	                 <div class="author">
 	                     <div class="gravatar">
-	                         <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
+	                         <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(c.changeset.author),20)}"/>
 	                     </div>
 	                     <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.urlify_commit(h.wrap_paragraphs(c.changeset.message),c.repo_name)}</div>
+	                 <div class="message">${h.urlify_commit(c.changeset.message, c.repo_name)}</div>
 	             </div>
 	             <div class="right">
 		             <div class="changes">
@@ -116,24 +122,36 @@
 	    </div>
 
     </div>
-
+    <script>
+    var _USERS_AC_DATA = ${c.users_array|n};
+    var _GROUPS_AC_DATA = ${c.users_groups_array|n};
+    AJAX_COMMENT_URL = "${url('changeset_comment',repo_name=c.repo_name,revision=c.changeset.raw_id)}";
+    AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
+    </script>
     ## diff block
     <%namespace name="diff_block" file="/changeset/diff_block.html"/>
     ${diff_block.diff_block(c.changes)}
 
     ## template for inline comment form
     <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
-    ${comment.comment_inline_form(c.changeset)}
+    ${comment.comment_inline_form()}
+
+    ## render comments and inlines
+    ${comment.generate_comments()}
 
-    ## render comments
-    ${comment.comments(c.changeset)}
+    ## main comment form and it status
+    ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id),
+                       h.changeset_status(c.rhodecode_db_repo, c.changeset.raw_id))}
+
+    ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
     <script type="text/javascript">
       YUE.onDOMReady(function(){
-    	  AJAX_COMMENT_URL = "${url('changeset_comment',repo_name=c.repo_name,revision=c.changeset.raw_id)}";
-    	  AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"
           YUE.on(YUQ('.show-inline-comments'),'change',function(e){
               var show = 'none';
               var target = e.currentTarget;
+              if(target == null){
+                  target = this;
+              }
               if(target.checked){
                   var show = ''
               }
@@ -150,6 +168,9 @@
 
           YUE.on(YUQ('.line'),'click',function(e){
               var tr = e.currentTarget;
+              if(tr == null){
+                  tr = this;
+              }
               injectInlineForm(tr);
           });
 
--- a/rhodecode/templates/changeset/changeset_comment_block.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/changeset/changeset_comment_block.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,2 +1,4 @@
+## this is a dummy html file for partial rendering on server and sending
+## generated output via ajax after comment submit
 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
 ${comment.comment_block(c.co)}
--- a/rhodecode/templates/changeset/changeset_file_comment.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/changeset/changeset_file_comment.html	Sun Sep 02 21:19:54 2012 +0200
@@ -7,17 +7,24 @@
   <div class="comment" id="comment-${co.comment_id}" line="${co.line_no}">
     <div class="comment-wrapp">
   	<div class="meta">
-  		<span class="user">
-  			<img src="${h.gravatar_url(co.author.email, 20)}" />
+        <div style="float:left"> <img src="${h.gravatar_url(co.author.email, 20)}" /> </div>
+  		<div class="user">
   			${co.author.username}
-  		</span>
-  		<span class="date">
+  		</div>
+  		<div class="date">
   			${h.age(co.modified_at)}
-  		</span>
+  		</div>
+        %if co.status_change:
+           <div  style="float:left" class="changeset-status-container">
+             <div style="float:left;padding:0px 2px 0px 2px"><span style="font-size: 18px;">&rsaquo;</span></div>
+             <div title="${_('Changeset status')}" class="changeset-status-lbl"> ${co.status_change[0].status_lbl}</div>
+             <div class="changeset-status-ico"><img src="${h.url(str('/images/icons/flag_status_%s.png' % co.status_change[0].status))}" /></div>
+           </div>
+        %endif
       %if h.HasPermissionAny('hg.admin', 'repository.admin')() or co.author.user_id == c.rhodecode_user.user_id:
-        <span class="buttons">
+        <div class="buttons">
           <span onClick="deleteComment(${co.comment_id})" class="delete-comment ui-btn">${_('Delete')}</span>
-        </span>
+        </div>
       %endif
   	</div>
   	<div class="text">
@@ -28,18 +35,23 @@
 </%def>
 
 
-<%def name="comment_inline_form(changeset)">
+<%def name="comment_inline_form()">
 <div id='comment-inline-form-template' style="display:none">
-  <div class="comment-inline-form">
+  <div class="comment-inline-form ac">
   %if c.rhodecode_user.username != 'default':
     <div class="overlay"><div class="overlay-text">${_('Submitting...')}</div></div>
-      ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=changeset.raw_id),class_='inline-form')}
+      ${h.form('#', class_='inline-form')}
       <div class="clearfix">
-          <div class="comment-help">${_('Commenting on line')} {1}. ${_('Comments parsed using')}
-          <a href="${h.url('rst_help')}">RST</a> ${_('syntax')} ${_('with')}
-          <span style="color:#003367" class="tooltip" title="${_('Use @username inside this text to send notification to this RhodeCode user')}">@mention</span> ${_('support')}
+          <div class="comment-help">${_('Commenting on line {1}.')}
+          ${(_('Comments parsed using %s syntax with %s support.') % (
+                 ('<a href="%s">RST</a>' % h.url('rst_help')),
+          	     ('<span style="color:#003367" class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
+               )
+            )|n
+           }
           </div>
-          <textarea id="text_{1}" name="text"></textarea>
+            <div class="mentions-container" id="mentions_container_{1}"></div>
+            <textarea id="text_{1}" name="text" class="yui-ac-input"></textarea>
       </div>
       <div class="comment-button">
       <input type="hidden" name="f_path" value="{0}">
@@ -52,7 +64,7 @@
       ${h.form('')}
       <div class="clearfix">
           <div class="comment-help">
-            ${'You need to be logged in to comment.'} <a href="${h.url('login_home',came_from=h.url.current())}">${_('Login now')}</a>
+            ${_('You need to be logged in to comment.')} <a href="${h.url('login_home',came_from=h.url.current())}">${_('Login now')}</a>
           </div>
       </div>
       <div class="comment-button">
@@ -65,8 +77,9 @@
 </%def>
 
 
-<%def name="inlines(changeset)">
-    <div class="comments-number">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
+## generates inlines taken from c.comments var
+<%def name="inlines()">
+    <div class="comments-number">${ungettext("%d comment", "%d comments", len(c.comments)) % len(c.comments)} ${ungettext("(%d inline)", "(%d inline)", c.inline_cnt) % c.inline_cnt}</div>
     %for path, lines in c.inline_comments:
         % for line,comments in lines.iteritems():
             <div style="display:none" class="inline-comment-placeholder" path="${path}" target_id="${h.safeid(h.safe_unicode(path))}">
@@ -79,11 +92,12 @@
 
 </%def>
 
-<%def name="comments(changeset)">
-
+## generate inline comments and the main ones
+<%def name="generate_comments()">
 <div class="comments">
     <div id="inline-comments-container">
-     ${inlines(changeset)}
+    ## generate inlines for this changeset
+     ${inlines()}
     </div>
 
     %for co in c.comments:
@@ -91,22 +105,59 @@
           ${comment_block(co)}
         </div>
     %endfor
+</div>
+</%def>
+
+## MAIN COMMENT FORM
+<%def name="comments(post_url, cur_status, close_btn=False)">
+
+<div class="comments">
     %if c.rhodecode_user.username != 'default':
-    <div class="comment-form">
-        ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=changeset.raw_id))}
+    <div class="comment-form ac">
+        ${h.form(post_url)}
         <strong>${_('Leave a comment')}</strong>
         <div class="clearfix">
             <div class="comment-help">
-                ${_('Comments parsed using')} <a href="${h.url('rst_help')}">RST</a> ${_('syntax')}
-                ${_('with')} <span style="color:#003367" class="tooltip" title="${_('Use @username inside this text to send notification to this RhodeCode user')}">@mention</span> ${_('support')}
+                ${(_('Comments parsed using %s syntax with %s support.') % (('<a href="%s">RST</a>' % h.url('rst_help')),
+          		'<span style="color:#003367" class="tooltip" title="%s">@mention</span>' %
+          		_('Use @username inside this text to send notification to this RhodeCode user')))|n}
+                | <label for="show_changeset_status_box" class="tooltip" title="${_('Check this to change current status of code-review for this changeset')}"> ${_('change status')}</label>
+                  <input style="vertical-align: bottom;margin-bottom:-2px" id="show_changeset_status_box" type="checkbox" name="change_changeset_status" />
             </div>
-                ${h.textarea('text')}
+            <div id="status_block_container" class="status-block" style="display:none">
+                %for status,lbl in c.changeset_statuses:
+                    <div class="">
+                        <img src="${h.url('/images/icons/flag_status_%s.png' % status)}" /> <input ${'checked="checked"' if status == cur_status else ''}" type="radio" name="changeset_status" value="${status}"> <label>${lbl}</label>
+                    </div>
+                %endfor
+            </div>
+            <div class="mentions-container" id="mentions_container"></div>
+             ${h.textarea('text')}
         </div>
         <div class="comment-button">
-        ${h.submit('save', _('Comment'), class_='ui-button')}
+        ${h.submit('save', _('Comment'), class_="ui-btn large")}
+        %if close_btn:
+           ${h.submit('save_close', _('Comment and close'), class_='ui-btn blue large')}
+        %endif
         </div>
         ${h.end_form()}
     </div>
     %endif
 </div>
+<script>
+YUE.onDOMReady(function () {
+   MentionsAutoComplete('text', 'mentions_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
+
+   // changeset status box listener
+   YUE.on(YUD.get('show_changeset_status_box'),'change',function(e){
+       if(e.currentTarget.checked){
+           YUD.setStyle('status_block_container','display','');
+       }
+       else{
+           YUD.setStyle('status_block_container','display','none');
+       }
+   })
+
+});
+</script>
 </%def>
--- a/rhodecode/templates/changeset/changeset_range.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/changeset/changeset_range.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,11 +2,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name}
+    ${_('%s Changesets') % c.repo_name} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
@@ -35,12 +35,17 @@
 	    <div id="changeset_compare_view_content">
 			<div class="container">
 			<table class="compare_view_commits noborder">
-            %for cs in c.cs_ranges:
+            %for cnt,cs in enumerate(c.cs_ranges):
                 <tr>
-                <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),14)}"/></div></td>
+                <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td>
                 <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td>
                 <td><div class="author">${h.person(cs.author)}</div></td>
                 <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td>
+                <td>
+                  %if c.statuses:
+                    <div title="${h.tooltip(_('Changeset status'))}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cnt])}" /></div>
+                  %endif
+                </td>
                 <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td>
                 </tr>
             %endfor
@@ -49,7 +54,7 @@
 	        <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
 	        <div class="cs_files">
 	               %for cs in c.cs_ranges:
-	                   <div class="cur_cs">r${cs}</div>
+	                   <div class="cur_cs">${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
 	                %for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]:
 	                    <div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div>
 	                %endfor
@@ -63,7 +68,12 @@
      %for cs in c.cs_ranges:
           ##${comment.comment_inline_form(cs)}
           ## diff block
-          <h3 style="border:none;padding-top:8px;">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</h3>
+          <h3 style="padding-top:8px;">
+          <a class="tooltip" title="${h.tooltip(cs.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</a>
+           <div class="gravatar">
+               <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),20)}"/>
+           </div>
+           </h3>
           ${diff_block.diff_block(c.changes[cs.raw_id])}
           ##${comment.comments(cs)}
 
--- a/rhodecode/templates/changeset/diff_block.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/changeset/diff_block.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,12 +1,12 @@
 ## -*- coding: utf-8 -*-
 ##usage:
 ## <%namespace name="diff_block" file="/changeset/diff_block.html"/>
-## ${diff_block.diff_block(changes)}
+## ${diff_block.diff_block(change)}
 ##
-<%def name="diff_block(changes)">
+<%def name="diff_block(change)">
 
-%for change,filenode,diff,cs1,cs2,stat in changes:
-    %if change !='removed':
+%for op,filenode,diff,cs1,cs2,stat in change:
+    %if op !='removed':
     <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}_target" style="clear:both;margin-top:25px"></div>
     <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}" class="diffblock  margined comm">
         <div class="code-header">
@@ -16,9 +16,9 @@
                     revision=filenode.changeset.raw_id,f_path=h.safe_unicode(filenode.path)))}
                 </div>
                 <div class="diff-actions">
-                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" title="${_('diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white_go.png')}"/></a>
-                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw')}" title="${_('raw diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
-                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download')}" title="${_('download diff')}" class="tooltip"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
+                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" class="tooltip" title="${h.tooltip(_('diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_go.png')}"/></a>
+                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw')}" class="tooltip" title="${h.tooltip(_('raw diff'))}"><img class="icon" src="${h.url('/images/icons/page_white.png')}"/></a>
+                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download')}" class="tooltip" title="${h.tooltip(_('download diff'))}"><img class="icon" src="${h.url('/images/icons/page_white_get.png')}"/></a>
                   ${c.ignorews_url(request.GET, h.FID(filenode.changeset.raw_id,filenode.path))}
                   ${c.context_url(request.GET, h.FID(filenode.changeset.raw_id,filenode.path))}
                 </div>
@@ -39,3 +39,23 @@
 %endfor
 
 </%def>
+
+<%def name="diff_block_simple(change)">
+
+  %for op,filenode_path,diff in change:
+    <div id="${h.FID('',filenode_path)}_target" style="clear:both;margin-top:25px"></div>
+    <div id="${h.FID('',filenode_path)}" class="diffblock  margined comm">
+      <div class="code-header">
+          <div class="changeset_header">
+              <div class="changeset_file">
+                  <a href="#">${h.safe_unicode(filenode_path)}</a>
+              </div>
+          </div>
+      </div>
+        <div class="code-body">
+            <div class="full_f_path" path="${h.safe_unicode(filenode_path)}"></div>
+            ${diff|n}
+        </div>
+    </div>
+  %endfor
+</%def>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/compare/compare_cs.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,27 @@
+## Changesets table !
+<div class="container">
+  <table class="compare_view_commits noborder">
+  %if not c.cs_ranges:
+    <tr><td>${_('No changesets')}</td></tr>
+  %else:
+    %for cnt, cs in enumerate(c.cs_ranges):
+        <tr>
+        <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td>
+        <td>
+          %if cs.raw_id in c.statuses:
+            <div title="${c.statuses[cs.raw_id][1]}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cs.raw_id][0])}" /></div>
+          %endif
+        </td>
+        <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.target_repo,revision=cs.raw_id))}
+        %if c.as_form:
+          ${h.hidden('revisions',cs.raw_id)}
+        %endif
+        </td>
+        <td><div class="author">${h.person(cs.author)}</div></td>
+        <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td>
+        <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td>
+        </tr>
+    %endfor
+  %endif
+  </table>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/compare/compare_diff.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,77 @@
+## -*- coding: utf-8 -*-
+<%inherit file="/base/base.html"/>
+
+<%def name="title()">
+    ${c.repo_name} ${_('Compare')} ${'%s@%s' % (c.org_repo.repo_name, c.org_ref)} -> ${'%s@%s' % (c.other_repo.repo_name, c.other_ref)}
+</%def>
+
+<%def name="breadcrumbs_links()">
+    ${h.link_to(_(u'Home'),h.url('/'))}
+    &raquo;
+    ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
+    &raquo;
+    ${_('Compare')}
+</%def>
+
+<%def name="page_nav()">
+    ${self.menu('changelog')}
+</%def>
+
+<%def name="main()">
+<div class="box">
+    <!-- box / title -->
+    <div class="title">
+        ${self.breadcrumbs()}
+    </div>
+    <div class="table">
+        <div id="body" class="diffblock">
+            <div class="code-header cv">
+                <h3 class="code-header-title">${_('Compare View')}</h3>
+                <div>
+                ${'%s@%s' % (c.org_repo.repo_name, c.org_ref)} -> ${'%s@%s' % (c.other_repo.repo_name, c.other_ref)}  <a href="${c.swap_url}">[swap]</a>
+                </div>
+            </div>
+        </div>
+        <div id="changeset_compare_view_content">
+            ##CS
+            <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Outgoing changesets')}</div>
+            <%include file="compare_cs.html" />
+
+            ## FILES
+            <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
+            <div class="cs_files">
+              %for fid, change, f, stat in c.files:
+                  <div class="cs_${change}">
+                    <div class="node">${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}</div>
+                    <div class="changes">${h.fancy_file_stats(stat)}</div>
+                  </div>
+              %endfor
+            </div>
+        </div>
+    </div>
+
+    ## diff block
+    <%namespace name="diff_block" file="/changeset/diff_block.html"/>
+    %for fid, change, f, stat in c.files:
+      ${diff_block.diff_block_simple([c.changes[fid]])}
+    %endfor
+
+     <script type="text/javascript">
+
+      YUE.onDOMReady(function(){
+
+          YUE.on(YUQ('.diff-menu-activate'),'click',function(e){
+              var act = e.currentTarget.nextElementSibling;
+
+              if(YUD.hasClass(act,'active')){
+                  YUD.removeClass(act,'active');
+                  YUD.setStyle(act,'display','none');
+              }else{
+                  YUD.addClass(act,'active');
+                  YUD.setStyle(act,'display','');
+              }
+          });
+      })
+    </script>
+    </div>
+</%def>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/data_table/_dt_elements.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,110 @@
+## DATA TABLE RE USABLE ELEMENTS
+## usage:
+## <%namespace name="dt" file="/data_table/_dt_elements.html"/>
+
+<%def name="repo_actions(repo_name)">
+  ${h.form(h.url('repo', 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: %s') % repo_name+"');")}
+  ${h.end_form()}
+</%def>
+
+<%def name="quick_menu(repo_name)">
+  <ul class="menu_items hidden">
+    <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
+    <li>
+       <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
+       <span class="icon">
+           <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
+       </span>
+       <span>${_('Summary')}</span>
+       </a>
+    </li>
+    <li>
+       <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
+       <span class="icon">
+           <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
+       </span>
+       <span>${_('Changelog')}</span>
+       </a>
+    </li>
+    <li>
+       <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
+       <span class="icon">
+           <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
+       </span>
+       <span>${_('Files')}</span>
+       </a>
+    </li>
+    <li>
+       <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
+       <span class="icon">
+           <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
+       </span>
+       <span>${_('Fork')}</span>
+       </a>
+    </li>
+  </ul>
+</%def>
+
+<%def name="repo_name(name,rtype,private,fork_of,short_name=False, admin=False)">
+    <%
+    def get_name(name,short_name=short_name):
+      if short_name:
+        return name.split('/')[-1]
+      else:
+        return name
+    %>
+  <div style="white-space: nowrap">
+   ##TYPE OF REPO
+   %if h.is_hg(rtype):
+     <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
+   %elif h.is_git(rtype):
+     <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
+   %endif
+
+   ##PRIVATE/PUBLIC
+   %if private and c.visual.show_private_icon:
+     <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
+   %elif not private and c.visual.show_public_icon:
+     <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
+   %endif
+
+   ##NAME
+   %if admin:
+    ${h.link_to(get_name(name),h.url('edit_repo',repo_name=name),class_="repo_name")}
+   %else:
+    ${h.link_to(get_name(name),h.url('summary_home',repo_name=name),class_="repo_name")}
+   %endif
+   %if fork_of:
+        <a href="${h.url('summary_home',repo_name=fork_of)}">
+        <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
+   %endif
+  </div>
+</%def>
+
+
+
+<%def name="revision(name,rev,tip,author,last_msg)">
+  <div>
+  %if rev >= 0:
+      <pre><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></pre>
+  %else:
+      ${_('No changesets yet')}
+  %endif
+  </div>
+</%def>
+
+<%def name="user_gravatar(email, size=24)">
+    <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(email, size)}"/> </div>
+</%def>
+
+<%def name="user_actions(user_id, username)">
+  ${h.form(h.url('delete_user', id=user_id),method='delete')}
+      ${h.submit('remove_',_('delete'),id="remove_user_%s" % user_id,
+      class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % username+"');")}
+  ${h.end_form()}
+</%def>
+
+<%def name="user_name(user_id, username)">
+    ${h.link_to(username,h.url('edit_user', id=user_id))}
+</%def>
--- a/rhodecode/templates/email_templates/changeset_comment.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/email_templates/changeset_comment.html	Sun Sep 02 21:19:54 2012 +0200
@@ -4,3 +4,9 @@
 <h4>${subject}</h4>
 
 ${body}
+
+% if status_change is not None:
+<div>
+    New status -> ${status_change}
+</div>
+% endif
--- a/rhodecode/templates/errors/error_document.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/errors/error_document.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,14 +1,16 @@
 ## -*- coding: utf-8 -*-
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
         <title>Error - ${c.error_message}</title>
         <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+        <meta name="robots" content="index, nofollow"/>
+        <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
+
+        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 	    %if c.redirect_time:
 	        <meta http-equiv="refresh" content="${c.redirect_time}; url=${c.url_redirect}"/>
 	    %endif
-        <link rel="icon" href="${h.url("/images/hgicon.png")}" type="image/png" />
-        <meta name="robots" content="index, nofollow"/>
 
         <!-- stylesheets -->
         <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
--- a/rhodecode/templates/files/file_diff.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/files/file_diff.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,11 +1,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('File diff')} - ${c.rhodecode_name}
+    ${_('%s File diff') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/files/files.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/files/files.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,11 +1,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Files')} - ${c.rhodecode_name}
+    ${_('%s files') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('files_home',repo_name=c.repo_name))}
     &raquo;
@@ -36,13 +36,107 @@
 		</div>
     </div>
 </div>
+
 <script type="text/javascript">
-var YPJAX_TITLE = "${c.repo_name} ${_('Files')} - ${c.rhodecode_name}";
-var current_url = "${h.url.current()}";
-var node_list_url = '${h.url("files_home",repo_name=c.repo_name,revision=c.changeset.raw_id,f_path='__FPATH__')}';
-var url_base = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.file.path)}';
-var truncated_lbl = "${_('search truncated')}";
-var nomatch_lbl = "${_('no matching files')}";
-fileBrowserListeners(current_url, node_list_url, url_base, truncated_lbl, nomatch_lbl);
+var CACHE = {};
+var CACHE_EXPIRE = 60*1000; //cache for 60s
+//used to construct links from the search list
+var node_list_url = '${h.url("files_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
+//send the nodelist request to this url
+var url_base = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
+
+var ypjax_links = function(){
+    YUE.on(YUQ('.ypjax-link'), 'click',function(e){
+    	
+    	//don't do ypjax on middle click
+    	if(e.which == 2 || !History.enabled){ 
+    		return true;
+    	}
+    	
+        var el = e.currentTarget;
+        var url = el.href;
+
+        var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}';
+        _base_url = _base_url.replace('//','/')
+        
+        //extract rev and the f_path from url.
+        parts = url.split(_base_url)
+        if(parts.length != 2){
+        	return false;
+        }
+        
+        var parts2 = parts[1].split('/');
+      	var rev = parts2.shift(); // pop the first element which is the revision
+      	var f_path = parts2.join('/');
+        
+        var title = "${_('%s files') % c.repo_name}" + " - " + f_path;
+        
+        var _node_list_url = node_list_url.replace('__REV__',rev);
+        var _url_base = url_base.replace('__REV__',rev).replace('__FPATH__', f_path);
+
+        // Change our States and save some data for handling events
+        var data = {url:url,title:title, url_base:_url_base,
+                    node_list_url:_node_list_url};
+        History.pushState(data, title, url);        
+        
+        //now we're sure that we can do ypjax things
+        YUE.preventDefault(e)
+        return false;
+    });
+}
+
+var callbacks = function(State){
+    ypjax_links();
+    tooltip_activate();
+    fileBrowserListeners(State.url, State.data.node_list_url, State.data.url_base);
+    // Inform Google Analytics of the change
+    if ( typeof window.pageTracker !== 'undefined' ) {
+        window.pageTracker._trackPageview(State.url);
+    }	
+}
+
+YUE.onDOMReady(function(){ 
+    ypjax_links();
+    var container = 'files_data';
+    //Bind to StateChange Event
+    History.Adapter.bind(window,'statechange',function(){
+        var State = History.getState();
+        cache_key = State.url;
+        //check if we have this request in cache maybe ?
+        var _cache_obj = CACHE[cache_key];
+        var _cur_time = new Date().getTime();
+        // get from cache if it's there and not yet expired !
+        if(_cache_obj !== undefined && _cache_obj[0] > _cur_time){
+            YUD.get(container).innerHTML=_cache_obj[1];
+            YUD.setStyle(container,'opacity','1.0');
+
+            //callbacks after ypjax call
+            callbacks(State);
+        }
+        else{
+          ypjax(State.url,container,function(o){
+          	//callbacks after ypjax call
+          	callbacks(State);
+          	if (o !== undefined){
+          	  //store our request in cache
+          	  var _expire_on = new Date().getTime()+CACHE_EXPIRE;
+              CACHE[cache_key] = [_expire_on, o.responseText];
+            }
+          });
+        }
+    });    
+ 
+    // init the search filter
+    var _State = {
+       url: "${h.url.current()}",
+       data: {
+         node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}"),
+         url_base: url_base.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}")
+       }
+    }
+    fileBrowserListeners(_State.url, _State.data.node_list_url, _State.data.url_base);
+});
+
 </script>
+
 </%def>
--- a/rhodecode/templates/files/files_add.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/files/files_add.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,7 +1,7 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Edit file')} - ${c.rhodecode_name}
+    ${_('%s Edit file') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="js_extra()">
@@ -12,7 +12,7 @@
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/files/files_browser.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/files/files_browser.html	Sun Sep 02 21:19:54 2012 +0200
@@ -11,9 +11,9 @@
 			${h.form(h.url.current())}
 			<div class="info_box">
 	          <span class="rev">${_('view')}@rev</span>
-	          <a class="ui-btn" href="${c.url_prev}" title="${_('previous revision')}">&laquo;</a>
+	          <a class="ui-btn ypjax-link" href="${c.url_prev}" title="${_('previous revision')}">&laquo;</a>
 	          ${h.text('at_rev',value=c.changeset.revision,size=5)}
-	          <a class="ui-btn" href="${c.url_next}" title="${_('next revision')}">&raquo;</a>
+	          <a class="ui-btn ypjax-link" href="${c.url_next}" title="${_('next revision')}">&raquo;</a>
 	          ## ${h.submit('view',_('view'),class_="ui-btn")}
 		    </div>
 			${h.end_form()}
@@ -88,14 +88,14 @@
 		             </td>
 		             <td>
 		             	%if node.is_file():
-		             		<div class="tooltip" title="${node.last_changeset.message}">
+		             		<div class="tooltip" title="${h.tooltip(node.last_changeset.message)}">
 		             		<pre>${'r%s:%s' % (node.last_changeset.revision,node.last_changeset.short_id)}</pre>
                             </div>
 		             	%endif
 		             </td>
 		             <td>
 		             	%if node.is_file():
-		             		<span class="tooltip" title="${node.last_changeset.date}">
+		             		<span class="tooltip" title="${h.tooltip(h.fmt_date(node.last_changeset.date))}">
                             ${h.age(node.last_changeset.date)}</span>
 		             	%endif
 		             </td>
--- a/rhodecode/templates/files/files_edit.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/files/files_edit.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,7 +1,7 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Edit file')} - ${c.rhodecode_name}
+    ${_('%s Edit file') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="js_extra()">
@@ -12,7 +12,7 @@
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/files/files_source.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/files/files_source.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,22 +1,34 @@
 <dl>
-	<dt style="padding-top:10px;font-size:16px">${_('History')}</dt>
+	<dt class="file_history">${_('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.changeset.raw_id)}
-		${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
-		${h.submit('diff','diff to revision',class_="ui-btn")}
-		${h.submit('show_rev','show at revision',class_="ui-btn")}
-		${h.end_form()}
-		</div>
+        <div>
+    		<div style="float:left">
+    		${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
+    		${h.hidden('diff2',c.file.changeset.raw_id)}
+    		${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
+    		${h.submit('diff',_('diff to revision'),class_="ui-btn")}
+    		${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
+    		${h.end_form()}
+    		</div>
+            <div class="file_author">
+                <div class="item">${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('<b>%s</b>' % len(c.authors))) }</div>
+                %for email, user in c.authors:
+                  <div class="contributor tooltip" style="float:left" title="${h.tooltip(user)}">
+                    <div class="gravatar" style="margin:1px"><img alt="gravatar" src="${h.gravatar_url(email, 20)}"/> </div>
+                  </div>
+                %endfor
+            </div>
+        </div>
+        <div style="clear:both"></div>
 	</dd>
+
 </dl>
 
 <div id="body" class="codeblock">
 	<div class="code-header">
         <div class="stats">
             <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div>
-            <div class="left item"><pre class="tooltip" title="${c.file.changeset.date}">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
+            <div class="left item"><pre class="tooltip" title="${h.tooltip(h.fmt_date(c.file.changeset.date))}">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
             <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
             <div class="left item last"><pre>${c.file.mimetype}</pre></div>
             <div class="buttons">
@@ -36,7 +48,7 @@
         </div>
         <div class="author">
             <div class="gravatar">
-                <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/>
+                <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(c.file.changeset.author),16)}"/>
             </div>
             <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div>
         </div>
--- a/rhodecode/templates/files/files_ypjax.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/files/files_ypjax.html	Sun Sep 02 21:19:54 2012 +0200
@@ -9,7 +9,7 @@
             <%include file='files_browser.html'/>
         %else:
             <%include file='files_source.html'/>
-        %endif
+        %endif        
 %else:
     <h2>
         <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a>
--- a/rhodecode/templates/followers/followers.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/followers/followers.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,11 +2,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Followers')} - ${c.rhodecode_name}
+    ${_('%s Followers') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/followers/followers_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/followers/followers_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -9,8 +9,8 @@
             <span style="font-size: 20px"> <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname})</span>
         </div>
         <div style="clear:both;padding-top: 10px"></div>
-        <div class="follower_date">${_('Started following')} -
-        <span class="tooltip" title="${f.follows_from}"> ${h.age(f.follows_from)}</span></div>
+        <div class="follower_date">${_('Started following -')}
+        <span class="tooltip" title="${h.tooltip(f.follows_from)}"> ${h.age(f.follows_from)}</span></div>
         <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div>
     </div>
 % endfor
--- a/rhodecode/templates/forks/fork.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/forks/fork.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,11 +2,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Fork')} - ${c.rhodecode_name}
+    ${_('%s Fork') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_info.repo_name,h.url('summary_home',repo_name=c.repo_info.repo_name))}
     &raquo;
@@ -36,12 +36,22 @@
                   ${h.hidden('fork_parent_id',c.repo_info.repo_id)}
               </div>
             </div>
+             <div class="field">
+                <div class="label">
+                    <label for="landing_rev">${_('Landing revision')}:</label>
+                </div>
+                <div class="input">
+                    ${h.select('landing_rev','',c.landing_revs,class_="medium")}
+                    <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
+                </div>
+            </div>
             <div class="field">
                  <div class="label">
                      <label for="repo_group">${_('Repository group')}:</label>
                  </div>
                  <div class="input">
                      ${h.select('repo_group','',c.repo_groups,class_="medium")}
+                     <span class="help-block">${_('Optionaly select a group to put this repository into.')}</span>
                  </div>
             </div>
             <div class="field">
@@ -50,6 +60,7 @@
                 </div>
                 <div class="textarea text-area editor">
                     ${h.textarea('description',cols=23,rows=5)}
+                    <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
                 </div>
              </div>
             <div class="field">
@@ -58,6 +69,7 @@
                 </div>
                 <div class="checkboxes">
                     ${h.checkbox('private',value="True")}
+                    <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
                 </div>
             </div>
             <div class="field">
@@ -66,6 +78,7 @@
                 </div>
                 <div class="checkboxes">
                     ${h.checkbox('copy_permissions',value="True", checked="checked")}
+                    <span class="help-block">${_('Copy permissions from forked repository')}</span>
                 </div>
              </div>
             <div class="field">
@@ -74,10 +87,11 @@
                 </div>
                 <div class="checkboxes">
                     ${h.checkbox('update_after_clone',value="True")}
+                    <span class="help-block">${_('Checkout source after making a clone')}</span>
                 </div>
              </div>
 	        <div class="buttons">
-	          ${h.submit('',_('fork this repository'),class_="ui-button")}
+	          ${h.submit('',_('fork this repository'),class_="ui-btn large")}
 	        </div>
         </div>
     </div>
--- a/rhodecode/templates/forks/forks.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/forks/forks.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,11 +2,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Forks')} - ${c.rhodecode_name}
+    ${_('%s Forks') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/forks/forks_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/forks/forks_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -15,7 +15,11 @@
 	        </div>
 	        <div style="clear:both;padding-top: 10px"></div>
 	        <div class="follower_date">${_('forked')} -
-	        <span class="tooltip" title="${f.created_on}"> ${h.age(f.created_on)}</span></div>
+	        <span class="tooltip" title="${h.tooltip(h.fmt_date(f.created_on))}"> ${h.age(f.created_on)}</span>
+            <a title="${_('compare fork with %s' % c.repo_name)}"
+               href="${h.url('compare_url',repo_name=f.repo_name,org_ref_type='branch',org_ref='default',other_ref_type='branch',other_ref='default', repo=c.repo_name)}"
+               class="ui-btn small">${_('Compare fork')}</a>
+             </div>
 	        <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div>
 	    </div>
 	% endfor
--- a/rhodecode/templates/index_base.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/index_base.html	Sun Sep 02 21:19:54 2012 +0200
@@ -41,7 +41,11 @@
                             ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
                             </div>
                         </td>
-                        <td>${gr.group_description}</td>
+                        %if c.visual.stylify_metatags:
+                            <td>${h.desc_stylize(gr.group_description)}</td>
+                        %else:
+                            <td>${gr.group_description}</td>
+                        %endif
                         ## this is commented out since for multi nested repos can be HEAVY!
                         ## in number of executed queries during traversing uncomment at will
                         ##<td><b>${gr.repositories_recursive_count}</b></td>
@@ -57,7 +61,7 @@
             </div>
             <div id='repos_list_wrap' class="yui-skin-sam">
             <%cnt=0%>
-            <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
+            <%namespace name="dt" file="/data_table/_dt_elements.html"/>
 
             <table id="repos_list">
             <thead>
@@ -85,11 +89,15 @@
                     </td>
                     ##DESCRIPTION
                     <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
+                       %if c.visual.stylify_metatags:
+                       ${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))}</span>
+                       %else:
                        ${h.truncate(repo['description'],60)}</span>
+                       %endif
                     </td>
                     ##LAST CHANGE DATE
                     <td>
-                      <span class="tooltip" title="${repo['last_change']}">${h.age(repo['last_change'])}</span>
+                      <span class="tooltip" date="${repo['last_change']}" title="${h.tooltip(h.fmt_date(repo['last_change']))}">${h.age(repo['last_change'])}</span>
                     </td>
                     ##LAST REVISION
                     <td>
@@ -119,11 +127,13 @@
         </div>
     </div>
     <script>
-      YUD.get('repo_count').innerHTML = ${cnt+1};
+      YUD.get('repo_count').innerHTML = ${cnt+1 if cnt else 0};
       var func = function(node){
           return node.parentNode.parentNode.parentNode.parentNode;
       }
 
+      var sort_by = "name";
+      var sort_dir = "asc";
 
       // groups table sorting
       var myColumnDefs = [
@@ -184,7 +194,7 @@
 
       var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
               {
-               sortedBy:{key:"name",dir:"asc"},
+               sortedBy:{key:sort_by,dir:sort_dir},
                MSG_SORTASC:"${_('Click to sort ascending')}",
                MSG_SORTDESC:"${_('Click to sort descending')}",
                MSG_EMPTY:"${_('No records found.')}",
--- a/rhodecode/templates/journal/journal.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/journal/journal.html	Sun Sep 02 21:19:54 2012 +0200
@@ -9,6 +9,10 @@
 <%def name="page_nav()">
 	${self.menu('home')}
 </%def>
+<%def name="head_extra()">
+<link href="${h.url('journal_atom', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('ATOM journal feed')}" type="application/atom+xml" />
+<link href="${h.url('journal_rss', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('RSS journal feed')}" type="application/rss+xml" />
+</%def>
 <%def name="main()">
 
     <div class="box box-left">
@@ -17,8 +21,13 @@
 	        <h5>${_('Journal')}</h5>
              <ul class="links">
                <li>
-                 <span><a id="refresh" href="${h.url('journal')}"><img class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/>
-                 </a></span>
+                 <span><a id="refresh" href="${h.url('journal')}"><img class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/></a></span>
+               </li>
+               <li>
+                 <span><a href="${h.url('journal_rss', api_key=c.rhodecode_user.api_key)}"><img class="icon" title="${_('RSS feed')}" alt="${_('RSS feed')}" src="${h.url('/images/icons/rss_16.png')}"/></a></span>
+               </li>
+               <li>
+                 <span><a href="${h.url('journal_atom', api_key=c.rhodecode_user.api_key)}"><img class="icon" title="${_('ATOM feed')}" alt="${_('ATOM feed')}" src="${h.url('/images/icons/atom.png')}"/></a></span>
                </li>
              </ul>
 	    </div>
@@ -53,7 +62,7 @@
                   <th class="left">${_('Action')}</th>
              </thead>
              <tbody>
-                 <%namespace name="dt" file="/_data_table/_dt_elements.html"/>
+                 <%namespace name="dt" file="/data_table/_dt_elements.html"/>
                  %for repo in c.user_repos:
                     <tr>
                         ##QUICK MENU
@@ -72,7 +81,7 @@
                         <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/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'],'',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
+                            ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
                           ${h.end_form()}
                         </td>
                     </tr>
@@ -119,9 +128,9 @@
                            <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
                          %endif
 
-                        %if entry.follows_repository.private:
+                        %if entry.follows_repository.private and c.visual.show_private_icon:
                           <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
-                        %else:
+                        %elif not entry.follows_repository.private and c.visual.show_public_icon:
                           <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
                         %endif
                         <span class="watched_repo">
--- a/rhodecode/templates/journal/journal_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/journal/journal_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -11,8 +11,8 @@
 	            <div class="journal_user">${user.name} ${user.lastname}</div>
 	            <div class="journal_action_container">
 	            % for entry in entries:
-		            <div class="journal_icon"> ${h.action_parser_icon(entry)}</div>
-		            <div class="journal_action">${h.action_parser(entry)[0]}</div>
+		            <div class="journal_icon"> ${h.action_parser(entry)[2]()}</div>
+		            <div class="journal_action">${h.action_parser(entry)[0]()}</div>
 		            <div class="journal_repo">
 		                <span class="journal_repo_name">
 		                %if entry.repository is not None:
@@ -24,7 +24,7 @@
 		                </span>
 		            </div>
 		            <div class="journal_action_params">${h.literal(h.action_parser(entry)[1]())}</div>
-		            <div class="date"><span class="tooltip" title="${entry.action_date}">${h.age(entry.action_date)}</span></div>
+		            <div class="date"><span class="tooltip" title="${h.tooltip(h.fmt_date(entry.action_date))}">${h.age(entry.action_date)}</span></div>
 	            %endfor
 	            </div>
 	        </div>
--- a/rhodecode/templates/journal/public_journal.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/journal/public_journal.html	Sun Sep 02 21:19:54 2012 +0200
@@ -9,33 +9,35 @@
 <%def name="page_nav()">
 	${self.menu('home')}
 </%def>
+<%def name="head_extra()">
+<link href="${h.url('public_journal_atom')}" rel="alternate" title="${_('ATOM public journal feed')}" type="application/atom+xml" />
+<link href="${h.url('public_journal_rss')}" rel="alternate" title="${_('RSS public journal feed')}" type="application/rss+xml" />
+</%def>
 <%def name="main()">
 
-    <div class="box">
-	    <!-- box / title -->
-	    <div class="title">
-	        <h5>${_('Public Journal')}</h5>
-                <ul class="links">
-                  <li>
-                    <span>${h.link_to(_('RSS'),h.url('public_journal_rss'),class_='rss_icon')}</span>
-                  </li>
-                  <li>
-                    <span>${h.link_to(_('Atom'),h.url('public_journal_atom'),class_='atom_icon')}</span>
-                  </li>
-
-                </ul>
-
-	    </div>
-		<script type="text/javascript">
-		function show_more_event(){
-		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 id="journal">${c.journal_data}</div>
-    </div>
+<div class="box">
+  <!-- box / title -->
+  <div class="title">
+    <h5>${_('Public Journal')}</h5>
+      <ul class="links">
+      <li>
+       <span><a href="${h.url('public_journal_rss')}"><img class="icon" title="${_('RSS feed')}" alt="${_('RSS feed')}" src="${h.url('/images/icons/atom.png')}"/></a></span>
+     </li>
+     <li>
+       <span><a href="${h.url('public_journal_atom')}"><img class="icon" title="${_('ATOM feed')}" alt="${_('ATOM feed')}" src="${h.url('/images/icons/rss_16.png')}"/></a></span>
+     </li>
+     </ul>
+  </div>
+  <script type="text/javascript">
+  function show_more_event(){
+  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 id="journal">${c.journal_data}</div>
+</div>
 
 </%def>
--- a/rhodecode/templates/login.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/login.html	Sun Sep 02 21:19:54 2012 +0200
@@ -51,7 +51,7 @@
                     </div>
                 </div>
                 <div class="buttons">
-                    ${h.submit('sign_in',_('Sign In'),class_="ui-button")}
+                    ${h.submit('sign_in',_('Sign In'),class_="ui-btn large")}
                 </div>
             </div>
             <!-- end fields -->
--- a/rhodecode/templates/password_reset.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/password_reset.html	Sun Sep 02 21:19:54 2012 +0200
@@ -27,7 +27,7 @@
 
 	            <div class="buttons">
 		            <div class="nohighlight">
-		              ${h.submit('send',_('Reset my password'),class_="ui-button")}
+		              ${h.submit('send',_('Reset my password'),class_="ui-btn large")}
 					  	<div class="activation_msg">${_('Password reset link will be send to matching email address')}</div>
 		            </div>
 	            </div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/pullrequests/pullrequest.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,189 @@
+<%inherit file="/base/base.html"/>
+
+<%def name="title()">
+    ${c.repo_name} ${_('New pull request')}
+</%def>
+
+<%def name="breadcrumbs_links()">
+    ${h.link_to(_(u'Home'),h.url('/'))}
+    &raquo;
+    ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
+    &raquo;
+    ${_('New pull request')}
+</%def>
+
+<%def name="main()">
+
+<div class="box">
+    <!-- box / title -->
+    <div class="title">
+        ${self.breadcrumbs()}
+    </div>
+    ${h.form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')}
+    <div style="float:left;padding:0px 30px 30px 30px">
+       <div style="padding:0px 5px 5px 5px">
+         <span>
+           <a id="refresh" href="#">
+             <img class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/>
+             ${_('refresh overview')}
+           </a>
+         </span>
+       </div>
+        ##ORG
+        <div style="float:left">
+            <div class="fork_user">
+                <div class="gravatar">
+                    <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_db_repo.user.email,24)}"/>
+                </div>
+                <span style="font-size: 20px">
+                ${h.select('org_repo','',c.org_repos,class_='refs')}:${h.select('org_ref','',c.org_refs,class_='refs')}
+                </span>
+                 <div style="padding:5px 3px 3px 42px;">${c.rhodecode_db_repo.description}</div>
+            </div>
+            <div style="clear:both;padding-top: 10px"></div>
+        </div>
+          <div style="float:left;font-size:24px;padding:0px 20px">
+          <img height=32 width=32 src="${h.url('/images/arrow_right_64.png')}"/>
+          </div>
+
+        ##OTHER, most Probably the PARENT OF THIS FORK
+        <div style="float:left">
+            <div class="fork_user">
+                <div class="gravatar">
+                    <img id="other_repo_gravatar" alt="gravatar" src=""/>
+                </div>
+                <span style="font-size: 20px">
+                ${h.select('other_repo',c.default_pull_request ,c.other_repos,class_='refs')}:${h.select('other_ref','',c.default_revs,class_='refs')}
+                </span>
+                 <div id="other_repo_desc" style="padding:5px 3px 3px 42px;"></div>
+            </div>
+            <div style="clear:both;padding-top: 10px"></div>
+        </div>
+       <div style="clear:both;padding-top: 10px"></div>
+       ## overview pulled by ajax
+       <div style="float:left" id="pull_request_overview"></div>
+       <div style="float:left;clear:both;padding:10px 10px 10px 0px;display:none">
+            <a id="pull_request_overview_url" href="#">${_('Detailed compare view')}</a>
+       </div>
+     </div>
+    <div style="float:left; border-left:1px dashed #eee">
+        <h4>${_('Pull request reviewers')}</h4>
+        <div id="reviewers" style="padding:0px 0px 0px 15px">
+          ## members goes here !
+          <div class="group_members_wrap">
+            <ul id="review_members" class="group_members">
+            %for member in c.review_members:
+              <li id="reviewer_${member.user_id}">
+                <div class="reviewers_member">
+                  <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
+                  <div style="float:left">${member.full_name} (${_('owner')})</div>
+                  <input type="hidden" value="${member.user_id}" name="review_members" />
+                  <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span>
+                </div>
+              </li>
+            %endfor
+            </ul>
+          </div>
+
+          <div class='ac'>
+            <div class="reviewer_ac">
+               ${h.text('user', class_='yui-ac-input')}
+               <span class="help-block">${_('Add reviewer to this pull request.')}</span>
+               <div id="reviewers_container"></div>
+            </div>
+          </div>
+        </div>
+    </div>
+    <h3>${_('Create new pull request')}</h3>
+
+    <div class="form">
+        <!-- fields -->
+
+        <div class="fields">
+
+             <div class="field">
+                <div class="label">
+                    <label for="pullrequest_title">${_('Title')}:</label>
+                </div>
+                <div class="input">
+                    ${h.text('pullrequest_title',size=30)}
+                </div>
+             </div>
+
+            <div class="field">
+                <div class="label label-textarea">
+                    <label for="pullrequest_desc">${_('description')}:</label>
+                </div>
+                <div class="textarea text-area editor">
+                    ${h.textarea('pullrequest_desc',size=30)}
+                </div>
+            </div>
+
+            <div class="buttons">
+                ${h.submit('save',_('Send pull request'),class_="ui-btn large")}
+                ${h.reset('reset',_('Reset'),class_="ui-btn large")}
+           </div>
+        </div>
+    </div>
+    ${h.end_form()}
+
+</div>
+
+<script type="text/javascript">
+  var _USERS_AC_DATA = ${c.users_array|n};
+  var _GROUPS_AC_DATA = ${c.users_groups_array|n};
+  PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
+
+  var other_repos_info = ${c.other_repos_info|n};
+  var loadPreview = function(){
+	  YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','none');
+      var url = "${h.url('compare_url',
+    	                 repo_name='org_repo',
+    	                 org_ref_type='org_ref_type', org_ref='org_ref',
+                         other_ref_type='other_ref_type', other_ref='other_ref',
+                         repo='other_repo',
+                         as_form=True)}";
+
+      var select_refs = YUQ('#pull_request_form select.refs')
+
+      for(var i=0;i<select_refs.length;i++){
+        var select_ref = select_refs[i];
+        var select_ref_data = select_ref.value.split(':');
+        var key = null;
+        var val = null;
+        if(select_ref_data.length>1){
+          key = select_ref.name+"_type";
+          val = select_ref_data[0];
+          url = url.replace(key,val);
+
+          key = select_ref.name;
+          val = select_ref_data[1];
+          url = url.replace(key,val);
+
+        }else{
+          key = select_ref.name;
+          val = select_ref.value;
+          url = url.replace(key,val);
+        }
+      }
+
+      ypjax(url,'pull_request_overview', function(data){
+    	  var sel_box = YUQ('#pull_request_form #other_repo')[0];
+    	  var repo_name = sel_box.options[sel_box.selectedIndex].value;
+    	  YUD.get('pull_request_overview_url').href = url;
+    	  YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
+    	  YUD.get('other_repo_gravatar').src = other_repos_info[repo_name]['gravatar'];
+    	  YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
+    	  YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
+      })
+  }
+  YUE.on('refresh','click',function(e){
+     loadPreview()
+  })
+
+  //lazy load overview after 0.5s
+  setTimeout(loadPreview, 500)
+
+</script>
+
+</%def>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/pullrequests/pullrequest_show.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,195 @@
+<%inherit file="/base/base.html"/>
+
+<%def name="title()">
+    ${c.repo_name} ${_('Pull request #%s') % c.pull_request.pull_request_id}
+</%def>
+
+<%def name="breadcrumbs_links()">
+    ${h.link_to(_(u'Home'),h.url('/'))}
+    &raquo;
+    ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
+    &raquo;
+    ${_('Pull request #%s') % c.pull_request.pull_request_id}
+</%def>
+
+<%def name="main()">
+
+<div class="box">
+    <!-- box / title -->
+    <div class="title">
+        ${self.breadcrumbs()}
+    </div>
+        %if c.pull_request.is_closed():
+        <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))}</div>
+        %endif
+    <h3>${_('Title')}: ${c.pull_request.title}</h3>
+        
+    <div class="form">
+      <div id="summary" class="fields">
+         <div class="field">
+          <div class="label-summary">
+              <label>${_('Status')}:</label>
+          </div>
+          <div class="input">
+            <div class="changeset-status-container" style="float:none;clear:both">
+            %if c.current_changeset_status:
+              <div title="${_('Pull request status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.current_changeset_status)}]</div>
+              <div class="changeset-status-ico" style="padding:1px 4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div>
+            %endif
+            </div>
+          </div>
+         </div>
+         <div class="field">
+          <div class="label-summary">
+              <label>${_('Still not reviewed by')}:</label>
+          </div>
+          <div class="input">
+            <div class="tooltip" title="${h.tooltip(','.join([x.username for x in c.pull_request_pending_reviewers]))}">${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div>
+          </div>
+         </div>                
+      </div>
+    </div>    
+    <div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div>
+    <div style="padding:4px 4px 10px 20px">
+      <div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div>
+    </div>
+
+    <div style="min-height:160px">
+      ##DIFF
+      <div class="table" style="float:left;clear:none">
+          <div id="body" class="diffblock">
+              <div style="white-space:pre-wrap;padding:5px">${_('Compare view')}</div>
+          </div>
+          <div id="changeset_compare_view_content">
+              ##CS
+              <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Incoming changesets')}</div>
+              <%include file="/compare/compare_cs.html" />
+
+              ## FILES
+              <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
+              <div class="cs_files">
+                %for fid, change, f, stat in c.files:
+                    <div class="cs_${change}">
+                      <div class="node">${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}</div>
+                      <div class="changes">${h.fancy_file_stats(stat)}</div>
+                    </div>
+                %endfor
+              </div>
+          </div>
+      </div>
+      ## REVIEWERS
+       <div style="float:left; border-left:1px dashed #eee">
+       <h4>${_('Pull request reviewers')}</h4>
+        <div id="reviewers" style="padding:0px 0px 0px 15px">
+          ## members goes here !
+          <div class="group_members_wrap">
+            <ul id="review_members" class="group_members">
+            %for member,status in c.pull_request_reviewers:
+              <li id="reviewer_${member.user_id}">
+                <div class="reviewers_member">
+                    <div style="float:left;padding:0px 3px 0px 0px" class="tooltip" title="${h.tooltip(h.changeset_status_lbl(status[0][1].status if status else 'not_reviewed'))}">
+                      <img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/>
+                    </div>
+                  <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
+                  <div style="float:left">${member.full_name} (${_('owner')})</div>
+                  <input type="hidden" value="${member.user_id}" name="review_members" />
+                  %if not c.pull_request.is_closed() and (h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id):
+                  <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span>
+                  %endif
+                </div>
+              </li>
+            %endfor
+            </ul>
+          </div>
+          %if not c.pull_request.is_closed():
+          <div class='ac'>
+            %if h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id:
+            <div class="reviewer_ac">
+               ${h.text('user', class_='yui-ac-input')}
+               <span class="help-block">${_('Add reviewer to this pull request.')}</span>
+               <div id="reviewers_container"></div>
+            </div>
+            <div style="padding:0px 10px">
+             <span id="update_pull_request" class="ui-btn xsmall">${_('save')}</span>
+            </div>
+            %endif
+          </div>
+          %endif
+        </div>
+       </div>
+    </div>
+    <script>
+    var _USERS_AC_DATA = ${c.users_array|n};
+    var _GROUPS_AC_DATA = ${c.users_groups_array|n};
+    AJAX_COMMENT_URL = "${url('pullrequest_comment',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}";
+    AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
+    AJAX_UPDATE_PULLREQUEST = "${url('pullrequest_update',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}"
+    </script>
+
+    ## diff block
+    <%namespace name="diff_block" file="/changeset/diff_block.html"/>
+    %for fid, change, f, stat in c.files:
+      ${diff_block.diff_block_simple([c.changes[fid]])}
+    %endfor
+
+    ## template for inline comment form
+    <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
+    ${comment.comment_inline_form()}
+
+    ## render comments and inlines
+    ${comment.generate_comments()}
+
+    % if not c.pull_request.is_closed():
+      ## main comment form and it status
+      ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name,
+                                pull_request_id=c.pull_request.pull_request_id),
+                                c.current_changeset_status,
+                                close_btn=True)}
+    %endif
+
+    <script type="text/javascript">
+      YUE.onDOMReady(function(){
+    	  PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
+
+          YUE.on(YUQ('.show-inline-comments'),'change',function(e){
+              var show = 'none';
+              var target = e.currentTarget;
+              if(target.checked){
+                  var show = ''
+              }
+              var boxid = YUD.getAttribute(target,'id_for');
+              var comments = YUQ('#{0} .inline-comments'.format(boxid));
+              for(c in comments){
+                 YUD.setStyle(comments[c],'display',show);
+              }
+              var btns = YUQ('#{0} .inline-comments-button'.format(boxid));
+              for(c in btns){
+                  YUD.setStyle(btns[c],'display',show);
+               }
+          })
+
+          YUE.on(YUQ('.line'),'click',function(e){
+              var tr = e.currentTarget;
+              injectInlineForm(tr);
+          });
+
+          // inject comments into they proper positions
+          var file_comments = YUQ('.inline-comment-placeholder');
+          renderInlineComments(file_comments);
+
+          YUE.on(YUD.get('update_pull_request'),'click',function(e){
+
+        	  var reviewers_ids = [];
+        	  var ids = YUQ('#review_members input');
+        	  for(var i=0; i<ids.length;i++){
+        		  var id = ids[i].value
+        		  reviewers_ids.push(id);
+        	  }
+        	  updateReviewers(reviewers_ids);
+          })
+      })
+    </script>
+
+</div>
+
+</%def>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/pullrequests/pullrequest_show_all.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,42 @@
+<%inherit file="/base/base.html"/>
+
+<%def name="title()">
+    ${c.repo_name} ${_('all pull requests')}
+</%def>
+
+<%def name="breadcrumbs_links()">
+    ${h.link_to(_(u'Home'),h.url('/'))}
+    &raquo;
+    ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
+    &raquo;
+    ${_('All pull requests')}
+</%def>
+
+<%def name="main()">
+
+<div class="box">
+    <!-- box / title -->
+    <div class="title">
+        ${self.breadcrumbs()}
+    </div>
+
+    %for pr in c.pull_requests:
+        <div>
+          <h4>
+          %if pr.is_closed():
+          <img src="${h.url('/images/icons/tick.png')}" alt="${_('Closed')}" />
+          %endif
+          <a href="${h.url('pullrequest_show',repo_name=c.repo_name,pull_request_id=pr.pull_request_id)}">
+          ${_('Pull request #%s opened by %s on %s') % (pr.pull_request_id, pr.author.full_name, h.fmt_date(pr.created_on))}
+          </a>
+          </h4>
+          <h5 style="border:0px;padding-bottom:0px">${_('Title')}: ${pr.title}</h5>
+          <div style="padding:0px 24px">${pr.description}</div>
+        </div>
+    %endfor
+
+</div>
+
+<script type="text/javascript"></script>
+
+</%def>
--- a/rhodecode/templates/register.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/register.html	Sun Sep 02 21:19:54 2012 +0200
@@ -44,10 +44,10 @@
 
 	             <div class="field">
 	                <div class="label">
-	                    <label for="name">${_('First Name')}:</label>
+	                    <label for="firstname">${_('First Name')}:</label>
 	                </div>
 	                <div class="input">
-	                    ${h.text('name',class_="medium")}
+	                    ${h.text('firstname',class_="medium")}
 	                </div>
 	             </div>
 
@@ -71,7 +71,7 @@
 
 	            <div class="buttons">
 		            <div class="nohighlight">
-		              ${h.submit('sign_up',_('Sign Up'),class_="ui-button")}
+		              ${h.submit('sign_up',_('Sign Up'),class_="ui-btn large")}
 		              %if c.auto_active:
 					  	<div class="activation_msg">${_('Your account will be activated right after registration')}</div>
 					  %else:
--- a/rhodecode/templates/repo_switcher_list.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/repo_switcher_list.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,17 +1,17 @@
 ## -*- coding: utf-8 -*-
 
 <li class="qfilter_rs">
-    <input type="text" style="border:0" value="quick filter..." name="filter" size="15" id="q_filter_rs" />
+    <input type="text" style="border:0;width:100%" value="${_('quick filter...')}" name="filter" id="q_filter_rs" />
 </li>
 
 %for repo in c.repos_list:
 
-      %if repo['dbrepo']['private']:
+      %if repo['dbrepo']['private'] and c.visual.show_private_icon:
          <li>
              <img src="${h.url('/images/icons/lock.png')}" alt="${_('Private repository')}" class="repo_switcher_type"/>
              ${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="repo_name %s" % repo['dbrepo']['repo_type'])}
           </li>
-      %else:
+      %elif not repo['dbrepo']['private'] and c.visual.show_public_icon:
          <li>
              <img src="${h.url('/images/icons/lock_open.png')}" alt="${_('Public repository')}" class="repo_switcher_type" />
              ${h.link_to(repo['name'],h.url('summary_home',repo_name=repo['name']),class_="repo_name %s" % repo['dbrepo']['repo_type'])}
--- a/rhodecode/templates/search/search.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/search/search.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,13 +1,19 @@
 ## -*- coding: utf-8 -*-
 <%inherit file="/base/base.html"/>
 <%def name="title()">
-   ${_('Search')}
-   ${'"%s"' % c.cur_query if c.cur_query else None}
+   %if c.cur_query:
 	%if c.repo_name:
-		${_('in repository: ') + c.repo_name}
+		${_('Search "%s" in repository: %s') % (c.cur_query, c.repo_name)}
 	%else:
-		${_('in all repositories')}
+		${_('Search "%s" in all repositories') % c.cur_query}
 	%endif
+   %else:
+	%if c.repo_name:
+		${_('Search in repository: %s') % c.repo_name}
+	%else:
+		${_('Search in all repositories')}
+	%endif
+   %endif
 	- ${c.rhodecode_name}
 </%def>
 <%def name="breadcrumbs()">
@@ -21,11 +27,11 @@
 <div class="box">
 	<!-- box / title -->
 	<div class="title">
-		<h5>${_('Search')}
+		<h5>
 		%if c.repo_name:
-			${_('in repository: ') + c.repo_name}
+			${_('Search in repository: %s') % c.repo_name}
 		%else:
-			${_('in all repositories')}
+			${_('Search in all repositories')}
 		%endif
 		</h5>
 	</div>
@@ -55,7 +61,7 @@
 	            </div>
                 <div class="select">
                     ${h.select('type',c.cur_type,[('content',_('File contents')),
-                        ##('commit',_('Commit messages')),
+                        ('commit',_('Commit messages')),
                         ('path',_('File names')),
                         ##('repository',_('Repository names')),
                         ])}
@@ -65,16 +71,17 @@
 		</div>
 	</div>
 	${h.end_form()}
-
-    %if c.cur_search == 'content':
+    <div class="search">
+    %if c.cur_type == 'content':
         <%include file='search_content.html'/>
-    %elif c.cur_search == 'path':
+    %elif c.cur_type == 'path':
         <%include file='search_path.html'/>
-    %elif c.cur_search == 'commit':
+    %elif c.cur_type == 'commit':
         <%include file='search_commit.html'/>
-    %elif c.cur_search == 'repository':
+    %elif c.cur_type == 'repository':
         <%include file='search_repository.html'/>
     %endif
+    </div>
 </div>
 
 </%def>
--- a/rhodecode/templates/search/search_commit.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/search/search_commit.html	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,45 @@
+##commit highligthing
+
+%for cnt,sr in enumerate(c.formated_results):
+    %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(sr['repository'],'search results check'):
+    <div class="table">
+        <div id="body${cnt}" class="codeblock">
+            <div class="code-header">
+                <div class="search-path">${h.link_to(h.literal('%s &raquo; %s' % (sr['repository'],sr['raw_id'])),
+                h.url('changeset_home',repo_name=sr['repository'],revision=sr['raw_id']))}
+                ${h.fmt_date(h.time_to_datetime(sr['date']))}
+                </div>
+            </div>
+            <div class="left">
+                <div class="author">
+                    <div class="gravatar">
+                        <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(sr['author']),20)}"/>
+                    </div>
+                    <span>${h.person(sr['author'])}</span><br/>
+                    <span><a href="mailto:${h.email_or_none(sr['author'])}">${h.email_or_none(sr['author'])}</a></span><br/>
+                </div>
+                %if sr['message_hl']:
+                <div class="search-code-body">
+                    <pre>${h.literal(sr['message_hl'])}</pre>
+                </div>
+                %else:
+                <div class="message">${h.urlify_commit(sr['message'], sr['repository'])}</div>
+                %endif
+            </div>
+        </div>
+    </div>
+    %else:
+        %if cnt == 0:
+        <div class="table">
+            <div id="body${cnt}" class="codeblock">
+                <div class="error">${_('Permission denied')}</div>
+            </div>
+        </div>
+        %endif
+    %endif
+%endfor
+%if c.cur_query and c.formated_results:
+<div class="pagination-wh pagination-left">
+    ${c.formated_results.pager('$link_previous ~2~ $link_next')}
+</div>
+%endif
--- a/rhodecode/templates/settings/repo_settings.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/settings/repo_settings.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,11 +2,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Settings')} - ${c.rhodecode_name}
+    ${_('%s Settings') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_info.repo_name,h.url('summary_home',repo_name=c.repo_info.repo_name))}
     &raquo;
@@ -53,6 +53,15 @@
                 </div>
             </div>
             <div class="field">
+                <div class="label">
+                    <label for="landing_rev">${_('Landing revision')}:</label>
+                </div>
+                <div class="input">
+                    ${h.select('landing_rev','',c.landing_revs,class_="medium")}
+                    <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
+                </div>
+            </div>
+            <div class="field">
                 <div class="label label-textarea">
                     <label for="description">${_('Description')}:</label>
                 </div>
@@ -81,8 +90,8 @@
                 </div>
 
             <div class="buttons">
-              ${h.submit('save','Save',class_="ui-button")}
-              ${h.reset('reset','Reset',class_="ui-button")}
+              ${h.submit('save',_('Save'),class_="ui-btn large")}
+              ${h.reset('reset',_('Reset'),class_="ui-btn large")}
             </div>
         </div>
     </div>
--- a/rhodecode/templates/shortlog/shortlog.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/shortlog/shortlog.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,12 +2,12 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Shortlog')} - ${c.rhodecode_name}
+    ${_('%s Shortlog') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/shortlog/shortlog_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/shortlog/shortlog_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -19,7 +19,7 @@
             h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
             title=cs.message)}
         </td>
-        <td><span class="tooltip" title="${cs.date}">
+        <td><span class="tooltip" title="${h.tooltip(h.fmt_date(cs.date))}">
                       ${h.age(cs.date)}</span>
         </td>
 		<td title="${cs.author}">${h.person(cs.author)}</td>
@@ -78,6 +78,11 @@
 
 <h4>${_('Existing repository?')}</h4>
 <pre>
-    ${c.rhodecode_repo.alias} push ${c.clone_repo_url}
+%if h.is_git(c.rhodecode_repo):
+    git remote add origin ${c.clone_repo_url}
+    git push -u origin master
+%else:
+    hg push ${c.clone_repo_url}
+%endif
 </pre>
 %endif
--- a/rhodecode/templates/summary/summary.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/summary/summary.html	Sun Sep 02 21:19:54 2012 +0200
@@ -1,11 +1,11 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
+    ${_('%s Summary') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 <%def name="breadcrumbs_links()">
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.dbrepo.just_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
@@ -16,6 +16,11 @@
 	${self.menu('summary')}
 </%def>
 
+<%def name="head_extra()">
+<link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" />
+<link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" />
+</%def>
+
 <%def name="main()">
     <%
     summary = lambda n:{False:'summary-short'}.get(n)
@@ -99,7 +104,11 @@
 			  <div class="label-summary">
 			      <label>${_('Description')}:</label>
 			  </div>
-			  <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
+              %if c.visual.stylify_metatags:
+                <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
+              %else:
+                <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
+              %endif        
 			 </div>
 
 			 <div class="field">
@@ -158,10 +167,10 @@
                     %endif
 		        %else:
 			        ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
-			             <span id="${'zip_link'}">${h.link_to('Download as zip',h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
+			             <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
                     <span style="vertical-align: bottom">
                         <input id="archive_subrepos" type="checkbox" name="subrepos" />
-                        <label for="archive_subrepos" class="tooltip" title="${_('Check this to download archive with subrepos')}" >${_('with subrepos')}</label>
+                        <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label>
                     </span>
 			    %endif
 			  </div>
@@ -220,11 +229,14 @@
 </div>
 
 %if c.readme_data:
-<div class="box" style="background-color: #FAFAFA">
-    <div id="readme" class="title">
-        <div class="breadcrumbs"><a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a></div>
+<div id="readme" class="box header-pos-fix" style="background-color: #FAFAFA">
+    <div id="readme" class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}">
+        <div class="breadcrumbs">
+            <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a>
+            <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">&para;</a>
+        </div>
     </div>
-    <div class="readme">
+    <div id="readme" class="readme">
       <div class="readme_box">
         ${c.readme_data|n}
       </div>
--- a/rhodecode/templates/switch_to_list.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/switch_to_list.html	Sun Sep 02 21:19:54 2012 +0200
@@ -4,7 +4,7 @@
     <ul>
     %if c.rhodecode_repo.branches.values():
         %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
-            <li><div><pre>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</pre></div></li>
+            <li><div><pre>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[0]))}</pre></div></li>
         %endfor
     %else:
         <li>${h.link_to(_('There are no branches yet'),'#')}</li>
@@ -16,7 +16,7 @@
     <ul>
     %if c.rhodecode_repo.tags.values():
         %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
-         <li><div><pre>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</pre></div></li>
+         <li><div><pre>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[0]))}</pre></div></li>
         %endfor
     %else:
         <li>${h.link_to(_('There are no tags yet'),'#')}</li>
--- a/rhodecode/templates/tags/tags.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/tags/tags.html	Sun Sep 02 21:19:54 2012 +0200
@@ -2,13 +2,13 @@
 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${c.repo_name} ${_('Tags')} - ${c.rhodecode_name}
+    ${_('%s Tags') % c.repo_name} - ${c.rhodecode_name}
 </%def>
 
 
 <%def name="breadcrumbs_links()">
     <input class="q_filter_box" id="q_filter_tags" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
-    ${h.link_to(u'Home',h.url('/'))}
+    ${h.link_to(_(u'Home'),h.url('/'))}
     &raquo;
     ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
     &raquo;
--- a/rhodecode/templates/tags/tags_data.html	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/templates/tags/tags_data.html	Sun Sep 02 21:19:54 2012 +0200
@@ -18,7 +18,7 @@
                     </span>
                 </span>
             </td>
-            <td><span class="tooltip" title="${h.age(tag[1].date)}">${tag[1].date}</span></td>
+            <td><span class="tooltip" title="${h.tooltip(h.age(tag[1].date))}">${h.fmt_date(tag[1].date)}</span></td>
 	        <td title="${tag[1].author}">${h.person(tag[1].author)}</td>
 	        <td>
                 <div>
--- a/rhodecode/tests/__init__.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -10,6 +10,9 @@
 import os
 import time
 import logging
+import datetime
+import hashlib
+import tempfile
 from os.path import join as jn
 
 from unittest import TestCase
@@ -24,9 +27,11 @@
 from rhodecode import is_windows
 from rhodecode.model.meta import Session
 from rhodecode.model.db import User
+from rhodecode.tests.nose_parametrized import parameterized
 
 import pylons.test
 
+
 os.environ['TZ'] = 'UTC'
 if not is_windows:
     time.tzset()
@@ -34,11 +39,15 @@
 log = logging.getLogger(__name__)
 
 __all__ = [
-    'environ', 'url', 'TestController', 'TESTS_TMP_PATH', 'HG_REPO',
-    'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO', 'HG_FORK', 'GIT_FORK',
-    'TEST_USER_ADMIN_LOGIN', 'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
+    'parameterized', 'environ', 'url', 'get_new_dir', 'TestController',
+    'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO',
+    'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
+    'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
     'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
-    'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL'
+    'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
+    'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
+    'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO',
+    'GIT_REMOTE_REPO', 'SCM_TESTS',
 ]
 
 # Invoke websetup with the current config file
@@ -47,6 +56,7 @@
 ##RUNNING DESIRED TESTS
 # nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
 # nosetests --pdb --pdb-failures
+# nosetests --with-coverage --cover-package=rhodecode.model.validators rhodecode.tests.test_validators
 environ = {}
 
 #SOME GLOBALS FOR TESTS
@@ -73,6 +83,45 @@
 HG_FORK = 'vcs_test_hg_fork'
 GIT_FORK = 'vcs_test_git_fork'
 
+## VCS
+SCM_TESTS = ['hg', 'git']
+uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
+
+GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
+
+TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
+TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix)
+TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix)
+
+
+HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
+
+TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO)
+TEST_HG_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcshgclone%s' % uniq_suffix)
+TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, 'vcshgpull%s' % uniq_suffix)
+
+TEST_DIR = tempfile.gettempdir()
+TEST_REPO_PREFIX = 'vcs-test'
+
+# cached repos if any !
+# comment out to get some other repos from bb or github
+GIT_REMOTE_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
+HG_REMOTE_REPO = jn(TESTS_TMP_PATH, HG_REPO)
+
+
+def get_new_dir(title):
+    """
+    Returns always new directory path.
+    """
+    from rhodecode.tests.vcs.utils import get_normalized_path
+    name = TEST_REPO_PREFIX
+    if title:
+        name = '-'.join((name, title))
+    hex = hashlib.sha1(str(time.time())).hexdigest()
+    name = '-'.join((name, hex))
+    path = os.path.join(TEST_DIR, name)
+    return get_normalized_path(path)
+
 
 class TestController(TestCase):
 
@@ -90,8 +139,8 @@
                  password=TEST_USER_ADMIN_PASS):
         self._logged_username = username
         response = self.app.post(url(controller='login', action='index'),
-                                 {'username':username,
-                                  'password':password})
+                                 {'username': username,
+                                  'password': password})
 
         if 'invalid user name' in response.body:
             self.fail('could not login using %s %s' % (username, password))
@@ -109,4 +158,8 @@
 
     def checkSessionFlash(self, response, msg):
         self.assertTrue('flash' in response.session)
-        self.assertTrue(msg in response.session['flash'][0][1])
+        if not msg in response.session['flash'][0][1]:
+            self.fail(
+                'msg `%s` not found in session flash: got `%s` instead' % (
+                      msg, response.session['flash'])
+            )
--- a/rhodecode/tests/_test_concurency.py	Sat May 19 14:54:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    rhodecode.tests.test_hg_operations
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    Test suite for making push/pull operations
-
-    :created_on: Dec 30, 2010
-    :author: marcink
-    :copyright: (C) 2010-2012 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, either version 3 of the License, or
-# (at your option) any later version.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-import os
-import sys
-import shutil
-import logging
-from os.path import join as jn
-from os.path import dirname as dn
-
-from tempfile import _RandomNameSequence
-from subprocess import Popen, PIPE
-
-from paste.deploy import appconfig
-from pylons import config
-from sqlalchemy import engine_from_config
-
-from rhodecode.lib.utils import add_cache
-from rhodecode.model import init_model
-from rhodecode.model import meta
-from rhodecode.model.db import User, Repository
-from rhodecode.lib.auth import get_crypt_password
-
-from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO
-from rhodecode.config.environment import load_environment
-
-rel_path = dn(dn(dn(os.path.abspath(__file__))))
-conf = appconfig('config:development.ini', relative_to=rel_path)
-load_environment(conf.global_conf, conf.local_conf)
-
-add_cache(conf)
-
-USER = 'test_admin'
-PASS = 'test12'
-HOST = 'hg.local'
-METHOD = 'pull'
-DEBUG = True
-log = logging.getLogger(__name__)
-
-
-class Command(object):
-
-    def __init__(self, cwd):
-        self.cwd = cwd
-
-    def execute(self, cmd, *args):
-        """Runs command on the system with given ``args``.
-        """
-
-        command = cmd + ' ' + ' '.join(args)
-        log.debug('Executing %s' % command)
-        if DEBUG:
-            print command
-        p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
-        stdout, stderr = p.communicate()
-        if DEBUG:
-            print stdout, stderr
-        return stdout, stderr
-
-def get_session():
-    engine = engine_from_config(conf, 'sqlalchemy.db1.')
-    init_model(engine)
-    sa = meta.Session
-    return sa
-
-
-def create_test_user(force=True):
-    print 'creating test user'
-    sa = get_session()
-
-    user = sa.query(User).filter(User.username == USER).scalar()
-
-    if force and user is not None:
-        print 'removing current user'
-        for repo in sa.query(Repository).filter(Repository.user == user).all():
-            sa.delete(repo)
-        sa.delete(user)
-        sa.commit()
-
-    if user is None or force:
-        print 'creating new one'
-        new_usr = User()
-        new_usr.username = USER
-        new_usr.password = get_crypt_password(PASS)
-        new_usr.email = 'mail@mail.com'
-        new_usr.name = 'test'
-        new_usr.lastname = 'lasttestname'
-        new_usr.active = True
-        new_usr.admin = True
-        sa.add(new_usr)
-        sa.commit()
-
-    print 'done'
-
-
-def create_test_repo(force=True):
-    print 'creating test repo'
-    from rhodecode.model.repo import RepoModel
-    sa = get_session()
-
-    user = sa.query(User).filter(User.username == USER).scalar()
-    if user is None:
-        raise Exception('user not found')
-
-
-    repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
-
-    if repo is None:
-        print 'repo not found creating'
-
-        form_data = {'repo_name':HG_REPO,
-                     'repo_type':'hg',
-                     'private':False,
-                     'clone_uri':'' }
-        rm = RepoModel(sa)
-        rm.base_path = '/home/hg'
-        rm.create(form_data, user)
-
-    print 'done'
-
-def set_anonymous_access(enable=True):
-    sa = get_session()
-    user = sa.query(User).filter(User.username == 'default').one()
-    user.active = enable
-    sa.add(user)
-    sa.commit()
-
-def get_anonymous_access():
-    sa = get_session()
-    return sa.query(User).filter(User.username == 'default').one().active
-
-
-#==============================================================================
-# TESTS
-#==============================================================================
-def test_clone_with_credentials(no_errors=False, repo=HG_REPO, method=METHOD,
-                                seq=None):
-    cwd = path = jn(TESTS_TMP_PATH, repo)
-
-    if seq == None:
-        seq = _RandomNameSequence().next()
-
-    try:
-        shutil.rmtree(path, ignore_errors=True)
-        os.makedirs(path)
-        #print 'made dirs %s' % jn(path)
-    except OSError:
-        raise
-
-    clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
-                  {'user':USER,
-                   'pass':PASS,
-                   'host':HOST,
-                   'cloned_repo':repo, }
-
-    dest = path + seq
-    if method == 'pull':
-        stdout, stderr = Command(cwd).execute('hg', method, '--cwd', dest, clone_url)
-    else:
-        stdout, stderr = Command(cwd).execute('hg', method, clone_url, dest)
-
-        if no_errors is False:
-            assert """adding file changes""" in stdout, 'no messages about cloning'
-            assert """abort""" not in stderr , 'got error from clone'
-
-if __name__ == '__main__':
-    try:
-        create_test_user(force=False)
-        seq = None
-        import time
-
-        try:
-            METHOD = sys.argv[3]
-        except:
-            pass
-
-        if METHOD == 'pull':
-            seq = _RandomNameSequence().next()
-            test_clone_with_credentials(repo=sys.argv[1], method='clone',
-                                        seq=seq)
-        s = time.time()
-        for i in range(1, int(sys.argv[2]) + 1):
-            print 'take', i
-            test_clone_with_credentials(repo=sys.argv[1], method=METHOD,
-                                        seq=seq)
-        print 'time taken %.3f' % (time.time() - s)
-    except Exception, e:
-        raise
-        sys.exit('stop on %s' % e)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/api/api_base.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,990 @@
+from __future__ import with_statement
+import random
+import mock
+
+from rhodecode.tests import *
+from rhodecode.lib.compat import json
+from rhodecode.lib.auth import AuthUser
+from rhodecode.model.user import UserModel
+from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.meta import Session
+from rhodecode.model.scm import ScmModel
+from rhodecode.model.db import Repository
+
+API_URL = '/_admin/api'
+
+
+def _build_data(apikey, method, **kw):
+    """
+    Builds API data with given random ID
+
+    :param random_id:
+    :type random_id:
+    """
+    random_id = random.randrange(1, 9999)
+    return random_id, json.dumps({
+        "id": random_id,
+        "api_key": apikey,
+        "method": method,
+        "args": kw
+    })
+
+jsonify = lambda obj: json.loads(json.dumps(obj))
+
+
+def crash(*args, **kwargs):
+    raise Exception('Total Crash !')
+
+
+def api_call(test_obj, params):
+    response = test_obj.app.post(API_URL, content_type='application/json',
+                                 params=params)
+    return response
+
+
+TEST_USERS_GROUP = 'test_users_group'
+
+
+def make_users_group(name=TEST_USERS_GROUP):
+    gr = UsersGroupModel().create(name=name)
+    UsersGroupModel().add_user_to_group(users_group=gr,
+                                        user=TEST_USER_ADMIN_LOGIN)
+    Session().commit()
+    return gr
+
+
+def destroy_users_group(name=TEST_USERS_GROUP):
+    UsersGroupModel().delete(users_group=name, force=True)
+    Session().commit()
+
+
+def create_repo(repo_name, repo_type):
+    # create new repo
+    form_data = dict(repo_name=repo_name,
+                     repo_name_full=repo_name,
+                     fork_name=None,
+                     description='description %s' % repo_name,
+                     repo_group=None,
+                     private=False,
+                     repo_type=repo_type,
+                     clone_uri=None,
+                     landing_rev='tip')
+    cur_user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
+    r = RepoModel().create(form_data, cur_user)
+    Session().commit()
+    return r
+
+
+def create_fork(fork_name, fork_type, fork_of):
+    fork = RepoModel(Session())._get_repo(fork_of)
+    r = create_repo(fork_name, fork_type)
+    r.fork = fork
+    Session().add(r)
+    Session().commit()
+    return r
+
+
+def destroy_repo(repo_name):
+    RepoModel().delete(repo_name)
+    Session().commit()
+
+
+class BaseTestApi(object):
+    REPO = None
+    REPO_TYPE = None
+
+    @classmethod
+    def setUpClass(self):
+        self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
+        self.apikey = self.usr.api_key
+        self.TEST_USER = UserModel().create_or_update(
+            username='test-api',
+            password='test',
+            email='test@api.rhodecode.org',
+            firstname='first',
+            lastname='last'
+        )
+        Session().commit()
+        self.TEST_USER_LOGIN = self.TEST_USER.username
+
+    @classmethod
+    def teardownClass(self):
+        pass
+
+    def setUp(self):
+        self.maxDiff = None
+        make_users_group()
+
+    def tearDown(self):
+        destroy_users_group()
+
+    def _compare_ok(self, id_, expected, given):
+        expected = jsonify({
+            'id': id_,
+            'error': None,
+            'result': expected
+        })
+        given = json.loads(given)
+        self.assertEqual(expected, given)
+
+    def _compare_error(self, id_, expected, given):
+        expected = jsonify({
+            'id': id_,
+            'error': expected,
+            'result': None
+        })
+        given = json.loads(given)
+        self.assertEqual(expected, given)
+
+#    def test_Optional(self):
+#        from rhodecode.controllers.api.api import Optional
+#        option1 = Optional(None)
+#        self.assertEqual('<Optional:%s>' % None, repr(option1))
+#
+#        self.assertEqual(1, Optional.extract(Optional(1)))
+#        self.assertEqual('trololo', Optional.extract('trololo'))
+
+    def test_api_wrong_key(self):
+        id_, params = _build_data('trololo', 'get_user')
+        response = api_call(self, params)
+
+        expected = 'Invalid API KEY'
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_missing_non_optional_param(self):
+        id_, params = _build_data(self.apikey, 'get_user')
+        response = api_call(self, params)
+
+        expected = 'Missing non optional `userid` arg in JSON DATA'
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_get_users(self):
+        id_, params = _build_data(self.apikey, 'get_users',)
+        response = api_call(self, params)
+        ret_all = []
+        for usr in UserModel().get_all():
+            ret = usr.get_api_data()
+            ret_all.append(jsonify(ret))
+        expected = ret_all
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_get_user(self):
+        id_, params = _build_data(self.apikey, 'get_user',
+                                  userid=TEST_USER_ADMIN_LOGIN)
+        response = api_call(self, params)
+
+        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
+        ret = usr.get_api_data()
+        ret['permissions'] = AuthUser(usr.user_id).permissions
+
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_get_user_that_does_not_exist(self):
+        id_, params = _build_data(self.apikey, 'get_user',
+                                  userid='trololo')
+        response = api_call(self, params)
+
+        expected = "user `%s` does not exist" % 'trololo'
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_pull(self):
+        #TODO: issues with rhodecode_extras here.. not sure why !
+        pass
+
+#        repo_name = 'test_pull'
+#        r = create_repo(repo_name, self.REPO_TYPE)
+#        r.clone_uri = TEST_self.REPO
+#        Session.add(r)
+#        Session.commit()
+#
+#        id_, params = _build_data(self.apikey, 'pull',
+#                                  repoid=repo_name,)
+#        response = self.app.post(API_URL, content_type='application/json',
+#                                 params=params)
+#
+#        expected = 'Pulled from `%s`' % repo_name
+#        self._compare_ok(id_, expected, given=response.body)
+#
+#        destroy_repo(repo_name)
+
+    def test_api_pull_error(self):
+        id_, params = _build_data(self.apikey, 'pull',
+                                  repoid=self.REPO,)
+        response = api_call(self, params)
+
+        expected = 'Unable to pull changes from `%s`' % self.REPO
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_rescan_repos(self):
+        id_, params = _build_data(self.apikey, 'rescan_repos')
+        response = api_call(self, params)
+
+        expected = {'added': [], 'removed': []}
+        self._compare_ok(id_, expected, given=response.body)
+
+    @mock.patch.object(ScmModel, 'repo_scan', crash)
+    def test_api_rescann_error(self):
+        id_, params = _build_data(self.apikey, 'rescan_repos',)
+        response = api_call(self, params)
+
+        expected = 'Error occurred during rescan repositories action'
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_lock_repo_lock_aquire(self):
+        id_, params = _build_data(self.apikey, 'lock',
+                                  userid=TEST_USER_ADMIN_LOGIN,
+                                  repoid=self.REPO,
+                                  locked=True)
+        response = api_call(self, params)
+        expected = ('User `%s` set lock state for repo `%s` to `%s`'
+                   % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_lock_repo_lock_release(self):
+        id_, params = _build_data(self.apikey, 'lock',
+                                  userid=TEST_USER_ADMIN_LOGIN,
+                                  repoid=self.REPO,
+                                  locked=False)
+        response = api_call(self, params)
+        expected = ('User `%s` set lock state for repo `%s` to `%s`'
+                   % (TEST_USER_ADMIN_LOGIN, self.REPO, False))
+        self._compare_ok(id_, expected, given=response.body)
+
+    @mock.patch.object(Repository, 'lock', crash)
+    def test_api_lock_error(self):
+        id_, params = _build_data(self.apikey, 'lock',
+                                  userid=TEST_USER_ADMIN_LOGIN,
+                                  repoid=self.REPO,
+                                  locked=True)
+        response = api_call(self, params)
+
+        expected = 'Error occurred locking repository `%s`' % self.REPO
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_create_existing_user(self):
+        id_, params = _build_data(self.apikey, 'create_user',
+                                  username=TEST_USER_ADMIN_LOGIN,
+                                  email='test@foo.com',
+                                  password='trololo')
+        response = api_call(self, params)
+
+        expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_create_user_with_existing_email(self):
+        id_, params = _build_data(self.apikey, 'create_user',
+                                  username=TEST_USER_ADMIN_LOGIN + 'new',
+                                  email=TEST_USER_REGULAR_EMAIL,
+                                  password='trololo')
+        response = api_call(self, params)
+
+        expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_create_user(self):
+        username = 'test_new_api_user'
+        email = username + "@foo.com"
+
+        id_, params = _build_data(self.apikey, 'create_user',
+                                  username=username,
+                                  email=email,
+                                  password='trololo')
+        response = api_call(self, params)
+
+        usr = UserModel().get_by_username(username)
+        ret = dict(
+            msg='created new user `%s`' % username,
+            user=jsonify(usr.get_api_data())
+        )
+
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+        UserModel().delete(usr.user_id)
+        Session().commit()
+
+    @mock.patch.object(UserModel, 'create_or_update', crash)
+    def test_api_create_user_when_exception_happened(self):
+
+        username = 'test_new_api_user'
+        email = username + "@foo.com"
+
+        id_, params = _build_data(self.apikey, 'create_user',
+                                  username=username,
+                                  email=email,
+                                  password='trololo')
+        response = api_call(self, params)
+        expected = 'failed to create user `%s`' % username
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_delete_user(self):
+        usr = UserModel().create_or_update(username=u'test_user',
+                                           password=u'qweqwe',
+                                           email=u'u232@rhodecode.org',
+                                           firstname=u'u1', lastname=u'u1')
+        Session().commit()
+        username = usr.username
+        email = usr.email
+        usr_id = usr.user_id
+        ## DELETE THIS USER NOW
+
+        id_, params = _build_data(self.apikey, 'delete_user',
+                                  userid=username,)
+        response = api_call(self, params)
+
+        ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
+               'user': None}
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    @mock.patch.object(UserModel, 'delete', crash)
+    def test_api_delete_user_when_exception_happened(self):
+        usr = UserModel().create_or_update(username=u'test_user',
+                                           password=u'qweqwe',
+                                           email=u'u232@rhodecode.org',
+                                           firstname=u'u1', lastname=u'u1')
+        Session().commit()
+        username = usr.username
+
+        id_, params = _build_data(self.apikey, 'delete_user',
+                                  userid=username,)
+        response = api_call(self, params)
+        ret = 'failed to delete ID:%s %s' % (usr.user_id,
+                                             usr.username)
+        expected = ret
+        self._compare_error(id_, expected, given=response.body)
+
+    @parameterized.expand([('firstname', 'new_username'),
+                           ('lastname', 'new_username'),
+                           ('email', 'new_username'),
+                           ('admin', True),
+                           ('admin', False),
+                           ('ldap_dn', 'test'),
+                           ('ldap_dn', None),
+                           ('active', False),
+                           ('active', True),
+                           ('password', 'newpass')
+                           ])
+    def test_api_update_user(self, name, expected):
+        usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
+        kw = {name: expected,
+              'userid': usr.user_id}
+        id_, params = _build_data(self.apikey, 'update_user', **kw)
+        response = api_call(self, params)
+
+        ret = {
+        'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN),
+        'user': jsonify(UserModel()\
+                            .get_by_username(self.TEST_USER_LOGIN)\
+                            .get_api_data())
+        }
+
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_update_user_no_changed_params(self):
+        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
+        ret = jsonify(usr.get_api_data())
+        id_, params = _build_data(self.apikey, 'update_user',
+                                  userid=TEST_USER_ADMIN_LOGIN)
+
+        response = api_call(self, params)
+        ret = {
+        'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
+        'user': ret
+        }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_update_user_by_user_id(self):
+        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
+        ret = jsonify(usr.get_api_data())
+        id_, params = _build_data(self.apikey, 'update_user',
+                                  userid=usr.user_id)
+
+        response = api_call(self, params)
+        ret = {
+        'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
+        'user': ret
+        }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    @mock.patch.object(UserModel, 'update_user', crash)
+    def test_api_update_user_when_exception_happens(self):
+        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
+        ret = jsonify(usr.get_api_data())
+        id_, params = _build_data(self.apikey, 'update_user',
+                                  userid=usr.user_id)
+
+        response = api_call(self, params)
+        ret = 'failed to update user `%s`' % usr.user_id
+
+        expected = ret
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_get_repo(self):
+        new_group = 'some_new_group'
+        make_users_group(new_group)
+        RepoModel().grant_users_group_permission(repo=self.REPO,
+                                                 group_name=new_group,
+                                                 perm='repository.read')
+        Session().commit()
+        id_, params = _build_data(self.apikey, 'get_repo',
+                                  repoid=self.REPO)
+        response = api_call(self, params)
+
+        repo = RepoModel().get_by_repo_name(self.REPO)
+        ret = repo.get_api_data()
+
+        members = []
+        for user in repo.repo_to_perm:
+            perm = user.permission.permission_name
+            user = user.user
+            user_data = user.get_api_data()
+            user_data['type'] = "user"
+            user_data['permission'] = perm
+            members.append(user_data)
+
+        for users_group in repo.users_group_to_perm:
+            perm = users_group.permission.permission_name
+            users_group = users_group.users_group
+            users_group_data = users_group.get_api_data()
+            users_group_data['type'] = "users_group"
+            users_group_data['permission'] = perm
+            members.append(users_group_data)
+
+        ret['members'] = members
+
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+        destroy_users_group(new_group)
+
+    def test_api_get_repo_that_doesn_not_exist(self):
+        id_, params = _build_data(self.apikey, 'get_repo',
+                                  repoid='no-such-repo')
+        response = api_call(self, params)
+
+        ret = 'repository `%s` does not exist' % 'no-such-repo'
+        expected = ret
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_get_repos(self):
+        id_, params = _build_data(self.apikey, 'get_repos')
+        response = api_call(self, params)
+
+        result = []
+        for repo in RepoModel().get_all():
+            result.append(repo.get_api_data())
+        ret = jsonify(result)
+
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    @parameterized.expand([('all', 'all'),
+                           ('dirs', 'dirs'),
+                           ('files', 'files'), ])
+    def test_api_get_repo_nodes(self, name, ret_type):
+        rev = 'tip'
+        path = '/'
+        id_, params = _build_data(self.apikey, 'get_repo_nodes',
+                                  repoid=self.REPO, revision=rev,
+                                  root_path=path,
+                                  ret_type=ret_type)
+        response = api_call(self, params)
+
+        # we don't the actual return types here since it's tested somewhere
+        # else
+        expected = json.loads(response.body)['result']
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_get_repo_nodes_bad_revisions(self):
+        rev = 'i-dont-exist'
+        path = '/'
+        id_, params = _build_data(self.apikey, 'get_repo_nodes',
+                                  repoid=self.REPO, revision=rev,
+                                  root_path=path,)
+        response = api_call(self, params)
+
+        expected = 'failed to get repo: `%s` nodes' % self.REPO
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_get_repo_nodes_bad_path(self):
+        rev = 'tip'
+        path = '/idontexits'
+        id_, params = _build_data(self.apikey, 'get_repo_nodes',
+                                  repoid=self.REPO, revision=rev,
+                                  root_path=path,)
+        response = api_call(self, params)
+
+        expected = 'failed to get repo: `%s` nodes' % self.REPO
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_get_repo_nodes_bad_ret_type(self):
+        rev = 'tip'
+        path = '/'
+        ret_type = 'error'
+        id_, params = _build_data(self.apikey, 'get_repo_nodes',
+                                  repoid=self.REPO, revision=rev,
+                                  root_path=path,
+                                  ret_type=ret_type)
+        response = api_call(self, params)
+
+        expected = 'ret_type must be one of %s' % (['files', 'dirs', 'all'])
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_create_repo(self):
+        repo_name = 'api-repo'
+        id_, params = _build_data(self.apikey, 'create_repo',
+                                    repo_name=repo_name,
+                                    owner=TEST_USER_ADMIN_LOGIN,
+                                    repo_type='hg',
+                                  )
+        response = api_call(self, params)
+
+        repo = RepoModel().get_by_repo_name(repo_name)
+        ret = {
+            'msg': 'Created new repository `%s`' % repo_name,
+            'repo': jsonify(repo.get_api_data())
+        }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+        destroy_repo(repo_name)
+
+    def test_api_create_repo_unknown_owner(self):
+        repo_name = 'api-repo'
+        owner = 'i-dont-exist'
+        id_, params = _build_data(self.apikey, 'create_repo',
+                                    repo_name=repo_name,
+                                    owner=owner,
+                                    repo_type='hg',
+                                  )
+        response = api_call(self, params)
+        expected = 'user `%s` does not exist' % owner
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_create_repo_exists(self):
+        repo_name = self.REPO
+        id_, params = _build_data(self.apikey, 'create_repo',
+                                    repo_name=repo_name,
+                                    owner=TEST_USER_ADMIN_LOGIN,
+                                    repo_type='hg',
+                                  )
+        response = api_call(self, params)
+        expected = "repo `%s` already exist" % repo_name
+        self._compare_error(id_, expected, given=response.body)
+
+    @mock.patch.object(RepoModel, 'create_repo', crash)
+    def test_api_create_repo_exception_occurred(self):
+        repo_name = 'api-repo'
+        id_, params = _build_data(self.apikey, 'create_repo',
+                                    repo_name=repo_name,
+                                    owner=TEST_USER_ADMIN_LOGIN,
+                                    repo_type='hg',
+                                  )
+        response = api_call(self, params)
+        expected = 'failed to create repository `%s`' % repo_name
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_delete_repo(self):
+        repo_name = 'api_delete_me'
+        create_repo(repo_name, self.REPO_TYPE)
+
+        id_, params = _build_data(self.apikey, 'delete_repo',
+                                  repoid=repo_name,)
+        response = api_call(self, params)
+
+        ret = {
+            'msg': 'Deleted repository `%s`' % repo_name,
+            'success': True
+        }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_delete_repo_exception_occurred(self):
+        repo_name = 'api_delete_me'
+        create_repo(repo_name, self.REPO_TYPE)
+        try:
+            with mock.patch.object(RepoModel, 'delete', crash):
+                id_, params = _build_data(self.apikey, 'delete_repo',
+                                          repoid=repo_name,)
+                response = api_call(self, params)
+
+                expected = 'failed to delete repository `%s`' % repo_name
+                self._compare_error(id_, expected, given=response.body)
+        finally:
+            destroy_repo(repo_name)
+
+    def test_api_fork_repo(self):
+        fork_name = 'api-repo-fork'
+        id_, params = _build_data(self.apikey, 'fork_repo',
+                                    repoid=self.REPO,
+                                    fork_name=fork_name,
+                                    owner=TEST_USER_ADMIN_LOGIN,
+                                  )
+        response = api_call(self, params)
+
+        ret = {
+            'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
+                                                     fork_name),
+            'success': True
+        }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+        destroy_repo(fork_name)
+
+    def test_api_fork_repo_unknown_owner(self):
+        fork_name = 'api-repo-fork'
+        owner = 'i-dont-exist'
+        id_, params = _build_data(self.apikey, 'fork_repo',
+                                    repoid=self.REPO,
+                                    fork_name=fork_name,
+                                    owner=owner,
+                                  )
+        response = api_call(self, params)
+        expected = 'user `%s` does not exist' % owner
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_fork_repo_fork_exists(self):
+        fork_name = 'api-repo-fork'
+        create_fork(fork_name, self.REPO_TYPE, self.REPO)
+
+        try:
+            fork_name = 'api-repo-fork'
+
+            id_, params = _build_data(self.apikey, 'fork_repo',
+                                        repoid=self.REPO,
+                                        fork_name=fork_name,
+                                        owner=TEST_USER_ADMIN_LOGIN,
+                                      )
+            response = api_call(self, params)
+
+            expected = "fork `%s` already exist" % fork_name
+            self._compare_error(id_, expected, given=response.body)
+        finally:
+            destroy_repo(fork_name)
+
+    def test_api_fork_repo_repo_exists(self):
+        fork_name = self.REPO
+
+        id_, params = _build_data(self.apikey, 'fork_repo',
+                                    repoid=self.REPO,
+                                    fork_name=fork_name,
+                                    owner=TEST_USER_ADMIN_LOGIN,
+                                  )
+        response = api_call(self, params)
+
+        expected = "repo `%s` already exist" % fork_name
+        self._compare_error(id_, expected, given=response.body)
+
+    @mock.patch.object(RepoModel, 'create_fork', crash)
+    def test_api_fork_repo_exception_occurred(self):
+        fork_name = 'api-repo-fork'
+        id_, params = _build_data(self.apikey, 'fork_repo',
+                                    repoid=self.REPO,
+                                    fork_name=fork_name,
+                                    owner=TEST_USER_ADMIN_LOGIN,
+                                  )
+        response = api_call(self, params)
+
+        expected = 'failed to fork repository `%s` as `%s`' % (self.REPO,
+                                                               fork_name)
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_get_users_group(self):
+        id_, params = _build_data(self.apikey, 'get_users_group',
+                                  usersgroupid=TEST_USERS_GROUP)
+        response = api_call(self, params)
+
+        users_group = UsersGroupModel().get_group(TEST_USERS_GROUP)
+        members = []
+        for user in users_group.members:
+            user = user.user
+            members.append(user.get_api_data())
+
+        ret = users_group.get_api_data()
+        ret['members'] = members
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_get_users_groups(self):
+
+        make_users_group('test_users_group2')
+
+        id_, params = _build_data(self.apikey, 'get_users_groups',)
+        response = api_call(self, params)
+
+        expected = []
+        for gr_name in [TEST_USERS_GROUP, 'test_users_group2']:
+            users_group = UsersGroupModel().get_group(gr_name)
+            ret = users_group.get_api_data()
+            expected.append(ret)
+        self._compare_ok(id_, expected, given=response.body)
+
+        UsersGroupModel().delete(users_group='test_users_group2')
+        Session().commit()
+
+    def test_api_create_users_group(self):
+        group_name = 'some_new_group'
+        id_, params = _build_data(self.apikey, 'create_users_group',
+                                  group_name=group_name)
+        response = api_call(self, params)
+
+        ret = {
+            'msg': 'created new users group `%s`' % group_name,
+            'users_group': jsonify(UsersGroupModel()\
+                                   .get_by_name(group_name)\
+                                   .get_api_data())
+        }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+        destroy_users_group(group_name)
+
+    def test_api_get_users_group_that_exist(self):
+        id_, params = _build_data(self.apikey, 'create_users_group',
+                                  group_name=TEST_USERS_GROUP)
+        response = api_call(self, params)
+
+        expected = "users group `%s` already exist" % TEST_USERS_GROUP
+        self._compare_error(id_, expected, given=response.body)
+
+    @mock.patch.object(UsersGroupModel, 'create', crash)
+    def test_api_get_users_group_exception_occurred(self):
+        group_name = 'exception_happens'
+        id_, params = _build_data(self.apikey, 'create_users_group',
+                                  group_name=group_name)
+        response = api_call(self, params)
+
+        expected = 'failed to create group `%s`' % group_name
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_add_user_to_users_group(self):
+        gr_name = 'test_group'
+        UsersGroupModel().create(gr_name)
+        Session().commit()
+        id_, params = _build_data(self.apikey, 'add_user_to_users_group',
+                                  usersgroupid=gr_name,
+                                  userid=TEST_USER_ADMIN_LOGIN)
+        response = api_call(self, params)
+
+        expected = {
+                    'msg': 'added member `%s` to users group `%s`' % (
+                                TEST_USER_ADMIN_LOGIN, gr_name
+                            ),
+                    'success': True}
+        self._compare_ok(id_, expected, given=response.body)
+
+        UsersGroupModel().delete(users_group=gr_name)
+        Session().commit()
+
+    def test_api_add_user_to_users_group_that_doesnt_exist(self):
+        id_, params = _build_data(self.apikey, 'add_user_to_users_group',
+                                  usersgroupid='false-group',
+                                  userid=TEST_USER_ADMIN_LOGIN)
+        response = api_call(self, params)
+
+        expected = 'users group `%s` does not exist' % 'false-group'
+        self._compare_error(id_, expected, given=response.body)
+
+    @mock.patch.object(UsersGroupModel, 'add_user_to_group', crash)
+    def test_api_add_user_to_users_group_exception_occurred(self):
+        gr_name = 'test_group'
+        UsersGroupModel().create(gr_name)
+        Session().commit()
+        id_, params = _build_data(self.apikey, 'add_user_to_users_group',
+                                  usersgroupid=gr_name,
+                                  userid=TEST_USER_ADMIN_LOGIN)
+        response = api_call(self, params)
+
+        expected = 'failed to add member to users group `%s`' % gr_name
+        self._compare_error(id_, expected, given=response.body)
+
+        UsersGroupModel().delete(users_group=gr_name)
+        Session().commit()
+
+    def test_api_remove_user_from_users_group(self):
+        gr_name = 'test_group_3'
+        gr = UsersGroupModel().create(gr_name)
+        UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
+        Session().commit()
+        id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
+                                  usersgroupid=gr_name,
+                                  userid=TEST_USER_ADMIN_LOGIN)
+        response = api_call(self, params)
+
+        expected = {
+                    'msg': 'removed member `%s` from users group `%s`' % (
+                                TEST_USER_ADMIN_LOGIN, gr_name
+                            ),
+                    'success': True}
+        self._compare_ok(id_, expected, given=response.body)
+
+        UsersGroupModel().delete(users_group=gr_name)
+        Session().commit()
+
+    @mock.patch.object(UsersGroupModel, 'remove_user_from_group', crash)
+    def test_api_remove_user_from_users_group_exception_occurred(self):
+        gr_name = 'test_group_3'
+        gr = UsersGroupModel().create(gr_name)
+        UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
+        Session().commit()
+        id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
+                                  usersgroupid=gr_name,
+                                  userid=TEST_USER_ADMIN_LOGIN)
+        response = api_call(self, params)
+
+        expected = 'failed to remove member from users group `%s`' % gr_name
+        self._compare_error(id_, expected, given=response.body)
+
+        UsersGroupModel().delete(users_group=gr_name)
+        Session().commit()
+
+    @parameterized.expand([('none', 'repository.none'),
+                           ('read', 'repository.read'),
+                           ('write', 'repository.write'),
+                           ('admin', 'repository.admin')])
+    def test_api_grant_user_permission(self, name, perm):
+        id_, params = _build_data(self.apikey, 'grant_user_permission',
+                                  repoid=self.REPO,
+                                  userid=TEST_USER_ADMIN_LOGIN,
+                                  perm=perm)
+        response = api_call(self, params)
+
+        ret = {
+                'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
+                    perm, TEST_USER_ADMIN_LOGIN, self.REPO
+                ),
+                'success': True
+            }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_grant_user_permission_wrong_permission(self):
+        perm = 'haha.no.permission'
+        id_, params = _build_data(self.apikey, 'grant_user_permission',
+                                  repoid=self.REPO,
+                                  userid=TEST_USER_ADMIN_LOGIN,
+                                  perm=perm)
+        response = api_call(self, params)
+
+        expected = 'permission `%s` does not exist' % perm
+        self._compare_error(id_, expected, given=response.body)
+
+    @mock.patch.object(RepoModel, 'grant_user_permission', crash)
+    def test_api_grant_user_permission_exception_when_adding(self):
+        perm = 'repository.read'
+        id_, params = _build_data(self.apikey, 'grant_user_permission',
+                                  repoid=self.REPO,
+                                  userid=TEST_USER_ADMIN_LOGIN,
+                                  perm=perm)
+        response = api_call(self, params)
+
+        expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
+                    TEST_USER_ADMIN_LOGIN, self.REPO
+                )
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_revoke_user_permission(self):
+        id_, params = _build_data(self.apikey, 'revoke_user_permission',
+                                  repoid=self.REPO,
+                                  userid=TEST_USER_ADMIN_LOGIN,)
+        response = api_call(self, params)
+
+        expected = {
+            'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
+                TEST_USER_ADMIN_LOGIN, self.REPO
+            ),
+            'success': True
+        }
+        self._compare_ok(id_, expected, given=response.body)
+
+    @mock.patch.object(RepoModel, 'revoke_user_permission', crash)
+    def test_api_revoke_user_permission_exception_when_adding(self):
+        id_, params = _build_data(self.apikey, 'revoke_user_permission',
+                                  repoid=self.REPO,
+                                  userid=TEST_USER_ADMIN_LOGIN,)
+        response = api_call(self, params)
+
+        expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
+                    TEST_USER_ADMIN_LOGIN, self.REPO
+                )
+        self._compare_error(id_, expected, given=response.body)
+
+    @parameterized.expand([('none', 'repository.none'),
+                           ('read', 'repository.read'),
+                           ('write', 'repository.write'),
+                           ('admin', 'repository.admin')])
+    def test_api_grant_users_group_permission(self, name, perm):
+        id_, params = _build_data(self.apikey, 'grant_users_group_permission',
+                                  repoid=self.REPO,
+                                  usersgroupid=TEST_USERS_GROUP,
+                                  perm=perm)
+        response = api_call(self, params)
+
+        ret = {
+            'msg': 'Granted perm: `%s` for users group: `%s` in repo: `%s`' % (
+                perm, TEST_USERS_GROUP, self.REPO
+            ),
+            'success': True
+        }
+        expected = ret
+        self._compare_ok(id_, expected, given=response.body)
+
+    def test_api_grant_users_group_permission_wrong_permission(self):
+        perm = 'haha.no.permission'
+        id_, params = _build_data(self.apikey, 'grant_users_group_permission',
+                                  repoid=self.REPO,
+                                  usersgroupid=TEST_USERS_GROUP,
+                                  perm=perm)
+        response = api_call(self, params)
+
+        expected = 'permission `%s` does not exist' % perm
+        self._compare_error(id_, expected, given=response.body)
+
+    @mock.patch.object(RepoModel, 'grant_users_group_permission', crash)
+    def test_api_grant_users_group_permission_exception_when_adding(self):
+        perm = 'repository.read'
+        id_, params = _build_data(self.apikey, 'grant_users_group_permission',
+                                  repoid=self.REPO,
+                                  usersgroupid=TEST_USERS_GROUP,
+                                  perm=perm)
+        response = api_call(self, params)
+
+        expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
+                    TEST_USERS_GROUP, self.REPO
+                )
+        self._compare_error(id_, expected, given=response.body)
+
+    def test_api_revoke_users_group_permission(self):
+        RepoModel().grant_users_group_permission(repo=self.REPO,
+                                                 group_name=TEST_USERS_GROUP,
+                                                 perm='repository.read')
+        Session().commit()
+        id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
+                                  repoid=self.REPO,
+                                  usersgroupid=TEST_USERS_GROUP,)
+        response = api_call(self, params)
+
+        expected = {
+            'msg': 'Revoked perm for users group: `%s` in repo: `%s`' % (
+                TEST_USERS_GROUP, self.REPO
+            ),
+            'success': True
+        }
+        self._compare_ok(id_, expected, given=response.body)
+
+    @mock.patch.object(RepoModel, 'revoke_users_group_permission', crash)
+    def test_api_revoke_users_group_permission_exception_when_adding(self):
+
+        id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
+                                  repoid=self.REPO,
+                                  usersgroupid=TEST_USERS_GROUP,)
+        response = api_call(self, params)
+
+        expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
+                    TEST_USERS_GROUP, self.REPO
+                )
+        self._compare_error(id_, expected, given=response.body)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/api/test_api_git.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,7 @@
+from rhodecode.tests import *
+from rhodecode.tests.api.api_base import BaseTestApi
+
+
+class TestGitApi(BaseTestApi, TestController):
+    REPO = GIT_REPO
+    REPO_TYPE = 'git'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/api/test_api_hg.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,7 @@
+from rhodecode.tests import *
+from rhodecode.tests.api.api_base import BaseTestApi
+
+
+class TestHgApi(BaseTestApi, TestController):
+    REPO = HG_REPO
+    REPO_TYPE = 'hg'
--- a/rhodecode/tests/functional/test_admin_notifications.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_admin_notifications.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,25 +1,25 @@
 from rhodecode.tests import *
-from rhodecode.model.db import Notification, User, UserNotification
+from rhodecode.model.db import Notification, User
 
 from rhodecode.model.user import UserModel
 from rhodecode.model.notification import NotificationModel
-from rhodecode.model.meta import Session
+
 
 class TestNotificationsController(TestController):
 
-
     def tearDown(self):
         for n in Notification.query().all():
             inst = Notification.get(n.notification_id)
-            Session.delete(inst)
-        Session.commit()
+            self.Session().delete(inst)
+        self.Session().commit()
 
     def test_index(self):
         self.log_user()
 
         u1 = UserModel().create_or_update(username='u1', password='qweqwe',
                                                email='u1@rhodecode.org',
-                                               name='u1', lastname='u1').user_id
+                                               firstname='u1', lastname='u1')
+        u1 = u1.user_id
 
         response = self.app.get(url('notifications'))
         self.assertTrue('''<div class="table">No notifications here yet</div>'''
@@ -30,7 +30,7 @@
         NotificationModel().create(created_by=u1, subject=u'test_notification_1',
                                    body=u'notification_1',
                                    recipients=[cur_user])
-        Session.commit()
+        self.Session().commit()
         response = self.app.get(url('notifications'))
         self.assertTrue(u'test_notification_1' in response.body)
 
@@ -58,28 +58,27 @@
 
         u1 = UserModel().create_or_update(username='u1', password='qweqwe',
                                                email='u1@rhodecode.org',
-                                               name='u1', lastname='u1')
+                                               firstname='u1', lastname='u1')
         u2 = UserModel().create_or_update(username='u2', password='qweqwe',
                                                email='u2@rhodecode.org',
-                                               name='u2', lastname='u2')
+                                               firstname='u2', lastname='u2')
 
         # make notifications
         notification = NotificationModel().create(created_by=cur_user,
                                                   subject=u'test',
                                                   body=u'hi there',
                                                   recipients=[cur_user, u1, u2])
-        Session.commit()
+        self.Session().commit()
         u1 = User.get(u1.user_id)
         u2 = User.get(u2.user_id)
 
         # check DB
-        get_notif = lambda un:[x.notification for x in un]
+        get_notif = lambda un: [x.notification for x in un]
         self.assertEqual(get_notif(cur_user.notifications), [notification])
         self.assertEqual(get_notif(u1.notifications), [notification])
         self.assertEqual(get_notif(u2.notifications), [notification])
         cur_usr_id = cur_user.user_id
 
-
         response = self.app.delete(url('notification',
                                        notification_id=
                                        notification.notification_id))
@@ -87,19 +86,15 @@
         cur_user = User.get(cur_usr_id)
         self.assertEqual(cur_user.notifications, [])
 
-
-#    def test_delete_browser_fakeout(self):
-#        response = self.app.post(url('notification', notification_id=1), params=dict(_method='delete'))
-
     def test_show(self):
         self.log_user()
         cur_user = self._get_logged_user()
         u1 = UserModel().create_or_update(username='u1', password='qweqwe',
                                                email='u1@rhodecode.org',
-                                               name='u1', lastname='u1')
+                                               firstname='u1', lastname='u1')
         u2 = UserModel().create_or_update(username='u2', password='qweqwe',
                                                email='u2@rhodecode.org',
-                                               name='u2', lastname='u2')
+                                               firstname='u2', lastname='u2')
 
         notification = NotificationModel().create(created_by=cur_user,
                                                   subject=u'test',
@@ -108,12 +103,3 @@
 
         response = self.app.get(url('notification',
                                     notification_id=notification.notification_id))
-
-#    def test_show_as_xml(self):
-#        response = self.app.get(url('formatted_notification', notification_id=1, format='xml'))
-#
-#    def test_edit(self):
-#        response = self.app.get(url('edit_notification', notification_id=1))
-#
-#    def test_edit_as_xml(self):
-#        response = self.app.get(url('formatted_edit_notification', notification_id=1, format='xml'))
--- a/rhodecode/tests/functional/test_admin_repos.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_admin_repos.py	Sun Sep 02 21:19:54 2012 +0200
@@ -3,8 +3,11 @@
 import os
 from rhodecode.lib import vcs
 
-from rhodecode.model.db import Repository
+from rhodecode.model.db import Repository, RepoGroup
 from rhodecode.tests import *
+from rhodecode.model.repos_group import ReposGroupModel
+from rhodecode.model.repo import RepoModel
+
 
 class TestAdminReposController(TestController):
 
@@ -24,17 +27,19 @@
         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',
-                                                'clone_uri':'',
-                                                'repo_group':'',
-                                                'description':description,
-                                                'private':private})
-        self.checkSessionFlash(response, 'created repository %s' % (repo_name))
+        response = self.app.post(url('repos'), {'repo_name': repo_name,
+                                                'repo_type': 'hg',
+                                                'clone_uri': '',
+                                                'repo_group': '',
+                                                'description': description,
+                                                'private': private,
+                                                'landing_rev': 'tip'})
+        self.checkSessionFlash(response,
+                               'created repository %s' % (repo_name))
 
         #test if the repo was created in the database
-        new_repo = self.Session.query(Repository).filter(Repository.repo_name ==
-                                                    repo_name).one()
+        new_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
         self.assertEqual(new_repo.description, description)
@@ -42,15 +47,13 @@
         #test if repository is visible in the list ?
         response = response.follow()
 
-        self.assertTrue(repo_name in response.body)
-
+        response.mustcontain(repo_name)
 
         #test if repository was created on filesystem
         try:
             vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
         except:
-            self.fail('no repo in filesystem')
-
+            self.fail('no repo %s in filesystem' % repo_name)
 
     def test_create_hg_non_ascii(self):
         self.log_user()
@@ -60,18 +63,19 @@
         description = 'description for newly created repo' + non_ascii
         description_unicode = description.decode('utf8')
         private = False
-        response = self.app.post(url('repos'), {'repo_name':repo_name,
-                                                'repo_type':'hg',
-                                                'clone_uri':'',
-                                                'repo_group':'',
-                                                'description':description,
-                                                'private':private})
+        response = self.app.post(url('repos'), {'repo_name': repo_name,
+                                                'repo_type': 'hg',
+                                                'clone_uri': '',
+                                                'repo_group': '',
+                                                'description': description,
+                                                'private': private,
+                                                'landing_rev': 'tip'})
         self.checkSessionFlash(response,
                                'created repository %s' % (repo_name_unicode))
 
         #test if the repo was created in the database
-        new_repo = self.Session.query(Repository).filter(Repository.repo_name ==
-                                                repo_name_unicode).one()
+        new_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name_unicode).one()
 
         self.assertEqual(new_repo.repo_name, repo_name_unicode)
         self.assertEqual(new_repo.description, description_unicode)
@@ -79,52 +83,129 @@
         #test if repository is visible in the list ?
         response = response.follow()
 
-        self.assertTrue(repo_name in response.body)
+        response.mustcontain(repo_name)
 
         #test if repository was created on filesystem
         try:
             vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
         except:
-            self.fail('no repo in filesystem')
-
+            self.fail('no repo %s in filesystem' % repo_name)
 
     def test_create_hg_in_group(self):
-        #TODO: write test !
-        pass
+        self.log_user()
+
+        ## create GROUP
+        group_name = 'sometest'
+        gr = ReposGroupModel().create(group_name=group_name,
+                                      group_description='test',)
+        self.Session().commit()
+
+        repo_name = 'ingroup'
+        repo_name_full = RepoGroup.url_sep().join([group_name, repo_name])
+        description = 'description for newly created repo'
+        private = False
+        response = self.app.post(url('repos'), {'repo_name': repo_name,
+                                                'repo_type': 'hg',
+                                                'clone_uri': '',
+                                                'repo_group': gr.group_id,
+                                                'description': description,
+                                                'private': private,
+                                                'landing_rev': 'tip'})
+        self.checkSessionFlash(response,
+                               'created repository %s' % (repo_name))
+
+        #test if the repo was created in the database
+        new_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name_full).one()
+
+        self.assertEqual(new_repo.repo_name, repo_name_full)
+        self.assertEqual(new_repo.description, description)
+
+        #test if repository is visible in the list ?
+        response = response.follow()
+
+        response.mustcontain(repo_name_full)
+
+        #test if repository was created on filesystem
+        try:
+            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name_full))
+        except:
+            ReposGroupModel().delete(group_name)
+            self.Session().commit()
+            self.fail('no repo %s in filesystem' % repo_name)
+
+        RepoModel().delete(repo_name_full)
+        ReposGroupModel().delete(group_name)
+        self.Session().commit()
 
     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',
-                                                'clone_uri':'',
-                                                'repo_group':'',
-                                                'description':description,
-                                                'private':private})
-
+        response = self.app.post(url('repos'), {'repo_name': repo_name,
+                                                'repo_type': 'git',
+                                                'clone_uri': '',
+                                                'repo_group': '',
+                                                'description': description,
+                                                'private': private,
+                                                'landing_rev': 'tip'})
+        self.checkSessionFlash(response,
+                               'created repository %s' % (repo_name))
 
-        #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.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name).one()
 
-        #test if the fork was created in the database
-        new_repo = self.Session.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'
+        self.assertEqual(new_repo.repo_name, repo_name)
+        self.assertEqual(new_repo.description, 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.mustcontain(repo_name)
 
         #test if repository was created on filesystem
         try:
             vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
         except:
-            assert False , 'no repo in filesystem'
+            self.fail('no repo %s in filesystem' % repo_name)
+
+    def test_create_git_non_ascii(self):
+        self.log_user()
+        non_ascii = "ąęł"
+        repo_name = "%s%s" % (NEW_GIT_REPO, non_ascii)
+        repo_name_unicode = repo_name.decode('utf8')
+        description = 'description for newly created repo' + non_ascii
+        description_unicode = description.decode('utf8')
+        private = False
+        response = self.app.post(url('repos'), {'repo_name': repo_name,
+                                                'repo_type': 'git',
+                                                'clone_uri': '',
+                                                'repo_group': '',
+                                                'description': description,
+                                                'private': private,
+                                                'landing_rev': 'tip'})
+        self.checkSessionFlash(response,
+                               'created repository %s' % (repo_name_unicode))
+
+        #test if the repo was created in the database
+        new_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name_unicode).one()
+
+        self.assertEqual(new_repo.repo_name, repo_name_unicode)
+        self.assertEqual(new_repo.description, description_unicode)
+
+        #test if repository is visible in the list ?
+        response = response.follow()
+
+        response.mustcontain(repo_name)
+
+        #test if repository was created on filesystem
+        try:
+            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
+        except:
+            self.fail('no repo %s in filesystem' % repo_name)
 
     def test_new(self):
         self.log_user()
@@ -140,27 +221,24 @@
         response = self.app.post(url('repo', repo_name=HG_REPO),
                                  params=dict(_method='put'))
 
-    def test_delete(self):
+    def test_delete_hg(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',
-                                                'clone_uri':'',
-                                                'repo_group':'',
-                                                'description':description,
-                                                'private':private})
-        self.assertTrue('flash' in response.session)
-
-        #test if we have a message for that repository
-        self.assertTrue('''created repository %s''' % (repo_name) in
-                        response.session['flash'][0])
+        response = self.app.post(url('repos'), {'repo_name': repo_name,
+                                                'repo_type': 'hg',
+                                                'clone_uri': '',
+                                                'repo_group': '',
+                                                'description': description,
+                                                'private': private,
+                                                'landing_rev': 'tip'})
+        self.checkSessionFlash(response,
+                               'created repository %s' % (repo_name))
 
         #test if the repo was created in the database
-        new_repo = self.Session.query(Repository).filter(Repository.repo_name ==
-                                                    repo_name).one()
+        new_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
         self.assertEqual(new_repo.description, description)
@@ -168,8 +246,13 @@
         #test if repository is visible in the list ?
         response = response.follow()
 
-        self.assertTrue(repo_name in response.body)
+        response.mustcontain(repo_name)
 
+        #test if repository was created on filesystem
+        try:
+            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
+        except:
+            self.fail('no repo %s in filesystem' % repo_name)
 
         response = self.app.delete(url('repo', repo_name=repo_name))
 
@@ -179,32 +262,79 @@
         response.follow()
 
         #check if repo was deleted from db
-        deleted_repo = self.Session.query(Repository).filter(Repository.repo_name
-                                                        == repo_name).scalar()
+        deleted_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name).scalar()
 
         self.assertEqual(deleted_repo, None)
 
+        self.assertEqual(os.path.isdir(os.path.join(TESTS_TMP_PATH, repo_name)),
+                                  False)
+
+    def test_delete_git(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': 'git',
+                                                'clone_uri': '',
+                                                'repo_group': '',
+                                                'description': description,
+                                                'private': private,
+                                                'landing_rev': 'tip'})
+        self.checkSessionFlash(response,
+                               'created repository %s' % (repo_name))
+
+        #test if the repo was created in the database
+        new_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name).one()
+
+        self.assertEqual(new_repo.repo_name, repo_name)
+        self.assertEqual(new_repo.description, description)
+
+        #test if repository is visible in the list ?
+        response = response.follow()
+
+        response.mustcontain(repo_name)
+
+        #test if repository was created on filesystem
+        try:
+            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
+        except:
+            self.fail('no repo %s in filesystem' % repo_name)
+
+        response = self.app.delete(url('repo', repo_name=repo_name))
+
+        self.assertTrue('''deleted repository %s''' % (repo_name) in
+                        response.session['flash'][0])
+
+        response.follow()
+
+        #check if repo was deleted from db
+        deleted_repo = self.Session().query(Repository)\
+            .filter(Repository.repo_name == repo_name).scalar()
+
+        self.assertEqual(deleted_repo, None)
+
+        self.assertEqual(os.path.isdir(os.path.join(TESTS_TMP_PATH, repo_name)),
+                                  False)
 
     def test_delete_repo_with_group(self):
         #TODO:
         pass
 
-
     def test_delete_browser_fakeout(self):
         response = self.app.post(url('repo', repo_name=HG_REPO),
                                  params=dict(_method='delete'))
 
-    def test_show(self):
+    def test_show_hg(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_show_git(self):
+        self.log_user()
+        response = self.app.get(url('repo', repo_name=GIT_REPO))
+
 
     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	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_admin_settings.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,8 +1,12 @@
 # -*- coding: utf-8 -*-
 
 from rhodecode.lib.auth import get_crypt_password, check_password
-from rhodecode.model.db import User, RhodeCodeSetting
+from rhodecode.model.db import User, RhodeCodeSetting, Repository
 from rhodecode.tests import *
+from rhodecode.lib import helpers as h
+from rhodecode.model.user import UserModel
+from rhodecode.model.scm import ScmModel
+
 
 class TestAdminSettingsController(TestController):
 
@@ -47,7 +51,6 @@
         response = self.app.get(url('formatted_admin_edit_setting',
                                     setting_id=1, format='xml'))
 
-
     def test_ga_code_active(self):
         self.log_user()
         old_title = 'RhodeCode'
@@ -67,8 +70,7 @@
                          .get_app_settings()['rhodecode_ga_code'], new_ga_code)
 
         response = response.follow()
-        self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
-                        in response.body)
+        response.mustcontain("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code)
 
     def test_ga_code_inactive(self):
         self.log_user()
@@ -89,9 +91,8 @@
                         .get_app_settings()['rhodecode_ga_code'], new_ga_code)
 
         response = response.follow()
-        self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
-                        not in response.body)
-
+        self.assertFalse("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
+                         in response.body)
 
     def test_title_change(self):
         self.log_user()
@@ -114,9 +115,7 @@
                              new_title.decode('utf-8'))
 
             response = response.follow()
-            self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title
-                        in response.body)
-
+            response.mustcontain("""<h1><a href="/">%s</a></h1>""" % new_title)
 
     def test_my_account(self):
         self.log_user()
@@ -124,89 +123,144 @@
 
         self.assertTrue('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'
-
+    @parameterized.expand([('firstname', 'new_username'),
+                           ('lastname', 'new_username'),
+                           ('admin', True),
+                           ('admin', False),
+                           ('ldap_dn', 'test'),
+                           ('ldap_dn', None),
+                           ('active', False),
+                           ('active', True),
+                           ('email', 'some@email.com'),
+                           ])
+    def test_my_account_update(self, name, expected):
+        uname = 'testme'
+        usr = UserModel().create_or_update(username=uname, password='qweqwe',
+                                           email='testme@rhodecod.org')
+        self.Session().commit()
+        params = usr.get_api_data()
+        user_id = usr.user_id
+        self.log_user(username=uname, password='qweqwe')
+        params.update({name: expected})
+        params.update({'password_confirmation': ''})
+        params.update({'new_password': ''})
 
-        response = self.app.post(url('admin_settings_my_account_update'),
-                                 params=dict(_method='put',
-                                             username='test_admin',
-                                             new_password=new_password,
-                                             password_confirmation = new_password,
-                                             password='',
-                                             name=new_name,
-                                             lastname=new_lastname,
-                                             email=new_email,))
-        response.follow()
-
-        assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
-        user = self.Session.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)
-        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)
+        try:
+            response = self.app.put(url('admin_settings_my_account_update',
+                                        id=user_id), params)
 
-        #bring back the admin settings
-        old_email = 'test_admin@mail.com'
-        old_name = 'RhodeCode'
-        old_lastname = 'Admin'
-        old_password = 'test12'
+            self.checkSessionFlash(response,
+                                   'Your account was updated successfully')
+
+            updated_user = User.get_by_username(uname)
+            updated_params = updated_user.get_api_data()
+            updated_params.update({'password_confirmation': ''})
+            updated_params.update({'new_password': ''})
 
-        response = self.app.post(url('admin_settings_my_account_update'), params=dict(
-                                                            _method='put',
-                                                            username='test_admin',
-                                                            new_password=old_password,
-                                                            password_confirmation = old_password,
-                                                            password='',
-                                                            name=old_name,
-                                                            lastname=old_lastname,
-                                                            email=old_email,))
+            params['last_login'] = updated_params['last_login']
+            if name == 'email':
+                params['emails'] = [expected]
+            if name == 'ldap_dn':
+                #cannot update this via form
+                params['ldap_dn'] = None
+            if name == 'active':
+                #my account cannot deactivate account
+                params['active'] = True
+            if name == 'admin':
+                #my account cannot make you an admin !
+                params['admin'] = False
 
-        response.follow()
-        self.checkSessionFlash(response,
-                               'Your account was updated successfully')
+            self.assertEqual(params, updated_params)
 
-        user = self.Session.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)
-
+        finally:
+            UserModel().delete('testme')
 
     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',
-                                                            username='test_admin',
-                                                            new_password='test12',
-                                                            password_confirmation = 'test122',
-                                                            name='NewName',
-                                                            lastname='NewLastname',
-                                                            email=new_email,))
+        new_email = 'test_regular@mail.com'  # already exisitn email
+        response = self.app.put(url('admin_settings_my_account_update'),
+                                params=dict(
+                                    username='test_admin',
+                                    new_password='test12',
+                                    password_confirmation='test122',
+                                    firstname='NewName',
+                                    lastname='NewLastname',
+                                    email=new_email,)
+                                )
 
-        assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email'
-
+        response.mustcontain('This e-mail address is already taken')
 
     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',
-                                                            username='test_admin',
-                                                            new_password='test12',
-                                                            password_confirmation = 'test122',
-                                                            name='NewName',
-                                                            lastname='NewLastname',
-                                                            email=new_email,))
-        assert 'An email address must contain a single @' in response.body, 'Missing error message about wrong email'
-        assert 'This username already exists' in response.body, 'Missing error message about existing user'
+        response = self.app.post(url('admin_settings_my_account_update'),
+                                 params=dict(
+                                            _method='put',
+                                            username='test_admin',
+                                            new_password='test12',
+                                            password_confirmation='test122',
+                                            firstname='NewName',
+                                            lastname='NewLastname',
+                                            email=new_email,)
+                                 )
+
+        response.mustcontain('An email address must contain a single @')
+        from rhodecode.model import validators
+        msg = validators.ValidUsername(edit=False,
+                                    old_data={})._messages['username_exists']
+        msg = h.html_escape(msg % {'username': 'test_admin'})
+        response.mustcontain(u"%s" % msg)
+
+    def test_set_repo_fork_has_no_self_id(self):
+        self.log_user()
+        repo = Repository.get_by_repo_name(HG_REPO)
+        response = self.app.get(url('edit_repo', repo_name=HG_REPO))
+        opt = """<option value="%s">vcs_test_git</option>""" % repo.repo_id
+        assert opt not in response.body
+
+    def test_set_fork_of_repo(self):
+        self.log_user()
+        repo = Repository.get_by_repo_name(HG_REPO)
+        repo2 = Repository.get_by_repo_name(GIT_REPO)
+        response = self.app.put(url('repo_as_fork', repo_name=HG_REPO),
+                                 params=dict(
+                                    id_fork_of=repo2.repo_id
+                                 ))
+        repo = Repository.get_by_repo_name(HG_REPO)
+        repo2 = Repository.get_by_repo_name(GIT_REPO)
+        self.checkSessionFlash(response,
+        'Marked repo %s as fork of %s' % (repo.repo_name, repo2.repo_name))
+
+        assert repo.fork == repo2
+        response = response.follow()
+        # check if given repo is selected
+
+        opt = """<option value="%s" selected="selected">%s</option>""" % (
+                                                repo2.repo_id, repo2.repo_name)
+        response.mustcontain(opt)
+
+        # clean session flash
+        #response = self.app.get(url('edit_repo', repo_name=HG_REPO))
+
+        ## mark it as None
+        response = self.app.put(url('repo_as_fork', repo_name=HG_REPO),
+                                 params=dict(
+                                    id_fork_of=None
+                                 ))
+        repo = Repository.get_by_repo_name(HG_REPO)
+        repo2 = Repository.get_by_repo_name(GIT_REPO)
+        self.checkSessionFlash(response,
+        'Marked repo %s as fork of %s' % (repo.repo_name, "Nothing"))
+        assert repo.fork == None
+
+    def test_set_fork_of_same_repo(self):
+        self.log_user()
+        repo = Repository.get_by_repo_name(HG_REPO)
+        response = self.app.put(url('repo_as_fork', repo_name=HG_REPO),
+                                 params=dict(
+                                    id_fork_of=repo.repo_id
+                                 ))
+        self.checkSessionFlash(response,
+                               'An error occurred during this operation')
--- a/rhodecode/tests/functional/test_admin_users.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_admin_users.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,8 +1,13 @@
+from sqlalchemy.orm.exc import NoResultFound
+
 from rhodecode.tests import *
 from rhodecode.model.db import User, Permission
 from rhodecode.lib.auth import check_password
-from sqlalchemy.orm.exc import NoResultFound
 from rhodecode.model.user import UserModel
+from rhodecode.model import validators
+from rhodecode.lib import helpers as h
+from rhodecode.model.meta import Session
+
 
 class TestAdminUsersController(TestController):
 
@@ -24,30 +29,28 @@
         email = 'mail@mail.com'
 
         response = self.app.post(url('users'),
-                                 {'username':username,
-                                   'password':password,
-                                   'password_confirmation':password_confirmation,
-                                   'name':name,
-                                   'active':True,
-                                   'lastname':lastname,
-                                   'email':email})
+                             {'username': username,
+                               'password': password,
+                               'password_confirmation': password_confirmation,
+                               'firstname': name,
+                               'active': True,
+                               'lastname': lastname,
+                               'email': email})
 
-
-        self.assertTrue('''created user %s''' % (username) in
-                        response.session['flash'][0])
+        self.checkSessionFlash(response, '''created user %s''' % (username))
 
         new_user = self.Session.query(User).\
             filter(User.username == username).one()
 
-        self.assertEqual(new_user.username,username)
-        self.assertEqual(check_password(password, new_user.password),True)
-        self.assertEqual(new_user.name,name)
-        self.assertEqual(new_user.lastname,lastname)
-        self.assertEqual(new_user.email,email)
+        self.assertEqual(new_user.username, username)
+        self.assertEqual(check_password(password, new_user.password), True)
+        self.assertEqual(new_user.name, name)
+        self.assertEqual(new_user.lastname, lastname)
+        self.assertEqual(new_user.email, email)
 
         response.follow()
         response = response.follow()
-        self.assertTrue("""edit">newtestuser</a>""" in response.body)
+        response.mustcontain("""newtestuser""")
 
     def test_create_err(self):
         self.log_user()
@@ -57,16 +60,18 @@
         lastname = 'lastname'
         email = 'errmail.com'
 
-        response = self.app.post(url('users'), {'username':username,
-                                               'password':password,
-                                               'name':name,
-                                               'active':False,
-                                               'lastname':lastname,
-                                               'email':email})
+        response = self.app.post(url('users'), {'username': username,
+                                               'password': password,
+                                               'name': name,
+                                               'active': False,
+                                               'lastname': lastname,
+                                               'email': email})
 
-        self.assertTrue("""<span class="error-message">Invalid username</span>""" in response.body)
-        self.assertTrue("""<span class="error-message">Please enter a value</span>""" in response.body)
-        self.assertTrue("""<span class="error-message">An email address must contain a single @</span>""" in response.body)
+        msg = validators.ValidUsername(False, {})._messages['system_invalid_username']
+        msg = h.html_escape(msg % {'username': 'new_user'})
+        response.mustcontain("""<span class="error-message">%s</span>""" % msg)
+        response.mustcontain("""<span class="error-message">Please enter a value</span>""")
+        response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""")
 
         def get_user():
             self.Session.query(User).filter(User.username == username).one()
@@ -80,8 +85,45 @@
     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))
+    @parameterized.expand([('firstname', 'new_username'),
+                           ('lastname', 'new_username'),
+                           ('admin', True),
+                           ('admin', False),
+                           ('ldap_dn', 'test'),
+                           ('ldap_dn', None),
+                           ('active', False),
+                           ('active', True),
+                           ('email', 'some@email.com'),
+                           ])
+    def test_update(self, name, expected):
+        self.log_user()
+        uname = 'testme'
+        usr = UserModel().create_or_update(username=uname, password='qweqwe',
+                                           email='testme@rhodecod.org')
+        self.Session().commit()
+        params = usr.get_api_data()
+        params.update({name: expected})
+        params.update({'password_confirmation': ''})
+        params.update({'new_password': ''})
+        if name == 'email':
+            params['emails'] = [expected]
+        if name == 'ldap_dn':
+            #cannot update this via form
+            params['ldap_dn'] = None
+        try:
+            response = self.app.put(url('user', id=usr.user_id), params)
+
+            self.checkSessionFlash(response, '''User updated successfully''')
+
+            updated_user = User.get_by_username(uname)
+            updated_params = updated_user.get_api_data()
+            updated_params.update({'password_confirmation': ''})
+            updated_params.update({'new_password': ''})
+
+            self.assertEqual(params, updated_params)
+
+        finally:
+            UserModel().delete('testme')
 
     def test_update_browser_fakeout(self):
         response = self.app.post(url('user', id=1), params=dict(_method='put'))
@@ -94,13 +136,13 @@
         lastname = 'lastname'
         email = 'todeletemail@mail.com'
 
-        response = self.app.post(url('users'), {'username':username,
-                                               'password':password,
-                                               'password_confirmation':password,
-                                               'name':name,
-                                               'active':True,
-                                               'lastname':lastname,
-                                               'email':email})
+        response = self.app.post(url('users'), {'username': username,
+                                               'password': password,
+                                               'password_confirmation': password,
+                                               'firstname': name,
+                                               'active': True,
+                                               'lastname': lastname,
+                                               'email': email})
 
         response = response.follow()
 
@@ -111,7 +153,6 @@
         self.assertTrue("""successfully deleted user""" in
                         response.session['flash'][0])
 
-
     def test_delete_browser_fakeout(self):
         response = self.app.post(url('user', id=1),
                                  params=dict(_method='delete'))
@@ -127,53 +168,123 @@
         user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
         response = self.app.get(url('edit_user', id=user.user_id))
 
-
     def test_add_perm_create_repo(self):
         self.log_user()
         perm_none = Permission.get_by_key('hg.create.none')
         perm_create = Permission.get_by_key('hg.create.repository')
 
-        user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
-
+        user = UserModel().create_or_update(username='dummy', password='qwe',
+                                            email='dummy', firstname='a',
+                                            lastname='b')
+        Session().commit()
+        uid = user.user_id
 
-        #User should have None permission on creation repository
-        self.assertEqual(UserModel().has_perm(user, perm_none), False)
-        self.assertEqual(UserModel().has_perm(user, perm_create), False)
+        try:
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(user, perm_none), False)
+            self.assertEqual(UserModel().has_perm(user, perm_create), False)
 
-        response = self.app.post(url('user_perm', id=user.user_id),
-                                 params=dict(_method='put',
-                                             create_repo_perm=True))
+            response = self.app.post(url('user_perm', id=uid),
+                                     params=dict(_method='put',
+                                                 create_repo_perm=True))
+
+            perm_none = Permission.get_by_key('hg.create.none')
+            perm_create = Permission.get_by_key('hg.create.repository')
 
-        perm_none = Permission.get_by_key('hg.create.none')
-        perm_create = Permission.get_by_key('hg.create.repository')
-
-        user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
-        #User should have None permission on creation repository
-        self.assertEqual(UserModel().has_perm(user, perm_none), False)
-        self.assertEqual(UserModel().has_perm(user, perm_create), True)
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(uid, perm_none), False)
+            self.assertEqual(UserModel().has_perm(uid, perm_create), True)
+        finally:
+            UserModel().delete(uid)
+            Session().commit()
 
     def test_revoke_perm_create_repo(self):
         self.log_user()
         perm_none = Permission.get_by_key('hg.create.none')
         perm_create = Permission.get_by_key('hg.create.repository')
 
-        user = User.get_by_username(TEST_USER_REGULAR2_LOGIN)
+        user = UserModel().create_or_update(username='dummy', password='qwe',
+                                            email='dummy', firstname='a',
+                                            lastname='b')
+        Session().commit()
+        uid = user.user_id
 
+        try:
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(user, perm_none), False)
+            self.assertEqual(UserModel().has_perm(user, perm_create), False)
+
+            response = self.app.post(url('user_perm', id=uid),
+                                     params=dict(_method='put'))
+
+            perm_none = Permission.get_by_key('hg.create.none')
+            perm_create = Permission.get_by_key('hg.create.repository')
 
-        #User should have None permission on creation repository
-        self.assertEqual(UserModel().has_perm(user, perm_none), False)
-        self.assertEqual(UserModel().has_perm(user, perm_create), False)
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(uid, perm_none), True)
+            self.assertEqual(UserModel().has_perm(uid, perm_create), False)
+        finally:
+            UserModel().delete(uid)
+            Session().commit()
+
+    def test_add_perm_fork_repo(self):
+        self.log_user()
+        perm_none = Permission.get_by_key('hg.fork.none')
+        perm_fork = Permission.get_by_key('hg.fork.repository')
+
+        user = UserModel().create_or_update(username='dummy', password='qwe',
+                                            email='dummy', firstname='a',
+                                            lastname='b')
+        Session().commit()
+        uid = user.user_id
+
+        try:
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(user, perm_none), False)
+            self.assertEqual(UserModel().has_perm(user, perm_fork), False)
 
-        response = self.app.post(url('user_perm', id=user.user_id),
-                                 params=dict(_method='put'))
+            response = self.app.post(url('user_perm', id=uid),
+                                     params=dict(_method='put',
+                                                 create_repo_perm=True))
+
+            perm_none = Permission.get_by_key('hg.create.none')
+            perm_create = Permission.get_by_key('hg.create.repository')
+
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(uid, perm_none), False)
+            self.assertEqual(UserModel().has_perm(uid, perm_create), True)
+        finally:
+            UserModel().delete(uid)
+            Session().commit()
+
+    def test_revoke_perm_fork_repo(self):
+        self.log_user()
+        perm_none = Permission.get_by_key('hg.fork.none')
+        perm_fork = Permission.get_by_key('hg.fork.repository')
 
-        perm_none = Permission.get_by_key('hg.create.none')
-        perm_create = Permission.get_by_key('hg.create.repository')
+        user = UserModel().create_or_update(username='dummy', password='qwe',
+                                            email='dummy', firstname='a',
+                                            lastname='b')
+        Session().commit()
+        uid = user.user_id
+
+        try:
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(user, perm_none), False)
+            self.assertEqual(UserModel().has_perm(user, perm_fork), False)
 
-        user = User.get_by_username(TEST_USER_REGULAR2_LOGIN)
-        #User should have None permission on creation repository
-        self.assertEqual(UserModel().has_perm(user, perm_none), True)
-        self.assertEqual(UserModel().has_perm(user, perm_create), False)
+            response = self.app.post(url('user_perm', id=uid),
+                                     params=dict(_method='put'))
+
+            perm_none = Permission.get_by_key('hg.create.none')
+            perm_create = Permission.get_by_key('hg.create.repository')
+
+            #User should have None permission on creation repository
+            self.assertEqual(UserModel().has_perm(uid, perm_none), True)
+            self.assertEqual(UserModel().has_perm(uid, perm_create), False)
+        finally:
+            UserModel().delete(uid)
+            Session().commit()
 
     def test_edit_as_xml(self):
         response = self.app.get(url('formatted_edit_user', id=1, format='xml'))
--- a/rhodecode/tests/functional/test_admin_users_groups.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_admin_users_groups.py	Sun Sep 02 21:19:54 2012 +0200
@@ -65,27 +65,48 @@
         users_group_name = TEST_USERS_GROUP + 'another2'
         response = self.app.post(url('users_groups'),
                                  {'users_group_name': users_group_name,
-                                  'active':True})
+                                  'active': True})
         response.follow()
 
         ug = UsersGroup.get_by_group_name(users_group_name)
         self.checkSessionFlash(response,
                                'created users group %s' % users_group_name)
-
+        ## ENABLE REPO CREATE ON A GROUP
         response = self.app.put(url('users_group_perm', id=ug.users_group_id),
                                  {'create_repo_perm': True})
 
         response.follow()
         ug = UsersGroup.get_by_group_name(users_group_name)
         p = Permission.get_by_key('hg.create.repository')
-        # check if user has this perm
+        p2 = Permission.get_by_key('hg.fork.none')
+        # check if user has this perms, they should be here since
+        # defaults are on
         perms = UsersGroupToPerm.query()\
             .filter(UsersGroupToPerm.users_group == ug).all()
-        perms = [[x.__dict__['users_group_id'],
-                  x.__dict__['permission_id'],] for x in perms]
+
         self.assertEqual(
-            perms,
-            [[ug.users_group_id, p.permission_id]]
+            [[x.users_group_id, x.permission_id, ] for x in perms],
+            [[ug.users_group_id, p.permission_id],
+             [ug.users_group_id, p2.permission_id]]
+        )
+
+        ## DISABLE REPO CREATE ON A GROUP
+        response = self.app.put(url('users_group_perm', id=ug.users_group_id),
+                                    {})
+
+        response.follow()
+        ug = UsersGroup.get_by_group_name(users_group_name)
+        p = Permission.get_by_key('hg.create.none')
+        p2 = Permission.get_by_key('hg.fork.none')
+        # check if user has this perms, they should be here since
+        # defaults are on
+        perms = UsersGroupToPerm.query()\
+            .filter(UsersGroupToPerm.users_group == ug).all()
+
+        self.assertEqual(
+            sorted([[x.users_group_id, x.permission_id, ] for x in perms]),
+            sorted([[ug.users_group_id, p.permission_id],
+             [ug.users_group_id, p2.permission_id]])
         )
 
         # DELETE !
@@ -101,8 +122,77 @@
         p = Permission.get_by_key('hg.create.repository')
         perms = UsersGroupToPerm.query()\
             .filter(UsersGroupToPerm.users_group_id == ugid).all()
-        perms = [[x.__dict__['users_group_id'],
-                  x.__dict__['permission_id'],] for x in perms]
+        perms = [[x.users_group_id,
+                  x.permission_id, ] for x in perms]
+        self.assertEqual(
+            perms,
+            []
+        )
+
+    def test_enable_repository_fork_on_group(self):
+        self.log_user()
+        users_group_name = TEST_USERS_GROUP + 'another2'
+        response = self.app.post(url('users_groups'),
+                                 {'users_group_name': users_group_name,
+                                  'active': True})
+        response.follow()
+
+        ug = UsersGroup.get_by_group_name(users_group_name)
+        self.checkSessionFlash(response,
+                               'created users group %s' % users_group_name)
+        ## ENABLE REPO CREATE ON A GROUP
+        response = self.app.put(url('users_group_perm', id=ug.users_group_id),
+                                 {'fork_repo_perm': True})
+
+        response.follow()
+        ug = UsersGroup.get_by_group_name(users_group_name)
+        p = Permission.get_by_key('hg.create.none')
+        p2 = Permission.get_by_key('hg.fork.repository')
+        # check if user has this perms, they should be here since
+        # defaults are on
+        perms = UsersGroupToPerm.query()\
+            .filter(UsersGroupToPerm.users_group == ug).all()
+
+        self.assertEqual(
+            [[x.users_group_id, x.permission_id, ] for x in perms],
+            [[ug.users_group_id, p.permission_id],
+             [ug.users_group_id, p2.permission_id]]
+        )
+
+        ## DISABLE REPO CREATE ON A GROUP
+        response = self.app.put(url('users_group_perm', id=ug.users_group_id),
+                                    {})
+
+        response.follow()
+        ug = UsersGroup.get_by_group_name(users_group_name)
+        p = Permission.get_by_key('hg.create.none')
+        p2 = Permission.get_by_key('hg.fork.none')
+        # check if user has this perms, they should be here since
+        # defaults are on
+        perms = UsersGroupToPerm.query()\
+            .filter(UsersGroupToPerm.users_group == ug).all()
+
+        self.assertEqual(
+            [[x.users_group_id, x.permission_id, ] for x in perms],
+            [[ug.users_group_id, p.permission_id],
+             [ug.users_group_id, p2.permission_id]]
+        )
+
+        # DELETE !
+        ug = UsersGroup.get_by_group_name(users_group_name)
+        ugid = ug.users_group_id
+        response = self.app.delete(url('users_group', id=ug.users_group_id))
+        response = response.follow()
+        gr = self.Session.query(UsersGroup)\
+                           .filter(UsersGroup.users_group_name ==
+                                   users_group_name).scalar()
+
+        self.assertEqual(gr, None)
+        p = Permission.get_by_key('hg.fork.repository')
+        perms = UsersGroupToPerm.query()\
+            .filter(UsersGroupToPerm.users_group_id == ugid).all()
+        perms = [[x.users_group_id,
+                  x.permission_id, ] for x in perms]
         self.assertEqual(
             perms,
             []
--- a/rhodecode/tests/functional/test_changelog.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_changelog.py	Sun Sep 02 21:19:54 2012 +0200
@@ -10,8 +10,10 @@
 
         response.mustcontain("""<div id="chg_20" class="container tablerow1">""")
         response.mustcontain(
-            """<input class="changeset_range" id="5e204e7583b9" """
-            """name="5e204e7583b9" type="checkbox" value="1" />"""
+            """<input class="changeset_range" """
+            """id="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
+            """name="5e204e7583b9c8e7b93a020bd036564b1e731dae" """
+            """type="checkbox" value="1" />"""
         )
         response.mustcontain(
             """<span class="changeset_id">154:"""
@@ -21,7 +23,7 @@
         response.mustcontain("""Small update at simplevcs app""")
 
         response.mustcontain(
-            """<div id="5e204e7583b9c8e7b93a020bd036564b1e731dae"  """
+            """<div id="changed_total_5e204e7583b9c8e7b93a020bd036564b1e731dae" """
             """style="float:right;" class="changed_total tooltip" """
             """title="Affected number of files, click to show """
             """more details">3</div>"""
@@ -29,22 +31,24 @@
 
         #pagination
         response = self.app.get(url(controller='changelog', action='index',
-                                    repo_name=HG_REPO), {'page':1})
+                                    repo_name=HG_REPO), {'page': 1})
         response = self.app.get(url(controller='changelog', action='index',
-                                    repo_name=HG_REPO), {'page':2})
+                                    repo_name=HG_REPO), {'page': 2})
         response = self.app.get(url(controller='changelog', action='index',
-                                    repo_name=HG_REPO), {'page':3})
+                                    repo_name=HG_REPO), {'page': 3})
         response = self.app.get(url(controller='changelog', action='index',
-                                    repo_name=HG_REPO), {'page':4})
+                                    repo_name=HG_REPO), {'page': 4})
         response = self.app.get(url(controller='changelog', action='index',
-                                    repo_name=HG_REPO), {'page':5})
+                                    repo_name=HG_REPO), {'page': 5})
         response = self.app.get(url(controller='changelog', action='index',
-                                    repo_name=HG_REPO), {'page':6})
+                                    repo_name=HG_REPO), {'page': 6})
 
         # Test response after pagination...
         response.mustcontain(
-            """<input class="changeset_range" id="46ad32a4f974" """
-            """name="46ad32a4f974" type="checkbox" value="1" />"""
+            """<input class="changeset_range" """
+            """id="46ad32a4f974e45472a898c6b0acb600320579b1" """
+            """name="46ad32a4f974e45472a898c6b0acb600320579b1" """
+            """type="checkbox" value="1" />"""
         )
         response.mustcontain(
             """<span class="changeset_id">64:"""
@@ -52,7 +56,7 @@
         )
 
         response.mustcontain(
-            """<div id="46ad32a4f974e45472a898c6b0acb600320579b1"  """
+            """<div id="changed_total_46ad32a4f974e45472a898c6b0acb600320579b1" """
             """style="float:right;" class="changed_total tooltip" """
             """title="Affected number of files, click to show """
             """more details">21</div>"""
--- a/rhodecode/tests/functional/test_changeset_comments.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_changeset_comments.py	Sun Sep 02 21:19:54 2012 +0200
@@ -40,8 +40,8 @@
                                 repo_name=HG_REPO, revision=rev))
         # test DB
         self.assertEqual(ChangesetComment.query().count(), 1)
-        self.assertTrue('''<div class="comments-number">%s '''
-                        '''comment(s) (0 inline)</div>''' % 1 in response.body)
+        response.mustcontain('''<div class="comments-number">%s comment '''
+                             '''(0 inline)</div>''' % 1)
 
         self.assertEqual(Notification.query().count(), 1)
         self.assertEqual(ChangesetComment.query().count(), 1)
@@ -76,7 +76,7 @@
         #test DB
         self.assertEqual(ChangesetComment.query().count(), 1)
         response.mustcontain(
-            '''<div class="comments-number">0 comment(s)'''
+            '''<div class="comments-number">0 comments'''
             ''' (%s inline)</div>''' % 1
         )
         response.mustcontain(
@@ -115,8 +115,8 @@
                                 repo_name=HG_REPO, revision=rev))
         # test DB
         self.assertEqual(ChangesetComment.query().count(), 1)
-        self.assertTrue('''<div class="comments-number">%s '''
-                        '''comment(s) (0 inline)</div>''' % 1 in response.body)
+        response.mustcontain('''<div class="comments-number">%s '''
+                             '''comment (0 inline)</div>''' % 1)
 
         self.assertEqual(Notification.query().count(), 2)
         users = [x.user.username for x in UserNotification.query().all()]
@@ -148,5 +148,5 @@
 
         response = self.app.get(url(controller='changeset', action='index',
                                 repo_name=HG_REPO, revision=rev))
-        self.assertTrue('''<div class="comments-number">0 comment(s)'''
-                        ''' (0 inline)</div>''' in response.body)
+        response.mustcontain('''<div class="comments-number">0 comments'''
+                             ''' (0 inline)</div>''')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_compare.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,189 @@
+from rhodecode.tests import *
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.meta import Session
+from rhodecode.model.db import Repository
+from rhodecode.model.scm import ScmModel
+from rhodecode.lib.vcs.backends.base import EmptyChangeset
+
+
+class TestCompareController(TestController):
+
+    def test_index_tag(self):
+        self.log_user()
+        tag1 = '0.1.3'
+        tag2 = '0.1.2'
+        response = self.app.get(url(controller='compare', action='index',
+                                    repo_name=HG_REPO,
+                                    org_ref_type="tag",
+                                    org_ref=tag1,
+                                    other_ref_type="tag",
+                                    other_ref=tag2,
+                                    ))
+        response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, tag1, HG_REPO, tag2))
+        ## outgoing changesets between tags
+        response.mustcontain('''<a href="/%s/changeset/17544fbfcd33ffb439e2b728b5d526b1ef30bfcf">r120:17544fbfcd33</a>''' % HG_REPO)
+        response.mustcontain('''<a href="/%s/changeset/36e0fc9d2808c5022a24f49d6658330383ed8666">r119:36e0fc9d2808</a>''' % HG_REPO)
+        response.mustcontain('''<a href="/%s/changeset/bb1a3ab98cc45cb934a77dcabf87a5a598b59e97">r118:bb1a3ab98cc4</a>''' % HG_REPO)
+        response.mustcontain('''<a href="/%s/changeset/41fda979f02fda216374bf8edac4e83f69e7581c">r117:41fda979f02f</a>''' % HG_REPO)
+        response.mustcontain('''<a href="/%s/changeset/9749bfbfc0d2eba208d7947de266303b67c87cda">r116:9749bfbfc0d2</a>''' % HG_REPO)
+        response.mustcontain('''<a href="/%s/changeset/70d4cef8a37657ee4cf5aabb3bd9f68879769816">r115:70d4cef8a376</a>''' % HG_REPO)
+        response.mustcontain('''<a href="/%s/changeset/c5ddebc06eaaba3010c2d66ea6ec9d074eb0f678">r112:c5ddebc06eaa</a>''' % HG_REPO)
+
+        ## files diff
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--1c5cf9e91c12">docs/api/utils/index.rst</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--e3305437df55">test_and_report.sh</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--c8e92ef85cd1">.hgignore</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--6e08b694d687">.hgtags</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2c14b00f3393">docs/api/index.rst</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--430ccbc82bdf">vcs/__init__.py</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--9c390eb52cd6">vcs/backends/hg.py</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--ebb592c595c0">vcs/utils/__init__.py</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--7abc741b5052">vcs/utils/annotate.py</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2ef0ef106c56">vcs/utils/diffs.py</a></div>''' % (HG_REPO, tag1,  tag2))
+        response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--3150cb87d4b7">vcs/utils/lazy.py</a></div>''' % (HG_REPO, tag1,  tag2))
+
+    def test_index_branch(self):
+        self.log_user()
+        response = self.app.get(url(controller='compare', action='index',
+                                    repo_name=HG_REPO,
+                                    org_ref_type="branch",
+                                    org_ref='default',
+                                    other_ref_type="branch",
+                                    other_ref='default',
+                                    ))
+
+        response.mustcontain('%s@default -> %s@default' % (HG_REPO, HG_REPO))
+        # branch are equal
+        response.mustcontain('<tr><td>No changesets</td></tr>')
+
+    def test_compare_revisions(self):
+        self.log_user()
+        rev1 = '3d8f361e72ab'
+        rev2 = 'b986218ba1c9'
+        response = self.app.get(url(controller='compare', action='index',
+                                    repo_name=HG_REPO,
+                                    org_ref_type="rev",
+                                    org_ref=rev1,
+                                    other_ref_type="rev",
+                                    other_ref=rev2,
+                                    ))
+        response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_REPO, rev2))
+        ## outgoing changesets between those revisions
+        response.mustcontain("""<a href="/%s/changeset/3d8f361e72ab303da48d799ff1ac40d5ac37c67e">r1:%s</a>""" % (HG_REPO, rev1))
+
+        ## files
+        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--c8e92ef85cd1">.hgignore</a>""" % (HG_REPO, rev1, rev2))
+
+    def test_compare_remote_repos(self):
+        self.log_user()
+
+        form_data = dict(
+            repo_name=HG_FORK,
+            repo_name_full=HG_FORK,
+            repo_group=None,
+            repo_type='hg',
+            description='',
+            private=False,
+            copy_permissions=False,
+            landing_rev='tip',
+            update_after_clone=False,
+            fork_parent_id=Repository.get_by_repo_name(HG_REPO),
+        )
+        RepoModel().create_fork(form_data, cur_user=TEST_USER_ADMIN_LOGIN)
+
+        Session().commit()
+
+        rev1 = '7d4bc8ec6be5'
+        rev2 = '56349e29c2af'
+
+        response = self.app.get(url(controller='compare', action='index',
+                                    repo_name=HG_REPO,
+                                    org_ref_type="rev",
+                                    org_ref=rev1,
+                                    other_ref_type="rev",
+                                    other_ref=rev2,
+                                    repo=HG_FORK
+                                    ))
+
+        try:
+            response.mustcontain('%s@%s -> %s@%s' % (HG_REPO, rev1, HG_FORK, rev2))
+            ## outgoing changesets between those revisions
+
+            response.mustcontain("""<a href="/%s/changeset/7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7">r6:%s</a>""" % (HG_REPO, rev1))
+            response.mustcontain("""<a href="/%s/changeset/6fff84722075f1607a30f436523403845f84cd9e">r5:6fff84722075</a>""" % (HG_REPO))
+            response.mustcontain("""<a href="/%s/changeset/2dda4e345facb0ccff1a191052dd1606dba6781d">r4:2dda4e345fac</a>""" % (HG_REPO))
+
+            ## files
+            response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2))
+            response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2))
+            response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2))
+        finally:
+            RepoModel().delete(HG_FORK)
+
+    def test_compare_extra_commits(self):
+        self.log_user()
+
+        repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
+                                        description='diff-test',
+                                        owner=TEST_USER_ADMIN_LOGIN)
+
+        repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
+                                        description='diff-test',
+                                        owner=TEST_USER_ADMIN_LOGIN)
+
+        Session().commit()
+        r1_id = repo1.repo_id
+        r1_name = repo1.repo_name
+        r2_id = repo2.repo_id
+        r2_name = repo2.repo_name
+
+        #commit something !
+        cs0 = ScmModel().create_node(
+            repo=repo1.scm_instance, repo_name=r1_name,
+            cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
+            author=TEST_USER_ADMIN_LOGIN,
+            message='commit1',
+            content='line1',
+            f_path='file1'
+        )
+
+        cs0_prim = ScmModel().create_node(
+            repo=repo2.scm_instance, repo_name=r2_name,
+            cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
+            author=TEST_USER_ADMIN_LOGIN,
+            message='commit1',
+            content='line1',
+            f_path='file1'
+        )
+
+        cs1 = ScmModel().commit_change(
+            repo=repo2.scm_instance, repo_name=r2_name,
+            cs=cs0_prim, user=TEST_USER_ADMIN_LOGIN, author=TEST_USER_ADMIN_LOGIN,
+            message='commit2',
+            content='line1\nline2',
+            f_path='file1'
+        )
+
+        rev1 = 'default'
+        rev2 = 'default'
+        response = self.app.get(url(controller='compare', action='index',
+                                    repo_name=r2_name,
+                                    org_ref_type="branch",
+                                    org_ref=rev1,
+                                    other_ref_type="branch",
+                                    other_ref=rev2,
+                                    repo=r1_name
+                                    ))
+
+        try:
+            response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
+
+            response.mustcontain("""<div class="message">commit2</div>""")
+            response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (r2_name, cs1.raw_id, cs1.short_id))
+            ## files
+            response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s#C--826e8142e6ba">file1</a>""" % (r2_name, rev1, rev2))
+
+
+        finally:
+            RepoModel().delete(r1_id)
+            RepoModel().delete(r2_id)
--- a/rhodecode/tests/functional/test_files.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_files.py	Sun Sep 02 21:19:54 2012 +0200
@@ -186,6 +186,14 @@
 
         response.mustcontain("""<span style="text-transform: uppercase;"><a href="#">branch: default</a></span>""")
 
+    def test_file_annotation_git(self):
+        self.log_user()
+        response = self.app.get(url(controller='files', action='index',
+                                    repo_name=GIT_REPO,
+                                    revision='master',
+                                    f_path='vcs/nodes.py',
+                                    annotate=True))
+
     def test_archival(self):
         self.log_user()
 
@@ -200,9 +208,10 @@
 
             self.assertEqual(response.status, '200 OK')
             heads = [
-            ('Content-Type', 'text/html; charset=utf-8'),
-            ('Content-Length', '0'), ('Pragma', 'no-cache'),
-            ('Cache-Control', 'no-cache')
+                ('Pragma', 'no-cache'),
+                ('Cache-Control', 'no-cache'),
+                ('Content-Disposition', 'attachment; filename=%s' % filename),
+                ('Content-Type', '%s; charset=utf-8' % info[0]),
             ]
             self.assertEqual(response.response._headers.items(), heads)
 
@@ -212,7 +221,8 @@
         for arch_ext in ['tar', 'rar', 'x', '..ax', '.zipz']:
             fname = '27cd5cce30c96924232dffcd24178a07ffeb5dfc%s' % arch_ext
 
-            response = self.app.get(url(controller='files', action='archivefile',
+            response = self.app.get(url(controller='files',
+                                        action='archivefile',
                                         repo_name=HG_REPO,
                                         fname=fname))
             response.mustcontain('Unknown archive type')
@@ -220,10 +230,11 @@
     def test_archival_wrong_revision(self):
         self.log_user()
 
-        for rev in ['00x000000', 'tar', 'wrong', '@##$@$424213232', '232dffcd']:
+        for rev in ['00x000000', 'tar', 'wrong', '@##$@$42413232', '232dffcd']:
             fname = '%s.zip' % rev
 
-            response = self.app.get(url(controller='files', action='archivefile',
+            response = self.app.get(url(controller='files',
+                                        action='archivefile',
                                         repo_name=HG_REPO,
                                         fname=fname))
             response.mustcontain('Unknown revision')
--- a/rhodecode/tests/functional/test_forks.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_forks.py	Sun Sep 02 21:19:54 2012 +0200
@@ -3,6 +3,7 @@
 from rhodecode.model.db import Repository
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.user import UserModel
+from rhodecode.model.meta import Session
 
 
 class TestForksController(TestController):
@@ -12,13 +13,13 @@
         self.password = u'qweqwe'
         self.u1 = UserModel().create_or_update(
             username=self.username, password=self.password,
-            email=u'fork_king@rhodecode.org', name=u'u1', lastname=u'u1'
+            email=u'fork_king@rhodecode.org', firstname=u'u1', lastname=u'u1'
         )
-        self.Session.commit()
+        Session().commit()
 
     def tearDown(self):
-        self.Session.delete(self.u1)
-        self.Session.commit()
+        Session().delete(self.u1)
+        Session().commit()
 
     def test_index(self):
         self.log_user()
@@ -28,7 +29,21 @@
 
         self.assertTrue("""There are no forks yet""" in response.body)
 
-    def test_index_with_fork(self):
+    def test_no_permissions_to_fork(self):
+        usr = self.log_user(TEST_USER_REGULAR_LOGIN,
+                            TEST_USER_REGULAR_PASS)['user_id']
+        user_model = UserModel()
+        user_model.revoke_perm(usr, 'hg.fork.repository')
+        user_model.grant_perm(usr, 'hg.fork.none')
+        u = UserModel().get(usr)
+        u.inherit_default_permissions = False
+        Session().commit()
+        # try create a fork
+        repo_name = HG_REPO
+        self.app.post(url(controller='forks', action='fork_create',
+                          repo_name=repo_name), {}, status=403)
+
+    def test_index_with_fork_hg(self):
         self.log_user()
 
         # create a fork
@@ -39,19 +54,49 @@
         response = self.app.post(url(controller='forks',
                                      action='fork_create',
                                     repo_name=repo_name),
-                                    {'repo_name':fork_name,
-                                     'repo_group':'',
-                                     'fork_parent_id':org_repo.repo_id,
-                                     'repo_type':'hg',
-                                     'description':description,
-                                     'private':'False'})
+                                    {'repo_name': fork_name,
+                                     'repo_group': '',
+                                     'fork_parent_id': org_repo.repo_id,
+                                     'repo_type': 'hg',
+                                     'description': description,
+                                     'private': 'False',
+                                     'landing_rev': 'tip'})
 
         response = self.app.get(url(controller='forks', action='forks',
                                     repo_name=repo_name))
 
-        self.assertTrue("""<a href="/%s/summary">"""
-                         """vcs_test_hg_fork</a>""" % fork_name
-                         in response.body)
+        response.mustcontain(
+            """<a href="/%s/summary">%s</a>""" % (fork_name, fork_name)
+        )
+
+        #remove this fork
+        response = self.app.delete(url('repo', repo_name=fork_name))
+
+    def test_index_with_fork_git(self):
+        self.log_user()
+
+        # create a fork
+        fork_name = GIT_FORK
+        description = 'fork of vcs test'
+        repo_name = GIT_REPO
+        org_repo = Repository.get_by_repo_name(repo_name)
+        response = self.app.post(url(controller='forks',
+                                     action='fork_create',
+                                    repo_name=repo_name),
+                                    {'repo_name': fork_name,
+                                     'repo_group': '',
+                                     'fork_parent_id': org_repo.repo_id,
+                                     'repo_type': 'git',
+                                     'description': description,
+                                     'private': 'False',
+                                     'landing_rev': 'tip'})
+
+        response = self.app.get(url(controller='forks', action='forks',
+                                    repo_name=repo_name))
+
+        response.mustcontain(
+            """<a href="/%s/summary">%s</a>""" % (fork_name, fork_name)
+        )
 
         #remove this fork
         response = self.app.delete(url('repo', repo_name=fork_name))
@@ -69,14 +114,15 @@
                                      'fork_parent_id':org_repo.repo_id,
                                      'repo_type':'hg',
                                      'description':description,
-                                     'private':'False'})
+                                     'private':'False',
+                                     'landing_rev': 'tip'})
 
         #test if we have a message that fork is ok
-        self.assertTrue('forked %s repository as %s' \
-                      % (repo_name, fork_name) in response.session['flash'][0])
+        self.checkSessionFlash(response,
+                'forked %s repository as %s' % (repo_name, fork_name))
 
         #test if the fork was created in the database
-        fork_repo = self.Session.query(Repository)\
+        fork_repo = Session().query(Repository)\
             .filter(Repository.repo_name == fork_name).one()
 
         self.assertEqual(fork_repo.repo_name, fork_name)
@@ -85,10 +131,6 @@
         #test if fork is visible in the list ?
         response = response.follow()
 
-        # check if fork is marked as fork
-        # wait for cache to expire
-        import time
-        time.sleep(10)
         response = self.app.get(url(controller='summary', action='index',
                                     repo_name=fork_name))
 
@@ -98,7 +140,7 @@
         usr = self.log_user(self.username, self.password)['user_id']
         repo_name = HG_REPO
 
-        forks = self.Session.query(Repository)\
+        forks = Session().query(Repository)\
             .filter(Repository.fork_id != None)\
             .all()
         self.assertEqual(1, len(forks))
@@ -107,7 +149,7 @@
         RepoModel().grant_user_permission(repo=forks[0],
                                           user=usr,
                                           perm='repository.read')
-        self.Session.commit()
+        Session().commit()
 
         response = self.app.get(url(controller='forks', action='forks',
                                     repo_name=repo_name))
@@ -118,7 +160,7 @@
         usr = self.log_user(self.username, self.password)['user_id']
         repo_name = HG_REPO
 
-        forks = self.Session.query(Repository)\
+        forks = Session().query(Repository)\
             .filter(Repository.fork_id != None)\
             .all()
         self.assertEqual(1, len(forks))
@@ -126,7 +168,7 @@
         # set none
         RepoModel().grant_user_permission(repo=forks[0],
                                           user=usr, perm='repository.none')
-        self.Session.commit()
+        Session().commit()
         # fork shouldn't be there
         response = self.app.get(url(controller='forks', action='forks',
                                     repo_name=repo_name))
--- a/rhodecode/tests/functional/test_home.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_home.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,4 +1,7 @@
+import time
 from rhodecode.tests import *
+from rhodecode.model.meta import Session
+from rhodecode.model.db import User
 
 
 class TestHomeController(TestController):
@@ -18,5 +21,41 @@
                         """open.png"/>""")
 
         response.mustcontain(
-"""<a title="Marcin Kuzminski &lt;marcin@python-works.com&gt;:\n
-merge" class="tooltip" href="/vcs_test_hg/changeset/27cd5cce30c96924232dffcd24178a07ffeb5dfc">r173:27cd5cce30c9</a>""")
+"""<a title="Marcin Kuzminski &amp;lt;marcin@python-works.com&amp;gt;:\n
+merge" class="tooltip" href="/vcs_test_hg/changeset/27cd5cce30c96924232"""
+"""dffcd24178a07ffeb5dfc">r173:27cd5cce30c9</a>"""
+)
+
+    def test_repo_summary_with_anonymous_access_disabled(self):
+        anon = User.get_by_username('default')
+        anon.active = False
+        Session().add(anon)
+        Session().commit()
+        time.sleep(1.5)  # must sleep for cache (1s to expire)
+        try:
+            response = self.app.get(url(controller='summary',
+                                        action='index', repo_name=HG_REPO),
+                                        status=302)
+            assert 'login' in response.location
+
+        finally:
+            anon = User.get_by_username('default')
+            anon.active = True
+            Session().add(anon)
+            Session().commit()
+
+    def test_index_with_anonymous_access_disabled(self):
+        anon = User.get_by_username('default')
+        anon.active = False
+        Session().add(anon)
+        Session().commit()
+        time.sleep(1.5)  # must sleep for cache (1s to expire)
+        try:
+            response = self.app.get(url(controller='home', action='index'),
+                                    status=302)
+            assert 'login' in response.location
+        finally:
+            anon = User.get_by_username('default')
+            anon.active = True
+            Session().add(anon)
+            Session().commit()
--- a/rhodecode/tests/functional/test_login.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_login.py	Sun Sep 02 21:19:54 2012 +0200
@@ -3,16 +3,17 @@
 from rhodecode.model.db import User, Notification
 from rhodecode.lib.utils2 import generate_api_key
 from rhodecode.lib.auth import check_password
-from rhodecode.model.meta import Session
+from rhodecode.lib import helpers as h
+from rhodecode.model import validators
 
 
 class TestLoginController(TestController):
 
     def tearDown(self):
         for n in Notification.query().all():
-            Session.delete(n)
+            self.Session().delete(n)
 
-        Session.commit()
+        self.Session().commit()
         self.assertEqual(Notification.query().all(), [])
 
     def test_index(self):
@@ -22,21 +23,21 @@
 
     def test_login_admin_ok(self):
         response = self.app.post(url(controller='login', action='index'),
-                                 {'username':'test_admin',
-                                  'password':'test12'})
+                                 {'username': 'test_admin',
+                                  'password': 'test12'})
         self.assertEqual(response.status, '302 Found')
-        self.assertEqual(response.session['rhodecode_user'].get('username') ,
+        self.assertEqual(response.session['rhodecode_user'].get('username'),
                          'test_admin')
         response = response.follow()
         self.assertTrue('%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',
-                                  'password':'test12'})
+                                 {'username': 'test_regular',
+                                  'password': 'test12'})
 
         self.assertEqual(response.status, '302 Found')
-        self.assertEqual(response.session['rhodecode_user'].get('username') ,
+        self.assertEqual(response.session['rhodecode_user'].get('username'),
                          'test_regular')
         response = response.follow()
         self.assertTrue('%s repository' % HG_REPO in response.body)
@@ -46,27 +47,45 @@
         test_came_from = '/_admin/users'
         response = self.app.post(url(controller='login', action='index',
                                      came_from=test_came_from),
-                                 {'username':'test_admin',
-                                  'password':'test12'})
+                                 {'username': 'test_admin',
+                                  'password': 'test12'})
         self.assertEqual(response.status, '302 Found')
         response = response.follow()
 
         self.assertEqual(response.status, '200 OK')
         self.assertTrue('Users administration' in response.body)
 
+    @parameterized.expand([
+          ('data:text/html,<script>window.alert("xss")</script>',),
+          ('mailto:test@rhodecode.org',),
+          ('file:///etc/passwd',),
+          ('ftp://some.ftp.server',),
+          ('http://other.domain',),
+    ])
+    def test_login_bad_came_froms(self, url_came_from):
+        response = self.app.post(url(controller='login', action='index',
+                                     came_from=url_came_from),
+                                 {'username': 'test_admin',
+                                  'password': 'test12'})
+        self.assertEqual(response.status, '302 Found')
+        self.assertEqual(response._environ['paste.testing_variables']
+                         ['tmpl_context'].came_from, '/')
+        response = response.follow()
+
+        self.assertEqual(response.status, '200 OK')
+
     def test_login_short_password(self):
         response = self.app.post(url(controller='login', action='index'),
-                                 {'username':'test_admin',
-                                  'password':'as'})
+                                 {'username': 'test_admin',
+                                  'password': 'as'})
         self.assertEqual(response.status, '200 OK')
 
         self.assertTrue('Enter 3 characters or more' in response.body)
 
     def test_login_wrong_username_password(self):
         response = self.app.post(url(controller='login', action='index'),
-                                 {'username':'error',
-                                  'password':'test12'})
-        self.assertEqual(response.status , '200 OK')
+                                 {'username': 'error',
+                                  'password': 'test12'})
 
         self.assertTrue('invalid user name' in response.body)
         self.assertTrue('invalid password' in response.body)
@@ -79,62 +98,63 @@
         self.assertTrue('Sign Up to RhodeCode' in response.body)
 
     def test_register_err_same_username(self):
+        uname = 'test_admin'
         response = self.app.post(url(controller='login', action='register'),
-                                            {'username':'test_admin',
-                                             'password':'test12',
-                                             'password_confirmation':'test12',
-                                             'email':'goodmail@domain.com',
-                                             'name':'test',
-                                             'lastname':'test'})
+                                            {'username': uname,
+                                             'password': 'test12',
+                                             'password_confirmation': 'test12',
+                                             'email': 'goodmail@domain.com',
+                                             'firstname': 'test',
+                                             'lastname': 'test'})
 
-        self.assertEqual(response.status , '200 OK')
-        self.assertTrue('This username already exists' in response.body)
+        msg = validators.ValidUsername()._messages['username_exists']
+        msg = h.html_escape(msg % {'username': uname})
+        response.mustcontain(msg)
 
     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'})
+                                            {'username': 'test_admin_0',
+                                             'password': 'test12',
+                                             'password_confirmation': 'test12',
+                                             'email': 'test_admin@mail.com',
+                                             'firstname': 'test',
+                                             'lastname': 'test'})
 
-        self.assertEqual(response.status , '200 OK')
-        response.mustcontain('This e-mail address is already taken')
+        msg = validators.UniqSystemEmail()()._messages['email_taken']
+        response.mustcontain(msg)
 
     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'})
-        self.assertEqual(response.status , '200 OK')
-        response.mustcontain('This e-mail address is already taken')
+                                            {'username': 'test_admin_1',
+                                             'password': 'test12',
+                                             'password_confirmation': 'test12',
+                                             'email': 'TesT_Admin@mail.COM',
+                                             'firstname': 'test',
+                                             'lastname': 'test'})
+        msg = validators.UniqSystemEmail()()._messages['email_taken']
+        response.mustcontain(msg)
 
     def test_register_err_wrong_data(self):
         response = self.app.post(url(controller='login', action='register'),
-                                            {'username':'xs',
-                                             'password':'test',
-                                             'password_confirmation':'test',
-                                             'email':'goodmailm',
-                                             'name':'test',
-                                             'lastname':'test'})
-        self.assertEqual(response.status , '200 OK')
+                                            {'username': 'xs',
+                                             'password': 'test',
+                                             'password_confirmation': 'test',
+                                             'email': 'goodmailm',
+                                             'firstname': 'test',
+                                             'lastname': 'test'})
+        self.assertEqual(response.status, '200 OK')
         response.mustcontain('An email address must contain a single @')
         response.mustcontain('Enter a value 6 characters long or more')
 
     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'})
+                                            {'username': 'error user',
+                                             'password': 'test12',
+                                             'password_confirmation': 'test12',
+                                             'email': 'goodmailm',
+                                             'firstname': 'test',
+                                             'lastname': 'test'})
 
-        self.assertEqual(response.status , '200 OK')
         response.mustcontain('An email address must contain a single @')
         response.mustcontain('Username may only contain '
                 'alphanumeric characters underscores, '
@@ -142,41 +162,42 @@
                 'alphanumeric character')
 
     def test_register_err_case_sensitive(self):
+        usr = 'Test_Admin'
         response = self.app.post(url(controller='login', action='register'),
-                                            {'username':'Test_Admin',
-                                             'password':'test12',
-                                             'password_confirmation':'test12',
-                                             'email':'goodmailm',
-                                             'name':'test',
-                                             'lastname':'test'})
+                                            {'username': usr,
+                                             'password': 'test12',
+                                             'password_confirmation': 'test12',
+                                             'email': 'goodmailm',
+                                             'firstname': 'test',
+                                             'lastname': 'test'})
 
-        self.assertEqual(response.status , '200 OK')
-        self.assertTrue('An email address must contain a single @' in response.body)
-        self.assertTrue('This username already exists' in response.body)
+        response.mustcontain('An email address must contain a single @')
+        msg = validators.ValidUsername()._messages['username_exists']
+        msg = h.html_escape(msg % {'username': usr})
+        response.mustcontain(msg)
 
     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'})
+                                        {'username': 'xxxaxn',
+                                         'password': 'ąćźżąśśśś',
+                                         'password_confirmation': 'ąćźżąśśśś',
+                                         'email': 'goodmailm@test.plx',
+                                         'firstname': 'test',
+                                         'lastname': 'test'})
 
-        self.assertEqual(response.status , '200 OK')
-        self.assertTrue('Invalid characters in password' in response.body)
+        msg = validators.ValidPassword()._messages['invalid_password']
+        response.mustcontain(msg)
 
     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'})
-
-        self.assertEqual(response.status, '200 OK')
-        response.mustcontain('Passwords do not match')
+                                            {'username': 'xs',
+                                             'password': '123qwe',
+                                             'password_confirmation': 'qwe123',
+                                             'email': 'goodmailm@test.plxa',
+                                             'firstname': 'test',
+                                             'lastname': 'test'})
+        msg = validators.ValidPasswordsMatch()._messages['password_mismatch']
+        response.mustcontain(msg)
 
     def test_register_ok(self):
         username = 'test_regular4'
@@ -186,17 +207,17 @@
         lastname = 'testlastname'
 
         response = self.app.post(url(controller='login', action='register'),
-                                            {'username':username,
-                                             'password':password,
-                                             'password_confirmation':password,
-                                             'email':email,
-                                             'name':name,
-                                             'lastname':lastname,
-                                             'admin':True}) # This should be overriden
+                                            {'username': username,
+                                             'password': password,
+                                             'password_confirmation': password,
+                                             'email': email,
+                                             'firstname': name,
+                                             'lastname': lastname,
+                                             'admin': True})  # This should be overriden
         self.assertEqual(response.status, '302 Found')
         self.checkSessionFlash(response, 'You have successfully registered into rhodecode')
 
-        ret = self.Session.query(User).filter(User.username == 'test_regular4').one()
+        ret = self.Session().query(User).filter(User.username == 'test_regular4').one()
         self.assertEqual(ret.username, username)
         self.assertEqual(check_password(password, ret.password), True)
         self.assertEqual(ret.email, email)
@@ -206,12 +227,15 @@
         self.assertEqual(ret.admin, False)
 
     def test_forgot_password_wrong_mail(self):
+        bad_email = 'marcin@wrongmail.org'
         response = self.app.post(
                         url(controller='login', action='password_reset'),
-                            {'email': 'marcin@wrongmail.org',}
+                            {'email': bad_email, }
         )
 
-        response.mustcontain("This e-mail address doesn't exist")
+        msg = validators.ValidSystemEmail()._messages['non_existing_email']
+        msg = h.html_escape(msg % {'email': bad_email})
+        response.mustcontain()
 
     def test_forgot_password(self):
         response = self.app.get(url(controller='login',
@@ -231,12 +255,12 @@
         new.name = name
         new.lastname = lastname
         new.api_key = generate_api_key(username)
-        self.Session.add(new)
-        self.Session.commit()
+        self.Session().add(new)
+        self.Session().commit()
 
         response = self.app.post(url(controller='login',
                                      action='password_reset'),
-                                 {'email':email, })
+                                 {'email': email, })
 
         self.checkSessionFlash(response, 'Your password reset link was sent')
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/functional/test_pullrequests.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,9 @@
+from rhodecode.tests import *
+
+
+class TestPullrequestsController(TestController):
+
+    def test_index(self):
+        self.log_user()
+        response = self.app.get(url(controller='pullrequests', action='index',
+                                    repo_name=HG_REPO))
--- a/rhodecode/tests/functional/test_search.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_search.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,7 +1,8 @@
+import os
 from rhodecode.tests import *
-import os
 from nose.plugins.skip import SkipTest
 
+
 class TestSearchController(TestController):
 
     def test_index(self):
@@ -18,20 +19,96 @@
         else:
             self.log_user()
             response = self.app.get(url(controller='search', action='index'),
-                                    {'q':HG_REPO})
+                                    {'q': HG_REPO})
             self.assertTrue('There is no index to search in. '
                             'Please run whoosh indexer' in response.body)
 
     def test_normal_search(self):
         self.log_user()
         response = self.app.get(url(controller='search', action='index'),
-                                {'q':'def repo'})
-        self.assertTrue('10 results' in response.body)
-        self.assertTrue('Permission denied' not in response.body)
+                                {'q': 'def repo'})
+        response.mustcontain('39 results')
 
     def test_repo_search(self):
         self.log_user()
         response = self.app.get(url(controller='search', action='index'),
-                                {'q':'repository:%s def test' % HG_REPO})
-        self.assertTrue('4 results' in response.body)
-        self.assertTrue('Permission denied' not in response.body)
+                                {'q': 'repository:%s def test' % HG_REPO})
+
+        response.mustcontain('4 results')
+
+    def test_search_last(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index'),
+                                {'q': 'last:t', 'type': 'commit'})
+
+        response.mustcontain('2 results')
+
+    def test_search_commit_message(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index'),
+                    {'q': 'bother to ask where to fetch repo during tests',
+                     'type': 'commit'})
+
+        response.mustcontain('2 results')
+        response.mustcontain('a00c1b6f5d7a6ae678fd553a8b81d92367f7ecf1')
+        response.mustcontain('c6eb379775c578a95dad8ddab53f963b80894850')
+
+    def test_search_commit_message_hg_repo(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index',
+                                    search_repo=HG_REPO),
+                    {'q': 'bother to ask where to fetch repo during tests',
+                     'type': 'commit'})
+
+        response.mustcontain('1 results')
+        response.mustcontain('a00c1b6f5d7a6ae678fd553a8b81d92367f7ecf1')
+
+    def test_search_commit_changed_file(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index'),
+                                {'q': 'changed:tests/utils.py',
+                                 'type': 'commit'})
+
+        response.mustcontain('20 results')
+
+    def test_search_commit_changed_files_get_commit(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index'),
+                                {'q': 'changed:vcs/utils/lazy.py',
+                                 'type': 'commit'})
+
+        response.mustcontain('7 results')
+        response.mustcontain('36e0fc9d2808c5022a24f49d6658330383ed8666')
+        response.mustcontain('af182745859d779f17336241a0815d15166ae1ee')
+        response.mustcontain('17438a11f72b93f56d0e08e7d1fa79a378578a82')
+        response.mustcontain('33fa3223355104431402a888fa77a4e9956feb3e')
+        response.mustcontain('d1f898326327e20524fe22417c22d71064fe54a1')
+        response.mustcontain('fe568b4081755c12abf6ba673ba777fc02a415f3')
+        response.mustcontain('bafe786f0d8c2ff7da5c1dcfcfa577de0b5e92f1')
+
+    def test_search_commit_added_file(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index'),
+                                {'q': 'added:README.rst',
+                                 'type': 'commit'})
+
+        response.mustcontain('2 results')
+        #HG
+        response.mustcontain('3803844fdbd3b711175fc3da9bdacfcd6d29a6fb')
+        #GIT
+        response.mustcontain('ff7ca51e58c505fec0dd2491de52c622bb7a806b')
+
+    def test_search_author(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index'),
+                    {'q': 'author:marcin@python-blog.com raw_id:b986218ba1c9b0d6a259fac9b050b1724ed8e545',
+                     'type': 'commit'})
+
+        response.mustcontain('1 results')
+
+    def test_search_file_name(self):
+        self.log_user()
+        response = self.app.get(url(controller='search', action='index'),
+                    {'q': 'README.rst', 'type': 'path'})
+
+        response.mustcontain('2 results')
--- a/rhodecode/tests/functional/test_summary.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/functional/test_summary.py	Sun Sep 02 21:19:54 2012 +0200
@@ -15,8 +15,8 @@
         #repo type
         response.mustcontain(
             """<img style="margin-bottom:2px" class="icon" """
-            """title="Mercurial repository" alt="Mercurial """
-            """repository" src="/images/icons/hgicon.png"/>"""
+            """title="Mercurial repository" alt="Mercurial repository" """
+            """src="/images/icons/hgicon.png"/>"""
         )
         response.mustcontain(
             """<img style="margin-bottom:2px" class="icon" """
@@ -41,10 +41,33 @@
         )
 
         # clone url...
-        response.mustcontain("""<input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="http://test_admin@localhost:80/vcs_test_hg"/>""")
-        response.mustcontain("""<input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="http://test_admin@localhost:80/_1"/>""")
+        response.mustcontain("""<input style="width:80%%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="http://test_admin@localhost:80/%s"/>""" % HG_REPO)
+        response.mustcontain("""<input style="display:none;width:80%%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="http://test_admin@localhost:80/_%s"/>""" % ID)
+
+    def test_index_git(self):
+        self.log_user()
+        ID = Repository.get_by_repo_name(GIT_REPO).repo_id
+        response = self.app.get(url(controller='summary',
+                                    action='index',
+                                    repo_name=GIT_REPO))
 
-    def test_index_by_id(self):
+        #repo type
+        response.mustcontain(
+            """<img style="margin-bottom:2px" class="icon" """
+            """title="Git repository" alt="Git repository" """
+            """src="/images/icons/giticon.png"/>"""
+        )
+        response.mustcontain(
+            """<img style="margin-bottom:2px" class="icon" """
+            """title="public repository" alt="public """
+            """repository" src="/images/icons/lock_open.png"/>"""
+        )
+
+        # clone url...
+        response.mustcontain("""<input style="width:80%%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="http://test_admin@localhost:80/%s"/>""" % GIT_REPO)
+        response.mustcontain("""<input style="display:none;width:80%%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="http://test_admin@localhost:80/_%s"/>""" % ID)
+
+    def test_index_by_id_hg(self):
         self.log_user()
         ID = Repository.get_by_repo_name(HG_REPO).repo_id
         response = self.app.get(url(controller='summary',
@@ -59,6 +82,21 @@
                         """title="public repository" alt="public """
                         """repository" src="/images/icons/lock_open.png"/>""")
 
+    def test_index_by_id_git(self):
+        self.log_user()
+        ID = Repository.get_by_repo_name(GIT_REPO).repo_id
+        response = self.app.get(url(controller='summary',
+                                    action='index',
+                                    repo_name='_%s' % ID))
+
+        #repo type
+        response.mustcontain("""<img style="margin-bottom:2px" class="icon" """
+                        """title="Git repository" alt="Git """
+                        """repository" src="/images/icons/giticon.png"/>""")
+        response.mustcontain("""<img style="margin-bottom:2px" class="icon" """
+                        """title="public repository" alt="public """
+                        """repository" src="/images/icons/lock_open.png"/>""")
+
     def _enable_stats(self):
         r = Repository.get_by_repo_name(HG_REPO)
         r.enable_statistics = True
--- a/rhodecode/tests/mem_watch	Sat May 19 14:54:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-ps -eo size,pid,user,command --sort -size | awk '{ hr=$1/1024 ; printf("%13.2f Mb ",hr) } { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }'|grep [p]aster
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/models/test_notifications.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,187 @@
+import os
+import unittest
+from rhodecode.tests import *
+
+from rhodecode.model.db import User, Notification, UserNotification
+from rhodecode.model.user import UserModel
+
+from rhodecode.model.meta import Session
+from rhodecode.model.notification import NotificationModel
+
+
+class TestNotifications(unittest.TestCase):
+
+    def __init__(self, methodName='runTest'):
+        Session.remove()
+        self.u1 = UserModel().create_or_update(username=u'u1',
+                                        password=u'qweqwe',
+                                        email=u'u1@rhodecode.org',
+                                        firstname=u'u1', lastname=u'u1')
+        Session().commit()
+        self.u1 = self.u1.user_id
+
+        self.u2 = UserModel().create_or_update(username=u'u2',
+                                        password=u'qweqwe',
+                                        email=u'u2@rhodecode.org',
+                                        firstname=u'u2', lastname=u'u3')
+        Session().commit()
+        self.u2 = self.u2.user_id
+
+        self.u3 = UserModel().create_or_update(username=u'u3',
+                                        password=u'qweqwe',
+                                        email=u'u3@rhodecode.org',
+                                        firstname=u'u3', lastname=u'u3')
+        Session().commit()
+        self.u3 = self.u3.user_id
+
+        super(TestNotifications, self).__init__(methodName=methodName)
+
+    def _clean_notifications(self):
+        for n in Notification.query().all():
+            Session().delete(n)
+
+        Session().commit()
+        self.assertEqual(Notification.query().all(), [])
+
+    def tearDown(self):
+        self._clean_notifications()
+
+    def test_create_notification(self):
+        self.assertEqual([], Notification.query().all())
+        self.assertEqual([], UserNotification.query().all())
+
+        usrs = [self.u1, self.u2]
+        notification = NotificationModel().create(created_by=self.u1,
+                                           subject=u'subj', body=u'hi there',
+                                           recipients=usrs)
+        Session().commit()
+        u1 = User.get(self.u1)
+        u2 = User.get(self.u2)
+        u3 = User.get(self.u3)
+        notifications = Notification.query().all()
+        self.assertEqual(len(notifications), 1)
+
+        self.assertEqual(notifications[0].recipients, [u1, u2])
+        self.assertEqual(notification.notification_id,
+                         notifications[0].notification_id)
+
+        unotification = UserNotification.query()\
+            .filter(UserNotification.notification == notification).all()
+
+        self.assertEqual(len(unotification), len(usrs))
+        self.assertEqual(set([x.user.user_id for x in unotification]),
+                         set(usrs))
+
+    def test_user_notifications(self):
+        self.assertEqual([], Notification.query().all())
+        self.assertEqual([], UserNotification.query().all())
+
+        notification1 = NotificationModel().create(created_by=self.u1,
+                                            subject=u'subj', body=u'hi there1',
+                                            recipients=[self.u3])
+        Session().commit()
+        notification2 = NotificationModel().create(created_by=self.u1,
+                                            subject=u'subj', body=u'hi there2',
+                                            recipients=[self.u3])
+        Session().commit()
+        u3 = Session().query(User).get(self.u3)
+
+        self.assertEqual(sorted([x.notification for x in u3.notifications]),
+                         sorted([notification2, notification1]))
+
+    def test_delete_notifications(self):
+        self.assertEqual([], Notification.query().all())
+        self.assertEqual([], UserNotification.query().all())
+
+        notification = NotificationModel().create(created_by=self.u1,
+                                           subject=u'title', body=u'hi there3',
+                                    recipients=[self.u3, self.u1, self.u2])
+        Session().commit()
+        notifications = Notification.query().all()
+        self.assertTrue(notification in notifications)
+
+        Notification.delete(notification.notification_id)
+        Session().commit()
+
+        notifications = Notification.query().all()
+        self.assertFalse(notification in notifications)
+
+        un = UserNotification.query().filter(UserNotification.notification
+                                             == notification).all()
+        self.assertEqual(un, [])
+
+    def test_delete_association(self):
+
+        self.assertEqual([], Notification.query().all())
+        self.assertEqual([], UserNotification.query().all())
+
+        notification = NotificationModel().create(created_by=self.u1,
+                                           subject=u'title', body=u'hi there3',
+                                    recipients=[self.u3, self.u1, self.u2])
+        Session().commit()
+
+        unotification = UserNotification.query()\
+                            .filter(UserNotification.notification ==
+                                    notification)\
+                            .filter(UserNotification.user_id == self.u3)\
+                            .scalar()
+
+        self.assertEqual(unotification.user_id, self.u3)
+
+        NotificationModel().delete(self.u3,
+                                   notification.notification_id)
+        Session().commit()
+
+        u3notification = UserNotification.query()\
+                            .filter(UserNotification.notification ==
+                                    notification)\
+                            .filter(UserNotification.user_id == self.u3)\
+                            .scalar()
+
+        self.assertEqual(u3notification, None)
+
+        # notification object is still there
+        self.assertEqual(Notification.query().all(), [notification])
+
+        #u1 and u2 still have assignments
+        u1notification = UserNotification.query()\
+                            .filter(UserNotification.notification ==
+                                    notification)\
+                            .filter(UserNotification.user_id == self.u1)\
+                            .scalar()
+        self.assertNotEqual(u1notification, None)
+        u2notification = UserNotification.query()\
+                            .filter(UserNotification.notification ==
+                                    notification)\
+                            .filter(UserNotification.user_id == self.u2)\
+                            .scalar()
+        self.assertNotEqual(u2notification, None)
+
+    def test_notification_counter(self):
+        self._clean_notifications()
+        self.assertEqual([], Notification.query().all())
+        self.assertEqual([], UserNotification.query().all())
+
+        NotificationModel().create(created_by=self.u1,
+                            subject=u'title', body=u'hi there_delete',
+                            recipients=[self.u3, self.u1])
+        Session().commit()
+
+        self.assertEqual(NotificationModel()
+                         .get_unread_cnt_for_user(self.u1), 1)
+        self.assertEqual(NotificationModel()
+                         .get_unread_cnt_for_user(self.u2), 0)
+        self.assertEqual(NotificationModel()
+                         .get_unread_cnt_for_user(self.u3), 1)
+
+        notification = NotificationModel().create(created_by=self.u1,
+                                           subject=u'title', body=u'hi there3',
+                                    recipients=[self.u3, self.u1, self.u2])
+        Session().commit()
+
+        self.assertEqual(NotificationModel()
+                         .get_unread_cnt_for_user(self.u1), 2)
+        self.assertEqual(NotificationModel()
+                         .get_unread_cnt_for_user(self.u2), 1)
+        self.assertEqual(NotificationModel()
+                         .get_unread_cnt_for_user(self.u3), 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/models/test_permissions.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,438 @@
+import os
+import unittest
+from rhodecode.tests import *
+
+from rhodecode.model.repos_group import ReposGroupModel
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm
+from rhodecode.model.user import UserModel
+
+from rhodecode.model.meta import Session
+from rhodecode.model.users_group import UsersGroupModel
+from rhodecode.lib.auth import AuthUser
+
+
+def _make_group(path, desc='desc', parent_id=None,
+                 skip_if_exists=False):
+
+    gr = RepoGroup.get_by_group_name(path)
+    if gr and skip_if_exists:
+        return gr
+
+    gr = ReposGroupModel().create(path, desc, parent_id)
+    return gr
+
+
+class TestPermissions(unittest.TestCase):
+    def __init__(self, methodName='runTest'):
+        super(TestPermissions, self).__init__(methodName=methodName)
+
+    def setUp(self):
+        self.u1 = UserModel().create_or_update(
+            username=u'u1', password=u'qweqwe',
+            email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1'
+        )
+        self.u2 = UserModel().create_or_update(
+            username=u'u2', password=u'qweqwe',
+            email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2'
+        )
+        self.u3 = UserModel().create_or_update(
+            username=u'u3', password=u'qweqwe',
+            email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3'
+        )
+        self.anon = User.get_by_username('default')
+        self.a1 = UserModel().create_or_update(
+            username=u'a1', password=u'qweqwe',
+            email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True
+        )
+        Session().commit()
+
+    def tearDown(self):
+        if hasattr(self, 'test_repo'):
+            RepoModel().delete(repo=self.test_repo)
+        UserModel().delete(self.u1)
+        UserModel().delete(self.u2)
+        UserModel().delete(self.u3)
+        UserModel().delete(self.a1)
+        if hasattr(self, 'g1'):
+            ReposGroupModel().delete(self.g1.group_id)
+        if hasattr(self, 'g2'):
+            ReposGroupModel().delete(self.g2.group_id)
+
+        if hasattr(self, 'ug1'):
+            UsersGroupModel().delete(self.ug1, force=True)
+
+        Session().commit()
+
+    def test_default_perms_set(self):
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        perms = {
+            'repositories_groups': {},
+            'global': set([u'hg.create.repository', u'repository.read',
+                           u'hg.register.manual_activate']),
+            'repositories': {u'vcs_test_hg': u'repository.read'}
+        }
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         perms['repositories'][HG_REPO])
+        new_perm = 'repository.write'
+        RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
+                                          perm=new_perm)
+        Session().commit()
+
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         new_perm)
+
+    def test_default_admin_perms_set(self):
+        a1_auth = AuthUser(user_id=self.a1.user_id)
+        perms = {
+            'repositories_groups': {},
+            'global': set([u'hg.admin']),
+            'repositories': {u'vcs_test_hg': u'repository.admin'}
+        }
+        self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
+                         perms['repositories'][HG_REPO])
+        new_perm = 'repository.write'
+        RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1,
+                                          perm=new_perm)
+        Session().commit()
+        # cannot really downgrade admins permissions !? they still get's set as
+        # admin !
+        u1_auth = AuthUser(user_id=self.a1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         perms['repositories'][HG_REPO])
+
+    def test_default_group_perms(self):
+        self.g1 = _make_group('test1', skip_if_exists=True)
+        self.g2 = _make_group('test2', skip_if_exists=True)
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        perms = {
+            'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
+            'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
+            'repositories': {u'vcs_test_hg': u'repository.read'}
+        }
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         perms['repositories'][HG_REPO])
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                         perms['repositories_groups'])
+
+    def test_default_admin_group_perms(self):
+        self.g1 = _make_group('test1', skip_if_exists=True)
+        self.g2 = _make_group('test2', skip_if_exists=True)
+        a1_auth = AuthUser(user_id=self.a1.user_id)
+        perms = {
+            'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
+            'global': set(['hg.admin']),
+            'repositories': {u'vcs_test_hg': 'repository.admin'}
+        }
+
+        self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
+                         perms['repositories'][HG_REPO])
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                         perms['repositories_groups'])
+
+    def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
+        # make group
+        self.ug1 = UsersGroupModel().create('G1')
+        # add user to group
+
+        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+
+        # set permission to lower
+        new_perm = 'repository.none'
+        RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
+        Session().commit()
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         new_perm)
+
+        # grant perm for group this should not override permission from user
+        # since it has explicitly set
+        new_perm_gr = 'repository.write'
+        RepoModel().grant_users_group_permission(repo=HG_REPO,
+                                                 group_name=self.ug1,
+                                                 perm=new_perm_gr)
+        # check perms
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        perms = {
+            'repositories_groups': {},
+            'global': set([u'hg.create.repository', u'repository.read',
+                           u'hg.register.manual_activate']),
+            'repositories': {u'vcs_test_hg': u'repository.read'}
+        }
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         new_perm)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                         perms['repositories_groups'])
+
+    def test_propagated_permission_from_users_group(self):
+        # make group
+        self.ug1 = UsersGroupModel().create('G1')
+        # add user to group
+
+        UsersGroupModel().add_user_to_group(self.ug1, self.u3)
+
+        # grant perm for group this should override default permission from user
+        new_perm_gr = 'repository.write'
+        RepoModel().grant_users_group_permission(repo=HG_REPO,
+                                                 group_name=self.ug1,
+                                                 perm=new_perm_gr)
+        # check perms
+        u3_auth = AuthUser(user_id=self.u3.user_id)
+        perms = {
+            'repositories_groups': {},
+            'global': set([u'hg.create.repository', u'repository.read',
+                           u'hg.register.manual_activate']),
+            'repositories': {u'vcs_test_hg': u'repository.read'}
+        }
+        self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
+                         new_perm_gr)
+        self.assertEqual(u3_auth.permissions['repositories_groups'],
+                         perms['repositories_groups'])
+
+    def test_propagated_permission_from_users_group_lower_weight(self):
+        # make group
+        self.ug1 = UsersGroupModel().create('G1')
+        # add user to group
+        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+
+        # set permission to lower
+        new_perm_h = 'repository.write'
+        RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
+                                          perm=new_perm_h)
+        Session().commit()
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         new_perm_h)
+
+        # grant perm for group this should NOT override permission from user
+        # since it's lower than granted
+        new_perm_l = 'repository.read'
+        RepoModel().grant_users_group_permission(repo=HG_REPO,
+                                                 group_name=self.ug1,
+                                                 perm=new_perm_l)
+        # check perms
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        perms = {
+            'repositories_groups': {},
+            'global': set([u'hg.create.repository', u'repository.read',
+                           u'hg.register.manual_activate']),
+            'repositories': {u'vcs_test_hg': u'repository.write'}
+        }
+        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
+                         new_perm_h)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                         perms['repositories_groups'])
+
+    def test_repo_in_group_permissions(self):
+        self.g1 = _make_group('group1', skip_if_exists=True)
+        self.g2 = _make_group('group2', skip_if_exists=True)
+        Session().commit()
+        # both perms should be read !
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                         {u'group1': u'group.read', u'group2': u'group.read'})
+
+        a1_auth = AuthUser(user_id=self.anon.user_id)
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.read', u'group2': u'group.read'})
+
+        #Change perms to none for both groups
+        ReposGroupModel().grant_user_permission(repos_group=self.g1,
+                                                user=self.anon,
+                                                perm='group.none')
+        ReposGroupModel().grant_user_permission(repos_group=self.g2,
+                                                user=self.anon,
+                                                perm='group.none')
+
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.none', u'group2': u'group.none'})
+
+        a1_auth = AuthUser(user_id=self.anon.user_id)
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.none', u'group2': u'group.none'})
+
+        # add repo to group
+        name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm'])
+        self.test_repo = RepoModel().create_repo(
+            repo_name=name,
+            repo_type='hg',
+            description='',
+            repos_group=self.g1,
+            owner=self.u1,
+        )
+        Session().commit()
+
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.none', u'group2': u'group.none'})
+
+        a1_auth = AuthUser(user_id=self.anon.user_id)
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.none', u'group2': u'group.none'})
+
+        #grant permission for u2 !
+        ReposGroupModel().grant_user_permission(repos_group=self.g1,
+                                                user=self.u2,
+                                                perm='group.read')
+        ReposGroupModel().grant_user_permission(repos_group=self.g2,
+                                                user=self.u2,
+                                                perm='group.read')
+        Session().commit()
+        self.assertNotEqual(self.u1, self.u2)
+        #u1 and anon should have not change perms while u2 should !
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.none', u'group2': u'group.none'})
+
+        u2_auth = AuthUser(user_id=self.u2.user_id)
+        self.assertEqual(u2_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.read', u'group2': u'group.read'})
+
+        a1_auth = AuthUser(user_id=self.anon.user_id)
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                 {u'group1': u'group.none', u'group2': u'group.none'})
+
+    def test_repo_group_user_as_user_group_member(self):
+        # create Group1
+        self.g1 = _make_group('group1', skip_if_exists=True)
+        Session().commit()
+        a1_auth = AuthUser(user_id=self.anon.user_id)
+
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                         {u'group1': u'group.read'})
+
+        # set default permission to none
+        ReposGroupModel().grant_user_permission(repos_group=self.g1,
+                                                user=self.anon,
+                                                perm='group.none')
+        # make group
+        self.ug1 = UsersGroupModel().create('G1')
+        # add user to group
+        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
+        Session().commit()
+
+        # check if user is in the group
+        membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members]
+        self.assertEqual(membrs, [self.u1.user_id])
+        # add some user to that group
+
+        # check his permissions
+        a1_auth = AuthUser(user_id=self.anon.user_id)
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                         {u'group1': u'group.none'})
+
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                         {u'group1': u'group.none'})
+
+        # grant ug1 read permissions for
+        ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
+                                                       group_name=self.ug1,
+                                                       perm='group.read')
+        Session().commit()
+        # check if the
+        obj = Session().query(UsersGroupRepoGroupToPerm)\
+            .filter(UsersGroupRepoGroupToPerm.group == self.g1)\
+            .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\
+            .scalar()
+        self.assertEqual(obj.permission.permission_name, 'group.read')
+
+        a1_auth = AuthUser(user_id=self.anon.user_id)
+
+        self.assertEqual(a1_auth.permissions['repositories_groups'],
+                         {u'group1': u'group.none'})
+
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        self.assertEqual(u1_auth.permissions['repositories_groups'],
+                         {u'group1': u'group.read'})
+
+    def test_inherited_permissions_from_default_on_user_enabled(self):
+        user_model = UserModel()
+        # enable fork and create on default user
+        usr = 'default'
+        user_model.revoke_perm(usr, 'hg.create.none')
+        user_model.grant_perm(usr, 'hg.create.repository')
+        user_model.revoke_perm(usr, 'hg.fork.none')
+        user_model.grant_perm(usr, 'hg.fork.repository')
+        # make sure inherit flag is turned on
+        self.u1.inherit_default_permissions = True
+        Session().commit()
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        # this user will have inherited permissions from default user
+        self.assertEqual(u1_auth.permissions['global'],
+                         set(['hg.create.repository', 'hg.fork.repository',
+                              'hg.register.manual_activate',
+                              'repository.read']))
+
+    def test_inherited_permissions_from_default_on_user_disabled(self):
+        user_model = UserModel()
+        # disable fork and create on default user
+        usr = 'default'
+        user_model.revoke_perm(usr, 'hg.create.repository')
+        user_model.grant_perm(usr, 'hg.create.none')
+        user_model.revoke_perm(usr, 'hg.fork.repository')
+        user_model.grant_perm(usr, 'hg.fork.none')
+        # make sure inherit flag is turned on
+        self.u1.inherit_default_permissions = True
+        Session().commit()
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        # this user will have inherited permissions from default user
+        self.assertEqual(u1_auth.permissions['global'],
+                         set(['hg.create.none', 'hg.fork.none',
+                              'hg.register.manual_activate',
+                              'repository.read']))
+
+    def test_non_inherited_permissions_from_default_on_user_enabled(self):
+        user_model = UserModel()
+        # enable fork and create on default user
+        usr = 'default'
+        user_model.revoke_perm(usr, 'hg.create.none')
+        user_model.grant_perm(usr, 'hg.create.repository')
+        user_model.revoke_perm(usr, 'hg.fork.none')
+        user_model.grant_perm(usr, 'hg.fork.repository')
+
+        #disable global perms on specific user
+        user_model.revoke_perm(self.u1, 'hg.create.repository')
+        user_model.grant_perm(self.u1, 'hg.create.none')
+        user_model.revoke_perm(self.u1, 'hg.fork.repository')
+        user_model.grant_perm(self.u1, 'hg.fork.none')
+
+        # make sure inherit flag is turned off
+        self.u1.inherit_default_permissions = False
+        Session().commit()
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        # this user will have non inherited permissions from he's
+        # explicitly set permissions
+        self.assertEqual(u1_auth.permissions['global'],
+                         set(['hg.create.none', 'hg.fork.none',
+                              'hg.register.manual_activate',
+                              'repository.read']))
+
+    def test_non_inherited_permissions_from_default_on_user_disabled(self):
+        user_model = UserModel()
+        # disable fork and create on default user
+        usr = 'default'
+        user_model.revoke_perm(usr, 'hg.create.repository')
+        user_model.grant_perm(usr, 'hg.create.none')
+        user_model.revoke_perm(usr, 'hg.fork.repository')
+        user_model.grant_perm(usr, 'hg.fork.none')
+
+        #enable global perms on specific user
+        user_model.revoke_perm(self.u1, 'hg.create.none')
+        user_model.grant_perm(self.u1, 'hg.create.repository')
+        user_model.revoke_perm(self.u1, 'hg.fork.none')
+        user_model.grant_perm(self.u1, 'hg.fork.repository')
+
+        # make sure inherit flag is turned off
+        self.u1.inherit_default_permissions = False
+        Session().commit()
+        u1_auth = AuthUser(user_id=self.u1.user_id)
+        # this user will have non inherited permissions from he's
+        # explicitly set permissions
+        self.assertEqual(u1_auth.permissions['global'],
+                         set(['hg.create.repository', 'hg.fork.repository',
+                              'hg.register.manual_activate',
+                              'repository.read']))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/models/test_repos_groups.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,172 @@
+import os
+import unittest
+from rhodecode.tests import *
+
+from rhodecode.model.repos_group import ReposGroupModel
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.db import RepoGroup, User
+from rhodecode.model.meta import Session
+from sqlalchemy.exc import IntegrityError
+
+
+def _make_group(path, desc='desc', parent_id=None,
+                 skip_if_exists=False):
+
+    gr = RepoGroup.get_by_group_name(path)
+    if gr and skip_if_exists:
+        return gr
+
+    gr = ReposGroupModel().create(path, desc, parent_id)
+    return gr
+
+
+class TestReposGroups(unittest.TestCase):
+
+    def setUp(self):
+        self.g1 = _make_group('test1', skip_if_exists=True)
+        Session().commit()
+        self.g2 = _make_group('test2', skip_if_exists=True)
+        Session().commit()
+        self.g3 = _make_group('test3', skip_if_exists=True)
+        Session().commit()
+
+    def tearDown(self):
+        print 'out'
+
+    def __check_path(self, *path):
+        """
+        Checks the path for existance !
+        """
+        path = [TESTS_TMP_PATH] + list(path)
+        path = os.path.join(*path)
+        return os.path.isdir(path)
+
+    def _check_folders(self):
+        print os.listdir(TESTS_TMP_PATH)
+
+    def __delete_group(self, id_):
+        ReposGroupModel().delete(id_)
+
+    def __update_group(self, id_, path, desc='desc', parent_id=None):
+        form_data = dict(
+            group_name=path,
+            group_description=desc,
+            group_parent_id=parent_id,
+            perms_updates=[],
+            perms_new=[],
+            enable_locking=False
+        )
+        gr = ReposGroupModel().update(id_, form_data)
+        return gr
+
+    def test_create_group(self):
+        g = _make_group('newGroup')
+        self.assertEqual(g.full_path, 'newGroup')
+
+        self.assertTrue(self.__check_path('newGroup'))
+
+    def test_create_same_name_group(self):
+        self.assertRaises(IntegrityError, lambda: _make_group('newGroup'))
+        Session().rollback()
+
+    def test_same_subgroup(self):
+        sg1 = _make_group('sub1', parent_id=self.g1.group_id)
+        self.assertEqual(sg1.parent_group, self.g1)
+        self.assertEqual(sg1.full_path, 'test1/sub1')
+        self.assertTrue(self.__check_path('test1', 'sub1'))
+
+        ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
+        self.assertEqual(ssg1.parent_group, sg1)
+        self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
+        self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
+
+    def test_remove_group(self):
+        sg1 = _make_group('deleteme')
+        self.__delete_group(sg1.group_id)
+
+        self.assertEqual(RepoGroup.get(sg1.group_id), None)
+        self.assertFalse(self.__check_path('deteteme'))
+
+        sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
+        self.__delete_group(sg1.group_id)
+
+        self.assertEqual(RepoGroup.get(sg1.group_id), None)
+        self.assertFalse(self.__check_path('test1', 'deteteme'))
+
+    def test_rename_single_group(self):
+        sg1 = _make_group('initial')
+
+        new_sg1 = self.__update_group(sg1.group_id, 'after')
+        self.assertTrue(self.__check_path('after'))
+        self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
+
+    def test_update_group_parent(self):
+
+        sg1 = _make_group('initial', parent_id=self.g1.group_id)
+
+        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
+        self.assertTrue(self.__check_path('test1', 'after'))
+        self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
+
+        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
+        self.assertTrue(self.__check_path('test3', 'after'))
+        self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
+
+        new_sg1 = self.__update_group(sg1.group_id, 'hello')
+        self.assertTrue(self.__check_path('hello'))
+
+        self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
+
+    def test_subgrouping_with_repo(self):
+
+        g1 = _make_group('g1')
+        g2 = _make_group('g2')
+
+        # create new repo
+        form_data = dict(repo_name='john',
+                         repo_name_full='john',
+                         fork_name=None,
+                         description=None,
+                         repo_group=None,
+                         private=False,
+                         repo_type='hg',
+                         clone_uri=None,
+                         landing_rev='tip',
+                         enable_locking=False)
+        cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
+        r = RepoModel().create(form_data, cur_user)
+
+        self.assertEqual(r.repo_name, 'john')
+
+        # put repo into group
+        form_data = form_data
+        form_data['repo_group'] = g1.group_id
+        form_data['perms_new'] = []
+        form_data['perms_updates'] = []
+        RepoModel().update(r.repo_name, form_data)
+        self.assertEqual(r.repo_name, 'g1/john')
+
+        self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
+        self.assertTrue(self.__check_path('g2', 'g1'))
+
+        # test repo
+        self.assertEqual(r.repo_name, RepoGroup.url_sep().join(['g2', 'g1',
+                                                                r.just_name]))
+
+    def test_move_to_root(self):
+        g1 = _make_group('t11')
+        Session().commit()
+        g2 = _make_group('t22', parent_id=g1.group_id)
+        Session().commit()
+
+        self.assertEqual(g2.full_path, 't11/t22')
+        self.assertTrue(self.__check_path('t11', 't22'))
+
+        g2 = self.__update_group(g2.group_id, 'g22', parent_id=None)
+        Session().commit()
+
+        self.assertEqual(g2.group_name, 'g22')
+        # we moved out group from t1 to '' so it's full path should be 'g2'
+        self.assertEqual(g2.full_path, 'g22')
+        self.assertFalse(self.__check_path('t11', 't22'))
+        self.assertTrue(self.__check_path('g22'))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/models/test_users.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,124 @@
+import unittest
+from rhodecode.tests import *
+
+from rhodecode.model.db import User, UsersGroup, UsersGroupMember, UserEmailMap,\
+    Permission
+from rhodecode.model.user import UserModel
+
+from rhodecode.model.meta import Session
+from rhodecode.model.users_group import UsersGroupModel
+
+
+class TestUser(unittest.TestCase):
+    def __init__(self, methodName='runTest'):
+        Session.remove()
+        super(TestUser, self).__init__(methodName=methodName)
+
+    def test_create_and_remove(self):
+        usr = UserModel().create_or_update(username=u'test_user',
+                                           password=u'qweqwe',
+                                     email=u'u232@rhodecode.org',
+                                     firstname=u'u1', lastname=u'u1')
+        Session().commit()
+        self.assertEqual(User.get_by_username(u'test_user'), usr)
+
+        # make users group
+        users_group = UsersGroupModel().create('some_example_group')
+        Session().commit()
+
+        UsersGroupModel().add_user_to_group(users_group, usr)
+        Session().commit()
+
+        self.assertEqual(UsersGroup.get(users_group.users_group_id), users_group)
+        self.assertEqual(UsersGroupMember.query().count(), 1)
+        UserModel().delete(usr.user_id)
+        Session().commit()
+
+        self.assertEqual(UsersGroupMember.query().all(), [])
+
+    def test_additonal_email_as_main(self):
+        usr = UserModel().create_or_update(username=u'test_user',
+                                           password=u'qweqwe',
+                                     email=u'main_email@rhodecode.org',
+                                     firstname=u'u1', lastname=u'u1')
+        Session().commit()
+
+        def do():
+            m = UserEmailMap()
+            m.email = u'main_email@rhodecode.org'
+            m.user = usr
+            Session().add(m)
+            Session().commit()
+        self.assertRaises(AttributeError, do)
+
+        UserModel().delete(usr.user_id)
+        Session().commit()
+
+    def test_extra_email_map(self):
+        usr = UserModel().create_or_update(username=u'test_user',
+                                           password=u'qweqwe',
+                                     email=u'main_email@rhodecode.org',
+                                     firstname=u'u1', lastname=u'u1')
+        Session().commit()
+
+        m = UserEmailMap()
+        m.email = u'main_email2@rhodecode.org'
+        m.user = usr
+        Session().add(m)
+        Session().commit()
+
+        u = User.get_by_email(email='main_email@rhodecode.org')
+        self.assertEqual(usr.user_id, u.user_id)
+        self.assertEqual(usr.username, u.username)
+
+        u = User.get_by_email(email='main_email2@rhodecode.org')
+        self.assertEqual(usr.user_id, u.user_id)
+        self.assertEqual(usr.username, u.username)
+        u = User.get_by_email(email='main_email3@rhodecode.org')
+        self.assertEqual(None, u)
+
+        UserModel().delete(usr.user_id)
+        Session().commit()
+
+
+class TestUsers(unittest.TestCase):
+
+    def __init__(self, methodName='runTest'):
+        super(TestUsers, self).__init__(methodName=methodName)
+
+    def setUp(self):
+        self.u1 = UserModel().create_or_update(username=u'u1',
+                                        password=u'qweqwe',
+                                        email=u'u1@rhodecode.org',
+                                        firstname=u'u1', lastname=u'u1')
+
+    def tearDown(self):
+        perm = Permission.query().all()
+        for p in perm:
+            UserModel().revoke_perm(self.u1, p)
+
+        UserModel().delete(self.u1)
+        Session().commit()
+
+    def test_add_perm(self):
+        perm = Permission.query().all()[0]
+        UserModel().grant_perm(self.u1, perm)
+        Session().commit()
+        self.assertEqual(UserModel().has_perm(self.u1, perm), True)
+
+    def test_has_perm(self):
+        perm = Permission.query().all()
+        for p in perm:
+            has_p = UserModel().has_perm(self.u1, p)
+            self.assertEqual(False, has_p)
+
+    def test_revoke_perm(self):
+        perm = Permission.query().all()[0]
+        UserModel().grant_perm(self.u1, perm)
+        Session().commit()
+        self.assertEqual(UserModel().has_perm(self.u1, perm), True)
+
+        #revoke
+        UserModel().revoke_perm(self.u1, perm)
+        Session().commit()
+        self.assertEqual(UserModel().has_perm(self.u1, perm), False)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/nose_parametrized.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,238 @@
+import re
+import new
+import inspect
+import logging
+import logging.handlers
+from functools import wraps
+
+from nose.tools import nottest
+from unittest import TestCase
+
+
+def _terrible_magic_get_defining_classes():
+    """ Returns the set of parent classes of the class currently being defined.
+        Will likely only work if called from the ``parameterized`` decorator.
+        This function is entirely @brandon_rhodes's fault, as he suggested
+        the implementation: http://stackoverflow.com/a/8793684/71522
+        """
+    stack = inspect.stack()
+    if len(stack) <= 4:
+        return []
+    frame = stack[3]
+    code_context = frame[4][0].strip()
+    if not code_context.startswith("class "):
+        return []
+    _, parents = code_context.split("(", 1)
+    parents, _ = parents.rsplit(")", 1)
+    return eval("[" + parents + "]", frame[0].f_globals, frame[0].f_locals)
+
+
+def parameterized(input):
+    """ Parameterize a test case:
+        >>> add1_tests = [(1, 2), (2, 3)]
+        >>> class TestFoo(object):
+        ...     @parameterized(add1_tests)
+        ...     def test_add1(self, input, expected):
+        ...         assert_equal(add1(input), expected)
+        >>> @parameterized(add1_tests)
+        ... def test_add1(input, expected):
+        ...     assert_equal(add1(input), expected)
+        >>>
+        """
+
+    if not hasattr(input, "__iter__"):
+        raise ValueError("expected iterable input; got %r" % (input,))
+
+    def parameterized_helper(f):
+        attached_instance_method = [False]
+
+        parent_classes = _terrible_magic_get_defining_classes()
+        if any(issubclass(cls, TestCase) for cls in parent_classes):
+            raise Exception("Warning: '@parameterized' tests won't work "
+                            "inside subclasses of 'TestCase' - use "
+                            "'@parameterized.expand' instead")
+
+        @wraps(f)
+        def parameterized_helper_method(self=None):
+            if self is not None and not attached_instance_method[0]:
+                # confusingly, we need to create a named instance method and
+                # attach that to the class...
+                cls = self.__class__
+                im_f = new.instancemethod(f, None, cls)
+                setattr(cls, f.__name__, im_f)
+                attached_instance_method[0] = True
+            for args in input:
+                if isinstance(args, basestring):
+                    args = [args]
+                # ... then pull that named instance method off, turning it into
+                # a bound method ...
+                if self is not None:
+                    args = [getattr(self, f.__name__)] + list(args)
+                else:
+                    args = [f] + list(args)
+                # ... then yield that as a tuple. If those steps aren't
+                # followed precicely, Nose gets upset and doesn't run the test
+                # or doesn't run setup methods.
+                yield tuple(args)
+
+        f.__name__ = "_helper_for_%s" % (f.__name__,)
+        parameterized_helper_method.parameterized_input = input
+        parameterized_helper_method.parameterized_func = f
+        return parameterized_helper_method
+
+    return parameterized_helper
+
+
+def to_safe_name(s):
+    return re.sub("[^a-zA-Z0-9_]", "", s)
+
+
+def parameterized_expand_helper(func_name, func, args):
+    def parameterized_expand_helper_helper(self=()):
+        if self != ():
+            self = (self,)
+        return func(*(self + args))
+    parameterized_expand_helper_helper.__name__ = func_name
+    return parameterized_expand_helper_helper
+
+
+def parameterized_expand(input):
+    """ A "brute force" method of parameterizing test cases. Creates new test
+        cases and injects them into the namespace that the wrapped function
+        is being defined in. Useful for parameterizing tests in subclasses
+        of 'UnitTest', where Nose test generators don't work.
+
+        >>> @parameterized.expand([("foo", 1, 2)])
+        ... def test_add1(name, input, expected):
+        ...     actual = add1(input)
+        ...     assert_equal(actual, expected)
+        ...
+        >>> locals()
+        ... 'test_add1_foo_0': <function ...> ...
+        >>>
+        """
+
+    def parameterized_expand_wrapper(f):
+        stack = inspect.stack()
+        frame = stack[1]
+        frame_locals = frame[0].f_locals
+
+        base_name = f.__name__
+        for num, args in enumerate(input):
+            name_suffix = "_%s" % (num,)
+            if len(args) > 0 and isinstance(args[0], basestring):
+                name_suffix += "_" + to_safe_name(args[0])
+            name = base_name + name_suffix
+            new_func = parameterized_expand_helper(name, f, args)
+            frame_locals[name] = new_func
+        return nottest(f)
+    return parameterized_expand_wrapper
+
+parameterized.expand = parameterized_expand
+
+
+def assert_contains(haystack, needle):
+    if needle not in haystack:
+        raise AssertionError("%r not in %r" % (needle, haystack))
+
+
+def assert_not_contains(haystack, needle):
+    if needle in haystack:
+        raise AssertionError("%r in %r" % (needle, haystack))
+
+
+def imported_from_test():
+    """ Returns true if it looks like this module is being imported by unittest
+        or nose. """
+    import re
+    import inspect
+    nose_re = re.compile(r"\bnose\b")
+    unittest_re = re.compile(r"\bunittest2?\b")
+    for frame in inspect.stack():
+        file = frame[1]
+        if nose_re.search(file) or unittest_re.search(file):
+            return True
+    return False
+
+
+def assert_raises(func, exc_type, str_contains=None, repr_contains=None):
+    try:
+        func()
+    except exc_type, e:
+        if str_contains is not None and str_contains not in str(e):
+            raise AssertionError("%s raised, but %r does not contain %r"
+                                 % (exc_type, str(e), str_contains))
+        if repr_contains is not None and repr_contains not in repr(e):
+            raise AssertionError("%s raised, but %r does not contain %r"
+                                 % (exc_type, repr(e), repr_contains))
+        return e
+    else:
+        raise AssertionError("%s not raised" % (exc_type,))
+
+
+log_handler = None
+
+
+def setup_logging():
+    """ Configures a log handler which will capure log messages during a test.
+        The ``logged_messages`` and ``assert_no_errors_logged`` functions can be
+        used to make assertions about these logged messages.
+
+        For example::
+
+            from ensi_common.testing import (
+                setup_logging, teardown_logging, assert_no_errors_logged,
+                assert_logged,
+            )
+
+            class TestWidget(object):
+                def setup(self):
+                    setup_logging()
+
+                def teardown(self):
+                    assert_no_errors_logged()
+                    teardown_logging()
+
+                def test_that_will_fail(self):
+                    log.warning("this warning message will trigger a failure")
+
+                def test_that_will_pass(self):
+                    log.info("but info messages are ok")
+                    assert_logged("info messages are ok")
+        """
+
+    global log_handler
+    if log_handler is not None:
+        logging.getLogger().removeHandler(log_handler)
+    log_handler = logging.handlers.BufferingHandler(1000)
+    formatter = logging.Formatter("%(name)s: %(levelname)s: %(message)s")
+    log_handler.setFormatter(formatter)
+    logging.getLogger().addHandler(log_handler)
+
+
+def teardown_logging():
+    global log_handler
+    if log_handler is not None:
+        logging.getLogger().removeHandler(log_handler)
+        log_handler = None
+
+
+def logged_messages():
+    assert log_handler, "setup_logging not called"
+    return [(log_handler.format(record), record) for record in log_handler.buffer]
+
+
+def assert_no_errors_logged():
+    for _, record in logged_messages():
+        if record.levelno >= logging.WARNING:
+            # Assume that the nose log capture plugin is being used, so it will
+            # show the exception.
+            raise AssertionError("an unexpected error was logged")
+
+
+def assert_logged(expected_msg_contents):
+    for msg, _ in logged_messages():
+        if expected_msg_contents in msg:
+            return
+    raise AssertionError("no logged message contains %r"
+                         % (expected_msg_contents,))
--- a/rhodecode/tests/rhodecode_crawler.py	Sat May 19 14:54:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    rhodecode.tests.test_crawer
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    Test for crawling a project for memory usage
-    This should be runned just as regular script together
-    with a watch script that will show memory usage.
-
-    watch -n1 ./rhodecode/tests/mem_watch
-
-    :created_on: Apr 21, 2010
-    :author: marcink
-    :copyright: (C) 2010-2012 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, either version 3 of the License, or
-# (at your option) any later version.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-
-import cookielib
-import urllib
-import urllib2
-import time
-import os
-import sys
-from os.path import join as jn
-from os.path import dirname as dn
-
-__here__ = os.path.abspath(__file__)
-__root__ = dn(dn(dn(__here__)))
-sys.path.append(__root__)
-
-from rhodecode.lib import vcs
-from rhodecode.lib.compat import OrderedSet
-from rhodecode.lib.vcs.exceptions import RepositoryError
-
-PASES = 3
-HOST = 'http://127.0.0.1'
-PORT = 5000
-BASE_URI = '%s:%s/' % (HOST, PORT)
-
-if len(sys.argv) == 2:
-    BASE_URI = sys.argv[1]
-
-if not BASE_URI.endswith('/'):
-    BASE_URI += '/'
-
-print 'Crawling @ %s' % BASE_URI
-BASE_URI += '%s'
-PROJECT_PATH = jn('/', 'home', 'marcink', 'hg_repos')
-PROJECTS = [
-    'linux-magx-pbranch',
-    'CPython',
-    'rhodecode_tip',
-]
-
-
-cj = cookielib.FileCookieJar('/tmp/rc_test_cookie.txt')
-o = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
-o.addheaders = [
-    ('User-agent', 'rhodecode-crawler'),
-    ('Accept-Language', 'en - us, en;q = 0.5')
-]
-
-urllib2.install_opener(o)
-
-
-def _get_repo(proj):
-    if isinstance(proj, basestring):
-        repo = vcs.get_repo(jn(PROJECT_PATH, proj))
-        proj = proj
-    else:
-        repo = proj
-        proj = repo.name
-
-    return repo, proj
-
-
-def test_changelog_walk(proj, pages=100):
-    repo, proj = _get_repo(proj)
-
-    total_time = 0
-    for i in range(1, pages):
-
-        page = '/'.join((proj, 'changelog',))
-
-        full_uri = (BASE_URI % page) + '?' + urllib.urlencode({'page':i})
-        s = time.time()
-        f = o.open(full_uri)
-        size = len(f.read())
-        e = time.time() - s
-        total_time += e
-        print 'visited %s size:%s req:%s ms' % (full_uri, size, e)
-
-    print 'total_time', total_time
-    print 'average on req', total_time / float(pages)
-
-
-def test_changeset_walk(proj, limit=None):
-    repo, proj = _get_repo(proj)
-
-    print 'processing', jn(PROJECT_PATH, proj)
-    total_time = 0
-
-    cnt = 0
-    for i in repo:
-        cnt += 1
-        raw_cs = '/'.join((proj, 'changeset', i.raw_id))
-        if limit and limit == cnt:
-            break
-
-        full_uri = (BASE_URI % raw_cs)
-        print '%s visiting %s\%s' % (cnt, full_uri, i)
-        s = time.time()
-        f = o.open(full_uri)
-        size = len(f.read())
-        e = time.time() - s
-        total_time += e
-        print '%s visited %s\%s size:%s req:%s ms' % (cnt, full_uri, i, size, e)
-
-    print 'total_time', total_time
-    print 'average on req', total_time / float(cnt)
-
-
-def test_files_walk(proj, limit=100):
-    repo, proj = _get_repo(proj)
-
-    print 'processing', jn(PROJECT_PATH, proj)
-    total_time = 0
-
-    paths_ = OrderedSet([''])
-    try:
-        tip = repo.get_changeset('tip')
-        for topnode, dirs, files in tip.walk('/'):
-
-            for dir in dirs:
-                paths_.add(dir.path)
-                for f in dir:
-                    paths_.add(f.path)
-
-            for f in files:
-                paths_.add(f.path)
-
-    except RepositoryError, e:
-        pass
-
-    cnt = 0
-    for f in paths_:
-        cnt += 1
-        if limit and limit == cnt:
-            break
-
-        file_path = '/'.join((proj, 'files', 'tip', f))
-        full_uri = (BASE_URI % file_path)
-        print '%s visiting %s' % (cnt, full_uri)
-        s = time.time()
-        f = o.open(full_uri)
-        size = len(f.read())
-        e = time.time() - s
-        total_time += e
-        print '%s visited OK size:%s req:%s ms' % (cnt, size, e)
-
-    print 'total_time', total_time
-    print 'average on req', total_time / float(cnt)
-
-if __name__ == '__main__':
-    for path in PROJECTS:
-        repo = vcs.get_repo(jn(PROJECT_PATH, path))
-        for i in range(PASES):
-            print 'PASS %s/%s' % (i, PASES)
-            test_changelog_walk(repo, pages=80)
-            test_changeset_walk(repo, limit=100)
-            test_files_walk(repo, limit=100)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/scripts/create_rc.sh	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,12 @@
+psql -U postgres -h localhost -c 'drop database if exists rhodecode;'
+psql -U postgres -h localhost -c 'create database rhodecode;'
+paster setup-rhodecode rc.ini -q --user=marcink --password=qweqwe --email=marcin@python-blog.com --repos=/home/marcink/repos
+API_KEY=`psql -R " " -A -U postgres -h localhost -c "select api_key from users where admin=TRUE" -d rhodecode | awk '{print $2}'`
+echo "run those after running server"
+echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@rhodecode.org"
+echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@rhodecode.org"
+echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@rhodecode.org"
+echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_users_group group_name:demo12"
+echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_users_group usersgroupid:demo12 userid:demo1"
+echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_users_group usersgroupid:demo12 userid:demo2"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/scripts/mem_watch	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,1 @@
+ps -eo size,pid,user,command --sort -size | awk '{ hr=$1/1024 ; printf("%13.2f Mb ",hr) } { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }'|grep [p]aster
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/scripts/test_concurency.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,213 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.tests.test_hg_operations
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test suite for making push/pull operations
+
+    :created_on: Dec 30, 2010
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+import shutil
+import logging
+from os.path import join as jn
+from os.path import dirname as dn
+
+from tempfile import _RandomNameSequence
+from subprocess import Popen, PIPE
+
+from paste.deploy import appconfig
+from pylons import config
+from sqlalchemy import engine_from_config
+
+from rhodecode.lib.utils import add_cache
+from rhodecode.model import init_model
+from rhodecode.model import meta
+from rhodecode.model.db import User, Repository
+from rhodecode.lib.auth import get_crypt_password
+
+from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO
+from rhodecode.config.environment import load_environment
+
+rel_path = dn(dn(dn(os.path.abspath(__file__))))
+conf = appconfig('config:development.ini', relative_to=rel_path)
+load_environment(conf.global_conf, conf.local_conf)
+
+add_cache(conf)
+
+USER = 'test_admin'
+PASS = 'test12'
+HOST = 'hg.local'
+METHOD = 'pull'
+DEBUG = True
+log = logging.getLogger(__name__)
+
+
+class Command(object):
+
+    def __init__(self, cwd):
+        self.cwd = cwd
+
+    def execute(self, cmd, *args):
+        """Runs command on the system with given ``args``.
+        """
+
+        command = cmd + ' ' + ' '.join(args)
+        log.debug('Executing %s' % command)
+        if DEBUG:
+            print command
+        p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
+        stdout, stderr = p.communicate()
+        if DEBUG:
+            print stdout, stderr
+        return stdout, stderr
+
+
+def get_session():
+    engine = engine_from_config(conf, 'sqlalchemy.db1.')
+    init_model(engine)
+    sa = meta.Session
+    return sa
+
+
+def create_test_user(force=True):
+    print 'creating test user'
+    sa = get_session()
+
+    user = sa.query(User).filter(User.username == USER).scalar()
+
+    if force and user is not None:
+        print 'removing current user'
+        for repo in sa.query(Repository).filter(Repository.user == user).all():
+            sa.delete(repo)
+        sa.delete(user)
+        sa.commit()
+
+    if user is None or force:
+        print 'creating new one'
+        new_usr = User()
+        new_usr.username = USER
+        new_usr.password = get_crypt_password(PASS)
+        new_usr.email = 'mail@mail.com'
+        new_usr.name = 'test'
+        new_usr.lastname = 'lasttestname'
+        new_usr.active = True
+        new_usr.admin = True
+        sa.add(new_usr)
+        sa.commit()
+
+    print 'done'
+
+
+def create_test_repo(force=True):
+    print 'creating test repo'
+    from rhodecode.model.repo import RepoModel
+    sa = get_session()
+
+    user = sa.query(User).filter(User.username == USER).scalar()
+    if user is None:
+        raise Exception('user not found')
+
+    repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
+
+    if repo is None:
+        print 'repo not found creating'
+
+        form_data = {'repo_name':HG_REPO,
+                     'repo_type':'hg',
+                     'private':False,
+                     'clone_uri':'' }
+        rm = RepoModel(sa)
+        rm.base_path = '/home/hg'
+        rm.create(form_data, user)
+
+    print 'done'
+
+
+def set_anonymous_access(enable=True):
+    sa = get_session()
+    user = sa.query(User).filter(User.username == 'default').one()
+    user.active = enable
+    sa.add(user)
+    sa.commit()
+
+
+def get_anonymous_access():
+    sa = get_session()
+    return sa.query(User).filter(User.username == 'default').one().active
+
+
+#==============================================================================
+# TESTS
+#==============================================================================
+def test_clone_with_credentials(no_errors=False, repo=HG_REPO, method=METHOD,
+                                seq=None):
+    cwd = path = jn(TESTS_TMP_PATH, repo)
+
+    if seq == None:
+        seq = _RandomNameSequence().next()
+
+    try:
+        shutil.rmtree(path, ignore_errors=True)
+        os.makedirs(path)
+        #print 'made dirs %s' % jn(path)
+    except OSError:
+        raise
+
+    clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
+                  {'user':USER,
+                   'pass':PASS,
+                   'host':HOST,
+                   'cloned_repo':repo, }
+
+    dest = path + seq
+    if method == 'pull':
+        stdout, stderr = Command(cwd).execute('hg', method, '--cwd', dest, clone_url)
+    else:
+        stdout, stderr = Command(cwd).execute('hg', method, clone_url, dest)
+
+        if no_errors is False:
+            assert """adding file changes""" in stdout, 'no messages about cloning'
+            assert """abort""" not in stderr , 'got error from clone'
+
+if __name__ == '__main__':
+    try:
+        create_test_user(force=False)
+        seq = None
+        import time
+
+        try:
+            METHOD = sys.argv[3]
+        except:
+            pass
+
+        if METHOD == 'pull':
+            seq = _RandomNameSequence().next()
+            test_clone_with_credentials(repo=sys.argv[1], method='clone',
+                                        seq=seq)
+        s = time.time()
+        for i in range(1, int(sys.argv[2]) + 1):
+            print 'take', i
+            test_clone_with_credentials(repo=sys.argv[1], method=METHOD,
+                                        seq=seq)
+        print 'time taken %.3f' % (time.time() - s)
+    except Exception, e:
+        raise
+        sys.exit('stop on %s' % e)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/scripts/test_crawler.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,184 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.tests.test_crawer
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test for crawling a project for memory usage
+    This should be runned just as regular script together
+    with a watch script that will show memory usage.
+
+    watch -n1 ./rhodecode/tests/mem_watch
+
+    :created_on: Apr 21, 2010
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+
+import cookielib
+import urllib
+import urllib2
+import time
+import os
+import sys
+from os.path import join as jn
+from os.path import dirname as dn
+
+__here__ = os.path.abspath(__file__)
+__root__ = dn(dn(dn(__here__)))
+sys.path.append(__root__)
+
+from rhodecode.lib import vcs
+from rhodecode.lib.compat import OrderedSet
+from rhodecode.lib.vcs.exceptions import RepositoryError
+
+PASES = 3
+HOST = 'http://127.0.0.1'
+PORT = 5000
+BASE_URI = '%s:%s/' % (HOST, PORT)
+
+if len(sys.argv) == 2:
+    BASE_URI = sys.argv[1]
+
+if not BASE_URI.endswith('/'):
+    BASE_URI += '/'
+
+print 'Crawling @ %s' % BASE_URI
+BASE_URI += '%s'
+PROJECT_PATH = jn('/', 'home', 'marcink', 'hg_repos')
+PROJECTS = [
+    'linux-magx-pbranch',
+    'CPython',
+    'rhodecode_tip',
+]
+
+
+cj = cookielib.FileCookieJar('/tmp/rc_test_cookie.txt')
+o = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
+o.addheaders = [
+    ('User-agent', 'rhodecode-crawler'),
+    ('Accept-Language', 'en - us, en;q = 0.5')
+]
+
+urllib2.install_opener(o)
+
+
+def _get_repo(proj):
+    if isinstance(proj, basestring):
+        repo = vcs.get_repo(jn(PROJECT_PATH, proj))
+        proj = proj
+    else:
+        repo = proj
+        proj = repo.name
+
+    return repo, proj
+
+
+def test_changelog_walk(proj, pages=100):
+    repo, proj = _get_repo(proj)
+
+    total_time = 0
+    for i in range(1, pages):
+
+        page = '/'.join((proj, 'changelog',))
+
+        full_uri = (BASE_URI % page) + '?' + urllib.urlencode({'page':i})
+        s = time.time()
+        f = o.open(full_uri)
+        size = len(f.read())
+        e = time.time() - s
+        total_time += e
+        print 'visited %s size:%s req:%s ms' % (full_uri, size, e)
+
+    print 'total_time', total_time
+    print 'average on req', total_time / float(pages)
+
+
+def test_changeset_walk(proj, limit=None):
+    repo, proj = _get_repo(proj)
+
+    print 'processing', jn(PROJECT_PATH, proj)
+    total_time = 0
+
+    cnt = 0
+    for i in repo:
+        cnt += 1
+        raw_cs = '/'.join((proj, 'changeset', i.raw_id))
+        if limit and limit == cnt:
+            break
+
+        full_uri = (BASE_URI % raw_cs)
+        print '%s visiting %s\%s' % (cnt, full_uri, i)
+        s = time.time()
+        f = o.open(full_uri)
+        size = len(f.read())
+        e = time.time() - s
+        total_time += e
+        print '%s visited %s\%s size:%s req:%s ms' % (cnt, full_uri, i, size, e)
+
+    print 'total_time', total_time
+    print 'average on req', total_time / float(cnt)
+
+
+def test_files_walk(proj, limit=100):
+    repo, proj = _get_repo(proj)
+
+    print 'processing', jn(PROJECT_PATH, proj)
+    total_time = 0
+
+    paths_ = OrderedSet([''])
+    try:
+        tip = repo.get_changeset('tip')
+        for topnode, dirs, files in tip.walk('/'):
+
+            for dir in dirs:
+                paths_.add(dir.path)
+                for f in dir:
+                    paths_.add(f.path)
+
+            for f in files:
+                paths_.add(f.path)
+
+    except RepositoryError, e:
+        pass
+
+    cnt = 0
+    for f in paths_:
+        cnt += 1
+        if limit and limit == cnt:
+            break
+
+        file_path = '/'.join((proj, 'files', 'tip', f))
+        full_uri = (BASE_URI % file_path)
+        print '%s visiting %s' % (cnt, full_uri)
+        s = time.time()
+        f = o.open(full_uri)
+        size = len(f.read())
+        e = time.time() - s
+        total_time += e
+        print '%s visited OK size:%s req:%s ms' % (cnt, size, e)
+
+    print 'total_time', total_time
+    print 'average on req', total_time / float(cnt)
+
+if __name__ == '__main__':
+    for path in PROJECTS:
+        repo = vcs.get_repo(jn(PROJECT_PATH, path))
+        for i in range(PASES):
+            print 'PASS %s/%s' % (i, PASES)
+            test_changelog_walk(repo, pages=80)
+            test_changeset_walk(repo, limit=100)
+            test_files_walk(repo, limit=100)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/scripts/test_vcs_operations.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,425 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.tests.test_scm_operations
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test suite for making push/pull operations.
+    Run using::
+
+     RC_WHOOSH_TEST_DISABLE=1 RC_NO_TMP_PATH=1 nosetests rhodecode/tests/scripts/test_vcs_operations.py
+
+    :created_on: Dec 30, 2010
+    :author: marcink
+    :copyright: (C) 2010-2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import os
+import tempfile
+import unittest
+from os.path import join as jn
+from os.path import dirname as dn
+
+from tempfile import _RandomNameSequence
+from subprocess import Popen, PIPE
+
+from rhodecode.tests import *
+from rhodecode.model.db import User, Repository, UserLog
+from rhodecode.model.meta import Session
+from rhodecode.model.repo import RepoModel
+
+DEBUG = True
+HOST = '127.0.0.1:5000'  # test host
+
+
+class Command(object):
+
+    def __init__(self, cwd):
+        self.cwd = cwd
+
+    def execute(self, cmd, *args):
+        """
+        Runs command on the system with given ``args``.
+        """
+
+        command = cmd + ' ' + ' '.join(args)
+        if DEBUG:
+            print '*** CMD %s ***' % command
+        p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
+        stdout, stderr = p.communicate()
+        if DEBUG:
+            print stdout, stderr
+        return stdout, stderr
+
+
+def _get_tmp_dir():
+    return tempfile.mkdtemp(prefix='rc_integration_test')
+
+
+def _construct_url(repo, dest=None, **kwargs):
+    if dest is None:
+        #make temp clone
+        dest = _get_tmp_dir()
+    params = {
+        'user': TEST_USER_ADMIN_LOGIN,
+        'passwd': TEST_USER_ADMIN_PASS,
+        'host': HOST,
+        'cloned_repo': repo,
+        'dest': dest
+    }
+    params.update(**kwargs)
+    if params['user'] and params['passwd']:
+        _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s %(dest)s' % params
+    else:
+        _url = 'http://(host)s/%(cloned_repo)s %(dest)s' % params
+    return _url
+
+
+def _add_files_and_push(vcs, DEST, **kwargs):
+    """
+    Generate some files, add it to DEST repo and push back
+    vcs is git or hg and defines what VCS we want to make those files for
+
+    :param vcs:
+    :param DEST:
+    """
+    # commit some stuff into this repo
+    cwd = path = jn(DEST)
+    #added_file = jn(path, '%ssetupążźć.py' % _RandomNameSequence().next())
+    added_file = jn(path, '%ssetup.py' % _RandomNameSequence().next())
+    Command(cwd).execute('touch %s' % added_file)
+    Command(cwd).execute('%s add %s' % (vcs, added_file))
+
+    for i in xrange(3):
+        cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
+        Command(cwd).execute(cmd)
+        if vcs == 'hg':
+            cmd = """hg commit -m 'commited new %s' -u '%s' %s """ % (
+                i, 'Marcin Kuźminski <marcin@python-blog.com>', added_file
+            )
+        elif vcs == 'git':
+            cmd = """git ci -m 'commited new %s' --author '%s' %s """ % (
+                i, 'Marcin Kuźminski <marcin@python-blog.com>', added_file
+            )
+        Command(cwd).execute(cmd)
+    # PUSH it back
+    if vcs == 'hg':
+        _REPO = HG_REPO
+    elif vcs == 'git':
+        _REPO = GIT_REPO
+
+    kwargs['dest'] = ''
+    clone_url = _construct_url(_REPO, **kwargs)
+    if 'clone_url' in kwargs:
+        clone_url = kwargs['clone_url']
+    if vcs == 'hg':
+        stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
+    elif vcs == 'git':
+        stdout, stderr = Command(cwd).execute('git push', clone_url + " master")
+
+    return stdout, stderr
+
+
+def set_anonymous_access(enable=True):
+    user = User.get_by_username(User.DEFAULT_USER)
+    user.active = enable
+    Session().add(user)
+    Session().commit()
+    print '\tanonymous access is now:', enable
+    if enable != User.get_by_username(User.DEFAULT_USER).active:
+        raise Exception('Cannot set anonymous access')
+
+
+#==============================================================================
+# TESTS
+#==============================================================================
+
+class TestVCSOperations(unittest.TestCase):
+
+    @classmethod
+    def setup_class(cls):
+        #DISABLE ANONYMOUS ACCESS
+        set_anonymous_access(False)
+
+    def setUp(self):
+        r = Repository.get_by_repo_name(GIT_REPO)
+        Repository.unlock(r)
+        r.enable_locking = False
+        Session().add(r)
+        Session().commit()
+
+        r = Repository.get_by_repo_name(HG_REPO)
+        Repository.unlock(r)
+        r.enable_locking = False
+        Session().add(r)
+        Session().commit()
+
+    def test_clone_hg_repo_by_admin(self):
+        clone_url = _construct_url(HG_REPO)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+
+        assert 'requesting all changes' in stdout
+        assert 'adding changesets' in stdout
+        assert 'adding manifests' in stdout
+        assert 'adding file changes' in stdout
+
+        assert stderr == ''
+
+    def test_clone_git_repo_by_admin(self):
+        clone_url = _construct_url(GIT_REPO)
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+
+        assert 'Cloning into' in stdout
+        assert stderr == ''
+
+    def test_clone_wrong_credentials_hg(self):
+        clone_url = _construct_url(HG_REPO, passwd='bad!')
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+        assert 'abort: authorization failed' in stderr
+
+    def test_clone_wrong_credentials_git(self):
+        clone_url = _construct_url(GIT_REPO, passwd='bad!')
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+        assert 'fatal: Authentication failed' in stderr
+
+    def test_clone_git_dir_as_hg(self):
+        clone_url = _construct_url(GIT_REPO)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+        assert 'HTTP Error 404: Not Found' in stderr
+
+    def test_clone_hg_repo_as_git(self):
+        clone_url = _construct_url(HG_REPO)
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+        assert 'not found:' in stderr
+
+    def test_clone_non_existing_path_hg(self):
+        clone_url = _construct_url('trololo')
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+        assert 'HTTP Error 404: Not Found' in stderr
+
+    def test_clone_non_existing_path_git(self):
+        clone_url = _construct_url('trololo')
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+        assert 'not found:' in stderr
+
+    def test_push_new_file_hg(self):
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(HG_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+
+        stdout, stderr = _add_files_and_push('hg', DEST)
+
+        assert 'pushing to' in stdout
+        assert 'Repository size' in stdout
+        assert 'Last revision is now' in stdout
+
+    def test_push_new_file_git(self):
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(GIT_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+
+        # commit some stuff into this repo
+        stdout, stderr = _add_files_and_push('git', DEST)
+
+        #WTF git stderr ?!
+        assert 'master -> master' in stderr
+
+    def test_push_wrong_credentials_hg(self):
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(HG_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+
+        stdout, stderr = _add_files_and_push('hg', DEST, user='bad',
+                                             passwd='name')
+
+        assert 'abort: authorization failed' in stderr
+
+    def test_push_wrong_credentials_git(self):
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(GIT_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+
+        stdout, stderr = _add_files_and_push('git', DEST, user='bad',
+                                             passwd='name')
+
+        assert 'fatal: Authentication failed' in stderr
+
+    def test_push_back_to_wrong_url_hg(self):
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(HG_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+
+        stdout, stderr = _add_files_and_push('hg', DEST,
+                                    clone_url='http://127.0.0.1:5000/tmp',)
+
+        assert 'HTTP Error 404: Not Found' in stderr
+
+    def test_push_back_to_wrong_url_git(self):
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(GIT_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+
+        stdout, stderr = _add_files_and_push('git', DEST,
+                                    clone_url='http://127.0.0.1:5000/tmp',)
+
+        assert 'not found:' in stderr
+
+    def test_clone_and_create_lock_hg(self):
+        # enable locking
+        r = Repository.get_by_repo_name(HG_REPO)
+        r.enable_locking = True
+        Session().add(r)
+        Session().commit()
+        # clone
+        clone_url = _construct_url(HG_REPO)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+
+        #check if lock was made
+        r = Repository.get_by_repo_name(HG_REPO)
+        assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
+
+    def test_clone_and_create_lock_git(self):
+        # enable locking
+        r = Repository.get_by_repo_name(GIT_REPO)
+        r.enable_locking = True
+        Session().add(r)
+        Session().commit()
+        # clone
+        clone_url = _construct_url(GIT_REPO)
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+
+        #check if lock was made
+        r = Repository.get_by_repo_name(GIT_REPO)
+        assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
+
+    def test_clone_after_repo_was_locked_hg(self):
+        #lock repo
+        r = Repository.get_by_repo_name(HG_REPO)
+        Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
+        #pull fails since repo is locked
+        clone_url = _construct_url(HG_REPO)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+        msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
+                % (HG_REPO, TEST_USER_ADMIN_LOGIN))
+        assert msg in stderr
+
+    def test_clone_after_repo_was_locked_git(self):
+        #lock repo
+        r = Repository.get_by_repo_name(GIT_REPO)
+        Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
+        #pull fails since repo is locked
+        clone_url = _construct_url(GIT_REPO)
+        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+        msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
+                % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
+        #TODO: fix this somehow later on GIT, GIT is stupid and even if we throw
+        # back 423 to it, it makes ANOTHER request and we fail there with 405 :/
+        msg = "405 Method Not Allowed"
+        assert msg in stderr
+
+    def test_push_on_locked_repo_by_other_user_hg(self):
+        #clone some temp
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(HG_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+
+        #lock repo
+        r = Repository.get_by_repo_name(HG_REPO)
+        # let this user actually push !
+        RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
+                                          perm='repository.write')
+        Session().commit()
+        Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
+
+        #push fails repo is locked by other user !
+        stdout, stderr = _add_files_and_push('hg', DEST,
+                                             user=TEST_USER_REGULAR_LOGIN,
+                                             passwd=TEST_USER_REGULAR_PASS)
+        msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
+                % (HG_REPO, TEST_USER_ADMIN_LOGIN))
+        assert msg in stderr
+
+#TODO: fix me ! somehow during tests hooks don't get called on GIT
+#    def test_push_on_locked_repo_by_other_user_git(self):
+#        #clone some temp
+#        DEST = _get_tmp_dir()
+#        clone_url = _construct_url(GIT_REPO, dest=DEST)
+#        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+#
+#        #lock repo
+#        r = Repository.get_by_repo_name(GIT_REPO)
+#        # let this user actually push !
+#        RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
+#                                          perm='repository.write')
+#        Session().commit()
+#        Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
+#
+#        #push fails repo is locked by other user !
+#        stdout, stderr = _add_files_and_push('git', DEST,
+#                                             user=TEST_USER_REGULAR_LOGIN,
+#                                             passwd=TEST_USER_REGULAR_PASS)
+#        msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
+#                % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
+#        #TODO: fix this somehow later on GIT, GIT is stupid and even if we throw
+#        # back 423 to it, it makes ANOTHER request and we fail there with 405 :/
+#        msg = "405 Method Not Allowed"
+#        assert msg in stderr
+
+    def test_push_unlocks_repository_hg(self):
+        # enable locking
+        r = Repository.get_by_repo_name(HG_REPO)
+        r.enable_locking = True
+        Session().add(r)
+        Session().commit()
+        #clone some temp
+        DEST = _get_tmp_dir()
+        clone_url = _construct_url(HG_REPO, dest=DEST)
+        stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
+
+        #check for lock repo after clone
+        r = Repository.get_by_repo_name(HG_REPO)
+        assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
+
+        #push is ok and repo is now unlocked
+        stdout, stderr = _add_files_and_push('hg', DEST)
+        assert ('remote: Released lock on repo `%s`' % HG_REPO) in stdout
+        #we need to cleanup the Session Here !
+        Session.remove()
+        r = Repository.get_by_repo_name(HG_REPO)
+        assert r.locked == [None, None]
+
+#TODO: fix me ! somehow during tests hooks don't get called on GIT
+#    def test_push_unlocks_repository_git(self):
+#        # enable locking
+#        r = Repository.get_by_repo_name(GIT_REPO)
+#        r.enable_locking = True
+#        Session().add(r)
+#        Session().commit()
+#        #clone some temp
+#        DEST = _get_tmp_dir()
+#        clone_url = _construct_url(GIT_REPO, dest=DEST)
+#        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
+#
+#        #check for lock repo after clone
+#        r = Repository.get_by_repo_name(GIT_REPO)
+#        assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
+#
+#        #push is ok and repo is now unlocked
+#        stdout, stderr = _add_files_and_push('git', DEST)
+#        #assert ('remote: Released lock on repo `%s`' % GIT_REPO) in stdout
+#        #we need to cleanup the Session Here !
+#        Session.remove()
+#        r = Repository.get_by_repo_name(GIT_REPO)
+#        assert r.locked == [None, None]
--- a/rhodecode/tests/test_hg_operations.py	Sat May 19 14:54:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,401 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    rhodecode.tests.test_hg_operations
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    Test suite for making push/pull operations
-
-    :created_on: Dec 30, 2010
-    :author: marcink
-    :copyright: (C) 2010-2012 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, either version 3 of the License, or
-# (at your option) any later version.
-#
-# 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, see <http://www.gnu.org/licenses/>.
-
-import os
-import time
-import sys
-import shutil
-import logging
-
-from os.path import join as jn
-from os.path import dirname as dn
-
-from tempfile import _RandomNameSequence
-from subprocess import Popen, PIPE
-
-from paste.deploy import appconfig
-from pylons import config
-from sqlalchemy import engine_from_config
-
-from rhodecode.lib.utils import add_cache
-from rhodecode.model import init_model
-from rhodecode.model import meta
-from rhodecode.model.db import User, Repository, UserLog
-from rhodecode.lib.auth import get_crypt_password
-
-from rhodecode.tests import TESTS_TMP_PATH, NEW_HG_REPO, HG_REPO
-from rhodecode.config.environment import load_environment
-
-rel_path = dn(dn(dn(os.path.abspath(__file__))))
-
-conf = appconfig('config:%s' % sys.argv[1], relative_to=rel_path)
-load_environment(conf.global_conf, conf.local_conf)
-
-add_cache(conf)
-
-USER = 'test_admin'
-PASS = 'test12'
-HOST = '127.0.0.1:5000'
-DEBUG = False
-print 'DEBUG:', DEBUG
-log = logging.getLogger(__name__)
-
-engine = engine_from_config(conf, 'sqlalchemy.db1.')
-init_model(engine)
-sa = meta.Session
-
-class Command(object):
-
-    def __init__(self, cwd):
-        self.cwd = cwd
-
-    def execute(self, cmd, *args):
-        """Runs command on the system with given ``args``.
-        """
-
-        command = cmd + ' ' + ' '.join(args)
-        log.debug('Executing %s' % command)
-        if DEBUG:
-            print command
-        p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
-        stdout, stderr = p.communicate()
-        if DEBUG:
-            print stdout, stderr
-        return stdout, stderr
-
-
-def test_wrapp(func):
-
-    def __wrapp(*args, **kwargs):
-        print '>>>%s' % func.__name__
-        try:
-            res = func(*args, **kwargs)
-        except Exception, e:
-            print ('###############\n-'
-                   '--%s failed %s--\n'
-                   '###############\n' % (func.__name__, e))
-            sys.exit()
-        print '++OK++'
-        return res
-    return __wrapp
-
-
-def create_test_user(force=True):
-    print '\tcreating test user'
-
-    user = User.get_by_username(USER)
-
-    if force and user is not None:
-        print '\tremoving current user'
-        for repo in Repository.query().filter(Repository.user == user).all():
-            sa.delete(repo)
-        sa.delete(user)
-        sa.commit()
-
-    if user is None or force:
-        print '\tcreating new one'
-        new_usr = User()
-        new_usr.username = USER
-        new_usr.password = get_crypt_password(PASS)
-        new_usr.email = 'mail@mail.com'
-        new_usr.name = 'test'
-        new_usr.lastname = 'lasttestname'
-        new_usr.active = True
-        new_usr.admin = True
-        sa.add(new_usr)
-        sa.commit()
-
-    print '\tdone'
-
-
-def create_test_repo(force=True):
-    from rhodecode.model.repo import RepoModel
-
-    user = User.get_by_username(USER)
-    if user is None:
-        raise Exception('user not found')
-
-
-    repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
-
-    if repo is None:
-        print '\trepo not found creating'
-
-        form_data = {'repo_name':HG_REPO,
-                     'repo_type':'hg',
-                     'private':False,
-                     'clone_uri':'' }
-        rm = RepoModel(sa)
-        rm.base_path = '/home/hg'
-        rm.create(form_data, user)
-
-
-def set_anonymous_access(enable=True):
-    user = User.get_by_username('default')
-    user.active = enable
-    sa.add(user)
-    sa.commit()
-    print '\tanonymous access is now:', enable
-    if enable != User.get_by_username('default').active:
-        raise Exception('Cannot set anonymous access')
-
-def get_anonymous_access():
-    user = User.get_by_username('default')
-    return user.active
-
-
-#==============================================================================
-# TESTS
-#==============================================================================
-@test_wrapp
-def test_clone_with_credentials(no_errors=False):
-    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
-
-    try:
-        shutil.rmtree(path, ignore_errors=True)
-        os.makedirs(path)
-        #print 'made dirs %s' % jn(path)
-    except OSError:
-        raise
-
-    print '\tchecking if anonymous access is enabled'
-    anonymous_access = get_anonymous_access()
-    if anonymous_access:
-        print '\tenabled, disabling it '
-        set_anonymous_access(enable=False)
-
-    clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \
-                  {'user':USER,
-                   'pass':PASS,
-                   'host':HOST,
-                   'cloned_repo':HG_REPO,
-                   'dest':path}
-
-    stdout, stderr = Command(cwd).execute('hg clone', clone_url)
-
-    if no_errors is False:
-        assert """adding file changes""" in stdout, 'no messages about cloning'
-        assert """abort""" not in stderr , 'got error from clone'
-
-
-@test_wrapp
-def test_clone_anonymous():
-    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
-
-    try:
-        shutil.rmtree(path, ignore_errors=True)
-        os.makedirs(path)
-        #print 'made dirs %s' % jn(path)
-    except OSError:
-        raise
-
-
-    print '\tchecking if anonymous access is enabled'
-    anonymous_access = get_anonymous_access()
-    if not anonymous_access:
-        print '\tnot enabled, enabling it '
-        set_anonymous_access(enable=True)
-
-    clone_url = 'http://%(host)s/%(cloned_repo)s %(dest)s' % \
-                  {'user':USER,
-                   'pass':PASS,
-                   'host':HOST,
-                   'cloned_repo':HG_REPO,
-                   'dest':path}
-
-    stdout, stderr = Command(cwd).execute('hg clone', clone_url)
-
-    assert """adding file changes""" in stdout, 'no messages about cloning'
-    assert """abort""" not in stderr , 'got error from clone'
-
-    #disable if it was enabled
-    if not anonymous_access:
-        print '\tdisabling anonymous access'
-        set_anonymous_access(enable=False)
-
-@test_wrapp
-def test_clone_wrong_credentials():
-    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
-
-    try:
-        shutil.rmtree(path, ignore_errors=True)
-        os.makedirs(path)
-        #print 'made dirs %s' % jn(path)
-    except OSError:
-        raise
-
-    print '\tchecking if anonymous access is enabled'
-    anonymous_access = get_anonymous_access()
-    if anonymous_access:
-        print '\tenabled, disabling it '
-        set_anonymous_access(enable=False)
-
-    clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s %(dest)s' % \
-                  {'user':USER + 'error',
-                   'pass':PASS,
-                   'host':HOST,
-                   'cloned_repo':HG_REPO,
-                   'dest':path}
-
-    stdout, stderr = Command(cwd).execute('hg clone', clone_url)
-
-    if not """abort: authorization failed"""  in stderr:
-        raise Exception('Failure')
-
-@test_wrapp
-def test_pull():
-    pass
-
-@test_wrapp
-def test_push_modify_file(f_name='setup.py'):
-    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
-    modified_file = jn(TESTS_TMP_PATH, HG_REPO, f_name)
-    for i in xrange(5):
-        cmd = """echo 'added_line%s' >> %s""" % (i, modified_file)
-        Command(cwd).execute(cmd)
-
-        cmd = """hg ci -m 'changed file %s' %s """ % (i, modified_file)
-        Command(cwd).execute(cmd)
-
-    Command(cwd).execute('hg push %s' % jn(TESTS_TMP_PATH, HG_REPO))
-
-@test_wrapp
-def test_push_new_file(commits=15, with_clone=True):
-
-    if with_clone:
-        test_clone_with_credentials(no_errors=True)
-
-    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
-    added_file = jn(path, '%ssetupążźć.py' % _RandomNameSequence().next())
-
-    Command(cwd).execute('touch %s' % added_file)
-
-    Command(cwd).execute('hg add %s' % added_file)
-
-    for i in xrange(commits):
-        cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
-        Command(cwd).execute(cmd)
-
-        cmd = """hg ci -m 'commited new %s' -u '%s' %s """ % (i,
-                                'Marcin Kuźminski <marcin@python-blog.com>',
-                                added_file)
-        Command(cwd).execute(cmd)
-
-    push_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
-                  {'user':USER,
-                   'pass':PASS,
-                   'host':HOST,
-                   'cloned_repo':HG_REPO,
-                   'dest':jn(TESTS_TMP_PATH, HG_REPO)}
-
-    Command(cwd).execute('hg push --verbose --debug %s' % push_url)
-
-@test_wrapp
-def test_push_wrong_credentials():
-    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
-    clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
-                  {'user':USER + 'xxx',
-                   'pass':PASS,
-                   'host':HOST,
-                   'cloned_repo':HG_REPO,
-                   'dest':jn(TESTS_TMP_PATH, HG_REPO)}
-
-    modified_file = jn(TESTS_TMP_PATH, HG_REPO, 'setup.py')
-    for i in xrange(5):
-        cmd = """echo 'added_line%s' >> %s""" % (i, modified_file)
-        Command(cwd).execute(cmd)
-
-        cmd = """hg ci -m 'commited %s' %s """ % (i, modified_file)
-        Command(cwd).execute(cmd)
-
-    Command(cwd).execute('hg push %s' % clone_url)
-
-@test_wrapp
-def test_push_wrong_path():
-    cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
-    added_file = jn(path, 'somefile.py')
-
-    try:
-        shutil.rmtree(path, ignore_errors=True)
-        os.makedirs(path)
-        print '\tmade dirs %s' % jn(path)
-    except OSError:
-        raise
-
-    Command(cwd).execute("""echo '' > %s""" % added_file)
-    Command(cwd).execute("""hg init %s""" % path)
-    Command(cwd).execute("""hg add %s""" % added_file)
-
-    for i in xrange(2):
-        cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
-        Command(cwd).execute(cmd)
-
-        cmd = """hg ci -m 'commited new %s' %s """ % (i, added_file)
-        Command(cwd).execute(cmd)
-
-    clone_url = 'http://%(user)s:%(pass)s@%(host)s/%(cloned_repo)s' % \
-                  {'user':USER,
-                   'pass':PASS,
-                   'host':HOST,
-                   'cloned_repo':HG_REPO + '_error',
-                   'dest':jn(TESTS_TMP_PATH, HG_REPO)}
-
-    stdout, stderr = Command(cwd).execute('hg push %s' % clone_url)
-    if not """abort: HTTP Error 403: Forbidden"""  in stderr:
-        raise Exception('Failure')
-
-@test_wrapp
-def get_logs():
-    return UserLog.query().all()
-
-@test_wrapp
-def test_logs(initial):
-    logs = UserLog.query().all()
-    operations = 4
-    if len(initial) + operations != len(logs):
-        raise Exception("missing number of logs initial:%s vs current:%s" % \
-                            (len(initial), len(logs)))
-
-
-if __name__ == '__main__':
-    create_test_user(force=False)
-    create_test_repo()
-
-    initial_logs = get_logs()
-    print 'initial activity logs: %s' % len(initial_logs)
-    s = time.time()
-    #test_push_modify_file()
-    test_clone_with_credentials()
-    test_clone_wrong_credentials()
-
-    test_push_new_file(commits=2, with_clone=True)
-
-    test_clone_anonymous()
-    test_push_wrong_path()
-
-    test_push_wrong_credentials()
-
-    test_logs(initial_logs)
-    print 'finished ok in %.3f' % (time.time() - s)
--- a/rhodecode/tests/test_libs.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/tests/test_libs.py	Sun Sep 02 21:19:54 2012 +0200
@@ -23,9 +23,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-
-
 import unittest
+import datetime
+import hashlib
+import mock
 from rhodecode.tests import *
 
 proto = 'http'
@@ -116,3 +117,61 @@
         'marian.user', 'marco-polo', 'marco_polo'
         ], key=lambda k: k.lower())
         self.assertEqual(s, extract_mentioned_users(sample))
+
+    def test_age(self):
+        import calendar
+        from rhodecode.lib.utils2 import age
+        n = datetime.datetime.now()
+        delt = lambda *args, **kwargs: datetime.timedelta(*args, **kwargs)
+        self.assertEqual(age(n), u'just now')
+        self.assertEqual(age(n - delt(seconds=1)), u'1 second ago')
+        self.assertEqual(age(n - delt(seconds=60 * 2)), u'2 minutes ago')
+        self.assertEqual(age(n - delt(hours=1)), u'1 hour ago')
+        self.assertEqual(age(n - delt(hours=24)), u'1 day ago')
+        self.assertEqual(age(n - delt(hours=24 * 5)), u'5 days ago')
+        self.assertEqual(age(n - delt(hours=24 * (calendar.mdays[n.month-1] + 2))),
+                         u'1 month and 2 days ago')
+        self.assertEqual(age(n - delt(hours=24 * 400)), u'1 year and 1 month ago')
+
+    def test_tag_exctrator(self):
+        sample = (
+            "hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
+            "[requires] [stale] [see<>=>] [see => http://url.com]"
+            "[requires => url] [lang => python] [just a tag]"
+            "[,d] [ => ULR ] [obsolete] [desc]]"
+        )
+        from rhodecode.lib.helpers import desc_stylize
+        res = desc_stylize(sample)
+        self.assertTrue('<div class="metatag" tag="tag">tag</div>' in res)
+        self.assertTrue('<div class="metatag" tag="obsolete">obsolete</div>' in res)
+        self.assertTrue('<div class="metatag" tag="stale">stale</div>' in res)
+        self.assertTrue('<div class="metatag" tag="lang">python</div>' in res)
+        self.assertTrue('<div class="metatag" tag="requires">requires =&gt; <a href="/url">url</a></div>' in res)
+        self.assertTrue('<div class="metatag" tag="tag">tag</div>' in res)
+
+    def test_alternative_gravatar(self):
+        from rhodecode.lib.helpers import gravatar_url
+        _md5 = lambda s: hashlib.md5(s).hexdigest()
+
+        def fake_conf(**kwargs):
+            from pylons import config
+            config['app_conf'] = {}
+            config['app_conf']['use_gravatar'] = True
+            config['app_conf'].update(kwargs)
+            return config
+        fake = fake_conf(alternative_gravatar_url='http://test.com/{email}')
+        with mock.patch('pylons.config', fake):
+            grav = gravatar_url(email_address='test@foo.com', size=24)
+            assert grav == 'http://test.com/test@foo.com'
+
+        fake = fake_conf(alternative_gravatar_url='http://test.com/{md5email}')
+        with mock.patch('pylons.config', fake):
+            em = 'test@foo.com'
+            grav = gravatar_url(email_address=em, size=24)
+            assert grav == 'http://test.com/%s' % (_md5(em))
+
+        fake = fake_conf(alternative_gravatar_url='http://test.com/{md5email}/{size}')
+        with mock.patch('pylons.config', fake):
+            em = 'test@foo.com'
+            grav = gravatar_url(email_address=em, size=24)
+            assert grav == 'http://test.com/%s/%s' % (_md5(em), 24)
--- a/rhodecode/tests/test_models.py	Sat May 19 14:54:50 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,715 +0,0 @@
-import os
-import unittest
-from rhodecode.tests import *
-
-from rhodecode.model.repos_group import ReposGroupModel
-from rhodecode.model.repo import RepoModel
-from rhodecode.model.db import RepoGroup, User, Notification, UserNotification, \
-    UsersGroup, UsersGroupMember, Permission, UsersGroupRepoGroupToPerm,\
-    Repository
-from sqlalchemy.exc import IntegrityError
-from rhodecode.model.user import UserModel
-
-from rhodecode.model.meta import Session
-from rhodecode.model.notification import NotificationModel
-from rhodecode.model.users_group import UsersGroupModel
-from rhodecode.lib.auth import AuthUser
-
-
-def _make_group(path, desc='desc', parent_id=None,
-                 skip_if_exists=False):
-
-    gr = RepoGroup.get_by_group_name(path)
-    if gr and skip_if_exists:
-        return gr
-
-    gr = ReposGroupModel().create(path, desc, parent_id)
-    return gr
-
-
-class TestReposGroups(unittest.TestCase):
-
-    def setUp(self):
-        self.g1 = _make_group('test1', skip_if_exists=True)
-        Session.commit()
-        self.g2 = _make_group('test2', skip_if_exists=True)
-        Session.commit()
-        self.g3 = _make_group('test3', skip_if_exists=True)
-        Session.commit()
-
-    def tearDown(self):
-        print 'out'
-
-    def __check_path(self, *path):
-        """
-        Checks the path for existance !
-        """
-        path = [TESTS_TMP_PATH] + list(path)
-        path = os.path.join(*path)
-        return os.path.isdir(path)
-
-    def _check_folders(self):
-        print os.listdir(TESTS_TMP_PATH)
-
-    def __delete_group(self, id_):
-        ReposGroupModel().delete(id_)
-
-    def __update_group(self, id_, path, desc='desc', parent_id=None):
-        form_data = dict(
-            group_name=path,
-            group_description=desc,
-            group_parent_id=parent_id,
-            perms_updates=[],
-            perms_new=[]
-        )
-        gr = ReposGroupModel().update(id_, form_data)
-        return gr
-
-    def test_create_group(self):
-        g = _make_group('newGroup')
-        self.assertEqual(g.full_path, 'newGroup')
-
-        self.assertTrue(self.__check_path('newGroup'))
-
-    def test_create_same_name_group(self):
-        self.assertRaises(IntegrityError, lambda:_make_group('newGroup'))
-        Session.rollback()
-
-    def test_same_subgroup(self):
-        sg1 = _make_group('sub1', parent_id=self.g1.group_id)
-        self.assertEqual(sg1.parent_group, self.g1)
-        self.assertEqual(sg1.full_path, 'test1/sub1')
-        self.assertTrue(self.__check_path('test1', 'sub1'))
-
-        ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
-        self.assertEqual(ssg1.parent_group, sg1)
-        self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
-        self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
-
-    def test_remove_group(self):
-        sg1 = _make_group('deleteme')
-        self.__delete_group(sg1.group_id)
-
-        self.assertEqual(RepoGroup.get(sg1.group_id), None)
-        self.assertFalse(self.__check_path('deteteme'))
-
-        sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
-        self.__delete_group(sg1.group_id)
-
-        self.assertEqual(RepoGroup.get(sg1.group_id), None)
-        self.assertFalse(self.__check_path('test1', 'deteteme'))
-
-    def test_rename_single_group(self):
-        sg1 = _make_group('initial')
-
-        new_sg1 = self.__update_group(sg1.group_id, 'after')
-        self.assertTrue(self.__check_path('after'))
-        self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
-
-    def test_update_group_parent(self):
-
-        sg1 = _make_group('initial', parent_id=self.g1.group_id)
-
-        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
-        self.assertTrue(self.__check_path('test1', 'after'))
-        self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
-
-        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
-        self.assertTrue(self.__check_path('test3', 'after'))
-        self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
-
-        new_sg1 = self.__update_group(sg1.group_id, 'hello')
-        self.assertTrue(self.__check_path('hello'))
-
-        self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
-
-    def test_subgrouping_with_repo(self):
-
-        g1 = _make_group('g1')
-        g2 = _make_group('g2')
-
-        # create new repo
-        form_data = dict(repo_name='john',
-                         repo_name_full='john',
-                         fork_name=None,
-                         description=None,
-                         repo_group=None,
-                         private=False,
-                         repo_type='hg',
-                         clone_uri=None)
-        cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
-        r = RepoModel().create(form_data, cur_user)
-
-        self.assertEqual(r.repo_name, 'john')
-
-        # put repo into group
-        form_data = form_data
-        form_data['repo_group'] = g1.group_id
-        form_data['perms_new'] = []
-        form_data['perms_updates'] = []
-        RepoModel().update(r.repo_name, form_data)
-        self.assertEqual(r.repo_name, 'g1/john')
-
-        self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
-        self.assertTrue(self.__check_path('g2', 'g1'))
-
-        # test repo
-        self.assertEqual(r.repo_name, RepoGroup.url_sep().join(['g2', 'g1', r.just_name]))
-
-    def test_move_to_root(self):
-        g1 = _make_group('t11')
-        Session.commit()
-        g2 = _make_group('t22', parent_id=g1.group_id)
-        Session.commit()
-
-        self.assertEqual(g2.full_path, 't11/t22')
-        self.assertTrue(self.__check_path('t11', 't22'))
-
-        g2 = self.__update_group(g2.group_id, 'g22', parent_id=None)
-        Session.commit()
-
-        self.assertEqual(g2.group_name, 'g22')
-        # we moved out group from t1 to '' so it's full path should be 'g2'
-        self.assertEqual(g2.full_path, 'g22')
-        self.assertFalse(self.__check_path('t11', 't22'))
-        self.assertTrue(self.__check_path('g22'))
-
-
-class TestUser(unittest.TestCase):
-    def __init__(self, methodName='runTest'):
-        Session.remove()
-        super(TestUser, self).__init__(methodName=methodName)
-
-    def test_create_and_remove(self):
-        usr = UserModel().create_or_update(username=u'test_user', password=u'qweqwe',
-                                     email=u'u232@rhodecode.org',
-                                     name=u'u1', lastname=u'u1')
-        Session.commit()
-        self.assertEqual(User.get_by_username(u'test_user'), usr)
-
-        # make users group
-        users_group = UsersGroupModel().create('some_example_group')
-        Session.commit()
-
-        UsersGroupModel().add_user_to_group(users_group, usr)
-        Session.commit()
-
-        self.assertEqual(UsersGroup.get(users_group.users_group_id), users_group)
-        self.assertEqual(UsersGroupMember.query().count(), 1)
-        UserModel().delete(usr.user_id)
-        Session.commit()
-
-        self.assertEqual(UsersGroupMember.query().all(), [])
-
-
-class TestNotifications(unittest.TestCase):
-
-    def __init__(self, methodName='runTest'):
-        Session.remove()
-        self.u1 = UserModel().create_or_update(username=u'u1',
-                                        password=u'qweqwe',
-                                        email=u'u1@rhodecode.org',
-                                        name=u'u1', lastname=u'u1')
-        Session.commit()
-        self.u1 = self.u1.user_id
-
-        self.u2 = UserModel().create_or_update(username=u'u2',
-                                        password=u'qweqwe',
-                                        email=u'u2@rhodecode.org',
-                                        name=u'u2', lastname=u'u3')
-        Session.commit()
-        self.u2 = self.u2.user_id
-
-        self.u3 = UserModel().create_or_update(username=u'u3',
-                                        password=u'qweqwe',
-                                        email=u'u3@rhodecode.org',
-                                        name=u'u3', lastname=u'u3')
-        Session.commit()
-        self.u3 = self.u3.user_id
-
-        super(TestNotifications, self).__init__(methodName=methodName)
-
-    def _clean_notifications(self):
-        for n in Notification.query().all():
-            Session.delete(n)
-
-        Session.commit()
-        self.assertEqual(Notification.query().all(), [])
-
-    def tearDown(self):
-        self._clean_notifications()
-
-    def test_create_notification(self):
-        self.assertEqual([], Notification.query().all())
-        self.assertEqual([], UserNotification.query().all())
-
-        usrs = [self.u1, self.u2]
-        notification = NotificationModel().create(created_by=self.u1,
-                                           subject=u'subj', body=u'hi there',
-                                           recipients=usrs)
-        Session.commit()
-        u1 = User.get(self.u1)
-        u2 = User.get(self.u2)
-        u3 = User.get(self.u3)
-        notifications = Notification.query().all()
-        self.assertEqual(len(notifications), 1)
-
-        unotification = UserNotification.query()\
-            .filter(UserNotification.notification == notification).all()
-
-        self.assertEqual(notifications[0].recipients, [u1, u2])
-        self.assertEqual(notification.notification_id,
-                         notifications[0].notification_id)
-        self.assertEqual(len(unotification), len(usrs))
-        self.assertEqual([x.user.user_id for x in unotification], usrs)
-
-    def test_user_notifications(self):
-        self.assertEqual([], Notification.query().all())
-        self.assertEqual([], UserNotification.query().all())
-
-        notification1 = NotificationModel().create(created_by=self.u1,
-                                            subject=u'subj', body=u'hi there1',
-                                            recipients=[self.u3])
-        Session.commit()
-        notification2 = NotificationModel().create(created_by=self.u1,
-                                            subject=u'subj', body=u'hi there2',
-                                            recipients=[self.u3])
-        Session.commit()
-        u3 = Session.query(User).get(self.u3)
-
-        self.assertEqual(sorted([x.notification for x in u3.notifications]),
-                         sorted([notification2, notification1]))
-
-    def test_delete_notifications(self):
-        self.assertEqual([], Notification.query().all())
-        self.assertEqual([], UserNotification.query().all())
-
-        notification = NotificationModel().create(created_by=self.u1,
-                                           subject=u'title', body=u'hi there3',
-                                    recipients=[self.u3, self.u1, self.u2])
-        Session.commit()
-        notifications = Notification.query().all()
-        self.assertTrue(notification in notifications)
-
-        Notification.delete(notification.notification_id)
-        Session.commit()
-
-        notifications = Notification.query().all()
-        self.assertFalse(notification in notifications)
-
-        un = UserNotification.query().filter(UserNotification.notification
-                                             == notification).all()
-        self.assertEqual(un, [])
-
-    def test_delete_association(self):
-
-        self.assertEqual([], Notification.query().all())
-        self.assertEqual([], UserNotification.query().all())
-
-        notification = NotificationModel().create(created_by=self.u1,
-                                           subject=u'title', body=u'hi there3',
-                                    recipients=[self.u3, self.u1, self.u2])
-        Session.commit()
-
-        unotification = UserNotification.query()\
-                            .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u3)\
-                            .scalar()
-
-        self.assertEqual(unotification.user_id, self.u3)
-
-        NotificationModel().delete(self.u3,
-                                   notification.notification_id)
-        Session.commit()
-
-        u3notification = UserNotification.query()\
-                            .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u3)\
-                            .scalar()
-
-        self.assertEqual(u3notification, None)
-
-        # notification object is still there
-        self.assertEqual(Notification.query().all(), [notification])
-
-        #u1 and u2 still have assignments
-        u1notification = UserNotification.query()\
-                            .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u1)\
-                            .scalar()
-        self.assertNotEqual(u1notification, None)
-        u2notification = UserNotification.query()\
-                            .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u2)\
-                            .scalar()
-        self.assertNotEqual(u2notification, None)
-
-    def test_notification_counter(self):
-        self._clean_notifications()
-        self.assertEqual([], Notification.query().all())
-        self.assertEqual([], UserNotification.query().all())
-
-        NotificationModel().create(created_by=self.u1,
-                            subject=u'title', body=u'hi there_delete',
-                            recipients=[self.u3, self.u1])
-        Session.commit()
-
-        self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u1), 1)
-        self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u2), 0)
-        self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u3), 1)
-
-        notification = NotificationModel().create(created_by=self.u1,
-                                           subject=u'title', body=u'hi there3',
-                                    recipients=[self.u3, self.u1, self.u2])
-        Session.commit()
-
-        self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u1), 2)
-        self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u2), 1)
-        self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u3), 2)
-
-
-class TestUsers(unittest.TestCase):
-
-    def __init__(self, methodName='runTest'):
-        super(TestUsers, self).__init__(methodName=methodName)
-
-    def setUp(self):
-        self.u1 = UserModel().create_or_update(username=u'u1',
-                                        password=u'qweqwe',
-                                        email=u'u1@rhodecode.org',
-                                        name=u'u1', lastname=u'u1')
-
-    def tearDown(self):
-        perm = Permission.query().all()
-        for p in perm:
-            UserModel().revoke_perm(self.u1, p)
-
-        UserModel().delete(self.u1)
-        Session.commit()
-
-    def test_add_perm(self):
-        perm = Permission.query().all()[0]
-        UserModel().grant_perm(self.u1, perm)
-        Session.commit()
-        self.assertEqual(UserModel().has_perm(self.u1, perm), True)
-
-    def test_has_perm(self):
-        perm = Permission.query().all()
-        for p in perm:
-            has_p = UserModel().has_perm(self.u1, p)
-            self.assertEqual(False, has_p)
-
-    def test_revoke_perm(self):
-        perm = Permission.query().all()[0]
-        UserModel().grant_perm(self.u1, perm)
-        Session.commit()
-        self.assertEqual(UserModel().has_perm(self.u1, perm), True)
-
-        #revoke
-        UserModel().revoke_perm(self.u1, perm)
-        Session.commit()
-        self.assertEqual(UserModel().has_perm(self.u1, perm), False)
-
-
-class TestPermissions(unittest.TestCase):
-    def __init__(self, methodName='runTest'):
-        super(TestPermissions, self).__init__(methodName=methodName)
-
-    def setUp(self):
-        self.u1 = UserModel().create_or_update(
-            username=u'u1', password=u'qweqwe',
-            email=u'u1@rhodecode.org', name=u'u1', lastname=u'u1'
-        )
-        self.u2 = UserModel().create_or_update(
-            username=u'u2', password=u'qweqwe',
-            email=u'u2@rhodecode.org', name=u'u2', lastname=u'u2'
-        )
-        self.anon = User.get_by_username('default')
-        self.a1 = UserModel().create_or_update(
-            username=u'a1', password=u'qweqwe',
-            email=u'a1@rhodecode.org', name=u'a1', lastname=u'a1', admin=True
-        )
-        Session.commit()
-
-    def tearDown(self):
-        if hasattr(self, 'test_repo'):
-            RepoModel().delete(repo=self.test_repo)
-        UserModel().delete(self.u1)
-        UserModel().delete(self.u2)
-        UserModel().delete(self.a1)
-        if hasattr(self, 'g1'):
-            ReposGroupModel().delete(self.g1.group_id)
-        if hasattr(self, 'g2'):
-            ReposGroupModel().delete(self.g2.group_id)
-
-        if hasattr(self, 'ug1'):
-            UsersGroupModel().delete(self.ug1, force=True)
-
-        Session.commit()
-
-    def test_default_perms_set(self):
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        perms = {
-            'repositories_groups': {},
-            'global': set([u'hg.create.repository', u'repository.read',
-                           u'hg.register.manual_activate']),
-            'repositories': {u'vcs_test_hg': u'repository.read'}
-        }
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
-                         perms['repositories'][HG_REPO])
-        new_perm = 'repository.write'
-        RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
-        Session.commit()
-
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], new_perm)
-
-    def test_default_admin_perms_set(self):
-        a1_auth = AuthUser(user_id=self.a1.user_id)
-        perms = {
-            'repositories_groups': {},
-            'global': set([u'hg.admin']),
-            'repositories': {u'vcs_test_hg': u'repository.admin'}
-        }
-        self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
-                         perms['repositories'][HG_REPO])
-        new_perm = 'repository.write'
-        RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1, perm=new_perm)
-        Session.commit()
-        # cannot really downgrade admins permissions !? they still get's set as
-        # admin !
-        u1_auth = AuthUser(user_id=self.a1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
-                         perms['repositories'][HG_REPO])
-
-    def test_default_group_perms(self):
-        self.g1 = _make_group('test1', skip_if_exists=True)
-        self.g2 = _make_group('test2', skip_if_exists=True)
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        perms = {
-            'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
-            'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
-            'repositories': {u'vcs_test_hg': u'repository.read'}
-        }
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
-                         perms['repositories'][HG_REPO])
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                         perms['repositories_groups'])
-
-    def test_default_admin_group_perms(self):
-        self.g1 = _make_group('test1', skip_if_exists=True)
-        self.g2 = _make_group('test2', skip_if_exists=True)
-        a1_auth = AuthUser(user_id=self.a1.user_id)
-        perms = {
-            'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
-            'global': set(['hg.admin']),
-            'repositories': {u'vcs_test_hg': 'repository.admin'}
-        }
-
-        self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
-                         perms['repositories'][HG_REPO])
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                         perms['repositories_groups'])
-
-    def test_propagated_permission_from_users_group(self):
-        # make group
-        self.ug1 = UsersGroupModel().create('G1')
-        # add user to group
-        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
-
-        # set permission to lower
-        new_perm = 'repository.none'
-        RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
-        Session.commit()
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
-                         new_perm)
-
-        # grant perm for group this should override permission from user
-        new_perm = 'repository.write'
-        RepoModel().grant_users_group_permission(repo=HG_REPO,
-                                                 group_name=self.ug1,
-                                                 perm=new_perm)
-        # check perms
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        perms = {
-            'repositories_groups': {},
-            'global': set([u'hg.create.repository', u'repository.read',
-                           u'hg.register.manual_activate']),
-            'repositories': {u'vcs_test_hg': u'repository.read'}
-        }
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
-                         new_perm)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                         perms['repositories_groups'])
-
-    def test_propagated_permission_from_users_group_lower_weight(self):
-        # make group
-        self.ug1 = UsersGroupModel().create('G1')
-        # add user to group
-        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
-
-        # set permission to lower
-        new_perm_h = 'repository.write'
-        RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
-                                          perm=new_perm_h)
-        Session.commit()
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
-                         new_perm_h)
-
-        # grant perm for group this should NOT override permission from user
-        # since it's lower than granted
-        new_perm_l = 'repository.read'
-        RepoModel().grant_users_group_permission(repo=HG_REPO,
-                                                 group_name=self.ug1,
-                                                 perm=new_perm_l)
-        # check perms
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        perms = {
-            'repositories_groups': {},
-            'global': set([u'hg.create.repository', u'repository.read',
-                           u'hg.register.manual_activate']),
-            'repositories': {u'vcs_test_hg': u'repository.write'}
-        }
-        self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
-                         new_perm_h)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                         perms['repositories_groups'])
-
-    def test_repo_in_group_permissions(self):
-        self.g1 = _make_group('group1', skip_if_exists=True)
-        self.g2 = _make_group('group2', skip_if_exists=True)
-        Session.commit()
-        # both perms should be read !
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                         {u'group1': u'group.read', u'group2': u'group.read'})
-
-        a1_auth = AuthUser(user_id=self.anon.user_id)
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.read', u'group2': u'group.read'})
-
-        #Change perms to none for both groups
-        ReposGroupModel().grant_user_permission(repos_group=self.g1,
-                                                user=self.anon,
-                                                perm='group.none')
-        ReposGroupModel().grant_user_permission(repos_group=self.g2,
-                                                user=self.anon,
-                                                perm='group.none')
-
-
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.none', u'group2': u'group.none'})
-
-        a1_auth = AuthUser(user_id=self.anon.user_id)
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.none', u'group2': u'group.none'})
-
-        # add repo to group
-        form_data = {
-            'repo_name':HG_REPO,
-            'repo_name_full':RepoGroup.url_sep().join([self.g1.group_name,HG_REPO]),
-            'repo_type':'hg',
-            'clone_uri':'',
-            'repo_group':self.g1.group_id,
-            'description':'desc',
-            'private':False
-        }
-        self.test_repo = RepoModel().create(form_data, cur_user=self.u1)
-        Session.commit()
-
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.none', u'group2': u'group.none'})
-
-        a1_auth = AuthUser(user_id=self.anon.user_id)
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.none', u'group2': u'group.none'})
-
-        #grant permission for u2 !
-        ReposGroupModel().grant_user_permission(repos_group=self.g1,
-                                                user=self.u2,
-                                                perm='group.read')
-        ReposGroupModel().grant_user_permission(repos_group=self.g2,
-                                                user=self.u2,
-                                                perm='group.read')
-        Session.commit()
-        self.assertNotEqual(self.u1, self.u2)
-        #u1 and anon should have not change perms while u2 should !
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.none', u'group2': u'group.none'})
-
-        u2_auth = AuthUser(user_id=self.u2.user_id)
-        self.assertEqual(u2_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.read', u'group2': u'group.read'})
-
-        a1_auth = AuthUser(user_id=self.anon.user_id)
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                 {u'group1': u'group.none', u'group2': u'group.none'})
-
-    def test_repo_group_user_as_user_group_member(self):
-        # create Group1
-        self.g1 = _make_group('group1', skip_if_exists=True)
-        Session.commit()
-        a1_auth = AuthUser(user_id=self.anon.user_id)
-
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                         {u'group1': u'group.read'})
-
-        # set default permission to none
-        ReposGroupModel().grant_user_permission(repos_group=self.g1,
-                                                user=self.anon,
-                                                perm='group.none')
-        # make group
-        self.ug1 = UsersGroupModel().create('G1')
-        # add user to group
-        UsersGroupModel().add_user_to_group(self.ug1, self.u1)
-        Session.commit()
-
-        # check if user is in the group
-        membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members]
-        self.assertEqual(membrs, [self.u1.user_id])
-        # add some user to that group
-
-        # check his permissions
-        a1_auth = AuthUser(user_id=self.anon.user_id)
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                         {u'group1': u'group.none'})
-
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                         {u'group1': u'group.none'})
-
-        # grant ug1 read permissions for
-        ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
-                                                       group_name=self.ug1,
-                                                       perm='group.read')
-        Session.commit()
-        # check if the
-        obj = Session.query(UsersGroupRepoGroupToPerm)\
-            .filter(UsersGroupRepoGroupToPerm.group == self.g1)\
-            .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\
-            .scalar()
-        self.assertEqual(obj.permission.permission_name, 'group.read')
-
-        a1_auth = AuthUser(user_id=self.anon.user_id)
-
-        self.assertEqual(a1_auth.permissions['repositories_groups'],
-                         {u'group1': u'group.none'})
-
-        u1_auth = AuthUser(user_id=self.u1.user_id)
-        self.assertEqual(u1_auth.permissions['repositories_groups'],
-                         {u'group1': u'group.read'})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/test_validators.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,246 @@
+# -*- coding: utf-8 -*-
+import unittest
+import formencode
+
+from rhodecode.tests import *
+
+from rhodecode.model import validators as v
+from rhodecode.model.users_group import UsersGroupModel
+
+from rhodecode.model.meta import Session
+from rhodecode.model.repos_group import ReposGroupModel
+from rhodecode.config.routing import ADMIN_PREFIX
+from rhodecode.model.db import ChangesetStatus
+from rhodecode.model.changeset_status import ChangesetStatusModel
+from rhodecode.model.comment import ChangesetCommentsModel
+
+
+class TestReposGroups(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_Message_extractor(self):
+        validator = v.ValidUsername()
+        self.assertRaises(formencode.Invalid, validator.to_python, 'default')
+
+        class StateObj(object):
+            pass
+
+        self.assertRaises(formencode.Invalid,
+                          validator.to_python, 'default', StateObj)
+
+    def test_ValidUsername(self):
+        validator = v.ValidUsername()
+
+        self.assertRaises(formencode.Invalid, validator.to_python, 'default')
+        self.assertRaises(formencode.Invalid, validator.to_python, 'new_user')
+        self.assertRaises(formencode.Invalid, validator.to_python, '.,')
+        self.assertRaises(formencode.Invalid, validator.to_python,
+                          TEST_USER_ADMIN_LOGIN)
+        self.assertEqual('test', validator.to_python('test'))
+
+        validator = v.ValidUsername(edit=True, old_data={'user_id': 1})
+
+    def test_ValidRepoUser(self):
+        validator = v.ValidRepoUser()
+        self.assertRaises(formencode.Invalid, validator.to_python, 'nouser')
+        self.assertEqual(TEST_USER_ADMIN_LOGIN,
+                         validator.to_python(TEST_USER_ADMIN_LOGIN))
+
+    def test_ValidUsersGroup(self):
+        validator = v.ValidUsersGroup()
+        self.assertRaises(formencode.Invalid, validator.to_python, 'default')
+        self.assertRaises(formencode.Invalid, validator.to_python, '.,')
+
+        gr = UsersGroupModel().create('test')
+        gr2 = UsersGroupModel().create('tes2')
+        Session.commit()
+        self.assertRaises(formencode.Invalid, validator.to_python, 'test')
+        assert gr.users_group_id != None
+        validator = v.ValidUsersGroup(edit=True,
+                                    old_data={'users_group_id':
+                                              gr2.users_group_id})
+
+        self.assertRaises(formencode.Invalid, validator.to_python, 'test')
+        self.assertRaises(formencode.Invalid, validator.to_python, 'TesT')
+        self.assertRaises(formencode.Invalid, validator.to_python, 'TEST')
+        UsersGroupModel().delete(gr)
+        UsersGroupModel().delete(gr2)
+        Session.commit()
+
+    def test_ValidReposGroup(self):
+        validator = v.ValidReposGroup()
+        model = ReposGroupModel()
+        self.assertRaises(formencode.Invalid, validator.to_python,
+                          {'group_name': HG_REPO, })
+        gr = model.create(group_name='test_gr', group_description='desc',
+                          parent=None,
+                          just_db=True)
+        self.assertRaises(formencode.Invalid,
+                          validator.to_python, {'group_name': gr.group_name, })
+
+        validator = v.ValidReposGroup(edit=True,
+                                      old_data={'group_id':  gr.group_id})
+        self.assertRaises(formencode.Invalid,
+                          validator.to_python, {
+                                        'group_name': gr.group_name + 'n',
+                                        'group_parent_id': gr.group_id
+                                        })
+        model.delete(gr)
+
+    def test_ValidPassword(self):
+        validator = v.ValidPassword()
+        self.assertEqual('lol', validator.to_python('lol'))
+        self.assertEqual(None, validator.to_python(None))
+        self.assertRaises(formencode.Invalid, validator.to_python, 'ąćżź')
+
+    def test_ValidPasswordsMatch(self):
+        validator = v.ValidPasswordsMatch()
+        self.assertRaises(formencode.Invalid,
+                    validator.to_python, {'password': 'pass',
+                                          'password_confirmation': 'pass2'})
+
+        self.assertRaises(formencode.Invalid,
+                    validator.to_python, {'new_password': 'pass',
+                                          'password_confirmation': 'pass2'})
+
+        self.assertEqual({'new_password': 'pass',
+                          'password_confirmation': 'pass'},
+                    validator.to_python({'new_password': 'pass',
+                                         'password_confirmation': 'pass'}))
+
+        self.assertEqual({'password': 'pass',
+                          'password_confirmation': 'pass'},
+                    validator.to_python({'password': 'pass',
+                                         'password_confirmation': 'pass'}))
+
+    def test_ValidAuth(self):
+        validator = v.ValidAuth()
+        valid_creds = {
+            'username': TEST_USER_REGULAR2_LOGIN,
+            'password': TEST_USER_REGULAR2_PASS,
+        }
+        invalid_creds = {
+            'username': 'err',
+            'password': 'err',
+        }
+        self.assertEqual(valid_creds, validator.to_python(valid_creds))
+        self.assertRaises(formencode.Invalid,
+                          validator.to_python, invalid_creds)
+
+    def test_ValidAuthToken(self):
+        validator = v.ValidAuthToken()
+        # this is untestable without a threadlocal
+#        self.assertRaises(formencode.Invalid,
+#                          validator.to_python, 'BadToken')
+        validator
+
+    def test_ValidRepoName(self):
+        validator = v.ValidRepoName()
+
+        self.assertRaises(formencode.Invalid,
+                          validator.to_python, {'repo_name': ''})
+
+        self.assertRaises(formencode.Invalid,
+                          validator.to_python, {'repo_name': HG_REPO})
+
+        gr = ReposGroupModel().create(group_name='group_test',
+                                      group_description='desc',
+                                      parent=None,)
+        self.assertRaises(formencode.Invalid,
+                          validator.to_python, {'repo_name': gr.group_name})
+
+        #TODO: write an error case for that ie. create a repo withinh a group
+#        self.assertRaises(formencode.Invalid,
+#                          validator.to_python, {'repo_name': 'some',
+#                                                'repo_group': gr.group_id})
+
+    def test_ValidForkName(self):
+        # this uses ValidRepoName validator
+        assert True
+
+    @parameterized.expand([
+        ('test', 'test'), ('lolz!', 'lolz'), ('  aavv', 'aavv'),
+        ('ala ma kota', 'ala-ma-kota'), ('@nooo', 'nooo'),
+        ('$!haha lolz !', 'haha-lolz'), ('$$$$$', ''), ('{}OK!', 'OK'),
+        ('/]re po', 're-po')])
+    def test_SlugifyName(self, name, expected):
+        validator = v.SlugifyName()
+        self.assertEqual(expected, validator.to_python(name))
+
+    def test_ValidCloneUri(self):
+            #TODO: write this one
+            pass
+
+    def test_ValidForkType(self):
+            validator = v.ValidForkType(old_data={'repo_type': 'hg'})
+            self.assertEqual('hg', validator.to_python('hg'))
+            self.assertRaises(formencode.Invalid, validator.to_python, 'git')
+
+    def test_ValidPerms(self):
+            #TODO: write this one
+            pass
+
+    def test_ValidSettings(self):
+        validator = v.ValidSettings()
+        self.assertEqual({'pass': 'pass'},
+                         validator.to_python(value={'user': 'test',
+                                                    'pass': 'pass'}))
+
+        self.assertEqual({'user2': 'test', 'pass': 'pass'},
+                         validator.to_python(value={'user2': 'test',
+                                                    'pass': 'pass'}))
+
+    def test_ValidPath(self):
+            validator = v.ValidPath()
+            self.assertEqual(TESTS_TMP_PATH,
+                             validator.to_python(TESTS_TMP_PATH))
+            self.assertRaises(formencode.Invalid, validator.to_python,
+                              '/no_such_dir')
+
+    def test_UniqSystemEmail(self):
+        validator = v.UniqSystemEmail(old_data={})
+
+        self.assertEqual('mail@python.org',
+                         validator.to_python('MaiL@Python.org'))
+
+        email = TEST_USER_REGULAR2_EMAIL
+        self.assertRaises(formencode.Invalid, validator.to_python, email)
+
+    def test_ValidSystemEmail(self):
+        validator = v.ValidSystemEmail()
+        email = TEST_USER_REGULAR2_EMAIL
+
+        self.assertEqual(email, validator.to_python(email))
+        self.assertRaises(formencode.Invalid, validator.to_python, 'err')
+
+    def test_LdapLibValidator(self):
+        validator = v.LdapLibValidator()
+        self.assertRaises(v.LdapImportError, validator.to_python, 'err')
+
+    def test_AttrLoginValidator(self):
+        validator = v.AttrLoginValidator()
+        self.assertRaises(formencode.Invalid, validator.to_python, 123)
+
+    def test_NotReviewedRevisions(self):
+        validator = v.NotReviewedRevisions()
+        rev = '0' * 40
+        # add status for a rev, that should throw an error because it is already
+        # reviewed
+        new_status = ChangesetStatus()
+        new_status.author = ChangesetStatusModel()._get_user(TEST_USER_ADMIN_LOGIN)
+        new_status.repo = ChangesetStatusModel()._get_repo(HG_REPO)
+        new_status.status = ChangesetStatus.STATUS_APPROVED
+        new_status.comment = None
+        new_status.revision = rev
+        Session().add(new_status)
+        Session().commit()
+        try:
+            self.assertRaises(formencode.Invalid, validator.to_python, [rev])
+        finally:
+            Session().delete(new_status)
+            Session().commit()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/__init__.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,56 @@
+"""
+Unit tests for vcs_ library.
+
+In order to run tests we need to prepare our environment first. Tests would be
+run for each engine listed at ``conf.SCM_TESTS`` - keys are aliases from
+``vcs.backends.BACKENDS``.
+
+For each SCM we run tests for, we need some repository. We would use
+repositories location from system environment variables or test suite defaults
+- see ``conf`` module for more detail. We simply try to check if repository at
+certain location exists, if not we would try to fetch them. At ``test_vcs`` or
+``test_common`` we run unit tests common for each repository type and for
+example specific mercurial tests are located at ``test_hg`` module.
+
+Oh, and tests are run with ``unittest.collector`` wrapped by ``collector``
+function at ``tests/__init__.py``.
+
+.. _vcs: http://bitbucket.org/marcinkuzminski/vcs
+.. _unittest: http://pypi.python.org/pypi/unittest
+
+"""
+import os
+from rhodecode.lib import vcs
+from rhodecode.lib.vcs.utils.compat import unittest
+from utils import VCSTestError, SCMFetcher
+from rhodecode.tests import *
+
+
+def setup_package():
+    """
+    Prepares whole package for tests which mainly means it would try to fetch
+    test repositories or use already existing ones.
+    """
+    fetchers = {
+        'hg': {
+            'alias': 'hg',
+            'test_repo_path': TEST_HG_REPO,
+            'remote_repo': HG_REMOTE_REPO,
+            'clone_cmd': 'hg clone',
+        },
+        'git': {
+            'alias': 'git',
+            'test_repo_path': TEST_GIT_REPO,
+            'remote_repo': GIT_REMOTE_REPO,
+            'clone_cmd': 'git clone --bare',
+        },
+    }
+    try:
+        for scm, fetcher_info in fetchers.items():
+            fetcher = SCMFetcher(**fetcher_info)
+            fetcher.setup()
+    except VCSTestError, err:
+        raise RuntimeError(str(err))
+
+#start_dir = os.path.abspath(os.path.dirname(__file__))
+#unittest.defaultTestLoader.discover(start_dir)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/aconfig	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,10 @@
+[user]
+name = Foo Bar
+email = foo.bar@example.com
+
+[ui]
+username = Foo Bar foo.bar@example.com
+
+[universal]
+foo = bar
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/base.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,111 @@
+"""
+Module providing backend independent mixin class. It requires that
+InMemoryChangeset class is working properly at backend class.
+"""
+import os
+from rhodecode.lib import vcs
+import time
+import shutil
+import datetime
+from rhodecode.lib.vcs.utils.compat import unittest
+
+from conf import SCM_TESTS, get_new_dir
+
+from rhodecode.lib.vcs.nodes import FileNode
+
+
+class BackendTestMixin(object):
+    """
+    This is a backend independent test case class which should be created
+    with ``type`` method.
+
+    It is required to set following attributes at subclass:
+
+    - ``backend_alias``: alias of used backend (see ``vcs.BACKENDS``)
+    - ``repo_path``: path to the repository which would be created for set of
+      tests
+    - ``recreate_repo_per_test``: If set to ``False``, repo would NOT be created
+      before every single test. Defaults to ``True``.
+    """
+    recreate_repo_per_test = True
+
+    @classmethod
+    def get_backend(cls):
+        return vcs.get_backend(cls.backend_alias)
+
+    @classmethod
+    def _get_commits(cls):
+        commits = [
+            {
+                'message': u'Initial commit',
+                'author': u'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': [
+                    FileNode('foobar', content='Foobar'),
+                    FileNode('foobar2', content='Foobar II'),
+                    FileNode('foo/bar/baz', content='baz here!'),
+                ],
+            },
+            {
+                'message': u'Changes...',
+                'author': u'Jane Doe <jane.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 21),
+                'added': [
+                    FileNode('some/new.txt', content='news...'),
+                ],
+                'changed': [
+                    FileNode('foobar', 'Foobar I'),
+                ],
+                'removed': [],
+            },
+        ]
+        return commits
+
+    @classmethod
+    def setUpClass(cls):
+        Backend = cls.get_backend()
+        cls.backend_class = Backend
+        cls.repo_path = get_new_dir(str(time.time()))
+        cls.repo = Backend(cls.repo_path, create=True)
+        cls.imc = cls.repo.in_memory_changeset
+
+        for commit in cls._get_commits():
+            for node in commit.get('added', []):
+                cls.imc.add(FileNode(node.path, content=node.content))
+            for node in commit.get('changed', []):
+                cls.imc.change(FileNode(node.path, content=node.content))
+            for node in commit.get('removed', []):
+                cls.imc.remove(FileNode(node.path))
+
+            cls.tip = cls.imc.commit(message=unicode(commit['message']),
+                                     author=unicode(commit['author']),
+                                     date=commit['date'])
+
+    @classmethod
+    def tearDownClass(cls):
+        if not getattr(cls, 'recreate_repo_per_test', False) and \
+            'VCS_REMOVE_TEST_DIRS' in os.environ:
+            shutil.rmtree(cls.repo_path)
+
+    def setUp(self):
+        if getattr(self, 'recreate_repo_per_test', False):
+            self.__class__.setUpClass()
+
+    def tearDown(self):
+        if getattr(self, 'recreate_repo_per_test', False) and \
+            'VCS_REMOVE_TEST_DIRS' in os.environ:
+            shutil.rmtree(self.repo_path)
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s base backend test' % alias).title().split())
+    bases = (BackendTestMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/conf.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,62 @@
+"""
+Unit tests configuration module for vcs.
+"""
+
+import os
+import time
+import hashlib
+import tempfile
+import datetime
+from rhodecode.tests import *
+from utils import get_normalized_path
+from os.path import join as jn
+
+TEST_TMP_PATH = TESTS_TMP_PATH
+#__all__ = (
+#    'TEST_HG_REPO', 'TEST_GIT_REPO', 'HG_REMOTE_REPO', 'GIT_REMOTE_REPO',
+#    'SCM_TESTS',
+#)
+#
+#SCM_TESTS = ['hg', 'git']
+#uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
+#
+THIS = os.path.abspath(os.path.dirname(__file__))
+#
+#GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
+#
+#TEST_TMP_PATH = os.environ.get('VCS_TEST_ROOT', '/tmp')
+#TEST_GIT_REPO = os.environ.get('VCS_TEST_GIT_REPO',
+#                              jn(TEST_TMP_PATH, 'vcs-git'))
+#TEST_GIT_REPO_CLONE = os.environ.get('VCS_TEST_GIT_REPO_CLONE',
+#                            jn(TEST_TMP_PATH, 'vcsgitclone%s' % uniq_suffix))
+#TEST_GIT_REPO_PULL = os.environ.get('VCS_TEST_GIT_REPO_PULL',
+#                            jn(TEST_TMP_PATH, 'vcsgitpull%s' % uniq_suffix))
+#
+#HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
+#TEST_HG_REPO = os.environ.get('VCS_TEST_HG_REPO',
+#                              jn(TEST_TMP_PATH, 'vcs-hg'))
+#TEST_HG_REPO_CLONE = os.environ.get('VCS_TEST_HG_REPO_CLONE',
+#                              jn(TEST_TMP_PATH, 'vcshgclone%s' % uniq_suffix))
+#TEST_HG_REPO_PULL = os.environ.get('VCS_TEST_HG_REPO_PULL',
+#                              jn(TEST_TMP_PATH, 'vcshgpull%s' % uniq_suffix))
+#
+#TEST_DIR = os.environ.get('VCS_TEST_ROOT', tempfile.gettempdir())
+#TEST_REPO_PREFIX = 'vcs-test'
+#
+#
+#def get_new_dir(title):
+#    """
+#    Returns always new directory path.
+#    """
+#    name = TEST_REPO_PREFIX
+#    if title:
+#        name = '-'.join((name, title))
+#    hex = hashlib.sha1(str(time.time())).hexdigest()
+#    name = '-'.join((name, hex))
+#    path = os.path.join(TEST_DIR, name)
+#    return get_normalized_path(path)
+
+PACKAGE_DIR = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '..'))
+
+TEST_USER_CONFIG_FILE = jn(THIS, 'aconfig')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_archives.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,108 @@
+from __future__ import with_statement
+
+import os
+import tarfile
+import zipfile
+import datetime
+import tempfile
+import StringIO
+from base import BackendTestMixin
+from conf import SCM_TESTS
+from rhodecode.lib.vcs.exceptions import VCSError
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class ArchivesTestCaseMixin(BackendTestMixin):
+
+    @classmethod
+    def _get_commits(cls):
+        start_date = datetime.datetime(2010, 1, 1, 20)
+        for x in xrange(5):
+            yield {
+                'message': 'Commit %d' % x,
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': start_date + datetime.timedelta(hours=12 * x),
+                'added': [
+                    FileNode('%d/file_%d.txt' % (x, x),
+                        content='Foobar %d' % x),
+                ],
+            }
+
+    def test_archive_zip(self):
+        path = tempfile.mkstemp()[1]
+        with open(path, 'wb') as f:
+            self.tip.fill_archive(stream=f, kind='zip', prefix='repo')
+        out = zipfile.ZipFile(path)
+
+        for x in xrange(5):
+            node_path = '%d/file_%d.txt' % (x, x)
+            decompressed = StringIO.StringIO()
+            decompressed.write(out.read('repo/' + node_path))
+            self.assertEqual(
+                decompressed.getvalue(),
+                self.tip.get_node(node_path).content)
+
+    def test_archive_tgz(self):
+        path = tempfile.mkstemp()[1]
+        with open(path, 'wb') as f:
+            self.tip.fill_archive(stream=f, kind='tgz', prefix='repo')
+        outdir = tempfile.mkdtemp()
+
+        outfile = tarfile.open(path, 'r|gz')
+        outfile.extractall(outdir)
+
+        for x in xrange(5):
+            node_path = '%d/file_%d.txt' % (x, x)
+            self.assertEqual(
+                open(os.path.join(outdir, 'repo/' + node_path)).read(),
+                self.tip.get_node(node_path).content)
+
+    def test_archive_tbz2(self):
+        path = tempfile.mkstemp()[1]
+        with open(path, 'w+b') as f:
+            self.tip.fill_archive(stream=f, kind='tbz2', prefix='repo')
+        outdir = tempfile.mkdtemp()
+
+        outfile = tarfile.open(path, 'r|bz2')
+        outfile.extractall(outdir)
+
+        for x in xrange(5):
+            node_path = '%d/file_%d.txt' % (x, x)
+            self.assertEqual(
+                open(os.path.join(outdir, 'repo/' + node_path)).read(),
+                self.tip.get_node(node_path).content)
+
+    def test_archive_default_stream(self):
+        tmppath = tempfile.mkstemp()[1]
+        with open(tmppath, 'w') as stream:
+            self.tip.fill_archive(stream=stream)
+        mystream = StringIO.StringIO()
+        self.tip.fill_archive(stream=mystream)
+        mystream.seek(0)
+        with open(tmppath, 'r') as f:
+            self.assertEqual(f.read(), mystream.read())
+
+    def test_archive_wrong_kind(self):
+        with self.assertRaises(VCSError):
+            self.tip.fill_archive(kind='wrong kind')
+
+    def test_archive_empty_prefix(self):
+        with self.assertRaises(VCSError):
+            self.tip.fill_archive(prefix='')
+
+    def test_archive_prefix_with_leading_slash(self):
+        with self.assertRaises(VCSError):
+            self.tip.fill_archive(prefix='/any')
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s archive test' % alias).title().split())
+    bases = (ArchivesTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_branches.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,118 @@
+from __future__ import with_statement
+
+from rhodecode.lib import vcs
+import datetime
+from rhodecode.lib.vcs.utils.compat import unittest
+
+from base import BackendTestMixin
+from conf import SCM_TESTS
+
+from rhodecode.lib.vcs.nodes import FileNode
+
+
+class BranchesTestCaseMixin(BackendTestMixin):
+
+    @classmethod
+    def _get_commits(cls):
+        commits = [
+            {
+                'message': 'Initial commit',
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': [
+                    FileNode('foobar', content='Foobar'),
+                    FileNode('foobar2', content='Foobar II'),
+                    FileNode('foo/bar/baz', content='baz here!'),
+                ],
+            },
+            {
+                'message': 'Changes...',
+                'author': 'Jane Doe <jane.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 21),
+                'added': [
+                    FileNode('some/new.txt', content='news...'),
+                ],
+                'changed': [
+                    FileNode('foobar', 'Foobar I'),
+                ],
+                'removed': [],
+            },
+        ]
+        return commits
+
+    def test_simple(self):
+        tip = self.repo.get_changeset()
+        self.assertEqual(tip.date, datetime.datetime(2010, 1, 1, 21))
+
+    def test_new_branch(self):
+        # This check must not be removed to ensure the 'branches' LazyProperty
+        # gets hit *before* the new 'foobar' branch got created:
+        self.assertFalse('foobar' in self.repo.branches)
+        self.imc.add(vcs.nodes.FileNode('docs/index.txt',
+            content='Documentation\n'))
+        foobar_tip = self.imc.commit(
+            message=u'New branch: foobar',
+            author=u'joe',
+            branch='foobar',
+        )
+        self.assertTrue('foobar' in self.repo.branches)
+        self.assertEqual(foobar_tip.branch, 'foobar')
+
+    def test_new_head(self):
+        tip = self.repo.get_changeset()
+        self.imc.add(vcs.nodes.FileNode('docs/index.txt',
+            content='Documentation\n'))
+        foobar_tip = self.imc.commit(
+            message=u'New branch: foobar',
+            author=u'joe',
+            branch='foobar',
+            parents=[tip],
+        )
+        self.imc.change(vcs.nodes.FileNode('docs/index.txt',
+            content='Documentation\nand more...\n'))
+        newtip = self.imc.commit(
+            message=u'At default branch',
+            author=u'joe',
+            branch=foobar_tip.branch,
+            parents=[foobar_tip],
+        )
+
+        newest_tip = self.imc.commit(
+            message=u'Merged with %s' % foobar_tip.raw_id,
+            author=u'joe',
+            branch=self.backend_class.DEFAULT_BRANCH_NAME,
+            parents=[newtip, foobar_tip],
+        )
+
+        self.assertEqual(newest_tip.branch,
+            self.backend_class.DEFAULT_BRANCH_NAME)
+
+    def test_branch_with_slash_in_name(self):
+        self.imc.add(vcs.nodes.FileNode('extrafile', content='Some data\n'))
+        self.imc.commit(u'Branch with a slash!', author=u'joe',
+            branch='issue/123')
+        self.assertTrue('issue/123' in self.repo.branches)
+
+    def test_branch_with_slash_in_name_and_similar_without(self):
+        self.imc.add(vcs.nodes.FileNode('extrafile', content='Some data\n'))
+        self.imc.commit(u'Branch with a slash!', author=u'joe',
+            branch='issue/123')
+        self.imc.add(vcs.nodes.FileNode('extrafile II', content='Some data\n'))
+        self.imc.commit(u'Branch without a slash...', author=u'joe',
+            branch='123')
+        self.assertIn('issue/123', self.repo.branches)
+        self.assertIn('123', self.repo.branches)
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s branches test' % alias).title().split())
+    bases = (BranchesTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_changesets.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,344 @@
+from __future__ import with_statement
+
+from rhodecode.lib import vcs
+import datetime
+from base import BackendTestMixin
+from conf import SCM_TESTS
+from rhodecode.lib.vcs.backends.base import BaseChangeset
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.exceptions import BranchDoesNotExistError
+from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
+from rhodecode.lib.vcs.exceptions import RepositoryError
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class TestBaseChangeset(unittest.TestCase):
+
+    def test_as_dict(self):
+        changeset = BaseChangeset()
+        changeset.id = 'ID'
+        changeset.raw_id = 'RAW_ID'
+        changeset.short_id = 'SHORT_ID'
+        changeset.revision = 1009
+        changeset.date = datetime.datetime(2011, 1, 30, 1, 45)
+        changeset.message = 'Message of a commit'
+        changeset.author = 'Joe Doe <joe.doe@example.com>'
+        changeset.added = [FileNode('foo/bar/baz'), FileNode('foobar')]
+        changeset.changed = []
+        changeset.removed = []
+        self.assertEqual(changeset.as_dict(), {
+            'id': 'ID',
+            'raw_id': 'RAW_ID',
+            'short_id': 'SHORT_ID',
+            'revision': 1009,
+            'date': datetime.datetime(2011, 1, 30, 1, 45),
+            'message': 'Message of a commit',
+            'author': {
+                'name': 'Joe Doe',
+                'email': 'joe.doe@example.com',
+            },
+            'added': ['foo/bar/baz', 'foobar'],
+            'changed': [],
+            'removed': [],
+        })
+
+class ChangesetsWithCommitsTestCaseixin(BackendTestMixin):
+    recreate_repo_per_test = True
+
+    @classmethod
+    def _get_commits(cls):
+        start_date = datetime.datetime(2010, 1, 1, 20)
+        for x in xrange(5):
+            yield {
+                'message': 'Commit %d' % x,
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': start_date + datetime.timedelta(hours=12 * x),
+                'added': [
+                    FileNode('file_%d.txt' % x, content='Foobar %d' % x),
+                ],
+            }
+
+    def test_new_branch(self):
+        self.imc.add(vcs.nodes.FileNode('docs/index.txt',
+            content='Documentation\n'))
+        foobar_tip = self.imc.commit(
+            message=u'New branch: foobar',
+            author=u'joe',
+            branch='foobar',
+        )
+        self.assertTrue('foobar' in self.repo.branches)
+        self.assertEqual(foobar_tip.branch, 'foobar')
+        # 'foobar' should be the only branch that contains the new commit
+        self.assertNotEqual(*self.repo.branches.values())
+
+    def test_new_head_in_default_branch(self):
+        tip = self.repo.get_changeset()
+        self.imc.add(vcs.nodes.FileNode('docs/index.txt',
+            content='Documentation\n'))
+        foobar_tip = self.imc.commit(
+            message=u'New branch: foobar',
+            author=u'joe',
+            branch='foobar',
+            parents=[tip],
+        )
+        self.imc.change(vcs.nodes.FileNode('docs/index.txt',
+            content='Documentation\nand more...\n'))
+        newtip = self.imc.commit(
+            message=u'At default branch',
+            author=u'joe',
+            branch=foobar_tip.branch,
+            parents=[foobar_tip],
+        )
+
+        newest_tip = self.imc.commit(
+            message=u'Merged with %s' % foobar_tip.raw_id,
+            author=u'joe',
+            branch=self.backend_class.DEFAULT_BRANCH_NAME,
+            parents=[newtip, foobar_tip],
+        )
+
+        self.assertEqual(newest_tip.branch,
+            self.backend_class.DEFAULT_BRANCH_NAME)
+
+    def test_get_changesets_respects_branch_name(self):
+        tip = self.repo.get_changeset()
+        self.imc.add(vcs.nodes.FileNode('docs/index.txt',
+            content='Documentation\n'))
+        doc_changeset = self.imc.commit(
+            message=u'New branch: docs',
+            author=u'joe',
+            branch='docs',
+        )
+        self.imc.add(vcs.nodes.FileNode('newfile', content=''))
+        self.imc.commit(
+            message=u'Back in default branch',
+            author=u'joe',
+            parents=[tip],
+        )
+        default_branch_changesets = self.repo.get_changesets(
+            branch_name=self.repo.DEFAULT_BRANCH_NAME)
+        self.assertNotIn(doc_changeset, default_branch_changesets)
+
+    def test_get_changeset_by_branch(self):
+        for branch, sha in self.repo.branches.iteritems():
+            self.assertEqual(sha, self.repo.get_changeset(branch).raw_id)
+
+    def test_get_changeset_by_tag(self):
+        for tag, sha in self.repo.tags.iteritems():
+            self.assertEqual(sha, self.repo.get_changeset(tag).raw_id)
+
+
+class ChangesetsTestCaseMixin(BackendTestMixin):
+    recreate_repo_per_test = False
+
+    @classmethod
+    def _get_commits(cls):
+        start_date = datetime.datetime(2010, 1, 1, 20)
+        for x in xrange(5):
+            yield {
+                'message': u'Commit %d' % x,
+                'author': u'Joe Doe <joe.doe@example.com>',
+                'date': start_date + datetime.timedelta(hours=12 * x),
+                'added': [
+                    FileNode('file_%d.txt' % x, content='Foobar %d' % x),
+                ],
+            }
+
+    def test_simple(self):
+        tip = self.repo.get_changeset()
+        self.assertEqual(tip.date, datetime.datetime(2010, 1, 3, 20))
+
+    def test_get_changesets_is_ordered_by_date(self):
+        changesets = list(self.repo.get_changesets())
+        ordered_by_date = sorted(changesets,
+            key=lambda cs: cs.date)
+        self.assertItemsEqual(changesets, ordered_by_date)
+
+    def test_get_changesets_respects_start(self):
+        second_id = self.repo.revisions[1]
+        changesets = list(self.repo.get_changesets(start=second_id))
+        self.assertEqual(len(changesets), 4)
+
+    def test_get_changesets_numerical_id_respects_start(self):
+        second_id = 1
+        changesets = list(self.repo.get_changesets(start=second_id))
+        self.assertEqual(len(changesets), 4)
+
+    def test_get_changesets_includes_start_changeset(self):
+        second_id = self.repo.revisions[1]
+        changesets = list(self.repo.get_changesets(start=second_id))
+        self.assertEqual(changesets[0].raw_id, second_id)
+
+    def test_get_changesets_respects_end(self):
+        second_id = self.repo.revisions[1]
+        changesets = list(self.repo.get_changesets(end=second_id))
+        self.assertEqual(changesets[-1].raw_id, second_id)
+        self.assertEqual(len(changesets), 2)
+
+    def test_get_changesets_numerical_id_respects_end(self):
+        second_id = 1
+        changesets = list(self.repo.get_changesets(end=second_id))
+        self.assertEqual(changesets.index(changesets[-1]), second_id)
+        self.assertEqual(len(changesets), 2)
+
+    def test_get_changesets_respects_both_start_and_end(self):
+        second_id = self.repo.revisions[1]
+        third_id = self.repo.revisions[2]
+        changesets = list(self.repo.get_changesets(start=second_id,
+            end=third_id))
+        self.assertEqual(len(changesets), 2)
+
+    def test_get_changesets_numerical_id_respects_both_start_and_end(self):
+        changesets = list(self.repo.get_changesets(start=2, end=3))
+        self.assertEqual(len(changesets), 2)
+
+    def test_get_changesets_includes_end_changeset(self):
+        second_id = self.repo.revisions[1]
+        changesets = list(self.repo.get_changesets(end=second_id))
+        self.assertEqual(changesets[-1].raw_id, second_id)
+
+    def test_get_changesets_respects_start_date(self):
+        start_date = datetime.datetime(2010, 2, 1)
+        for cs in self.repo.get_changesets(start_date=start_date):
+            self.assertGreaterEqual(cs.date, start_date)
+
+    def test_get_changesets_respects_end_date(self):
+        end_date = datetime.datetime(2010, 2, 1)
+        for cs in self.repo.get_changesets(end_date=end_date):
+            self.assertLessEqual(cs.date, end_date)
+
+    def test_get_changesets_respects_reverse(self):
+        changesets_id_list = [cs.raw_id for cs in
+            self.repo.get_changesets(reverse=True)]
+        self.assertItemsEqual(changesets_id_list, reversed(self.repo.revisions))
+
+    def test_get_filenodes_generator(self):
+        tip = self.repo.get_changeset()
+        filepaths = [node.path for node in tip.get_filenodes_generator()]
+        self.assertItemsEqual(filepaths, ['file_%d.txt' % x for x in xrange(5)])
+
+    def test_size(self):
+        tip = self.repo.get_changeset()
+        size = 5 * len('Foobar N') # Size of 5 files
+        self.assertEqual(tip.size, size)
+
+    def test_author(self):
+        tip = self.repo.get_changeset()
+        self.assertEqual(tip.author, u'Joe Doe <joe.doe@example.com>')
+
+    def test_author_name(self):
+        tip = self.repo.get_changeset()
+        self.assertEqual(tip.author_name, u'Joe Doe')
+
+    def test_author_email(self):
+        tip = self.repo.get_changeset()
+        self.assertEqual(tip.author_email, u'joe.doe@example.com')
+
+    def test_get_changesets_raise_changesetdoesnotexist_for_wrong_start(self):
+        with self.assertRaises(ChangesetDoesNotExistError):
+            list(self.repo.get_changesets(start='foobar'))
+
+    def test_get_changesets_raise_changesetdoesnotexist_for_wrong_end(self):
+        with self.assertRaises(ChangesetDoesNotExistError):
+            list(self.repo.get_changesets(end='foobar'))
+
+    def test_get_changesets_raise_branchdoesnotexist_for_wrong_branch_name(self):
+        with self.assertRaises(BranchDoesNotExistError):
+            list(self.repo.get_changesets(branch_name='foobar'))
+
+    def test_get_changesets_raise_repositoryerror_for_wrong_start_end(self):
+        start = self.repo.revisions[-1]
+        end = self.repo.revisions[0]
+        with self.assertRaises(RepositoryError):
+            list(self.repo.get_changesets(start=start, end=end))
+
+    def test_get_changesets_numerical_id_reversed(self):
+        with self.assertRaises(RepositoryError):
+            [x for x in self.repo.get_changesets(start=3, end=2)]
+
+    def test_get_changesets_numerical_id_respects_both_start_and_end_last(self):
+        with self.assertRaises(RepositoryError):
+            last = len(self.repo.revisions)
+            list(self.repo.get_changesets(start=last-1, end=last-2))
+
+    def test_get_changesets_numerical_id_last_zero_error(self):
+        with self.assertRaises(RepositoryError):
+            last = len(self.repo.revisions)
+            list(self.repo.get_changesets(start=last-1, end=0))
+
+
+class ChangesetsChangesTestCaseMixin(BackendTestMixin):
+    recreate_repo_per_test = False
+
+    @classmethod
+    def _get_commits(cls):
+        return [
+            {
+                'message': u'Initial',
+                'author': u'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': [
+                    FileNode('foo/bar', content='foo'),
+                    FileNode('foobar', content='foo'),
+                    FileNode('qwe', content='foo'),
+                ],
+            },
+            {
+                'message': u'Massive changes',
+                'author': u'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 22),
+                'added': [FileNode('fallout', content='War never changes')],
+                'changed': [
+                    FileNode('foo/bar', content='baz'),
+                    FileNode('foobar', content='baz'),
+                ],
+                'removed': [FileNode('qwe')],
+            },
+        ]
+
+    def test_initial_commit(self):
+        changeset = self.repo.get_changeset(0)
+        self.assertItemsEqual(changeset.added, [
+            changeset.get_node('foo/bar'),
+            changeset.get_node('foobar'),
+            changeset.get_node('qwe'),
+        ])
+        self.assertItemsEqual(changeset.changed, [])
+        self.assertItemsEqual(changeset.removed, [])
+
+    def test_head_added(self):
+        changeset = self.repo.get_changeset()
+        self.assertItemsEqual(changeset.added, [
+            changeset.get_node('fallout'),
+        ])
+        self.assertItemsEqual(changeset.changed, [
+            changeset.get_node('foo/bar'),
+            changeset.get_node('foobar'),
+        ])
+        self.assertEqual(len(changeset.removed), 1)
+        self.assertEqual(list(changeset.removed)[0].path, 'qwe')
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    # tests with additional commits
+    cls_name = ''.join(('%s changesets with commits test' % alias).title().split())
+    bases = (ChangesetsWithCommitsTestCaseixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+    # tests without additional commits
+    cls_name = ''.join(('%s changesets test' % alias).title().split())
+    bases = (ChangesetsTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+    # tests changes
+    cls_name = ''.join(('%s changesets changes test' % alias).title().split())
+    bases = (ChangesetsChangesTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_filenodes_unicode_path.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,49 @@
+# encoding: utf8
+
+from __future__ import with_statement
+
+import datetime
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.utils.compat import unittest
+from test_inmemchangesets import BackendBaseTestCase
+from conf import SCM_TESTS
+
+
+class FileNodeUnicodePathTestsMixin(object):
+
+    fname = 'ąśðąęłąć.txt'
+    ufname = (fname).decode('utf-8')
+
+    def get_commits(self):
+        self.nodes = [
+            FileNode(self.fname, content='Foobar'),
+        ]
+
+        commits = [
+            {
+                'message': 'Initial commit',
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': self.nodes,
+            },
+        ]
+        return commits
+
+    def test_filenode_path(self):
+        node = self.tip.get_node(self.fname)
+        unode = self.tip.get_node(self.ufname)
+        self.assertEqual(node, unode)
+
+
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s file node unicode path test' % alias).title()
+        .split())
+    bases = (FileNodeUnicodePathTestsMixin, BackendBaseTestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_getitem.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,44 @@
+from __future__ import with_statement
+
+import datetime
+from base import BackendTestMixin
+from conf import SCM_TESTS
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class GetitemTestCaseMixin(BackendTestMixin):
+
+    @classmethod
+    def _get_commits(cls):
+        start_date = datetime.datetime(2010, 1, 1, 20)
+        for x in xrange(5):
+            yield {
+                'message': 'Commit %d' % x,
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': start_date + datetime.timedelta(hours=12 * x),
+                'added': [
+                    FileNode('file_%d.txt' % x, content='Foobar %d' % x),
+                ],
+            }
+
+    def test__getitem__last_item_is_tip(self):
+        self.assertEqual(self.repo[-1], self.repo.get_changeset())
+
+    def test__getitem__returns_correct_items(self):
+        changesets = [self.repo[x] for x in xrange(len(self.repo.revisions))]
+        self.assertEqual(changesets, list(self.repo.get_changesets()))
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s getitem test' % alias).title().split())
+    bases = (GetitemTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_getslice.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,56 @@
+from __future__ import with_statement
+
+import datetime
+from base import BackendTestMixin
+from conf import SCM_TESTS
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class GetsliceTestCaseMixin(BackendTestMixin):
+
+    @classmethod
+    def _get_commits(cls):
+        start_date = datetime.datetime(2010, 1, 1, 20)
+        for x in xrange(5):
+            yield {
+                'message': 'Commit %d' % x,
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': start_date + datetime.timedelta(hours=12 * x),
+                'added': [
+                    FileNode('file_%d.txt' % x, content='Foobar %d' % x),
+                ],
+            }
+
+    def test__getslice__last_item_is_tip(self):
+        self.assertEqual(list(self.repo[-1:])[0], self.repo.get_changeset())
+
+    def test__getslice__respects_start_index(self):
+        self.assertEqual(list(self.repo[2:]),
+            [self.repo.get_changeset(rev) for rev in self.repo.revisions[2:]])
+
+    def test__getslice__respects_negative_start_index(self):
+        self.assertEqual(list(self.repo[-2:]),
+            [self.repo.get_changeset(rev) for rev in self.repo.revisions[-2:]])
+
+    def test__getslice__respects_end_index(self):
+        self.assertEqual(list(self.repo[:2]),
+            [self.repo.get_changeset(rev) for rev in self.repo.revisions[:2]])
+
+    def test__getslice__respects_negative_end_index(self):
+        self.assertEqual(list(self.repo[:-2]),
+            [self.repo.get_changeset(rev) for rev in self.repo.revisions[:-2]])
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s getslice test' % alias).title().split())
+    bases = (GetsliceTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_git.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,702 @@
+from __future__ import with_statement
+
+import os
+import mock
+import datetime
+from rhodecode.lib.vcs.backends.git import GitRepository, GitChangeset
+from rhodecode.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
+from rhodecode.lib.vcs.nodes import NodeKind, FileNode, DirNode, NodeState
+from rhodecode.lib.vcs.utils.compat import unittest
+from rhodecode.tests.vcs.base import BackendTestMixin
+from conf import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
+
+
+class GitRepositoryTest(unittest.TestCase):
+
+    def __check_for_existing_repo(self):
+        if os.path.exists(TEST_GIT_REPO_CLONE):
+            self.fail('Cannot test git clone repo as location %s already '
+                      'exists. You should manually remove it first.'
+                      % TEST_GIT_REPO_CLONE)
+
+    def setUp(self):
+        self.repo = GitRepository(TEST_GIT_REPO)
+
+    def test_wrong_repo_path(self):
+        wrong_repo_path = '/tmp/errorrepo'
+        self.assertRaises(RepositoryError, GitRepository, wrong_repo_path)
+
+    def test_repo_clone(self):
+        self.__check_for_existing_repo()
+        repo = GitRepository(TEST_GIT_REPO)
+        repo_clone = GitRepository(TEST_GIT_REPO_CLONE,
+            src_url=TEST_GIT_REPO, create=True, update_after_clone=True)
+        self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
+        # Checking hashes of changesets should be enough
+        for changeset in repo.get_changesets():
+            raw_id = changeset.raw_id
+            self.assertEqual(raw_id, repo_clone.get_changeset(raw_id).raw_id)
+
+    def test_repo_clone_without_create(self):
+        self.assertRaises(RepositoryError, GitRepository,
+            TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
+
+    def test_repo_clone_with_update(self):
+        repo = GitRepository(TEST_GIT_REPO)
+        clone_path = TEST_GIT_REPO_CLONE + '_with_update'
+        repo_clone = GitRepository(clone_path,
+            create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
+        self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
+
+        #check if current workdir was updated
+        fpath = os.path.join(clone_path, 'MANIFEST.in')
+        self.assertEqual(True, os.path.isfile(fpath),
+            'Repo was cloned and updated but file %s could not be found'
+            % fpath)
+
+    def test_repo_clone_without_update(self):
+        repo = GitRepository(TEST_GIT_REPO)
+        clone_path = TEST_GIT_REPO_CLONE + '_without_update'
+        repo_clone = GitRepository(clone_path,
+            create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
+        self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
+        #check if current workdir was *NOT* updated
+        fpath = os.path.join(clone_path, 'MANIFEST.in')
+        # Make sure it's not bare repo
+        self.assertFalse(repo_clone._repo.bare)
+        self.assertEqual(False, os.path.isfile(fpath),
+            'Repo was cloned and updated but file %s was found'
+            % fpath)
+
+    def test_repo_clone_into_bare_repo(self):
+        repo = GitRepository(TEST_GIT_REPO)
+        clone_path = TEST_GIT_REPO_CLONE + '_bare.git'
+        repo_clone = GitRepository(clone_path, create=True,
+            src_url=repo.path, bare=True)
+        self.assertTrue(repo_clone._repo.bare)
+
+    def test_create_repo_is_not_bare_by_default(self):
+        repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
+        self.assertFalse(repo._repo.bare)
+
+    def test_create_bare_repo(self):
+        repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
+        self.assertTrue(repo._repo.bare)
+
+    def test_revisions(self):
+        # there are 112 revisions (by now)
+        # so we can assume they would be available from now on
+        subset = set([
+            'c1214f7e79e02fc37156ff215cd71275450cffc3',
+            '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
+            'fa6600f6848800641328adbf7811fd2372c02ab2',
+            '102607b09cdd60e2793929c4f90478be29f85a17',
+            '49d3fd156b6f7db46313fac355dca1a0b94a0017',
+            '2d1028c054665b962fa3d307adfc923ddd528038',
+            'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
+            'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
+            'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
+            '8430a588b43b5d6da365400117c89400326e7992',
+            'd955cd312c17b02143c04fa1099a352b04368118',
+            'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
+            'add63e382e4aabc9e1afdc4bdc24506c269b7618',
+            'f298fe1189f1b69779a4423f40b48edf92a703fc',
+            'bd9b619eb41994cac43d67cf4ccc8399c1125808',
+            '6e125e7c890379446e98980d8ed60fba87d0f6d1',
+            'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
+            '0b05e4ed56c802098dfc813cbe779b2f49e92500',
+            '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
+            '45223f8f114c64bf4d6f853e3c35a369a6305520',
+            'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
+            'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
+            '27d48942240f5b91dfda77accd2caac94708cc7d',
+            '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
+            'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
+        self.assertTrue(subset.issubset(set(self.repo.revisions)))
+
+
+
+    def test_slicing(self):
+        #4 1 5 10 95
+        for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
+                                 (10, 20, 10), (5, 100, 95)]:
+            revs = list(self.repo[sfrom:sto])
+            self.assertEqual(len(revs), size)
+            self.assertEqual(revs[0], self.repo.get_changeset(sfrom))
+            self.assertEqual(revs[-1], self.repo.get_changeset(sto - 1))
+
+
+    def test_branches(self):
+        # TODO: Need more tests here
+        # Removed (those are 'remotes' branches for cloned repo)
+        #self.assertTrue('master' in self.repo.branches)
+        #self.assertTrue('gittree' in self.repo.branches)
+        #self.assertTrue('web-branch' in self.repo.branches)
+        for name, id in self.repo.branches.items():
+            self.assertTrue(isinstance(
+                self.repo.get_changeset(id), GitChangeset))
+
+    def test_tags(self):
+        # TODO: Need more tests here
+        self.assertTrue('v0.1.1' in self.repo.tags)
+        self.assertTrue('v0.1.2' in self.repo.tags)
+        for name, id in self.repo.tags.items():
+            self.assertTrue(isinstance(
+                self.repo.get_changeset(id), GitChangeset))
+
+    def _test_single_changeset_cache(self, revision):
+        chset = self.repo.get_changeset(revision)
+        self.assertTrue(revision in self.repo.changesets)
+        self.assertTrue(chset is self.repo.changesets[revision])
+
+    def test_initial_changeset(self):
+        id = self.repo.revisions[0]
+        init_chset = self.repo.get_changeset(id)
+        self.assertEqual(init_chset.message, 'initial import\n')
+        self.assertEqual(init_chset.author,
+            'Marcin Kuzminski <marcin@python-blog.com>')
+        for path in ('vcs/__init__.py',
+                     'vcs/backends/BaseRepository.py',
+                     'vcs/backends/__init__.py'):
+            self.assertTrue(isinstance(init_chset.get_node(path), FileNode))
+        for path in ('', 'vcs', 'vcs/backends'):
+            self.assertTrue(isinstance(init_chset.get_node(path), DirNode))
+
+        self.assertRaises(NodeDoesNotExistError, init_chset.get_node, path='foobar')
+
+        node = init_chset.get_node('vcs/')
+        self.assertTrue(hasattr(node, 'kind'))
+        self.assertEqual(node.kind, NodeKind.DIR)
+
+        node = init_chset.get_node('vcs')
+        self.assertTrue(hasattr(node, 'kind'))
+        self.assertEqual(node.kind, NodeKind.DIR)
+
+        node = init_chset.get_node('vcs/__init__.py')
+        self.assertTrue(hasattr(node, 'kind'))
+        self.assertEqual(node.kind, NodeKind.FILE)
+
+    def test_not_existing_changeset(self):
+        self.assertRaises(RepositoryError, self.repo.get_changeset,
+            'f' * 40)
+
+    def test_changeset10(self):
+
+        chset10 = self.repo.get_changeset(self.repo.revisions[9])
+        README = """===
+VCS
+===
+
+Various Version Control System management abstraction layer for Python.
+
+Introduction
+------------
+
+TODO: To be written...
+
+"""
+        node = chset10.get_node('README.rst')
+        self.assertEqual(node.kind, NodeKind.FILE)
+        self.assertEqual(node.content, README)
+
+
+class GitChangesetTest(unittest.TestCase):
+
+    def setUp(self):
+        self.repo = GitRepository(TEST_GIT_REPO)
+
+    def test_default_changeset(self):
+        tip = self.repo.get_changeset()
+        self.assertEqual(tip, self.repo.get_changeset(None))
+        self.assertEqual(tip, self.repo.get_changeset('tip'))
+
+    def test_root_node(self):
+        tip = self.repo.get_changeset()
+        self.assertTrue(tip.root is tip.get_node(''))
+
+    def test_lazy_fetch(self):
+        """
+        Test if changeset's nodes expands and are cached as we walk through
+        the revision. This test is somewhat hard to write as order of tests
+        is a key here. Written by running command after command in a shell.
+        """
+        hex = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
+        self.assertTrue(hex in self.repo.revisions)
+        chset = self.repo.get_changeset(hex)
+        self.assertTrue(len(chset.nodes) == 0)
+        root = chset.root
+        self.assertTrue(len(chset.nodes) == 1)
+        self.assertTrue(len(root.nodes) == 8)
+        # accessing root.nodes updates chset.nodes
+        self.assertTrue(len(chset.nodes) == 9)
+
+        docs = root.get_node('docs')
+        # we haven't yet accessed anything new as docs dir was already cached
+        self.assertTrue(len(chset.nodes) == 9)
+        self.assertTrue(len(docs.nodes) == 8)
+        # accessing docs.nodes updates chset.nodes
+        self.assertTrue(len(chset.nodes) == 17)
+
+        self.assertTrue(docs is chset.get_node('docs'))
+        self.assertTrue(docs is root.nodes[0])
+        self.assertTrue(docs is root.dirs[0])
+        self.assertTrue(docs is chset.get_node('docs'))
+
+    def test_nodes_with_changeset(self):
+        hex = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
+        chset = self.repo.get_changeset(hex)
+        root = chset.root
+        docs = root.get_node('docs')
+        self.assertTrue(docs is chset.get_node('docs'))
+        api = docs.get_node('api')
+        self.assertTrue(api is chset.get_node('docs/api'))
+        index = api.get_node('index.rst')
+        self.assertTrue(index is chset.get_node('docs/api/index.rst'))
+        self.assertTrue(index is chset.get_node('docs')\
+            .get_node('api')\
+            .get_node('index.rst'))
+
+    def test_branch_and_tags(self):
+        '''
+        rev0 = self.repo.revisions[0]
+        chset0 = self.repo.get_changeset(rev0)
+        self.assertEqual(chset0.branch, 'master')
+        self.assertEqual(chset0.tags, [])
+
+        rev10 = self.repo.revisions[10]
+        chset10 = self.repo.get_changeset(rev10)
+        self.assertEqual(chset10.branch, 'master')
+        self.assertEqual(chset10.tags, [])
+
+        rev44 = self.repo.revisions[44]
+        chset44 = self.repo.get_changeset(rev44)
+        self.assertEqual(chset44.branch, 'web-branch')
+
+        tip = self.repo.get_changeset('tip')
+        self.assertTrue('tip' in tip.tags)
+        '''
+        # Those tests would fail - branches are now going
+        # to be changed at main API in order to support git backend
+        pass
+
+    def _test_slices(self, limit, offset):
+        count = self.repo.count()
+        changesets = self.repo.get_changesets(limit=limit, offset=offset)
+        idx = 0
+        for changeset in changesets:
+            rev = offset + idx
+            idx += 1
+            rev_id = self.repo.revisions[rev]
+            if idx > limit:
+                self.fail("Exceeded limit already (getting revision %s, "
+                    "there are %s total revisions, offset=%s, limit=%s)"
+                    % (rev_id, count, offset, limit))
+            self.assertEqual(changeset, self.repo.get_changeset(rev_id))
+        result = list(self.repo.get_changesets(limit=limit, offset=offset))
+        start = offset
+        end = limit and offset + limit or None
+        sliced = list(self.repo[start:end])
+        self.failUnlessEqual(result, sliced,
+            msg="Comparison failed for limit=%s, offset=%s"
+            "(get_changeset returned: %s and sliced: %s"
+            % (limit, offset, result, sliced))
+
+    def _test_file_size(self, revision, path, size):
+        node = self.repo.get_changeset(revision).get_node(path)
+        self.assertTrue(node.is_file())
+        self.assertEqual(node.size, size)
+
+    def test_file_size(self):
+        to_check = (
+            ('c1214f7e79e02fc37156ff215cd71275450cffc3',
+                'vcs/backends/BaseRepository.py', 502),
+            ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
+                'vcs/backends/hg.py', 854),
+            ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
+                'setup.py', 1068),
+
+            ('d955cd312c17b02143c04fa1099a352b04368118',
+                'vcs/backends/base.py', 2921),
+            ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
+                'vcs/backends/base.py', 3936),
+            ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
+                'vcs/backends/base.py', 6189),
+        )
+        for revision, path, size in to_check:
+            self._test_file_size(revision, path, size)
+
+    def test_file_history(self):
+        # we can only check if those revisions are present in the history
+        # as we cannot update this test every time file is changed
+        files = {
+            'setup.py': [
+                '54386793436c938cff89326944d4c2702340037d',
+                '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
+                '998ed409c795fec2012b1c0ca054d99888b22090',
+                '5e0eb4c47f56564395f76333f319d26c79e2fb09',
+                '0115510b70c7229dbc5dc49036b32e7d91d23acd',
+                '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
+                '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
+                '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
+                'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
+            ],
+            'vcs/nodes.py': [
+                '33fa3223355104431402a888fa77a4e9956feb3e',
+                'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
+                'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
+                'ab5721ca0a081f26bf43d9051e615af2cc99952f',
+                'c877b68d18e792a66b7f4c529ea02c8f80801542',
+                '4313566d2e417cb382948f8d9d7c765330356054',
+                '6c2303a793671e807d1cfc70134c9ca0767d98c2',
+                '54386793436c938cff89326944d4c2702340037d',
+                '54000345d2e78b03a99d561399e8e548de3f3203',
+                '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
+                '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
+                '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
+                '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
+                'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
+                '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
+                '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
+                '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
+                '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
+                'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
+                'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
+                'f15c21f97864b4f071cddfbf2750ec2e23859414',
+                'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
+                'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
+                '84dec09632a4458f79f50ddbbd155506c460b4f9',
+                '0115510b70c7229dbc5dc49036b32e7d91d23acd',
+                '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
+                '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
+                'b8d04012574729d2c29886e53b1a43ef16dd00a1',
+                '6970b057cffe4aab0a792aa634c89f4bebf01441',
+                'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
+                'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
+            ],
+            'vcs/backends/git.py': [
+                '4cf116ad5a457530381135e2f4c453e68a1b0105',
+                '9a751d84d8e9408e736329767387f41b36935153',
+                'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
+                '428f81bb652bcba8d631bce926e8834ff49bdcc6',
+                '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
+                '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
+                '50e08c506174d8645a4bb517dd122ac946a0f3bf',
+                '54000345d2e78b03a99d561399e8e548de3f3203',
+            ],
+        }
+        for path, revs in files.items():
+            node = self.repo.get_changeset(revs[0]).get_node(path)
+            node_revs = [chset.raw_id for chset in node.history]
+            self.assertTrue(set(revs).issubset(set(node_revs)),
+                "We assumed that %s is subset of revisions for which file %s "
+                "has been changed, and history of that node returned: %s"
+                % (revs, path, node_revs))
+
+    def test_file_annotate(self):
+        files = {
+            'vcs/backends/__init__.py': {
+                'c1214f7e79e02fc37156ff215cd71275450cffc3': {
+                    'lines_no': 1,
+                    'changesets': [
+                        'c1214f7e79e02fc37156ff215cd71275450cffc3',
+                    ],
+                },
+                '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
+                    'lines_no': 21,
+                    'changesets': [
+                        '49d3fd156b6f7db46313fac355dca1a0b94a0017',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                    ],
+                },
+                'e29b67bd158580fc90fc5e9111240b90e6e86064': {
+                    'lines_no': 32,
+                    'changesets': [
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '54000345d2e78b03a99d561399e8e548de3f3203',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '78c3f0c23b7ee935ec276acb8b8212444c33c396',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '78c3f0c23b7ee935ec276acb8b8212444c33c396',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '992f38217b979d0b0987d0bae3cc26dac85d9b19',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                        '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
+                    ],
+                },
+            },
+        }
+
+        for fname, revision_dict in files.items():
+            for rev, data in revision_dict.items():
+                cs = self.repo.get_changeset(rev)
+                ann = cs.get_file_annotate(fname)
+
+                l1 = [x[1].raw_id for x in ann]
+                l2 = files[fname][rev]['changesets']
+                self.assertTrue(l1 == l2 , "The lists of revision for %s@rev %s"
+                                "from annotation list should match each other, "
+                                "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
+
+    def test_files_state(self):
+        """
+        Tests state of FileNodes.
+        """
+        node = self.repo\
+            .get_changeset('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0')\
+            .get_node('vcs/utils/diffs.py')
+        self.assertTrue(node.state, NodeState.ADDED)
+        self.assertTrue(node.added)
+        self.assertFalse(node.changed)
+        self.assertFalse(node.not_changed)
+        self.assertFalse(node.removed)
+
+        node = self.repo\
+            .get_changeset('33fa3223355104431402a888fa77a4e9956feb3e')\
+            .get_node('.hgignore')
+        self.assertTrue(node.state, NodeState.CHANGED)
+        self.assertFalse(node.added)
+        self.assertTrue(node.changed)
+        self.assertFalse(node.not_changed)
+        self.assertFalse(node.removed)
+
+        node = self.repo\
+            .get_changeset('e29b67bd158580fc90fc5e9111240b90e6e86064')\
+            .get_node('setup.py')
+        self.assertTrue(node.state, NodeState.NOT_CHANGED)
+        self.assertFalse(node.added)
+        self.assertFalse(node.changed)
+        self.assertTrue(node.not_changed)
+        self.assertFalse(node.removed)
+
+        # If node has REMOVED state then trying to fetch it would raise
+        # ChangesetError exception
+        chset = self.repo.get_changeset(
+            'fa6600f6848800641328adbf7811fd2372c02ab2')
+        path = 'vcs/backends/BaseRepository.py'
+        self.assertRaises(NodeDoesNotExistError, chset.get_node, path)
+        # but it would be one of ``removed`` (changeset's attribute)
+        self.assertTrue(path in [rf.path for rf in chset.removed])
+
+        chset = self.repo.get_changeset(
+            '54386793436c938cff89326944d4c2702340037d')
+        changed = ['setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
+            'vcs/nodes.py']
+        self.assertEqual(set(changed), set([f.path for f in chset.changed]))
+
+    def test_commit_message_is_unicode(self):
+        for cs in self.repo:
+            self.assertEqual(type(cs.message), unicode)
+
+    def test_changeset_author_is_unicode(self):
+        for cs in self.repo:
+            self.assertEqual(type(cs.author), unicode)
+
+    def test_repo_files_content_is_unicode(self):
+        changeset = self.repo.get_changeset()
+        for node in changeset.get_node('/'):
+            if node.is_file():
+                self.assertEqual(type(node.content), unicode)
+
+    def test_wrong_path(self):
+        # There is 'setup.py' in the root dir but not there:
+        path = 'foo/bar/setup.py'
+        tip = self.repo.get_changeset()
+        self.assertRaises(VCSError, tip.get_node, path)
+
+    def test_author_email(self):
+        self.assertEqual('marcin@python-blog.com',
+          self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3')\
+          .author_email)
+        self.assertEqual('lukasz.balcerzak@python-center.pl',
+          self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b')\
+          .author_email)
+        self.assertEqual('none@none',
+          self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992')\
+          .author_email)
+
+    def test_author_username(self):
+        self.assertEqual('Marcin Kuzminski',
+          self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3')\
+          .author_name)
+        self.assertEqual('Lukasz Balcerzak',
+          self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b')\
+          .author_name)
+        self.assertEqual('marcink',
+          self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992')\
+          .author_name)
+
+
+class GitSpecificTest(unittest.TestCase):
+
+    def test_error_is_raised_for_added_if_diff_name_status_is_wrong(self):
+        repo = mock.MagicMock()
+        changeset = GitChangeset(repo, 'foobar')
+        changeset._diff_name_status = 'foobar'
+        with self.assertRaises(VCSError):
+            changeset.added
+
+    def test_error_is_raised_for_changed_if_diff_name_status_is_wrong(self):
+        repo = mock.MagicMock()
+        changeset = GitChangeset(repo, 'foobar')
+        changeset._diff_name_status = 'foobar'
+        with self.assertRaises(VCSError):
+            changeset.added
+
+    def test_error_is_raised_for_removed_if_diff_name_status_is_wrong(self):
+        repo = mock.MagicMock()
+        changeset = GitChangeset(repo, 'foobar')
+        changeset._diff_name_status = 'foobar'
+        with self.assertRaises(VCSError):
+            changeset.added
+
+
+class GitSpecificWithRepoTest(BackendTestMixin, unittest.TestCase):
+    backend_alias = 'git'
+
+    @classmethod
+    def _get_commits(cls):
+        return [
+            {
+                'message': 'Initial',
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': [
+                    FileNode('foobar/static/js/admin/base.js', content='base'),
+                    FileNode('foobar/static/admin', content='admin',
+                        mode=0120000), # this is a link
+                    FileNode('foo', content='foo'),
+                ],
+            },
+            {
+                'message': 'Second',
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 22),
+                'added': [
+                    FileNode('foo2', content='foo2'),
+                ],
+            },
+        ]
+
+    def test_paths_slow_traversing(self):
+        cs = self.repo.get_changeset()
+        self.assertEqual(cs.get_node('foobar').get_node('static').get_node('js')
+            .get_node('admin').get_node('base.js').content, 'base')
+
+    def test_paths_fast_traversing(self):
+        cs = self.repo.get_changeset()
+        self.assertEqual(cs.get_node('foobar/static/js/admin/base.js').content,
+            'base')
+
+    def test_workdir_get_branch(self):
+        self.repo.run_git_command('checkout -b production')
+        # Regression test: one of following would fail if we don't check
+        # .git/HEAD file
+        self.repo.run_git_command('checkout production')
+        self.assertEqual(self.repo.workdir.get_branch(), 'production')
+        self.repo.run_git_command('checkout master')
+        self.assertEqual(self.repo.workdir.get_branch(), 'master')
+
+    def test_get_diff_runs_git_command_with_hashes(self):
+        self.repo.run_git_command = mock.Mock(return_value=['', ''])
+        self.repo.get_diff(0, 1)
+        self.repo.run_git_command.assert_called_once_with('diff -U%s %s %s' %
+            (3, self.repo._get_revision(0), self.repo._get_revision(1)))
+
+    def test_get_diff_runs_git_command_with_str_hashes(self):
+        self.repo.run_git_command = mock.Mock(return_value=['', ''])
+        self.repo.get_diff(self.repo.EMPTY_CHANGESET, 1)
+        self.repo.run_git_command.assert_called_once_with('show -U%s %s' %
+            (3, self.repo._get_revision(1)))
+
+    def test_get_diff_runs_git_command_with_path_if_its_given(self):
+        self.repo.run_git_command = mock.Mock(return_value=['', ''])
+        self.repo.get_diff(0, 1, 'foo')
+        self.repo.run_git_command.assert_called_once_with('diff -U%s %s %s -- "foo"'
+            % (3, self.repo._get_revision(0), self.repo._get_revision(1)))
+
+
+class GitRegressionTest(BackendTestMixin, unittest.TestCase):
+    backend_alias = 'git'
+
+    @classmethod
+    def _get_commits(cls):
+        return [
+            {
+                'message': 'Initial',
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': [
+                    FileNode('bot/__init__.py', content='base'),
+                    FileNode('bot/templates/404.html', content='base'),
+                    FileNode('bot/templates/500.html', content='base'),
+                ],
+            },
+            {
+                'message': 'Second',
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 22),
+                'added': [
+                    FileNode('bot/build/migrations/1.py', content='foo2'),
+                    FileNode('bot/build/migrations/2.py', content='foo2'),
+                    FileNode('bot/build/static/templates/f.html', content='foo2'),
+                    FileNode('bot/build/static/templates/f1.html', content='foo2'),
+                    FileNode('bot/build/templates/err.html', content='foo2'),
+                    FileNode('bot/build/templates/err2.html', content='foo2'),
+                ],
+            },
+        ]
+
+    def test_similar_paths(self):
+        cs = self.repo.get_changeset()
+        paths = lambda *n:[x.path for x in n]
+        self.assertEqual(paths(*cs.get_nodes('bot')), ['bot/build', 'bot/templates', 'bot/__init__.py'])
+        self.assertEqual(paths(*cs.get_nodes('bot/build')), ['bot/build/migrations', 'bot/build/static', 'bot/build/templates'])
+        self.assertEqual(paths(*cs.get_nodes('bot/build/static')), ['bot/build/static/templates'])
+        # this get_nodes below causes troubles !
+        self.assertEqual(paths(*cs.get_nodes('bot/build/static/templates')), ['bot/build/static/templates/f.html', 'bot/build/static/templates/f1.html'])
+        self.assertEqual(paths(*cs.get_nodes('bot/build/templates')), ['bot/build/templates/err.html', 'bot/build/templates/err2.html'])
+        self.assertEqual(paths(*cs.get_nodes('bot/templates/')), ['bot/templates/404.html', 'bot/templates/500.html'])
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_hg.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,557 @@
+from __future__ import with_statement
+
+import os
+from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialChangeset
+from rhodecode.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
+from rhodecode.lib.vcs.nodes import NodeKind, NodeState
+from conf import PACKAGE_DIR, TEST_HG_REPO, TEST_HG_REPO_CLONE, \
+    TEST_HG_REPO_PULL
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+# Use only clean mercurial's ui
+import mercurial.scmutil
+mercurial.scmutil.rcpath()
+if mercurial.scmutil._rcpath:
+    mercurial.scmutil._rcpath = mercurial.scmutil._rcpath[:1]
+
+
+class MercurialRepositoryTest(unittest.TestCase):
+
+    def __check_for_existing_repo(self):
+        if os.path.exists(TEST_HG_REPO_CLONE):
+            self.fail('Cannot test mercurial clone repo as location %s already '
+                      'exists. You should manually remove it first.'
+                      % TEST_HG_REPO_CLONE)
+
+    def setUp(self):
+        self.repo = MercurialRepository(TEST_HG_REPO)
+
+    def test_wrong_repo_path(self):
+        wrong_repo_path = '/tmp/errorrepo'
+        self.assertRaises(RepositoryError, MercurialRepository, wrong_repo_path)
+
+    def test_unicode_path_repo(self):
+        self.assertRaises(VCSError,lambda:MercurialRepository(u'iShouldFail'))
+
+    def test_repo_clone(self):
+        self.__check_for_existing_repo()
+        repo = MercurialRepository(TEST_HG_REPO)
+        repo_clone = MercurialRepository(TEST_HG_REPO_CLONE,
+            src_url=TEST_HG_REPO, update_after_clone=True)
+        self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
+        # Checking hashes of changesets should be enough
+        for changeset in repo.get_changesets():
+            raw_id = changeset.raw_id
+            self.assertEqual(raw_id, repo_clone.get_changeset(raw_id).raw_id)
+
+    def test_repo_clone_with_update(self):
+        repo = MercurialRepository(TEST_HG_REPO)
+        repo_clone = MercurialRepository(TEST_HG_REPO_CLONE + '_w_update',
+            src_url=TEST_HG_REPO, update_after_clone=True)
+        self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
+
+        #check if current workdir was updated
+        self.assertEqual(os.path.isfile(os.path.join(TEST_HG_REPO_CLONE \
+                                                    + '_w_update',
+                                                    'MANIFEST.in')), True,)
+
+    def test_repo_clone_without_update(self):
+        repo = MercurialRepository(TEST_HG_REPO)
+        repo_clone = MercurialRepository(TEST_HG_REPO_CLONE + '_wo_update',
+            src_url=TEST_HG_REPO, update_after_clone=False)
+        self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
+        self.assertEqual(os.path.isfile(os.path.join(TEST_HG_REPO_CLONE \
+                                                    + '_wo_update',
+                                                    'MANIFEST.in')), False,)
+
+    def test_pull(self):
+        if os.path.exists(TEST_HG_REPO_PULL):
+            self.fail('Cannot test mercurial pull command as location %s '
+                      'already exists. You should manually remove it first'
+                      % TEST_HG_REPO_PULL)
+        repo_new = MercurialRepository(TEST_HG_REPO_PULL, create=True)
+        self.assertTrue(len(self.repo.revisions) > len(repo_new.revisions))
+
+        repo_new.pull(self.repo.path)
+        repo_new = MercurialRepository(TEST_HG_REPO_PULL)
+        self.assertTrue(len(self.repo.revisions) == len(repo_new.revisions))
+
+    def test_revisions(self):
+        # there are 21 revisions at bitbucket now
+        # so we can assume they would be available from now on
+        subset = set(['b986218ba1c9b0d6a259fac9b050b1724ed8e545',
+                 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
+                 '6cba7170863a2411822803fa77a0a264f1310b35',
+                 '56349e29c2af3ac913b28bde9a2c6154436e615b',
+                 '2dda4e345facb0ccff1a191052dd1606dba6781d',
+                 '6fff84722075f1607a30f436523403845f84cd9e',
+                 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
+                 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
+                 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
+                 'be90031137367893f1c406e0a8683010fd115b79',
+                 'db8e58be770518cbb2b1cdfa69146e47cd481481',
+                 '84478366594b424af694a6c784cb991a16b87c21',
+                 '17f8e105dddb9f339600389c6dc7175d395a535c',
+                 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
+                 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
+                 '786facd2c61deb9cf91e9534735124fb8fc11842',
+                 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
+                 'aa6a0de05b7612707db567078e130a6cd114a9a7',
+                 'eada5a770da98ab0dd7325e29d00e0714f228d09'
+                ])
+        self.assertTrue(subset.issubset(set(self.repo.revisions)))
+
+
+        # check if we have the proper order of revisions
+        org = ['b986218ba1c9b0d6a259fac9b050b1724ed8e545',
+                '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
+                '6cba7170863a2411822803fa77a0a264f1310b35',
+                '56349e29c2af3ac913b28bde9a2c6154436e615b',
+                '2dda4e345facb0ccff1a191052dd1606dba6781d',
+                '6fff84722075f1607a30f436523403845f84cd9e',
+                '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
+                '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
+                'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
+                'be90031137367893f1c406e0a8683010fd115b79',
+                'db8e58be770518cbb2b1cdfa69146e47cd481481',
+                '84478366594b424af694a6c784cb991a16b87c21',
+                '17f8e105dddb9f339600389c6dc7175d395a535c',
+                '20a662e756499bde3095ffc9bc0643d1def2d0eb',
+                '2e319b85e70a707bba0beff866d9f9de032aa4f9',
+                '786facd2c61deb9cf91e9534735124fb8fc11842',
+                '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
+                'aa6a0de05b7612707db567078e130a6cd114a9a7',
+                'eada5a770da98ab0dd7325e29d00e0714f228d09',
+                '2c1885c735575ca478bf9e17b0029dca68824458',
+                'd9bcd465040bf869799b09ad732c04e0eea99fe9',
+                '469e9c847fe1f6f7a697b8b25b4bc5b48780c1a7',
+                '4fb8326d78e5120da2c7468dcf7098997be385da',
+                '62b4a097164940bd66030c4db51687f3ec035eed',
+                '536c1a19428381cfea92ac44985304f6a8049569',
+                '965e8ab3c44b070cdaa5bf727ddef0ada980ecc4',
+                '9bb326a04ae5d98d437dece54be04f830cf1edd9',
+                'f8940bcb890a98c4702319fbe36db75ea309b475',
+                'ff5ab059786ebc7411e559a2cc309dfae3625a3b',
+                '6b6ad5f82ad5bb6190037671bd254bd4e1f4bf08',
+                'ee87846a61c12153b51543bf860e1026c6d3dcba', ]
+        self.assertEqual(org, self.repo.revisions[:31])
+
+    def test_iter_slice(self):
+        sliced = list(self.repo[:10])
+        itered = list(self.repo)[:10]
+        self.assertEqual(sliced, itered)
+
+    def test_slicing(self):
+        #4 1 5 10 95
+        for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
+                                 (10, 20, 10), (5, 100, 95)]:
+            revs = list(self.repo[sfrom:sto])
+            self.assertEqual(len(revs), size)
+            self.assertEqual(revs[0], self.repo.get_changeset(sfrom))
+            self.assertEqual(revs[-1], self.repo.get_changeset(sto - 1))
+
+    def test_branches(self):
+        # TODO: Need more tests here
+
+        #active branches
+        self.assertTrue('default' in self.repo.branches)
+        self.assertTrue('git' in self.repo.branches)
+
+        # closed
+        self.assertTrue('web' in self.repo._get_branches(closed=True))
+
+        for name, id in self.repo.branches.items():
+            self.assertTrue(isinstance(
+                self.repo.get_changeset(id), MercurialChangeset))
+
+    def test_tip_in_tags(self):
+        # tip is always a tag
+        self.assertIn('tip', self.repo.tags)
+
+    def test_tip_changeset_in_tags(self):
+        tip = self.repo.get_changeset()
+        self.assertEqual(self.repo.tags['tip'], tip.raw_id)
+
+    def test_initial_changeset(self):
+
+        init_chset = self.repo.get_changeset(0)
+        self.assertEqual(init_chset.message, 'initial import')
+        self.assertEqual(init_chset.author,
+            'Marcin Kuzminski <marcin@python-blog.com>')
+        self.assertEqual(sorted(init_chset._file_paths),
+            sorted([
+                'vcs/__init__.py',
+                'vcs/backends/BaseRepository.py',
+                'vcs/backends/__init__.py',
+            ])
+        )
+        self.assertEqual(sorted(init_chset._dir_paths),
+            sorted(['', 'vcs', 'vcs/backends']))
+
+        self.assertRaises(NodeDoesNotExistError, init_chset.get_node, path='foobar')
+
+        node = init_chset.get_node('vcs/')
+        self.assertTrue(hasattr(node, 'kind'))
+        self.assertEqual(node.kind, NodeKind.DIR)
+
+        node = init_chset.get_node('vcs')
+        self.assertTrue(hasattr(node, 'kind'))
+        self.assertEqual(node.kind, NodeKind.DIR)
+
+        node = init_chset.get_node('vcs/__init__.py')
+        self.assertTrue(hasattr(node, 'kind'))
+        self.assertEqual(node.kind, NodeKind.FILE)
+
+    def test_not_existing_changeset(self):
+        #rawid
+        self.assertRaises(RepositoryError, self.repo.get_changeset,
+            'abcd' * 10)
+        #shortid
+        self.assertRaises(RepositoryError, self.repo.get_changeset,
+            'erro' * 4)
+        #numeric
+        self.assertRaises(RepositoryError, self.repo.get_changeset,
+            self.repo.count() + 1)
+
+
+        # Small chance we ever get to this one
+        revision = pow(2, 30)
+        self.assertRaises(RepositoryError, self.repo.get_changeset, revision)
+
+    def test_changeset10(self):
+
+        chset10 = self.repo.get_changeset(10)
+        README = """===
+VCS
+===
+
+Various Version Control System management abstraction layer for Python.
+
+Introduction
+------------
+
+TODO: To be written...
+
+"""
+        node = chset10.get_node('README.rst')
+        self.assertEqual(node.kind, NodeKind.FILE)
+        self.assertEqual(node.content, README)
+
+
+class MercurialChangesetTest(unittest.TestCase):
+
+    def setUp(self):
+        self.repo = MercurialRepository(TEST_HG_REPO)
+
+    def _test_equality(self, changeset):
+        revision = changeset.revision
+        self.assertEqual(changeset, self.repo.get_changeset(revision))
+
+    def test_equality(self):
+        self.setUp()
+        revs = [0, 10, 20]
+        changesets = [self.repo.get_changeset(rev) for rev in revs]
+        for changeset in changesets:
+            self._test_equality(changeset)
+
+    def test_default_changeset(self):
+        tip = self.repo.get_changeset('tip')
+        self.assertEqual(tip, self.repo.get_changeset())
+        self.assertEqual(tip, self.repo.get_changeset(revision=None))
+        self.assertEqual(tip, list(self.repo[-1:])[0])
+
+    def test_root_node(self):
+        tip = self.repo.get_changeset('tip')
+        self.assertTrue(tip.root is tip.get_node(''))
+
+    def test_lazy_fetch(self):
+        """
+        Test if changeset's nodes expands and are cached as we walk through
+        the revision. This test is somewhat hard to write as order of tests
+        is a key here. Written by running command after command in a shell.
+        """
+        self.setUp()
+        chset = self.repo.get_changeset(45)
+        self.assertTrue(len(chset.nodes) == 0)
+        root = chset.root
+        self.assertTrue(len(chset.nodes) == 1)
+        self.assertTrue(len(root.nodes) == 8)
+        # accessing root.nodes updates chset.nodes
+        self.assertTrue(len(chset.nodes) == 9)
+
+        docs = root.get_node('docs')
+        # we haven't yet accessed anything new as docs dir was already cached
+        self.assertTrue(len(chset.nodes) == 9)
+        self.assertTrue(len(docs.nodes) == 8)
+        # accessing docs.nodes updates chset.nodes
+        self.assertTrue(len(chset.nodes) == 17)
+
+        self.assertTrue(docs is chset.get_node('docs'))
+        self.assertTrue(docs is root.nodes[0])
+        self.assertTrue(docs is root.dirs[0])
+        self.assertTrue(docs is chset.get_node('docs'))
+
+    def test_nodes_with_changeset(self):
+        self.setUp()
+        chset = self.repo.get_changeset(45)
+        root = chset.root
+        docs = root.get_node('docs')
+        self.assertTrue(docs is chset.get_node('docs'))
+        api = docs.get_node('api')
+        self.assertTrue(api is chset.get_node('docs/api'))
+        index = api.get_node('index.rst')
+        self.assertTrue(index is chset.get_node('docs/api/index.rst'))
+        self.assertTrue(index is chset.get_node('docs')\
+            .get_node('api')\
+            .get_node('index.rst'))
+
+    def test_branch_and_tags(self):
+        chset0 = self.repo.get_changeset(0)
+        self.assertEqual(chset0.branch, 'default')
+        self.assertEqual(chset0.tags, [])
+
+        chset10 = self.repo.get_changeset(10)
+        self.assertEqual(chset10.branch, 'default')
+        self.assertEqual(chset10.tags, [])
+
+        chset44 = self.repo.get_changeset(44)
+        self.assertEqual(chset44.branch, 'web')
+
+        tip = self.repo.get_changeset('tip')
+        self.assertTrue('tip' in tip.tags)
+
+    def _test_file_size(self, revision, path, size):
+        node = self.repo.get_changeset(revision).get_node(path)
+        self.assertTrue(node.is_file())
+        self.assertEqual(node.size, size)
+
+    def test_file_size(self):
+        to_check = (
+            (10, 'setup.py', 1068),
+            (20, 'setup.py', 1106),
+            (60, 'setup.py', 1074),
+
+            (10, 'vcs/backends/base.py', 2921),
+            (20, 'vcs/backends/base.py', 3936),
+            (60, 'vcs/backends/base.py', 6189),
+        )
+        for revision, path, size in to_check:
+            self._test_file_size(revision, path, size)
+
+    def test_file_history(self):
+        # we can only check if those revisions are present in the history
+        # as we cannot update this test every time file is changed
+        files = {
+            'setup.py': [7, 18, 45, 46, 47, 69, 77],
+            'vcs/nodes.py': [7, 8, 24, 26, 30, 45, 47, 49, 56, 57, 58, 59, 60,
+                61, 73, 76],
+            'vcs/backends/hg.py': [4, 5, 6, 11, 12, 13, 14, 15, 16, 21, 22, 23,
+                26, 27, 28, 30, 31, 33, 35, 36, 37, 38, 39, 40, 41, 44, 45, 47,
+                48, 49, 53, 54, 55, 58, 60, 61, 67, 68, 69, 70, 73, 77, 78, 79,
+                82],
+        }
+        for path, revs in files.items():
+            tip = self.repo.get_changeset(revs[-1])
+            node = tip.get_node(path)
+            node_revs = [chset.revision for chset in node.history]
+            self.assertTrue(set(revs).issubset(set(node_revs)),
+                "We assumed that %s is subset of revisions for which file %s "
+                "has been changed, and history of that node returned: %s"
+                % (revs, path, node_revs))
+
+    def test_file_annotate(self):
+        files = {
+                 'vcs/backends/__init__.py':
+                  {89: {'lines_no': 31,
+                        'changesets': [32, 32, 61, 32, 32, 37, 32, 32, 32, 44,
+                                       37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
+                                       32, 32, 32, 32, 37, 32, 37, 37, 32,
+                                       32, 32]},
+                   20: {'lines_no': 1,
+                        'changesets': [4]},
+                   55: {'lines_no': 31,
+                        'changesets': [32, 32, 45, 32, 32, 37, 32, 32, 32, 44,
+                                       37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
+                                       32, 32, 32, 32, 37, 32, 37, 37, 32,
+                                       32, 32]}},
+                 'vcs/exceptions.py':
+                 {89: {'lines_no': 18,
+                       'changesets': [16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+                                      16, 16, 17, 16, 16, 18, 18, 18]},
+                  20: {'lines_no': 18,
+                       'changesets': [16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+                                      16, 16, 17, 16, 16, 18, 18, 18]},
+                  55: {'lines_no': 18, 'changesets': [16, 16, 16, 16, 16, 16,
+                                                      16, 16, 16, 16, 16, 16,
+                                                      17, 16, 16, 18, 18, 18]}},
+                 'MANIFEST.in': {89: {'lines_no': 5,
+                                      'changesets': [7, 7, 7, 71, 71]},
+                                 20: {'lines_no': 3,
+                                      'changesets': [7, 7, 7]},
+                                 55: {'lines_no': 3,
+                                     'changesets': [7, 7, 7]}}}
+
+
+        for fname, revision_dict in files.items():
+            for rev, data in revision_dict.items():
+                cs = self.repo.get_changeset(rev)
+                ann = cs.get_file_annotate(fname)
+
+                l1 = [x[1].revision for x in ann]
+                l2 = files[fname][rev]['changesets']
+                self.assertTrue(l1 == l2 , "The lists of revision for %s@rev%s"
+                                "from annotation list should match each other,"
+                                "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
+
+    def test_changeset_state(self):
+        """
+        Tests which files have been added/changed/removed at particular revision
+        """
+
+        # rev 46ad32a4f974:
+        # hg st --rev 46ad32a4f974
+        #    changed: 13
+        #    added:   20
+        #    removed: 1
+        changed = set(['.hgignore'
+            , 'README.rst' , 'docs/conf.py' , 'docs/index.rst' , 'setup.py'
+            , 'tests/test_hg.py' , 'tests/test_nodes.py' , 'vcs/__init__.py'
+            , 'vcs/backends/__init__.py' , 'vcs/backends/base.py'
+            , 'vcs/backends/hg.py' , 'vcs/nodes.py' , 'vcs/utils/__init__.py'])
+
+        added = set(['docs/api/backends/hg.rst'
+            , 'docs/api/backends/index.rst' , 'docs/api/index.rst'
+            , 'docs/api/nodes.rst' , 'docs/api/web/index.rst'
+            , 'docs/api/web/simplevcs.rst' , 'docs/installation.rst'
+            , 'docs/quickstart.rst' , 'setup.cfg' , 'vcs/utils/baseui_config.py'
+            , 'vcs/utils/web.py' , 'vcs/web/__init__.py' , 'vcs/web/exceptions.py'
+            , 'vcs/web/simplevcs/__init__.py' , 'vcs/web/simplevcs/exceptions.py'
+            , 'vcs/web/simplevcs/middleware.py' , 'vcs/web/simplevcs/models.py'
+            , 'vcs/web/simplevcs/settings.py' , 'vcs/web/simplevcs/utils.py'
+            , 'vcs/web/simplevcs/views.py'])
+
+        removed = set(['docs/api.rst'])
+
+        chset64 = self.repo.get_changeset('46ad32a4f974')
+        self.assertEqual(set((node.path for node in chset64.added)), added)
+        self.assertEqual(set((node.path for node in chset64.changed)), changed)
+        self.assertEqual(set((node.path for node in chset64.removed)), removed)
+
+        # rev b090f22d27d6:
+        # hg st --rev b090f22d27d6
+        #    changed: 13
+        #    added:   20
+        #    removed: 1
+        chset88 = self.repo.get_changeset('b090f22d27d6')
+        self.assertEqual(set((node.path for node in chset88.added)), set())
+        self.assertEqual(set((node.path for node in chset88.changed)),
+            set(['.hgignore']))
+        self.assertEqual(set((node.path for node in chset88.removed)), set())
+#
+        # 85:
+        #    added:   2 ['vcs/utils/diffs.py', 'vcs/web/simplevcs/views/diffs.py']
+        #    changed: 4 ['vcs/web/simplevcs/models.py', ...]
+        #    removed: 1 ['vcs/utils/web.py']
+        chset85 = self.repo.get_changeset(85)
+        self.assertEqual(set((node.path for node in chset85.added)), set([
+            'vcs/utils/diffs.py',
+            'vcs/web/simplevcs/views/diffs.py']))
+        self.assertEqual(set((node.path for node in chset85.changed)), set([
+            'vcs/web/simplevcs/models.py',
+            'vcs/web/simplevcs/utils.py',
+            'vcs/web/simplevcs/views/__init__.py',
+            'vcs/web/simplevcs/views/repository.py',
+            ]))
+        self.assertEqual(set((node.path for node in chset85.removed)),
+            set(['vcs/utils/web.py']))
+
+
+    def test_files_state(self):
+        """
+        Tests state of FileNodes.
+        """
+        chset = self.repo.get_changeset(85)
+        node = chset.get_node('vcs/utils/diffs.py')
+        self.assertTrue(node.state, NodeState.ADDED)
+        self.assertTrue(node.added)
+        self.assertFalse(node.changed)
+        self.assertFalse(node.not_changed)
+        self.assertFalse(node.removed)
+
+        chset = self.repo.get_changeset(88)
+        node = chset.get_node('.hgignore')
+        self.assertTrue(node.state, NodeState.CHANGED)
+        self.assertFalse(node.added)
+        self.assertTrue(node.changed)
+        self.assertFalse(node.not_changed)
+        self.assertFalse(node.removed)
+
+        chset = self.repo.get_changeset(85)
+        node = chset.get_node('setup.py')
+        self.assertTrue(node.state, NodeState.NOT_CHANGED)
+        self.assertFalse(node.added)
+        self.assertFalse(node.changed)
+        self.assertTrue(node.not_changed)
+        self.assertFalse(node.removed)
+
+        # If node has REMOVED state then trying to fetch it would raise
+        # ChangesetError exception
+        chset = self.repo.get_changeset(2)
+        path = 'vcs/backends/BaseRepository.py'
+        self.assertRaises(NodeDoesNotExistError, chset.get_node, path)
+        # but it would be one of ``removed`` (changeset's attribute)
+        self.assertTrue(path in [rf.path for rf in chset.removed])
+
+    def test_commit_message_is_unicode(self):
+        for cm in self.repo:
+            self.assertEqual(type(cm.message), unicode)
+
+    def test_changeset_author_is_unicode(self):
+        for cm in self.repo:
+            self.assertEqual(type(cm.author), unicode)
+
+    def test_repo_files_content_is_unicode(self):
+        test_changeset = self.repo.get_changeset(100)
+        for node in test_changeset.get_node('/'):
+            if node.is_file():
+                self.assertEqual(type(node.content), unicode)
+
+    def test_wrong_path(self):
+        # There is 'setup.py' in the root dir but not there:
+        path = 'foo/bar/setup.py'
+        self.assertRaises(VCSError, self.repo.get_changeset().get_node, path)
+
+
+    def test_archival_file(self):
+        #TODO:
+        pass
+
+    def test_archival_as_generator(self):
+        #TODO:
+        pass
+
+    def test_archival_wrong_kind(self):
+        tip = self.repo.get_changeset()
+        self.assertRaises(VCSError, tip.fill_archive, kind='error')
+
+    def test_archival_empty_prefix(self):
+        #TODO:
+        pass
+
+
+    def test_author_email(self):
+        self.assertEqual('marcin@python-blog.com',
+                         self.repo.get_changeset('b986218ba1c9').author_email)
+        self.assertEqual('lukasz.balcerzak@python-center.pl',
+                         self.repo.get_changeset('3803844fdbd3').author_email)
+        self.assertEqual('',
+                         self.repo.get_changeset('84478366594b').author_email)
+
+    def test_author_username(self):
+        self.assertEqual('Marcin Kuzminski',
+                         self.repo.get_changeset('b986218ba1c9').author_name)
+        self.assertEqual('Lukasz Balcerzak',
+                         self.repo.get_changeset('3803844fdbd3').author_name)
+        self.assertEqual('marcink',
+                         self.repo.get_changeset('84478366594b').author_name)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_inmemchangesets.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,340 @@
+"""
+Tests so called "in memory changesets" commit API of vcs.
+"""
+from __future__ import with_statement
+
+from rhodecode.lib import vcs
+import time
+import datetime
+from conf import SCM_TESTS, get_new_dir
+from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
+from rhodecode.lib.vcs.exceptions import NodeAlreadyAddedError
+from rhodecode.lib.vcs.exceptions import NodeAlreadyExistsError
+from rhodecode.lib.vcs.exceptions import NodeAlreadyRemovedError
+from rhodecode.lib.vcs.exceptions import NodeAlreadyChangedError
+from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
+from rhodecode.lib.vcs.exceptions import NodeNotChangedError
+from rhodecode.lib.vcs.nodes import DirNode
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class InMemoryChangesetTestMixin(object):
+    """
+    This is a backend independent test case class which should be created
+    with ``type`` method.
+
+    It is required to set following attributes at subclass:
+
+    - ``backend_alias``: alias of used backend (see ``vcs.BACKENDS``)
+    - ``repo_path``: path to the repository which would be created for set of
+      tests
+    """
+
+    def get_backend(self):
+        return vcs.get_backend(self.backend_alias)
+
+    def setUp(self):
+        Backend = self.get_backend()
+        self.repo_path = get_new_dir(str(time.time()))
+        self.repo = Backend(self.repo_path, create=True)
+        self.imc = self.repo.in_memory_changeset
+        self.nodes = [
+            FileNode('foobar', content='Foo & bar'),
+            FileNode('foobar2', content='Foo & bar, doubled!'),
+            FileNode('foo bar with spaces', content=''),
+            FileNode('foo/bar/baz', content='Inside'),
+        ]
+
+    def test_add(self):
+        rev_count = len(self.repo.revisions)
+        to_add = [FileNode(node.path, content=node.content)
+            for node in self.nodes]
+        for node in to_add:
+            self.imc.add(node)
+        message = u'Added: %s' % ', '.join((node.path for node in self.nodes))
+        author = unicode(self.__class__)
+        changeset = self.imc.commit(message=message, author=author)
+
+        newtip = self.repo.get_changeset()
+        self.assertEqual(changeset, newtip)
+        self.assertEqual(rev_count + 1, len(self.repo.revisions))
+        self.assertEqual(newtip.message, message)
+        self.assertEqual(newtip.author, author)
+        self.assertTrue(not any((self.imc.added, self.imc.changed,
+            self.imc.removed)))
+        for node in to_add:
+            self.assertEqual(newtip.get_node(node.path).content, node.content)
+
+    def test_add_in_bulk(self):
+        rev_count = len(self.repo.revisions)
+        to_add = [FileNode(node.path, content=node.content)
+            for node in self.nodes]
+        self.imc.add(*to_add)
+        message = u'Added: %s' % ', '.join((node.path for node in self.nodes))
+        author = unicode(self.__class__)
+        changeset = self.imc.commit(message=message, author=author)
+
+        newtip = self.repo.get_changeset()
+        self.assertEqual(changeset, newtip)
+        self.assertEqual(rev_count + 1, len(self.repo.revisions))
+        self.assertEqual(newtip.message, message)
+        self.assertEqual(newtip.author, author)
+        self.assertTrue(not any((self.imc.added, self.imc.changed,
+            self.imc.removed)))
+        for node in to_add:
+            self.assertEqual(newtip.get_node(node.path).content, node.content)
+
+    def test_add_actually_adds_all_nodes_at_second_commit_too(self):
+        self.imc.add(FileNode('foo/bar/image.png', content='\0'))
+        self.imc.add(FileNode('foo/README.txt', content='readme!'))
+        changeset = self.imc.commit(u'Initial', u'joe.doe@example.com')
+        self.assertTrue(isinstance(changeset.get_node('foo'), DirNode))
+        self.assertTrue(isinstance(changeset.get_node('foo/bar'), DirNode))
+        self.assertEqual(changeset.get_node('foo/bar/image.png').content, '\0')
+        self.assertEqual(changeset.get_node('foo/README.txt').content, 'readme!')
+
+        # commit some more files again
+        to_add = [
+            FileNode('foo/bar/foobaz/bar', content='foo'),
+            FileNode('foo/bar/another/bar', content='foo'),
+            FileNode('foo/baz.txt', content='foo'),
+            FileNode('foobar/foobaz/file', content='foo'),
+            FileNode('foobar/barbaz', content='foo'),
+        ]
+        self.imc.add(*to_add)
+        changeset = self.imc.commit(u'Another', u'joe.doe@example.com')
+        self.assertEqual(changeset.get_node('foo/bar/foobaz/bar').content, 'foo')
+        self.assertEqual(changeset.get_node('foo/bar/another/bar').content, 'foo')
+        self.assertEqual(changeset.get_node('foo/baz.txt').content, 'foo')
+        self.assertEqual(changeset.get_node('foobar/foobaz/file').content, 'foo')
+        self.assertEqual(changeset.get_node('foobar/barbaz').content, 'foo')
+
+    def test_add_raise_already_added(self):
+        node = FileNode('foobar', content='baz')
+        self.imc.add(node)
+        self.assertRaises(NodeAlreadyAddedError, self.imc.add, node)
+
+    def test_check_integrity_raise_already_exist(self):
+        node = FileNode('foobar', content='baz')
+        self.imc.add(node)
+        self.imc.commit(message=u'Added foobar', author=unicode(self))
+        self.imc.add(node)
+        self.assertRaises(NodeAlreadyExistsError, self.imc.commit,
+            message='new message',
+            author=str(self))
+
+    def test_change(self):
+        self.imc.add(FileNode('foo/bar/baz', content='foo'))
+        self.imc.add(FileNode('foo/fbar', content='foobar'))
+        tip = self.imc.commit(u'Initial', u'joe.doe@example.com')
+
+        # Change node's content
+        node = FileNode('foo/bar/baz', content='My **changed** content')
+        self.imc.change(node)
+        self.imc.commit(u'Changed %s' % node.path, u'joe.doe@example.com')
+
+        newtip = self.repo.get_changeset()
+        self.assertNotEqual(tip, newtip)
+        self.assertNotEqual(tip.id, newtip.id)
+        self.assertEqual(newtip.get_node('foo/bar/baz').content,
+            'My **changed** content')
+
+    def test_change_raise_empty_repository(self):
+        node = FileNode('foobar')
+        self.assertRaises(EmptyRepositoryError, self.imc.change, node)
+
+    def test_check_integrity_change_raise_node_does_not_exist(self):
+        node = FileNode('foobar', content='baz')
+        self.imc.add(node)
+        self.imc.commit(message=u'Added foobar', author=unicode(self))
+        node = FileNode('not-foobar', content='')
+        self.imc.change(node)
+        self.assertRaises(NodeDoesNotExistError, self.imc.commit,
+            message='Changed not existing node',
+            author=str(self))
+
+    def test_change_raise_node_already_changed(self):
+        node = FileNode('foobar', content='baz')
+        self.imc.add(node)
+        self.imc.commit(message=u'Added foobar', author=unicode(self))
+        node = FileNode('foobar', content='more baz')
+        self.imc.change(node)
+        self.assertRaises(NodeAlreadyChangedError, self.imc.change, node)
+
+    def test_check_integrity_change_raise_node_not_changed(self):
+        self.test_add()  # Performs first commit
+
+        node = FileNode(self.nodes[0].path, content=self.nodes[0].content)
+        self.imc.change(node)
+        self.assertRaises(NodeNotChangedError, self.imc.commit,
+            message=u'Trying to mark node as changed without touching it',
+            author=unicode(self))
+
+    def test_change_raise_node_already_removed(self):
+        node = FileNode('foobar', content='baz')
+        self.imc.add(node)
+        self.imc.commit(message=u'Added foobar', author=unicode(self))
+        self.imc.remove(FileNode('foobar'))
+        self.assertRaises(NodeAlreadyRemovedError, self.imc.change, node)
+
+    def test_remove(self):
+        self.test_add()  # Performs first commit
+
+        tip = self.repo.get_changeset()
+        node = self.nodes[0]
+        self.assertEqual(node.content, tip.get_node(node.path).content)
+        self.imc.remove(node)
+        self.imc.commit(message=u'Removed %s' % node.path, author=unicode(self))
+
+        newtip = self.repo.get_changeset()
+        self.assertNotEqual(tip, newtip)
+        self.assertNotEqual(tip.id, newtip.id)
+        self.assertRaises(NodeDoesNotExistError, newtip.get_node, node.path)
+
+    def test_remove_last_file_from_directory(self):
+        node = FileNode('omg/qwe/foo/bar', content='foobar')
+        self.imc.add(node)
+        self.imc.commit(u'added', u'joe doe')
+
+        self.imc.remove(node)
+        tip = self.imc.commit(u'removed', u'joe doe')
+        self.assertRaises(NodeDoesNotExistError, tip.get_node, 'omg/qwe/foo/bar')
+
+    def test_remove_raise_node_does_not_exist(self):
+        self.imc.remove(self.nodes[0])
+        self.assertRaises(NodeDoesNotExistError, self.imc.commit,
+            message='Trying to remove node at empty repository',
+            author=str(self))
+
+    def test_check_integrity_remove_raise_node_does_not_exist(self):
+        self.test_add()  # Performs first commit
+
+        node = FileNode('no-such-file')
+        self.imc.remove(node)
+        self.assertRaises(NodeDoesNotExistError, self.imc.commit,
+            message=u'Trying to remove not existing node',
+            author=unicode(self))
+
+    def test_remove_raise_node_already_removed(self):
+        self.test_add() # Performs first commit
+
+        node = FileNode(self.nodes[0].path)
+        self.imc.remove(node)
+        self.assertRaises(NodeAlreadyRemovedError, self.imc.remove, node)
+
+    def test_remove_raise_node_already_changed(self):
+        self.test_add()  # Performs first commit
+
+        node = FileNode(self.nodes[0].path, content='Bending time')
+        self.imc.change(node)
+        self.assertRaises(NodeAlreadyChangedError, self.imc.remove, node)
+
+    def test_reset(self):
+        self.imc.add(FileNode('foo', content='bar'))
+        #self.imc.change(FileNode('baz', content='new'))
+        #self.imc.remove(FileNode('qwe'))
+        self.imc.reset()
+        self.assertTrue(not any((self.imc.added, self.imc.changed,
+            self.imc.removed)))
+
+    def test_multiple_commits(self):
+        N = 3  # number of commits to perform
+        last = None
+        for x in xrange(N):
+            fname = 'file%s' % str(x).rjust(5, '0')
+            content = 'foobar\n' * x
+            node = FileNode(fname, content=content)
+            self.imc.add(node)
+            commit = self.imc.commit(u"Commit no. %s" % (x + 1), author=u'vcs')
+            self.assertTrue(last != commit)
+            last = commit
+
+        # Check commit number for same repo
+        self.assertEqual(len(self.repo.revisions), N)
+
+        # Check commit number for recreated repo
+        backend = self.get_backend()
+        repo = backend(self.repo_path)
+        self.assertEqual(len(repo.revisions), N)
+
+    def test_date_attr(self):
+        node = FileNode('foobar.txt', content='Foobared!')
+        self.imc.add(node)
+        date = datetime.datetime(1985, 1, 30, 1, 45)
+        commit = self.imc.commit(u"Committed at time when I was born ;-)",
+            author=u'lb', date=date)
+
+        self.assertEqual(commit.date, date)
+
+
+class BackendBaseTestCase(unittest.TestCase):
+    """
+    Base test class for tests which requires repository.
+    """
+    backend_alias = 'hg'
+    commits = [
+        {
+            'message': 'Initial commit',
+            'author': 'Joe Doe <joe.doe@example.com>',
+            'date': datetime.datetime(2010, 1, 1, 20),
+            'added': [
+                FileNode('foobar', content='Foobar'),
+                FileNode('foobar2', content='Foobar II'),
+                FileNode('foo/bar/baz', content='baz here!'),
+            ],
+        },
+    ]
+
+    def get_backend(self):
+        return vcs.get_backend(self.backend_alias)
+
+    def get_commits(self):
+        """
+        Returns list of commits which builds repository for each tests.
+        """
+        if hasattr(self, 'commits'):
+            return self.commits
+
+    def get_new_repo_path(self):
+        """
+        Returns newly created repository's directory.
+        """
+        backend = self.get_backend()
+        key = '%s-%s' % (backend.alias, str(time.time()))
+        repo_path = get_new_dir(key)
+        return repo_path
+
+    def setUp(self):
+        Backend = self.get_backend()
+        self.backend_class = Backend
+        self.repo_path = self.get_new_repo_path()
+        self.repo = Backend(self.repo_path, create=True)
+        self.imc = self.repo.in_memory_changeset
+
+        for commit in self.get_commits():
+            for node in commit.get('added', []):
+                self.imc.add(FileNode(node.path, content=node.content))
+            for node in commit.get('changed', []):
+                self.imc.change(FileNode(node.path, content=node.content))
+            for node in commit.get('removed', []):
+                self.imc.remove(FileNode(node.path))
+            self.imc.commit(message=unicode(commit['message']),
+                            author=unicode(commit['author']),
+                date=commit['date'])
+
+        self.tip = self.repo.get_changeset()
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s in memory changeset test' % alias).title().split())
+    bases = (InMemoryChangesetTestMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_nodes.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,183 @@
+from __future__ import with_statement
+
+import stat
+from rhodecode.lib.vcs.nodes import DirNode
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.nodes import Node
+from rhodecode.lib.vcs.nodes import NodeError
+from rhodecode.lib.vcs.nodes import NodeKind
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class NodeBasicTest(unittest.TestCase):
+
+    def test_init(self):
+        """
+        Cannot innitialize Node objects with path with slash at the beginning.
+        """
+        wrong_paths = (
+            '/foo',
+            '/foo/bar'
+        )
+        for path in wrong_paths:
+            self.assertRaises(NodeError, Node, path, NodeKind.FILE)
+
+        wrong_paths = (
+            '/foo/',
+            '/foo/bar/'
+        )
+        for path in wrong_paths:
+            self.assertRaises(NodeError, Node, path, NodeKind.DIR)
+
+    def test_name(self):
+        node = Node('', NodeKind.DIR)
+        self.assertEqual(node.name, '')
+
+        node = Node('path', NodeKind.FILE)
+        self.assertEqual(node.name, 'path')
+
+        node = Node('path/', NodeKind.DIR)
+        self.assertEqual(node.name, 'path')
+
+        node = Node('some/path', NodeKind.FILE)
+        self.assertEqual(node.name, 'path')
+
+        node = Node('some/path/', NodeKind.DIR)
+        self.assertEqual(node.name, 'path')
+
+    def test_root_node(self):
+        self.assertRaises(NodeError, Node, '', NodeKind.FILE)
+
+    def test_kind_setter(self):
+        node = Node('', NodeKind.DIR)
+        self.assertRaises(NodeError, setattr, node, 'kind', NodeKind.FILE)
+
+    def _test_parent_path(self, node_path, expected_parent_path):
+        """
+        Tests if node's parent path are properly computed.
+        """
+        node = Node(node_path, NodeKind.DIR)
+        parent_path = node.get_parent_path()
+        self.assertTrue(parent_path.endswith('/') or \
+            node.is_root() and parent_path == '')
+        self.assertEqual(parent_path, expected_parent_path,
+            "Node's path is %r and parent path is %r but should be %r"
+            % (node.path, parent_path, expected_parent_path))
+
+    def test_parent_path(self):
+        test_paths = (
+            # (node_path, expected_parent_path)
+            ('', ''),
+            ('some/path/', 'some/'),
+            ('some/longer/path/', 'some/longer/'),
+        )
+        for node_path, expected_parent_path in test_paths:
+            self._test_parent_path(node_path, expected_parent_path)
+
+    '''
+    def _test_trailing_slash(self, path):
+        if not path.endswith('/'):
+            self.fail("Trailing slash tests needs paths to end with slash")
+        for kind in NodeKind.FILE, NodeKind.DIR:
+            self.assertRaises(NodeError, Node, path=path, kind=kind)
+
+    def test_trailing_slash(self):
+        for path in ('/', 'foo/', 'foo/bar/', 'foo/bar/biz/'):
+            self._test_trailing_slash(path)
+    '''
+
+    def test_is_file(self):
+        node = Node('any', NodeKind.FILE)
+        self.assertTrue(node.is_file())
+
+        node = FileNode('any')
+        self.assertTrue(node.is_file())
+        self.assertRaises(AttributeError, getattr, node, 'nodes')
+
+    def test_is_dir(self):
+        node = Node('any_dir', NodeKind.DIR)
+        self.assertTrue(node.is_dir())
+
+        node = DirNode('any_dir')
+
+        self.assertTrue(node.is_dir())
+        self.assertRaises(NodeError, getattr, node, 'content')
+
+    def test_dir_node_iter(self):
+        nodes = [
+            DirNode('docs'),
+            DirNode('tests'),
+            FileNode('bar'),
+            FileNode('foo'),
+            FileNode('readme.txt'),
+            FileNode('setup.py'),
+        ]
+        dirnode = DirNode('', nodes=nodes)
+        for node in dirnode:
+            node == dirnode.get_node(node.path)
+
+    def test_node_state(self):
+        """
+        Without link to changeset nodes should raise NodeError.
+        """
+        node = FileNode('anything')
+        self.assertRaises(NodeError, getattr, node, 'state')
+        node = DirNode('anything')
+        self.assertRaises(NodeError, getattr, node, 'state')
+
+    def test_file_node_stat(self):
+        node = FileNode('foobar', 'empty... almost')
+        mode = node.mode  # default should be 0100644
+        self.assertTrue(mode & stat.S_IRUSR)
+        self.assertTrue(mode & stat.S_IWUSR)
+        self.assertTrue(mode & stat.S_IRGRP)
+        self.assertTrue(mode & stat.S_IROTH)
+        self.assertFalse(mode & stat.S_IWGRP)
+        self.assertFalse(mode & stat.S_IWOTH)
+        self.assertFalse(mode & stat.S_IXUSR)
+        self.assertFalse(mode & stat.S_IXGRP)
+        self.assertFalse(mode & stat.S_IXOTH)
+
+    def test_file_node_is_executable(self):
+        node = FileNode('foobar', 'empty... almost', mode=0100755)
+        self.assertTrue(node.is_executable())
+
+        node = FileNode('foobar', 'empty... almost', mode=0100500)
+        self.assertTrue(node.is_executable())
+
+        node = FileNode('foobar', 'empty... almost', mode=0100644)
+        self.assertFalse(node.is_executable())
+
+    def test_mimetype(self):
+        py_node = FileNode('test.py')
+        tar_node = FileNode('test.tar.gz')
+
+        ext = 'CustomExtension'
+
+        my_node2 = FileNode('myfile2')
+        my_node2._mimetype = [ext]
+
+        my_node3 = FileNode('myfile3')
+        my_node3._mimetype = [ext,ext]
+
+        self.assertEqual(py_node.mimetype,'text/x-python')
+        self.assertEqual(py_node.get_mimetype(),('text/x-python',None))
+
+        self.assertEqual(tar_node.mimetype,'application/x-tar')
+        self.assertEqual(tar_node.get_mimetype(),('application/x-tar','gzip'))
+
+        self.assertRaises(NodeError,my_node2.get_mimetype)
+
+        self.assertEqual(my_node3.mimetype,ext)
+        self.assertEqual(my_node3.get_mimetype(),[ext,ext])
+
+class NodeContentTest(unittest.TestCase):
+
+    def test_if_binary(self):
+        data = """\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f??a\x00\x00\x00\x04gAMA\x00\x00\xaf?7\x05\x8a?\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq?e<\x00\x00\x025IDAT8?\xa5\x93?K\x94Q\x14\x87\x9f\xf7?Q\x1bs4?\x03\x9a\xa8?B\x02\x8b$\x10[U;i\x13?6h?&h[?"\x14j?\xa2M\x7fB\x14F\x9aQ?&\x842?\x0b\x89"\x82??!?\x9c!\x9c2l??{N\x8bW\x9dY\xb4\t/\x1c?=\x9b?}????\xa9*;9!?\x83\x91?[?\\v*?D\x04\'`EpNp\xa2X\'U?pVq"Sw.\x1e?\x08\x01D?jw????\xbc??7{|\x9b?\x89$\x01??W@\x15\x9c\x05q`Lt/\x97?\x94\xa1d?\x18~?\x18?\x18W[%\xb0?\x83??\x14\x88\x8dB?\xa6H\tL\tl\x19>/\x01`\xac\xabx?\x9cl\nx\xb0\x98\x07\x95\x88D$"q[\x19?d\x00(o\n\xa0??\x7f\xb9\xa4?\x1bF\x1f\x8e\xac\xa8?j??eUU}?.?\x9f\x8cE??x\x94??\r\xbdtoJU5"0N\x10U?\x00??V\t\x02\x9f\x81?U?\x00\x9eM\xae2?r\x9b7\x83\x82\x8aP3????.?&"?\xb7ZP \x0c<?O\xa5\t}\xb8?\x99\xa6?\x87?\x1di|/\xa0??0\xbe\x1fp?d&\x1a\xad\x95\x8a\x07?\t*\x10??b:?d?.\x13C\x8a?\x12\xbe\xbf\x8e?{???\x08?\x80\xa7\x13+d\x13>J?\x80\x15T\x95\x9a\x00??S\x8c\r?\xa1\x03\x07?\x96\x9b\xa7\xab=E??\xa4\xb3?\x19q??B\x91=\x8d??k?J\x0bV"??\xf7x?\xa1\x00?\\.\x87\x87???\x02F@D\x99],??\x10#?X\xb7=\xb9\x10?Z\x1by???cI??\x1ag?\x92\xbc?T?t[\x92\x81?<_\x17~\x92\x88?H%?\x10Q\x02\x9f\n\x81qQ\x0bm?\x1bX?\xb1AK\xa6\x9e\xb9?u\xb2?1\xbe|/\x92M@\xa2!F?\xa9>"\r<DT?>\x92\x8e?>\x9a9Qv\x127?a\xac?Y?8?:??]X???9\x80\xb7?u?\x0b#BZ\x8d=\x1d?p\x00\x00\x00\x00IEND\xaeB`\x82"""
+        filenode = FileNode('calendar.png', content=data)
+        self.assertTrue(filenode.is_binary)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_repository.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,215 @@
+from __future__ import with_statement
+import datetime
+from base import BackendTestMixin
+from conf import SCM_TESTS
+from conf import TEST_USER_CONFIG_FILE
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.utils.compat import unittest
+from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
+
+
+class RepositoryBaseTest(BackendTestMixin):
+    recreate_repo_per_test = False
+
+    @classmethod
+    def _get_commits(cls):
+        return super(RepositoryBaseTest, cls)._get_commits()[:1]
+
+    def test_get_config_value(self):
+        self.assertEqual(self.repo.get_config_value('universal', 'foo',
+            TEST_USER_CONFIG_FILE), 'bar')
+
+    def test_get_config_value_defaults_to_None(self):
+        self.assertEqual(self.repo.get_config_value('universal', 'nonexist',
+            TEST_USER_CONFIG_FILE), None)
+
+    def test_get_user_name(self):
+        self.assertEqual(self.repo.get_user_name(TEST_USER_CONFIG_FILE),
+            'Foo Bar')
+
+    def test_get_user_email(self):
+        self.assertEqual(self.repo.get_user_email(TEST_USER_CONFIG_FILE),
+            'foo.bar@example.com')
+
+
+
+class RepositoryGetDiffTest(BackendTestMixin):
+
+    @classmethod
+    def _get_commits(cls):
+        commits = [
+            {
+                'message': 'Initial commit',
+                'author': 'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': [
+                    FileNode('foobar', content='foobar'),
+                    FileNode('foobar2', content='foobar2'),
+                ],
+            },
+            {
+                'message': 'Changed foobar, added foobar3',
+                'author': 'Jane Doe <jane.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 21),
+                'added': [
+                    FileNode('foobar3', content='foobar3'),
+                ],
+                'changed': [
+                    FileNode('foobar', 'FOOBAR'),
+                ],
+            },
+            {
+                'message': 'Removed foobar, changed foobar3',
+                'author': 'Jane Doe <jane.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 22),
+                'changed': [
+                    FileNode('foobar3', content='FOOBAR\nFOOBAR\nFOOBAR\n'),
+                ],
+                'removed': [FileNode('foobar')],
+            },
+        ]
+        return commits
+
+    def test_raise_for_wrong(self):
+        with self.assertRaises(ChangesetDoesNotExistError):
+            self.repo.get_diff('a' * 40, 'b' * 40)
+
+class GitRepositoryGetDiffTest(RepositoryGetDiffTest, unittest.TestCase):
+    backend_alias = 'git'
+
+    def test_initial_commit_diff(self):
+        initial_rev = self.repo.revisions[0]
+        self.assertEqual(self.repo.get_diff(self.repo.EMPTY_CHANGESET, initial_rev), '''diff --git a/foobar b/foobar
+new file mode 100644
+index 0000000..f6ea049
+--- /dev/null
++++ b/foobar
+@@ -0,0 +1 @@
++foobar
+\ No newline at end of file
+diff --git a/foobar2 b/foobar2
+new file mode 100644
+index 0000000..e8c9d6b
+--- /dev/null
++++ b/foobar2
+@@ -0,0 +1 @@
++foobar2
+\ No newline at end of file
+''')
+
+    def test_second_changeset_diff(self):
+        revs = self.repo.revisions
+        self.assertEqual(self.repo.get_diff(revs[0], revs[1]), '''diff --git a/foobar b/foobar
+index f6ea049..389865b 100644
+--- a/foobar
++++ b/foobar
+@@ -1 +1 @@
+-foobar
+\ No newline at end of file
++FOOBAR
+\ No newline at end of file
+diff --git a/foobar3 b/foobar3
+new file mode 100644
+index 0000000..c11c37d
+--- /dev/null
++++ b/foobar3
+@@ -0,0 +1 @@
++foobar3
+\ No newline at end of file
+''')
+
+    def test_third_changeset_diff(self):
+        revs = self.repo.revisions
+        self.assertEqual(self.repo.get_diff(revs[1], revs[2]), '''diff --git a/foobar b/foobar
+deleted file mode 100644
+index 389865b..0000000
+--- a/foobar
++++ /dev/null
+@@ -1 +0,0 @@
+-FOOBAR
+\ No newline at end of file
+diff --git a/foobar3 b/foobar3
+index c11c37d..f932447 100644
+--- a/foobar3
++++ b/foobar3
+@@ -1 +1,3 @@
+-foobar3
+\ No newline at end of file
++FOOBAR
++FOOBAR
++FOOBAR
+''')
+
+
+class HgRepositoryGetDiffTest(RepositoryGetDiffTest, unittest.TestCase):
+    backend_alias = 'hg'
+
+    def test_initial_commit_diff(self):
+        initial_rev = self.repo.revisions[0]
+        self.assertEqual(self.repo.get_diff(self.repo.EMPTY_CHANGESET, initial_rev), '''diff --git a/foobar b/foobar
+new file mode 100755
+--- /dev/null
++++ b/foobar
+@@ -0,0 +1,1 @@
++foobar
+\ No newline at end of file
+diff --git a/foobar2 b/foobar2
+new file mode 100755
+--- /dev/null
++++ b/foobar2
+@@ -0,0 +1,1 @@
++foobar2
+\ No newline at end of file
+''')
+
+    def test_second_changeset_diff(self):
+        revs = self.repo.revisions
+        self.assertEqual(self.repo.get_diff(revs[0], revs[1]), '''diff --git a/foobar b/foobar
+--- a/foobar
++++ b/foobar
+@@ -1,1 +1,1 @@
+-foobar
+\ No newline at end of file
++FOOBAR
+\ No newline at end of file
+diff --git a/foobar3 b/foobar3
+new file mode 100755
+--- /dev/null
++++ b/foobar3
+@@ -0,0 +1,1 @@
++foobar3
+\ No newline at end of file
+''')
+
+    def test_third_changeset_diff(self):
+        revs = self.repo.revisions
+        self.assertEqual(self.repo.get_diff(revs[1], revs[2]), '''diff --git a/foobar b/foobar
+deleted file mode 100755
+--- a/foobar
++++ /dev/null
+@@ -1,1 +0,0 @@
+-FOOBAR
+\ No newline at end of file
+diff --git a/foobar3 b/foobar3
+--- a/foobar3
++++ b/foobar3
+@@ -1,1 +1,3 @@
+-foobar3
+\ No newline at end of file
++FOOBAR
++FOOBAR
++FOOBAR
+''')
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = alias.capitalize() + RepositoryBaseTest.__name__
+    bases = (RepositoryBaseTest, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_tags.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,61 @@
+from __future__ import with_statement
+
+from base import BackendTestMixin
+from conf import SCM_TESTS
+from rhodecode.lib.vcs.exceptions import TagAlreadyExistError
+from rhodecode.lib.vcs.exceptions import TagDoesNotExistError
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class TagsTestCaseMixin(BackendTestMixin):
+
+    def test_new_tag(self):
+        tip = self.repo.get_changeset()
+        tagsize = len(self.repo.tags)
+        tag = self.repo.tag('last-commit', 'joe', tip.raw_id)
+
+        self.assertEqual(len(self.repo.tags), tagsize + 1)
+        for top, dirs, files in tip.walk():
+            self.assertEqual(top, tag.get_node(top.path))
+
+    def test_tag_already_exist(self):
+        tip = self.repo.get_changeset()
+        self.repo.tag('last-commit', 'joe', tip.raw_id)
+
+        self.assertRaises(TagAlreadyExistError,
+            self.repo.tag, 'last-commit', 'joe', tip.raw_id)
+
+        chset = self.repo.get_changeset(0)
+        self.assertRaises(TagAlreadyExistError,
+            self.repo.tag, 'last-commit', 'jane', chset.raw_id)
+
+    def test_remove_tag(self):
+        tip = self.repo.get_changeset()
+        self.repo.tag('last-commit', 'joe', tip.raw_id)
+        tagsize = len(self.repo.tags)
+
+        self.repo.remove_tag('last-commit', user='evil joe')
+        self.assertEqual(len(self.repo.tags), tagsize - 1)
+
+    def test_remove_tag_which_does_not_exist(self):
+        self.assertRaises(TagDoesNotExistError,
+            self.repo.remove_tag, 'last-commit', user='evil joe')
+
+    def test_name_with_slash(self):
+        self.repo.tag('19/10/11', 'joe')
+        self.assertTrue('19/10/11' in self.repo.tags)
+        self.repo.tag('11', 'joe')
+        self.assertTrue('11' in self.repo.tags)
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s tags test' % alias).title().split())
+    bases = (TagsTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_utils.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,279 @@
+from __future__ import with_statement
+
+import os
+import mock
+import time
+import shutil
+import tempfile
+import datetime
+from rhodecode.lib.vcs.utils.compat import unittest
+from rhodecode.lib.vcs.utils.paths import get_dirs_for_path
+from rhodecode.lib.vcs.utils.helpers import get_dict_for_attrs
+from rhodecode.lib.vcs.utils.helpers import get_scm
+from rhodecode.lib.vcs.utils.helpers import get_scms_for_path
+from rhodecode.lib.vcs.utils.helpers import get_total_seconds
+from rhodecode.lib.vcs.utils.helpers import parse_changesets
+from rhodecode.lib.vcs.utils.helpers import parse_datetime
+from rhodecode.lib.vcs.utils import author_email, author_name
+from rhodecode.lib.vcs.utils.paths import get_user_home
+from rhodecode.lib.vcs.exceptions import VCSError
+
+from conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
+
+
+class PathsTest(unittest.TestCase):
+
+    def _test_get_dirs_for_path(self, path, expected):
+        """
+        Tests if get_dirs_for_path returns same as expected.
+        """
+        expected = sorted(expected)
+        result = sorted(get_dirs_for_path(path))
+        self.assertEqual(result, expected,
+            msg="%s != %s which was expected result for path %s"
+            % (result, expected, path))
+
+    def test_get_dirs_for_path(self):
+        path = 'foo/bar/baz/file'
+        paths_and_results = (
+            ('foo/bar/baz/file', ['foo', 'foo/bar', 'foo/bar/baz']),
+            ('foo/bar/', ['foo', 'foo/bar']),
+            ('foo/bar', ['foo']),
+        )
+        for path, expected in paths_and_results:
+            self._test_get_dirs_for_path(path, expected)
+
+
+    def test_get_scm(self):
+        self.assertEqual(('hg', TEST_HG_REPO), get_scm(TEST_HG_REPO))
+        self.assertEqual(('git', TEST_GIT_REPO), get_scm(TEST_GIT_REPO))
+
+    def test_get_two_scms_for_path(self):
+        multialias_repo_path = os.path.join(TEST_TMP_PATH, 'hg-git-repo-2')
+        if os.path.isdir(multialias_repo_path):
+            shutil.rmtree(multialias_repo_path)
+
+        os.mkdir(multialias_repo_path)
+
+        self.assertRaises(VCSError, get_scm, multialias_repo_path)
+
+    def test_get_scm_error_path(self):
+        self.assertRaises(VCSError, get_scm, 'err')
+
+    def test_get_scms_for_path(self):
+        dirpath = tempfile.gettempdir()
+        new = os.path.join(dirpath, 'vcs-scms-for-path-%s' % time.time())
+        os.mkdir(new)
+        self.assertEqual(get_scms_for_path(new), [])
+
+        os.mkdir(os.path.join(new, '.tux'))
+        self.assertEqual(get_scms_for_path(new), [])
+
+        os.mkdir(os.path.join(new, '.git'))
+        self.assertEqual(set(get_scms_for_path(new)), set(['git']))
+
+        os.mkdir(os.path.join(new, '.hg'))
+        self.assertEqual(set(get_scms_for_path(new)), set(['git', 'hg']))
+
+
+class TestParseChangesets(unittest.TestCase):
+
+    def test_main_is_returned_correctly(self):
+        self.assertEqual(parse_changesets('123456'), {
+            'start': None,
+            'main': '123456',
+            'end': None,
+        })
+
+    def test_start_is_returned_correctly(self):
+        self.assertEqual(parse_changesets('aaabbb..'), {
+            'start': 'aaabbb',
+            'main': None,
+            'end': None,
+        })
+
+    def test_end_is_returned_correctly(self):
+        self.assertEqual(parse_changesets('..cccddd'), {
+            'start': None,
+            'main': None,
+            'end': 'cccddd',
+        })
+
+    def test_that_two_or_three_dots_are_allowed(self):
+        text1 = 'a..b'
+        text2 = 'a...b'
+        self.assertEqual(parse_changesets(text1), parse_changesets(text2))
+
+    def test_that_input_is_stripped_first(self):
+        text1 = 'a..bb'
+        text2 = '  a..bb\t\n\t '
+        self.assertEqual(parse_changesets(text1), parse_changesets(text2))
+
+    def test_that_exception_is_raised(self):
+        text = '123456.789012' # single dot is not recognized
+        with self.assertRaises(ValueError):
+            parse_changesets(text)
+
+    def test_non_alphanumeric_raises_exception(self):
+        with self.assertRaises(ValueError):
+            parse_changesets('aaa@bbb')
+
+
+class TestParseDatetime(unittest.TestCase):
+
+    def test_datetime_text(self):
+        self.assertEqual(parse_datetime('2010-04-07 21:29:41'),
+            datetime.datetime(2010, 4, 7, 21, 29, 41))
+
+    def test_no_seconds(self):
+        self.assertEqual(parse_datetime('2010-04-07 21:29'),
+            datetime.datetime(2010, 4, 7, 21, 29))
+
+    def test_date_only(self):
+        self.assertEqual(parse_datetime('2010-04-07'),
+            datetime.datetime(2010, 4, 7))
+
+    def test_another_format(self):
+        self.assertEqual(parse_datetime('04/07/10 21:29:41'),
+            datetime.datetime(2010, 4, 7, 21, 29, 41))
+
+    def test_now(self):
+        self.assertTrue(parse_datetime('now') - datetime.datetime.now() <
+            datetime.timedelta(seconds=1))
+
+    def test_today(self):
+        today = datetime.date.today()
+        self.assertEqual(parse_datetime('today'),
+            datetime.datetime(*today.timetuple()[:3]))
+
+    def test_yesterday(self):
+        yesterday = datetime.date.today() - datetime.timedelta(days=1)
+        self.assertEqual(parse_datetime('yesterday'),
+            datetime.datetime(*yesterday.timetuple()[:3]))
+
+    def test_tomorrow(self):
+        tomorrow = datetime.date.today() + datetime.timedelta(days=1)
+        args = tomorrow.timetuple()[:3] + (23, 59, 59)
+        self.assertEqual(parse_datetime('tomorrow'), datetime.datetime(*args))
+
+    def test_days(self):
+        timestamp = datetime.datetime.today() - datetime.timedelta(days=3)
+        args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
+        expected = datetime.datetime(*args)
+        self.assertEqual(parse_datetime('3d'), expected)
+        self.assertEqual(parse_datetime('3 d'), expected)
+        self.assertEqual(parse_datetime('3 day'), expected)
+        self.assertEqual(parse_datetime('3 days'), expected)
+
+    def test_weeks(self):
+        timestamp = datetime.datetime.today() - datetime.timedelta(days=3 * 7)
+        args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
+        expected = datetime.datetime(*args)
+        self.assertEqual(parse_datetime('3w'), expected)
+        self.assertEqual(parse_datetime('3 w'), expected)
+        self.assertEqual(parse_datetime('3 week'), expected)
+        self.assertEqual(parse_datetime('3 weeks'), expected)
+
+    def test_mixed(self):
+        timestamp = datetime.datetime.today() - datetime.timedelta(days=2 * 7 + 3)
+        args = timestamp.timetuple()[:3] + (0, 0, 0, 0)
+        expected = datetime.datetime(*args)
+        self.assertEqual(parse_datetime('2w3d'), expected)
+        self.assertEqual(parse_datetime('2w 3d'), expected)
+        self.assertEqual(parse_datetime('2w 3 days'), expected)
+        self.assertEqual(parse_datetime('2 weeks 3 days'), expected)
+
+
+class TestAuthorExtractors(unittest.TestCase):
+    TEST_AUTHORS = [('Marcin Kuzminski <marcin@python-works.com>',
+                    ('Marcin Kuzminski', 'marcin@python-works.com')),
+                  ('Marcin Kuzminski Spaces < marcin@python-works.com >',
+                    ('Marcin Kuzminski Spaces', 'marcin@python-works.com')),
+                  ('Marcin Kuzminski <marcin.kuzminski@python-works.com>',
+                    ('Marcin Kuzminski', 'marcin.kuzminski@python-works.com')),
+                  ('mrf RFC_SPEC <marcin+kuzminski@python-works.com>',
+                    ('mrf RFC_SPEC', 'marcin+kuzminski@python-works.com')),
+                  ('username <user@email.com>',
+                    ('username', 'user@email.com')),
+                  ('username <user@email.com',
+                   ('username', 'user@email.com')),
+                  ('broken missing@email.com',
+                   ('broken', 'missing@email.com')),
+                  ('<justemail@mail.com>',
+                   ('', 'justemail@mail.com')),
+                  ('justname',
+                   ('justname', '')),
+                  ('Mr Double Name withemail@email.com ',
+                   ('Mr Double Name', 'withemail@email.com')),
+                  ]
+
+    def test_author_email(self):
+
+        for test_str, result in self.TEST_AUTHORS:
+            self.assertEqual(result[1], author_email(test_str))
+
+
+    def test_author_name(self):
+
+        for test_str, result in self.TEST_AUTHORS:
+            self.assertEqual(result[0], author_name(test_str))
+
+
+class TestGetDictForAttrs(unittest.TestCase):
+
+    def test_returned_dict_has_expected_attrs(self):
+        obj = mock.Mock()
+        obj.NOT_INCLUDED = 'this key/value should not be included'
+        obj.CONST = True
+        obj.foo = 'aaa'
+        obj.attrs = {'foo': 'bar'}
+        obj.date = datetime.datetime(2010, 12, 31)
+        obj.count = 1001
+
+        self.assertEqual(get_dict_for_attrs(obj, ['CONST', 'foo', 'attrs',
+            'date', 'count']), {
+            'CONST': True,
+            'foo': 'aaa',
+            'attrs': {'foo': 'bar'},
+            'date': datetime.datetime(2010, 12, 31),
+            'count': 1001,
+        })
+
+
+class TestGetTotalSeconds(unittest.TestCase):
+
+    def assertTotalSecondsEqual(self, timedelta, expected_seconds):
+        result = get_total_seconds(timedelta)
+        self.assertEqual(result, expected_seconds,
+            "We computed %s seconds for %s but expected %s"
+            % (result, timedelta, expected_seconds))
+
+    def test_get_total_seconds_returns_proper_value(self):
+        self.assertTotalSecondsEqual(datetime.timedelta(seconds=1001), 1001)
+
+    def test_get_total_seconds_returns_proper_value_for_partial_seconds(self):
+        self.assertTotalSecondsEqual(datetime.timedelta(seconds=50.65), 50.65)
+
+
+class TestGetUserHome(unittest.TestCase):
+
+    @mock.patch.object(os, 'environ', {})
+    def test_defaults_to_none(self):
+        self.assertEqual(get_user_home(), '')
+
+    @mock.patch.object(os, 'environ', {'HOME': '/home/foobar'})
+    def test_unix_like(self):
+        self.assertEqual(get_user_home(), '/home/foobar')
+
+    @mock.patch.object(os, 'environ', {'USERPROFILE': '/Users/foobar'})
+    def test_windows_like(self):
+        self.assertEqual(get_user_home(), '/Users/foobar')
+
+    @mock.patch.object(os, 'environ', {'HOME': '/home/foobar',
+        'USERPROFILE': '/Users/foobar'})
+    def test_prefers_home_over_userprofile(self):
+        self.assertEqual(get_user_home(), '/home/foobar')
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_utils_filesize.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,26 @@
+from __future__ import with_statement
+
+from rhodecode.lib.vcs.utils.filesize import filesizeformat
+from rhodecode.lib.vcs.utils.compat import unittest
+
+
+class TestFilesizeformat(unittest.TestCase):
+
+    def test_bytes(self):
+        self.assertEqual(filesizeformat(10), '10 B')
+
+    def test_kilobytes(self):
+        self.assertEqual(filesizeformat(1024 * 2), '2 KB')
+
+    def test_megabytes(self):
+        self.assertEqual(filesizeformat(1024 * 1024 * 2.3), '2.3 MB')
+
+    def test_gigabytes(self):
+        self.assertEqual(filesizeformat(1024 * 1024 * 1024 * 12.92), '12.92 GB')
+
+    def test_that_function_respects_sep_paramtere(self):
+        self.assertEqual(filesizeformat(1, ''), '1B')
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_vcs.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,84 @@
+from __future__ import with_statement
+
+from rhodecode.lib.vcs import VCSError, get_repo, get_backend
+from rhodecode.lib.vcs.backends.hg import MercurialRepository
+from rhodecode.lib.vcs.utils.compat import unittest
+from conf import TEST_HG_REPO, TEST_GIT_REPO, TEST_TMP_PATH
+import os
+import shutil
+
+
+class VCSTest(unittest.TestCase):
+    """
+    Tests for main module's methods.
+    """
+
+    def test_get_backend(self):
+        hg = get_backend('hg')
+        self.assertEqual(hg, MercurialRepository)
+
+    def test_alias_detect_hg(self):
+        alias = 'hg'
+        path = TEST_HG_REPO
+        backend = get_backend(alias)
+        repo = backend(path)
+        self.assertEqual('hg',repo.alias)
+
+    def test_alias_detect_git(self):
+        alias = 'git'
+        path = TEST_GIT_REPO
+        backend = get_backend(alias)
+        repo = backend(path)
+        self.assertEqual('git',repo.alias)
+
+    def test_wrong_alias(self):
+        alias = 'wrong_alias'
+        self.assertRaises(VCSError, get_backend, alias)
+
+    def test_get_repo(self):
+        alias = 'hg'
+        path = TEST_HG_REPO
+        backend = get_backend(alias)
+        repo = backend(path)
+
+        self.assertEqual(repo.__class__, get_repo(path, alias).__class__)
+        self.assertEqual(repo.path, get_repo(path, alias).path)
+
+    def test_get_repo_autoalias_hg(self):
+        alias = 'hg'
+        path = TEST_HG_REPO
+        backend = get_backend(alias)
+        repo = backend(path)
+
+        self.assertEqual(repo.__class__, get_repo(path).__class__)
+        self.assertEqual(repo.path, get_repo(path).path)
+
+    def test_get_repo_autoalias_git(self):
+        alias = 'git'
+        path = TEST_GIT_REPO
+        backend = get_backend(alias)
+        repo = backend(path)
+
+        self.assertEqual(repo.__class__, get_repo(path).__class__)
+        self.assertEqual(repo.path, get_repo(path).path)
+
+
+    def test_get_repo_err(self):
+        blank_repo_path = os.path.join(TEST_TMP_PATH, 'blank-error-repo')
+        if os.path.isdir(blank_repo_path):
+            shutil.rmtree(blank_repo_path)
+
+        os.mkdir(blank_repo_path)
+        self.assertRaises(VCSError, get_repo, blank_repo_path)
+        self.assertRaises(VCSError, get_repo, blank_repo_path + 'non_existing')
+
+    def test_get_repo_multialias(self):
+        multialias_repo_path = os.path.join(TEST_TMP_PATH, 'hg-git-repo')
+        if os.path.isdir(multialias_repo_path):
+            shutil.rmtree(multialias_repo_path)
+
+        os.mkdir(multialias_repo_path)
+
+        os.mkdir(os.path.join(multialias_repo_path, '.git'))
+        os.mkdir(os.path.join(multialias_repo_path, '.hg'))
+        self.assertRaises(VCSError, get_repo, multialias_repo_path)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/test_workdirs.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,90 @@
+from __future__ import with_statement
+
+import datetime
+from rhodecode.lib.vcs.nodes import FileNode
+from rhodecode.lib.vcs.utils.compat import unittest
+from base import BackendTestMixin
+from conf import SCM_TESTS
+
+
+class WorkdirTestCaseMixin(BackendTestMixin):
+
+    @classmethod
+    def _get_commits(cls):
+        commits = [
+            {
+                'message': u'Initial commit',
+                'author': u'Joe Doe <joe.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 20),
+                'added': [
+                    FileNode('foobar', content='Foobar'),
+                    FileNode('foobar2', content='Foobar II'),
+                    FileNode('foo/bar/baz', content='baz here!'),
+                ],
+            },
+            {
+                'message': u'Changes...',
+                'author': u'Jane Doe <jane.doe@example.com>',
+                'date': datetime.datetime(2010, 1, 1, 21),
+                'added': [
+                    FileNode('some/new.txt', content='news...'),
+                ],
+                'changed': [
+                    FileNode('foobar', 'Foobar I'),
+                ],
+                'removed': [],
+            },
+        ]
+        return commits
+
+    def test_get_branch_for_default_branch(self):
+        self.assertEqual(self.repo.workdir.get_branch(),
+            self.repo.DEFAULT_BRANCH_NAME)
+
+    def test_get_branch_after_adding_one(self):
+        self.imc.add(FileNode('docs/index.txt',
+            content='Documentation\n'))
+        self.imc.commit(
+            message=u'New branch: foobar',
+            author=u'joe',
+            branch='foobar',
+        )
+
+    def test_get_changeset(self):
+        self.imc.add(FileNode('docs/index.txt',
+            content='Documentation\n'))
+        head = self.imc.commit(
+            message=u'New branch: foobar',
+            author=u'joe',
+            branch='foobar',
+        )
+        self.assertEqual(self.repo.workdir.get_changeset(), head)
+
+    def test_checkout_branch(self):
+        from rhodecode.lib.vcs.exceptions import BranchDoesNotExistError
+        # first, 'foobranch' does not exist.
+        self.assertRaises(BranchDoesNotExistError, self.repo.workdir.checkout_branch,
+                          branch='foobranch')
+        # create new branch 'foobranch'.
+        self.imc.add(FileNode('file1', content='blah'))
+        self.imc.commit(message=u'asd', author=u'john', branch='foobranch')
+        # go back to the default branch
+        self.repo.workdir.checkout_branch()
+        self.assertEqual(self.repo.workdir.get_branch(), self.backend_class.DEFAULT_BRANCH_NAME)
+        # checkout 'foobranch'
+        self.repo.workdir.checkout_branch('foobranch')
+        self.assertEqual(self.repo.workdir.get_branch(), 'foobranch')
+
+
+# For each backend create test case class
+for alias in SCM_TESTS:
+    attrs = {
+        'backend_alias': alias,
+    }
+    cls_name = ''.join(('%s branch test' % alias).title().split())
+    bases = (WorkdirTestCaseMixin, unittest.TestCase)
+    globals()[cls_name] = type(cls_name, bases, attrs)
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/tests/vcs/utils.py	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,97 @@
+"""
+Utilities for tests only. These are not or should not be used normally -
+functions here are crafted as we don't want to use ``vcs`` to verify tests.
+"""
+import os
+import re
+import sys
+
+from subprocess import Popen
+
+
+class VCSTestError(Exception):
+    pass
+
+
+def run_command(cmd, args):
+    """
+    Runs command on the system with given ``args``.
+    """
+    command = ' '.join((cmd, args))
+    p = Popen(command, shell=True)
+    status = os.waitpid(p.pid, 0)[1]
+    return status
+
+
+def eprint(msg):
+    """
+    Prints given ``msg`` into sys.stderr as nose test runner hides all output
+    from sys.stdout by default and if we want to pipe stream somewhere we don't
+    need those verbose messages anyway.
+    Appends line break.
+    """
+    sys.stderr.write(msg)
+    sys.stderr.write('\n')
+
+
+class SCMFetcher(object):
+
+    def __init__(self, alias, test_repo_path, remote_repo, clone_cmd):
+        """
+        :param clone_cmd: command which would clone remote repository; pass
+          only first bits - remote path and destination would be appended
+          using ``remote_repo`` and ``test_repo_path``
+        """
+        self.alias = alias
+        self.test_repo_path = test_repo_path
+        self.remote_repo = remote_repo
+        self.clone_cmd = clone_cmd
+
+    def setup(self):
+        if not os.path.isdir(self.test_repo_path):
+            self.fetch_repo()
+
+    def fetch_repo(self):
+        """
+        Tries to fetch repository from remote path.
+        """
+        remote = self.remote_repo
+        eprint("Fetching repository %s into %s" % (remote, self.test_repo_path))
+        run_command(self.clone_cmd,  '%s %s' % (remote, self.test_repo_path))
+
+
+def get_normalized_path(path):
+    """
+    If given path exists, new path would be generated and returned. Otherwise
+    same whats given is returned. Assumes that there would be no more than
+    10000 same named files.
+    """
+    if os.path.exists(path):
+        dir, basename = os.path.split(path)
+        splitted_name = basename.split('.')
+        if len(splitted_name) > 1:
+            ext = splitted_name[-1]
+        else:
+            ext = None
+        name = '.'.join(splitted_name[:-1])
+        matcher = re.compile(r'^.*-(\d{5})$')
+        start = 0
+        m = matcher.match(name)
+        if not m:
+            # Haven't append number yet so return first
+            newname = '%s-00000' % name
+            newpath = os.path.join(dir, newname)
+            if ext:
+                newpath = '.'.join((newpath, ext))
+            return get_normalized_path(newpath)
+        else:
+            start = int(m.group(1)[-5:]) + 1
+            for x in xrange(start, 10000):
+                newname = name[:-5] + str(x).rjust(5, '0')
+                newpath = os.path.join(dir, newname)
+                if ext:
+                    newpath = '.'.join((newpath, ext))
+                if not os.path.exists(newpath):
+                    return newpath
+        raise VCSTestError("Couldn't compute new path for %s" % path)
+    return path
Binary file rhodecode/tests/vcs_test_git.tar.gz has changed
Binary file rhodecode/tests/vcs_test_hg.tar.gz has changed
--- a/rhodecode/websetup.py	Sat May 19 14:54:50 2012 +0200
+++ b/rhodecode/websetup.py	Sun Sep 02 21:19:54 2012 +0200
@@ -38,7 +38,7 @@
     dbconf = conf['sqlalchemy.db1.url']
     dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'],
                         tests=False)
-    dbmanage.create_tables(override=True)
+    dbmanage.create_tables(override=True, defaults=command.options.__dict__)
     dbmanage.set_db_version()
     opts = dbmanage.config_prompt(None, defaults=command.options.__dict__)
     dbmanage.create_settings(opts)
--- a/setup.cfg	Sat May 19 14:54:50 2012 +0200
+++ b/setup.cfg	Sun Sep 02 21:19:54 2012 +0200
@@ -1,5 +1,5 @@
 [egg_info]
-tag_build = 
+tag_build =
 tag_svn_revision = true
 
 [easy_install]
--- a/setup.py	Sat May 19 14:54:50 2012 +0200
+++ b/setup.py	Sun Sep 02 21:19:54 2012 +0200
@@ -1,11 +1,70 @@
+import os
 import sys
-from rhodecode import get_version
-from rhodecode import __license__
-from rhodecode import __py_version__
-from rhodecode import requirements
+import platform
+
+if sys.version_info < (2, 5):
+    raise Exception('RhodeCode requires python 2.5 or later')
+
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+
+def _get_meta_var(name, data, callback_handler=None):
+    import re
+    matches = re.compile(r'(?:%s)\s*=\s*(.*)' % name).search(data)
+    if matches:
+        if not callable(callback_handler):
+            callback_handler = lambda v: v
+
+        return callback_handler(eval(matches.groups()[0]))
+
+_meta = open(os.path.join(here, 'rhodecode', '__init__.py'), 'rb')
+_metadata = _meta.read()
+_meta.close()
+
+callback = lambda V: ('.'.join(map(str, V[:3])) + '.'.join(V[3:]))
+__version__ = _get_meta_var('VERSION', _metadata, callback)
+__license__ = _get_meta_var('__license__', _metadata)
+__author__ = _get_meta_var('__author__', _metadata)
+__url__ = _get_meta_var('__url__', _metadata)
+# defines current platform
+__platform__ = platform.system()
+
+is_windows = __platform__ in _get_meta_var('PLATFORM_WIN', _metadata)
 
-if __py_version__ < (2, 5):
-    raise Exception('RhodeCode requires python 2.5 or later')
+requirements = [
+    "waitress==0.8.1",
+    "webob==1.0.8",
+    "Pylons==1.0.0",
+    "Beaker==1.6.4",
+    "WebHelpers==1.3",
+    "formencode==1.2.4",
+    "SQLAlchemy==0.7.8",
+    "Mako==0.7.2",
+    "pygments>=1.5",
+    "whoosh>=2.4.0,<2.5",
+    "celery>=2.2.5,<2.3",
+    "babel",
+    "python-dateutil>=1.5.0,<2.0.0",
+    "dulwich>=0.8.5,<0.9.0",
+    "markdown==2.1.1",
+    "docutils==0.8.1",
+    "simplejson==2.5.2",
+    "mock",
+]
+
+if sys.version_info < (2, 6):
+    requirements.append("pysqlite")
+
+if sys.version_info < (2, 7):
+    requirements.append("unittest2")
+
+if is_windows:
+    requirements.append("mercurial>=2.3.0,<2.4")
+else:
+    requirements.append("py-bcrypt")
+    requirements.append("mercurial>=2.3.0,<2.4")
+
 
 dependency_links = [
 ]
@@ -62,15 +121,15 @@
 
 setup(
     name='RhodeCode',
-    version=get_version(),
+    version=__version__,
     description=description,
     long_description=long_description,
     keywords=keywords,
     license=__license__,
-    author='Marcin Kuzminski',
+    author=__author__,
     author_email='marcin@python-works.com',
     dependency_links=dependency_links,
-    url='http://rhodecode.org',
+    url=__url__,
     install_requires=requirements,
     classifiers=classifiers,
     setup_requires=["PasteScript>=1.6.3"],
@@ -87,6 +146,9 @@
     zip_safe=False,
     paster_plugins=['PasteScript', 'Pylons'],
     entry_points="""
+    [console_scripts]
+    rhodecode-api =  rhodecode.bin.rhodecode_api:main
+
     [paste.app_factory]
     main = rhodecode.config.middleware:make_app
 
@@ -95,6 +157,7 @@
 
     [paste.global_paster_command]
     setup-rhodecode=rhodecode.config.setup_rhodecode:SetupCommand
+    cleanup-repos=rhodecode.lib.cleanup:CleanupCommand
     make-index=rhodecode.lib.indexers:MakeIndex
     make-rcext=rhodecode.config.rcextensions.make_rcextensions:MakeRcExt
     upgrade-db=rhodecode.lib.dbmigrate:UpgradeDb
--- a/test.ini	Sat May 19 14:54:50 2012 +0200
+++ b/test.ini	Sun Sep 02 21:19:54 2012 +0200
@@ -30,15 +30,16 @@
 
 [server:main]
 ##nr of threads to spawn
-threadpool_workers = 5
+#threadpool_workers = 5
 
 ##max request before thread respawn
-threadpool_max_requests = 2
+#threadpool_max_requests = 2
 
 ##option to use threads of process
-use_threadpool = true
+#use_threadpool = true
 
-use = egg:Paste#http
+#use = egg:Paste#http
+use = egg:waitress#main
 host = 127.0.0.1
 port = 5000
 
@@ -91,7 +92,12 @@
 ## a prefix key for this instance used for cache invalidation when running 
 ## multiple instances of rhodecode, make sure it's globally unique for 
 ## all running rhodecode instances. Leave empty if you don't use it
-instance_id = 
+instance_id =
+
+## alternative return HTTP header for failed authentication. Default HTTP
+## response is 401 HTTPUnauthorized. Currently HG clients have troubles with 
+## handling that. Set this variable to 403 to return HTTPForbidden
+auth_ret_code =
 
 ####################################
 ###        CELERY CONFIG        ####
@@ -204,9 +210,9 @@
 #########################################################
 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG    ###
 #########################################################
-sqlalchemy.db1.url = sqlite:///%(here)s/test.db
-#sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
-#sqlalchemy.db1.url = mysql://root:qwe123qwe@localhost/rhodecode_tests
+sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.sqlite
+#sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_test
+#sqlalchemy.db1.url = mysql://root:qwe@localhost/rhodecode_test
 
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
@@ -228,11 +234,11 @@
 ## LOGGERS ##
 #############
 [logger_root]
-level = ERROR
+level = DEBUG
 handlers = console
 
 [logger_routes]
-level = ERROR
+level = DEBUG
 handlers = 
 qualname = routes.middleware
 # "level = DEBUG" logs the route matched and routing variables.
@@ -251,7 +257,7 @@
 propagate = 1
 
 [logger_rhodecode]
-level = ERROR
+level = DEBUG
 handlers = 
 qualname = rhodecode
 propagate = 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tox.ini	Sun Sep 02 21:19:54 2012 +0200
@@ -0,0 +1,112 @@
+[tox]
+envlist = py25-sqlite,
+          py25-mysql,
+          py25-postgresql,
+          py26-sqlite,
+          py26-mysql,
+          py26-postgresql,
+          py27-sqlite,
+          py27-mysql,
+          py27-postgresql
+
+
+#### PYTHON 2.5 ####                    
+[testenv:py25-sqlite]
+basepython =
+    python2.5
+commands =
+    nosetests []
+setenv = 
+    TEST_DB=sqlite:////tmp/rhodecode_test.sqlite
+
+[testenv:py25-mysql]
+basepython =
+    python2.5
+commands =
+    mysql -uroot -pqwe -hlocalhost -e 'drop database if exists rhodecode_test;'
+    mysql -uroot -pqwe -hlocalhost -e 'create database rhodecode_test;'
+    nosetests []
+deps =
+    mysql-python
+setenv = 
+    TEST_DB=mysql://root:qwe@localhost/rhodecode_test
+
+[testenv:py25-postgresql]
+basepython =
+    python2.5
+commands =
+    psql -Upostgres -Wqwe -hlocalhost -c 'drop database if exists rhodecode_test;'
+    psql -Upostgres -Wqwe -hlocalhost -c 'create database rhodecode_test;'
+    nosetests []
+deps =
+    psycopg2    
+setenv = 
+    TEST_DB=postgresql://postgres:qwe@localhost/rhodecode_test
+
+
+#### PYTHON 2.6 ####
+[testenv:py26-sqlite]
+basepython =
+    python2.6
+commands =
+    nosetests []
+setenv = 
+    TEST_DB=sqlite:////tmp/rhodecode_test.sqlite
+
+[testenv:py26-mysql]
+basepython =
+    python2.6
+commands =
+    mysql -uroot -pqwe -hlocalhost -e 'drop database if exists rhodecode_test;'
+    mysql -uroot -pqwe -hlocalhost -e 'create database rhodecode_test;'
+    nosetests []
+deps =
+    mysql-python
+setenv = 
+    TEST_DB=mysql://root:qwe@localhost/rhodecode_test
+
+[testenv:py26-postgresql]
+basepython =
+    python2.6
+commands =
+    psql -Upostgres -Wqwe -hlocalhost -c 'drop database if exists rhodecode_test;'
+    psql -Upostgres -Wqwe -hlocalhost -c 'create database rhodecode_test;'
+    nosetests []
+deps =
+    psycopg2    
+setenv = 
+    TEST_DB=postgresql://postgres:qwe@localhost/rhodecode_test
+
+
+#### PYTHON 2.7 ####
+[testenv:py27-sqlite]
+basepython =
+    python2.7
+commands =
+    nosetests []
+setenv = 
+    TEST_DB=sqlite:////tmp/rhodecode_test.sqlite
+
+[testenv:py27-mysql]
+basepython =
+    python2.7
+commands =
+    mysql -uroot -pqwe -hlocalhost -e 'drop database if exists rhodecode_test;'
+    mysql -uroot -pqwe -hlocalhost -e 'create database rhodecode_test;'
+    nosetests []
+deps =
+    mysql-python
+setenv = 
+    TEST_DB=mysql://root:qwe@localhost/rhodecode_test
+
+[testenv:py27-postgresql]
+basepython =
+    python2.7
+commands =
+    psql -Upostgres -Wqwe -hlocalhost -c 'drop database if exists rhodecode_test;'
+    psql -Upostgres -Wqwe -hlocalhost -c 'create database rhodecode_test;'
+    nosetests []
+deps =
+    psycopg2    
+setenv = 
+    TEST_DB=postgresql://postgres:qwe@localhost/rhodecode_test        
\ No newline at end of file