Changeset - 45df84d36b44
[Not reviewed]
beta
0 6 0
Marcin Kuzminski - 13 years ago 2013-04-06 02:49:42
marcin@python-works.com
Implemented preview for comments
6 files changed with 135 insertions and 24 deletions:
0 comments (0 inline, 0 general)
rhodecode/config/routing.py
Show inline comments
 
"""
 
Routes configuration
 

	
 
The more specific and detailed routes should be defined first so they
 
may take precedent over the more generic routes. For more information
 
refer to the routes manual at http://routes.groovie.org/docs/
 
"""
 
from __future__ import with_statement
 
from routes import Mapper
 

	
 
# prefix for non repository related links needs to be prefixed with `/`
 
ADMIN_PREFIX = '/_admin'
 

	
 

	
 
def make_map(config):
 
    """Create, configure and return the routes Mapper"""
 
    rmap = Mapper(directory=config['pylons.paths']['controllers'],
 
                 always_scan=config['debug'])
 
    rmap.minimization = False
 
    rmap.explicit = False
 

	
 
    from rhodecode.lib.utils import is_valid_repo
 
    from rhodecode.lib.utils import is_valid_repos_group
 

	
 
    def check_repo(environ, match_dict):
 
        """
 
        check for valid repository for proper 404 handling
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        from rhodecode.model.db import Repository
 
        repo_name = match_dict.get('repo_name')
 

	
 
        if match_dict.get('f_path'):
 
            #fix for multiple initial slashes that causes errors
 
            match_dict['f_path'] = match_dict['f_path'].lstrip('/')
 

	
 
        try:
 
            by_id = repo_name.split('_')
 
            if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
 
                repo_name = Repository.get(by_id[1]).repo_name
 
                match_dict['repo_name'] = repo_name
 
        except Exception:
 
            pass
 

	
 
        return is_valid_repo(repo_name, config['base_path'])
 

	
 
    def check_group(environ, match_dict):
 
        """
 
        check for valid repository group for proper 404 handling
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repos_group_name = match_dict.get('group_name')
 
        return is_valid_repos_group(repos_group_name, config['base_path'])
 

	
 
    def check_group_skip_path(environ, match_dict):
 
        """
 
        check for valid repository group for proper 404 handling, but skips
 
        verification of existing path
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repos_group_name = match_dict.get('group_name')
 
        return is_valid_repos_group(repos_group_name, config['base_path'],
 
                                    skip_path_check=True)
 

	
 
    def check_int(environ, match_dict):
 
        return match_dict.get('id').isdigit()
 

	
 
    # The ErrorController route (handles 404/500 error pages); it should
 
    # likely stay at the top, ensuring it can always be resolved
 
    rmap.connect('/error/{action}', controller='error')
 
    rmap.connect('/error/{action}/{id}', controller='error')
 

	
 
    #==========================================================================
 
    # CUSTOM ROUTES HERE
 
    #==========================================================================
 

	
 
    #MAIN PAGE
 
    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:.*?}',
 
                 controller='home', action='branch_tag_switcher')
 
    rmap.connect('bugtracker',
 
                 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
 
                 _static=True)
 
    rmap.connect('rst_help',
 
                 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
 
                 _static=True)
 
    rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
 

	
 
    #ADMIN REPOSITORY REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/repos') as m:
 
        m.connect("repos", "/repos",
 
             action="create", conditions=dict(method=["POST"]))
 
        m.connect("repos", "/repos",
 
             action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_repos", "/repos.{format}",
 
             action="index",
 
            conditions=dict(method=["GET"]))
 
        m.connect("new_repo", "/create_repository",
 
                  action="create_repository", conditions=dict(method=["GET"]))
 
        m.connect("/repos/{repo_name:.*?}",
 
             action="update", conditions=dict(method=["PUT"],
 
                                              function=check_repo))
 
        m.connect("/repos/{repo_name:.*?}",
 
             action="delete", conditions=dict(method=["DELETE"],
 
                                              function=check_repo))
 
        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:.*?}",
 
             action="show", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
 
             action="show", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        #add repo perm member
 
        m.connect('set_repo_perm_member', "/set_repo_perm_member/{repo_name:.*?}",
 
             action="set_repo_perm_member",
 
             conditions=dict(method=["POST"], function=check_repo))
 

	
 
        #ajax delete repo perm user
 
        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:.*?}",
 
                  action="delete_perm_users_group",
 
                  conditions=dict(method=["DELETE"], function=check_repo))
 

	
 
        #settings actions
 
        m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
 
                  action="repo_stats", conditions=dict(method=["DELETE"],
 
                                                       function=check_repo))
 
        m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
 
                  action="repo_cache", conditions=dict(method=["DELETE"],
 
                                                       function=check_repo))
 
        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:.*?}",
 
                  action="repo_pull", conditions=dict(method=["PUT"],
 
                                                      function=check_repo))
 
        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))
 
        m.connect('toggle_locking', "/locking_toggle/{repo_name:.*?}",
 
                  action="toggle_locking", conditions=dict(method=["GET"],
 
                                                      function=check_repo))
 

	
 
        #repo fields
 
        m.connect('create_repo_fields', "/repo_fields/{repo_name:.*?}/new",
 
                  action="create_repo_field", conditions=dict(method=["PUT"],
 
                                                      function=check_repo))
 

	
 
        m.connect('delete_repo_fields', "/repo_fields/{repo_name:.*?}/{field_id}",
 
                  action="delete_repo_field", conditions=dict(method=["DELETE"],
 
                                                      function=check_repo))
 

	
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/repos_groups') as m:
 
        m.connect("repos_groups", "/repos_groups",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("repos_groups", "/repos_groups",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_repos_groups", "/repos_groups.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_repos_group", "/repos_groups/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("update_repos_group", "/repos_groups/{group_name:.*?}",
 
                  action="update", conditions=dict(method=["PUT"],
 
                                                   function=check_group))
 
        m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
 
                  action="delete", conditions=dict(method=["DELETE"],
 
                                                   function=check_group_skip_path))
 
        m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
 
                  action="edit", conditions=dict(method=["GET"],
 
                                                 function=check_group))
 
        m.connect("formatted_edit_repos_group",
 
                  "/repos_groups/{group_name:.*?}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"],
 
                                                 function=check_group))
 
        m.connect("repos_group", "/repos_groups/{group_name:.*?}",
 
                  action="show", conditions=dict(method=["GET"],
 
                                                 function=check_group))
 
        m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}",
 
                  action="show", conditions=dict(method=["GET"],
 
                                                 function=check_group))
 
        # ajax delete repository group perm user
 
        m.connect('delete_repos_group_user_perm',
 
                  "/delete_repos_group_user_perm/{group_name:.*?}",
 
             action="delete_repos_group_user_perm",
 
             conditions=dict(method=["DELETE"], function=check_group))
 

	
 
        # ajax delete repository group perm users_group
 
        m.connect('delete_repos_group_users_group_perm',
 
                  "/delete_repos_group_users_group_perm/{group_name:.*?}",
 
                  action="delete_repos_group_users_group_perm",
 
                  conditions=dict(method=["DELETE"], function=check_group))
 

	
 
    #ADMIN USER REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/users') as m:
 
        m.connect("users", "/users",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("users", "/users",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_users", "/users.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_user", "/users/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_user", "/users/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("update_user", "/users/{id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("delete_user", "/users/{id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("edit_user", "/users/{id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_edit_user",
 
                  "/users/{id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("user", "/users/{id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_user", "/users/{id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 

	
 
        #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"]))
 
        m.connect("user_ips", "/users_ips/{id}",
 
                  action="add_ip", conditions=dict(method=["PUT"]))
 
        m.connect("user_ips_delete", "/users_ips/{id}",
 
                  action="delete_ip", conditions=dict(method=["DELETE"]))
 

	
 
    #ADMIN USER GROUPS REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/users_groups') as m:
 
        m.connect("users_groups", "/users_groups",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("users_groups", "/users_groups",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_users_groups", "/users_groups.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_users_group", "/users_groups/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_users_group", "/users_groups/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("update_users_group", "/users_groups/{id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("delete_users_group", "/users_groups/{id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("edit_users_group", "/users_groups/{id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_edit_users_group",
 
                  "/users_groups/{id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("users_group", "/users_groups/{id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_users_group", "/users_groups/{id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 

	
 
        #EXTRAS USER ROUTES
 
        m.connect("users_group_perm", "/users_groups_perm/{id}",
 
                  action="update_perm", conditions=dict(method=["PUT"]))
 

	
 
    #ADMIN GROUP REST ROUTES
 
    rmap.resource('group', 'groups',
 
                  controller='admin/groups', path_prefix=ADMIN_PREFIX)
 

	
 
    #ADMIN PERMISSIONS REST ROUTES
 
    rmap.resource('permission', 'permissions',
 
                  controller='admin/permissions', path_prefix=ADMIN_PREFIX)
 

	
 
    #ADMIN DEFAULTS REST ROUTES
 
    rmap.resource('default', 'defaults',
 
                  controller='admin/defaults', path_prefix=ADMIN_PREFIX)
 

	
 
    ##ADMIN LDAP SETTINGS
 
    rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
 
                 controller='admin/ldap_settings', action='ldap_settings',
 
                 conditions=dict(method=["POST"]))
 

	
 
    rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
 
                 controller='admin/ldap_settings')
 

	
 
    #ADMIN SETTINGS REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/settings') as m:
 
        m.connect("admin_settings", "/settings",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("admin_settings", "/settings",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_settings", "/settings.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("admin_new_setting", "/settings/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_new_setting", "/settings/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("/settings/{setting_id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("/settings/{setting_id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_edit_setting",
 
                  "/settings/{setting_id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("admin_setting", "/settings/{setting_id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_account", "/my_account",
 
                  action="my_account", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_account_update", "/my_account_update",
 
                  action="my_account_update", conditions=dict(method=["PUT"]))
 
        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,
 
                        controller='admin/notifications') as m:
 
        m.connect("notifications", "/notifications",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("notifications", "/notifications",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
 
                  action="mark_all_read", conditions=dict(method=["GET"]))
 
        m.connect("formatted_notifications", "/notifications.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_notification", "/notifications/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_notification", "/notifications/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("/notification/{notification_id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("/notification/{notification_id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("edit_notification", "/notification/{notification_id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_edit_notification",
 
                  "/notification/{notification_id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("notification", "/notification/{notification_id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 

	
 
    #ADMIN MAIN PAGES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/admin') as m:
 
        m.connect('admin_home', '', action='index')
 
        m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
 
                  action='add_repo')
 

	
 
    #==========================================================================
 
    # API V2
 
    #==========================================================================
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='api/api') as m:
 
        m.connect('api', '/api')
 

	
 
    #USER 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,
 
                 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")
 

	
 
    rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
 
                 controller='journal', action='toggle_following',
 
                 conditions=dict(method=["POST"]))
 

	
 
    #SEARCH
 
    rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
 
    rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
 
                 controller='search',
 
                 conditions=dict(function=check_repo))
 
    rmap.connect('search_repo', '/{repo_name:.*?}/search',
 
                 controller='search',
 
                 conditions=dict(function=check_repo),
 
                 )
 

	
 
    #LOGIN/LOGOUT/REGISTER/SIGN IN
 
    rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
 
    rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
 
                 action='logout')
 

	
 
    rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
 
                 action='register')
 

	
 
    rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
 
                 controller='login', action='password_reset')
 

	
 
    rmap.connect('reset_password_confirmation',
 
                 '%s/password_reset_confirmation' % ADMIN_PREFIX,
 
                 controller='login', action='password_reset_confirmation')
 

	
 
    #FEEDS
 
    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',
 
                controller='feed', action='atom',
 
                conditions=dict(function=check_repo))
 

	
 
    #==========================================================================
 
    # REPOSITORY ROUTES
 
    #==========================================================================
 
    rmap.connect('summary_home', '/{repo_name:.*?}',
 
                controller='summary',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('repo_size', '/{repo_name:.*?}/repo_size',
 
                controller='summary', action='repo_size',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('repos_group_home', '/{group_name:.*}',
 
                controller='admin/repos_groups', action="show_by_name",
 
                conditions=dict(function=check_group))
 

	
 
    rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
 
                controller='changeset', revision='tip',
 
                conditions=dict(function=check_repo))
 

	
 
    # no longer user, but kept for routes to work
 
    rmap.connect("_edit_repo", "/{repo_name:.*?}/edit",
 
                 controller='admin/repos', action="edit",
 
                 conditions=dict(method=["GET"], function=check_repo)
 
                 )
 

	
 
    rmap.connect("edit_repo", "/{repo_name:.*?}/settings",
 
                 controller='admin/repos', action="edit",
 
                 conditions=dict(method=["GET"], function=check_repo)
 
                 )
 

	
 
    #still working url for backward compat.
 
    rmap.connect('raw_changeset_home_depraced',
 
                 '/{repo_name:.*?}/raw-changeset/{revision}',
 
                 controller='changeset', action='changeset_raw',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    ## new URLs
 
    rmap.connect('changeset_raw_home',
 
                 '/{repo_name:.*?}/changeset-diff/{revision}',
 
                 controller='changeset', action='changeset_raw',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_patch_home',
 
                 '/{repo_name:.*?}/changeset-patch/{revision}',
 
                 controller='changeset', action='changeset_patch',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_download_home',
 
                 '/{repo_name:.*?}/changeset-download/{revision}',
 
                 controller='changeset', action='changeset_download',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_comment',
 
                 '/{repo_name:.*?}/changeset/{revision}/comment',
 
                controller='changeset', revision='tip', action='comment',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_comment_preview',
 
                 '/{repo_name:.*?}/changeset/comment/preview',
 
                controller='changeset', action='preview_comment',
 
                conditions=dict(function=check_repo, method=["POST"]))
 

	
 
    rmap.connect('changeset_comment_delete',
 
                 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
 
                controller='changeset', action='delete_comment',
 
                conditions=dict(function=check_repo, method=["DELETE"]))
 

	
 
    rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
 
                 controller='changeset', action='changeset_info')
 

	
 
    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|__other_ref_type__)',
 
                            other_ref_type='(branch|book|tag|rev|__org_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_summary', '/{repo_name:.*?}/summary',
 
                controller='summary', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
 
                controller='shortlog', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
 
                controller='shortlog', f_path=None,
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('branches_home', '/{repo_name:.*?}/branches',
 
                controller='branches', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('tags_home', '/{repo_name:.*?}/tags',
 
                controller='tags', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
 
                controller='bookmarks', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
 
                controller='changelog', conditions=dict(function=check_repo))
 

	
 
    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:.*}',
 
                controller='files', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_home_nopath', '/{repo_name:.*?}/files/{revision}',
 
                controller='files', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_history_home',
 
                 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
 
                 controller='files', action='history', revision='tip', f_path='',
 
                 conditions=dict(function=check_repo))
 

	
 
    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:.*}',
 
                 controller='files', action='rawfile', revision='tip',
 
                 f_path='', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_raw_home',
 
                 '/{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:.*}',
 
                 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:.*}',
 
                 controller='files', action='edit', revision='tip',
 
                 f_path='', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_add_home',
 
                 '/{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}',
 
                controller='files', action='archivefile',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_nodelist_home',
 
                 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
 
                controller='files', action='nodelist',
 
                conditions=dict(function=check_repo))
 

	
 
    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',
 
                controller='forks', action='fork',
 
                conditions=dict(function=check_repo))
 

	
 
    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',
 
                 controller='followers', action='followers',
 
                 conditions=dict(function=check_repo))
 

	
 
    return rmap
rhodecode/controllers/changeset.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.changeset
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    changeset controller for pylons showoing changes beetween
 
    revisions
 

	
 
    :created_on: Apr 25, 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 logging
 
import traceback
 
from collections import defaultdict
 
from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound
 

	
 
from pylons import tmpl_context as c, url, request, response
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 
from rhodecode.lib.utils import jsonify
 

	
 
from rhodecode.lib.vcs.exceptions import RepositoryError, \
 
    ChangesetDoesNotExistError
 

	
 
import rhodecode.lib.helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
 
    NotAnonymous
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import action_logger
 
from rhodecode.lib.compat import OrderedDict
 
from rhodecode.lib import diffs
 
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.model.repo import RepoModel
 
from rhodecode.lib.diffs import LimitedDiffContainer
 
from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.utils2 import safe_unicode
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def _update_with_GET(params, GET):
 
    for k in ['diff1', 'diff2', 'diff']:
 
        params[k] += GET.getall(k)
 

	
 

	
 
def anchor_url(revision, path, GET):
 
    fid = h.FID(revision, path)
 
    return h.url.current(anchor=fid, **dict(GET))
 

	
 

	
 
def get_ignore_ws(fid, GET):
 
    ig_ws_global = GET.get('ignorews')
 
    ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
 
    if ig_ws:
 
        try:
 
            return int(ig_ws[0].split(':')[-1])
 
        except Exception:
 
            pass
 
    return ig_ws_global
 

	
 

	
 
def _ignorews_url(GET, fileid=None):
 
    fileid = str(fileid) if fileid else None
 
    params = defaultdict(list)
 
    _update_with_GET(params, GET)
 
    lbl = _('Show white space')
 
    ig_ws = get_ignore_ws(fileid, GET)
 
    ln_ctx = get_line_ctx(fileid, GET)
 
    # global option
 
    if fileid is None:
 
        if ig_ws is None:
 
            params['ignorews'] += [1]
 
            lbl = _('Ignore white space')
 
        ctx_key = 'context'
 
        ctx_val = ln_ctx
 
    # per file options
 
    else:
 
        if ig_ws is None:
 
            params[fileid] += ['WS:1']
 
            lbl = _('Ignore white space')
 

	
 
        ctx_key = fileid
 
        ctx_val = 'C:%s' % ln_ctx
 
    # if we have passed in ln_ctx pass it along to our params
 
    if ln_ctx:
 
        params[ctx_key] += [ctx_val]
 

	
 
    params['anchor'] = fileid
 
    img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
 
    return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
 

	
 

	
 
def get_line_ctx(fid, GET):
 
    ln_ctx_global = GET.get('context')
 
    if fid:
 
        ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
 
    else:
 
        _ln_ctx = filter(lambda k: k.startswith('C'), GET)
 
        ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx  else ln_ctx_global
 
        if ln_ctx:
 
            ln_ctx = [ln_ctx]
 

	
 
    if ln_ctx:
 
        retval = ln_ctx[0].split(':')[-1]
 
    else:
 
        retval = ln_ctx_global
 

	
 
    try:
 
        return int(retval)
 
    except Exception:
 
        return 3
 

	
 

	
 
def _context_url(GET, fileid=None):
 
    """
 
    Generates url for context lines
 

	
 
    :param fileid:
 
    """
 

	
 
    fileid = str(fileid) if fileid else None
 
    ig_ws = get_ignore_ws(fileid, GET)
 
    ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2
 

	
 
    params = defaultdict(list)
 
    _update_with_GET(params, GET)
 

	
 
    # global option
 
    if fileid is None:
 
        if ln_ctx > 0:
 
            params['context'] += [ln_ctx]
 

	
 
        if ig_ws:
 
            ig_ws_key = 'ignorews'
 
            ig_ws_val = 1
 

	
 
    # per file option
 
    else:
 
        params[fileid] += ['C:%s' % ln_ctx]
 
        ig_ws_key = fileid
 
        ig_ws_val = 'WS:%s' % 1
 

	
 
    if ig_ws:
 
        params[ig_ws_key] += [ig_ws_val]
 

	
 
    lbl = _('%s line context') % ln_ctx
 

	
 
    params['anchor'] = fileid
 
    img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
 
    return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
 

	
 

	
 
class ChangesetController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    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, method='show'):
 
        c.anchor_url = anchor_url
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
 
        c.fulldiff = fulldiff = request.GET.get('fulldiff')
 
        #get ranges of revisions if preset
 
        rev_range = revision.split('...')[:2]
 
        enable_comments = True
 
        try:
 
            if len(rev_range) == 2:
 
                enable_comments = False
 
                rev_start = rev_range[0]
 
                rev_end = rev_range[1]
 
                rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
 
                                                             end=rev_end)
 
            else:
 
                rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
 

	
 
            c.cs_ranges = list(rev_ranges)
 
            if not c.cs_ranges:
 
                raise RepositoryError('Changeset range returned empty result')
 

	
 
        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
 
            log.error(traceback.format_exc())
 
            h.flash(str(e), category='error')
 
            raise HTTPNotFound()
 

	
 
        c.changes = OrderedDict()
 

	
 
        c.lines_added = 0  # count of lines added
 
        c.lines_deleted = 0  # count of lines removes
 

	
 
        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:
 
            inlines = []
 
            if method == 'show':
 
                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,
 
                                                revision=changeset.raw_id))
 

	
 
                #comments from PR
 
                st = ChangesetStatusModel().get_statuses(
 
                            c.rhodecode_db_repo.repo_id, changeset.raw_id,
 
                            with_revisions=True)
 
                # from associated statuses, check the pull requests, and
 
                # show comments from them
 

	
 
                prs = set([x.pull_request for x in
 
                           filter(lambda x: x.pull_request != None, st)])
 

	
 
                for pr in prs:
 
                    c.comments.extend(pr.comments)
 
                inlines = ChangesetCommentsModel()\
 
                            .get_inline_comments(c.rhodecode_db_repo.repo_id,
 
                                                 revision=changeset.raw_id)
 
                c.inline_comments.extend(inlines)
 

	
 
            c.changes[changeset.raw_id] = []
 

	
 
            cs2 = changeset.raw_id
 
            cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset()
 
            context_lcl = get_line_ctx('', request.GET)
 
            ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET)
 

	
 
            _diff = c.rhodecode_repo.get_diff(cs1, cs2,
 
                ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
 
            diff_limit = self.cut_off_limit if not fulldiff else None
 
            diff_processor = diffs.DiffProcessor(_diff,
 
                                                 vcs=c.rhodecode_repo.alias,
 
                                                 format='gitdiff',
 
                                                 diff_limit=diff_limit)
 
            cs_changes = OrderedDict()
 
            if method == 'show':
 
                _parsed = diff_processor.prepare()
 
                c.limited_diff = False
 
                if isinstance(_parsed, LimitedDiffContainer):
 
                    c.limited_diff = True
 
                for f in _parsed:
 
                    st = f['stats']
 
                    if st[0] != 'b':
 
                        c.lines_added += st[0]
 
                        c.lines_deleted += st[1]
 
                    fid = h.FID(changeset.raw_id, f['filename'])
 
                    diff = diff_processor.as_html(enable_comments=enable_comments,
 
                                                  parsed_lines=[f])
 
                    cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'],
 
                                       diff, st]
 
            else:
 
                # downloads/raw we only need RAW diff nothing else
 
                diff = diff_processor.as_raw()
 
                cs_changes[''] = [None, None, None, None, diff, None]
 
            c.changes[changeset.raw_id] = cs_changes
 

	
 
        #sort comments by how they were generated
 
        c.comments = sorted(c.comments, key=lambda x: x.comment_id)
 

	
 
        # count inline comments
 
        for __, lines in c.inline_comments:
 
            for comments in lines.values():
 
                c.inline_cnt += len(comments)
 

	
 
        if len(c.cs_ranges) == 1:
 
            c.changeset = c.cs_ranges[0]
 
            c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id
 
                                     for x in c.changeset.parents])
 
        if method == 'download':
 
            response.content_type = 'text/plain'
 
            response.content_disposition = 'attachment; filename=%s.diff' \
 
                                            % revision[:12]
 
            return diff
 
        elif method == 'patch':
 
            response.content_type = 'text/plain'
 
            c.diff = safe_unicode(diff)
 
            return render('changeset/patch_changeset.html')
 
        elif method == 'raw':
 
            response.content_type = 'text/plain'
 
            return diff
 
        elif method == 'show':
 
            if len(c.cs_ranges) == 1:
 
                return render('changeset/changeset.html')
 
            else:
 
                return render('changeset/changeset_range.html')
 

	
 
    def changeset_raw(self, revision):
 
        return self.index(revision, method='raw')
 

	
 
    def changeset_patch(self, revision):
 
        return self.index(revision, method='patch')
 

	
 
    def changeset_download(self, revision):
 
        return self.index(revision, method='download')
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def comment(self, repo_name, revision):
 
        status = request.POST.get('changeset_status')
 
        change_status = request.POST.get('change_changeset_status')
 
        text = request.POST.get('text')
 
        if status and change_status:
 
            text = text or (_('Status change -> %s')
 
                            % ChangesetStatus.get_status_lbl(status))
 

	
 
        c.co = comm = ChangesetCommentsModel().create(
 
            text=text,
 
            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'),
 
            status_change=(ChangesetStatus.get_status_lbl(status)
 
                           if status and change_status else None)
 
        )
 

	
 
        # 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))
 
        #only ajax below
 
        data = {
 
           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
 
        }
 
        if comm:
 
            data.update(comm.get_dict())
 
            data.update({'rendered_text':
 
                         render('changeset/changeset_comment_block.html')})
 

	
 
        return data
 

	
 
    @NotAnonymous()
 
    def preview_comment(self):
 
        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            raise HTTPBadRequest()
 
        text = request.POST.get('text')
 
        if text:
 
            return h.rst_w_mentions(text)
 
        return ''
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def delete_comment(self, repo_name, comment_id):
 
        co = ChangesetComment.get(comment_id)
 
        owner = 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()
 

	
 
    @jsonify
 
    def changeset_info(self, repo_name, revision):
 
        if request.is_xhr:
 
            try:
 
                return c.rhodecode_repo.get_changeset(revision)
 
            except ChangesetDoesNotExistError, e:
 
                return EmptyChangeset(message=str(e))
 
        else:
 
            raise HTTPBadRequest()
rhodecode/public/css/style.css
Show inline comments
 
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
 
    border: 0;
 
    outline: 0;
 
    font-size: 100%;
 
    vertical-align: baseline;
 
    background: transparent;
 
    margin: 0;
 
    padding: 0;
 
}
 

	
 
body {
 
    line-height: 1;
 
    height: 100%;
 
    background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
 
    font-family: Lucida Grande, Verdana, Lucida Sans Regular,
 
        Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
 
    color: #000;
 
    margin: 0;
 
    padding: 0;
 
    font-size: 12px;
 
}
 

	
 
ol, ul {
 
    list-style: none;
 
}
 

	
 
blockquote, q {
 
    quotes: none;
 
}
 

	
 
blockquote:before, blockquote:after, q:before, q:after {
 
    content: none;
 
}
 

	
 
:focus {
 
    outline: 0;
 
}
 

	
 
del {
 
    text-decoration: line-through;
 
}
 

	
 
table {
 
    border-collapse: collapse;
 
    border-spacing: 0;
 
}
 

	
 
html {
 
    height: 100%;
 
}
 

	
 
a {
 
    color: #003367;
 
    text-decoration: none;
 
    cursor: pointer;
 
}
 

	
 
a:hover {
 
    color: #316293;
 
    text-decoration: underline;
 
}
 

	
 
h1, h2, h3, h4, h5, h6,
 
div.h1, div.h2, div.h3, div.h4, div.h5, div.h6 {
 
    color: #292929;
 
    font-weight: 700;
 
}
 

	
 
h1, div.h1 {
 
    font-size: 22px;
 
}
 

	
 
h2, div.h2 {
 
    font-size: 20px;
 
}
 

	
 
h3, div.h3 {
 
    font-size: 18px;
 
}
 

	
 
h4, div.h4 {
 
    font-size: 16px;
 
}
 

	
 
h5, div.h5 {
 
    font-size: 14px;
 
}
 

	
 
h6, div.h6 {
 
    font-size: 11px;
 
}
 

	
 
ul.circle {
 
    list-style-type: circle;
 
}
 

	
 
ul.disc {
 
    list-style-type: disc;
 
}
 

	
 
ul.square {
 
    list-style-type: square;
 
}
 

	
 
ol.lower-roman {
 
    list-style-type: lower-roman;
 
}
 

	
 
ol.upper-roman {
 
    list-style-type: upper-roman;
 
}
 

	
 
ol.lower-alpha {
 
    list-style-type: lower-alpha;
 
}
 

	
 
ol.upper-alpha {
 
    list-style-type: upper-alpha;
 
}
 

	
 
ol.decimal {
 
    list-style-type: decimal;
 
}
 

	
 
div.color {
 
    clear: both;
 
    overflow: hidden;
 
    position: absolute;
 
    background: #FFF;
 
    margin: 7px 0 0 60px;
 
    padding: 1px 1px 1px 0;
 
}
 

	
 
div.color a {
 
    width: 15px;
 
    height: 15px;
 
    display: block;
 
    float: left;
 
    margin: 0 0 0 1px;
 
    padding: 0;
 
}
 

	
 
div.options {
 
    clear: both;
 
    overflow: hidden;
 
    position: absolute;
 
    background: #FFF;
 
    margin: 7px 0 0 162px;
 
    padding: 0;
 
}
 

	
 
div.options a {
 
    height: 1%;
 
    display: block;
 
    text-decoration: none;
 
    margin: 0;
 
    padding: 3px 8px;
 
}
 

	
 
.top-left-rounded-corner {
 
    -webkit-border-top-left-radius: 8px;
 
    -khtml-border-radius-topleft: 8px;
 
    border-top-left-radius: 8px;
 
}
 

	
 
.top-right-rounded-corner {
 
    -webkit-border-top-right-radius: 8px;
 
    -khtml-border-radius-topright: 8px;
 
    border-top-right-radius: 8px;
 
}
 

	
 
.bottom-left-rounded-corner {
 
    -webkit-border-bottom-left-radius: 8px;
 
    -khtml-border-radius-bottomleft: 8px;
 
    border-bottom-left-radius: 8px;
 
}
 

	
 
.bottom-right-rounded-corner {
 
    -webkit-border-bottom-right-radius: 8px;
 
    -khtml-border-radius-bottomright: 8px;
 
    border-bottom-right-radius: 8px;
 
}
 

	
 
.top-left-rounded-corner-mid {
 
    -webkit-border-top-left-radius: 4px;
 
    -khtml-border-radius-topleft: 4px;
 
    border-top-left-radius: 4px;
 
}
 

	
 
.top-right-rounded-corner-mid {
 
    -webkit-border-top-right-radius: 4px;
 
    -khtml-border-radius-topright: 4px;
 
    border-top-right-radius: 4px;
 
}
 

	
 
.bottom-left-rounded-corner-mid {
 
    -webkit-border-bottom-left-radius: 4px;
 
    -khtml-border-radius-bottomleft: 4px;
 
    border-bottom-left-radius: 4px;
 
}
 

	
 
.bottom-right-rounded-corner-mid {
 
    -webkit-border-bottom-right-radius: 4px;
 
    -khtml-border-radius-bottomright: 4px;
 
    border-bottom-right-radius: 4px;
 
}
 

	
 
.help-block {
 
    color: #999999;
 
    display: block;
 
    margin-bottom: 0;
 
    margin-top: 5px;
 
}
 

	
 
.empty_data {
 
    color: #B9B9B9;
 
}
 

	
 
a.permalink {
 
    visibility: hidden;
 
    position: absolute;
 
    margin: 3px 4px;
 
}
 

	
 
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 {
 
}
 
#header ul#logged-user {
 
    margin-bottom: 5px !important;
 
    -webkit-border-radius: 0px 0px 8px 8px;
 
    -khtml-border-radius: 0px 0px 8px 8px;
 
    border-radius: 0px 0px 8px 8px;
 
    height: 37px;
 
    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);
 
    background-image: -ms-linear-gradient(top, #003b76, #00376e);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
 
    background-image: -webkit-linear-gradient(top, #003b76, #00376e);
 
    background-image: -o-linear-gradient(top, #003b76, #00376e);
 
    background-image: linear-gradient(to bottom, #003b76, #00376e);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
 
    box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
}
 

	
 
#header ul#logged-user li {
 
    list-style: none;
 
    float: left;
 
    margin: 8px 0 0;
 
    padding: 4px 12px;
 
    border-left: 1px solid #316293;
 
}
 

	
 
#header ul#logged-user li.first {
 
    border-left: none;
 
    margin: 4px;
 
}
 

	
 
#header ul#logged-user li.first div.gravatar {
 
    margin-top: -2px;
 
}
 

	
 
#header ul#logged-user li.first div.account {
 
    padding-top: 4px;
 
    float: left;
 
}
 

	
 
#header ul#logged-user li.last {
 
    border-right: none;
 
}
 

	
 
#header ul#logged-user li a {
 
    color: #fff;
 
    font-weight: 700;
 
    text-decoration: none;
 
}
 

	
 
#header ul#logged-user li a:hover {
 
    text-decoration: underline;
 
}
 

	
 
#header ul#logged-user li.highlight a {
 
    color: #fff;
 
}
 

	
 
#header ul#logged-user li.highlight a:hover {
 
    color: #FFF;
 
}
 
#header-dd {
 
    clear: both;
 
    position: fixed !important;
 
    background-color: #003B76;
 
    opacity: 0.01;
 
    cursor: pointer;
 
    min-height: 10px;
 
    width: 100% !important;
 
    -webkit-border-radius: 0px 0px 4px 4px;
 
    -khtml-border-radius: 0px 0px 4px 4px;
 
    border-radius: 0px 0px 4px 4px;
 
}
 

	
 
#header-dd:hover {
 
    opacity: 0.2;
 
    -webkit-transition: opacity 0.5s ease-in-out;
 
    -moz-transition: opacity 0.5s ease-in-out;
 
    transition: opacity 0.5s ease-in-out;
 
}
 

	
 
#header #header-inner {
 
    min-height: 44px;
 
    clear: both;
 
    position: relative;
 
    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);
 
    background-image: -ms-linear-gradient(top, #003b76, #00376e);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
 
    background-image: -webkit-linear-gradient(top, #003b76, #00376e);
 
    background-image: -o-linear-gradient(top, #003b76, #00376e);
 
    background-image: linear-gradient(to bottom, #003b76, #00376e);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
 
    margin: 0;
 
    padding: 0;
 
    display: block;
 
    box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
    -webkit-border-radius: 0px 0px 4px 4px;
 
    -khtml-border-radius: 0px 0px 4px 4px;
 
    border-radius: 0px 0px 4px 4px;
 
}
 
#header #header-inner.hover {
 
    width: 100% !important;
 
    -webkit-border-radius: 0px 0px 0px 0px;
 
    -khtml-border-radius: 0px 0px 0px 0px;
 
    border-radius: 0px 0px 0px 0px;
 
    position: fixed !important;
 
    z-index: 10000;
 
}
 

	
 
.ie7 #header #header-inner.hover,
 
.ie8 #header #header-inner.hover,
 
.ie9 #header #header-inner.hover
 
{
 
    z-index: auto !important;
 
}
 

	
 
.header-pos-fix, .anchor {
 
    margin-top: -46px;
 
    padding-top: 46px;
 
}
 

	
 
#header #header-inner #home a {
 
    height: 40px;
 
    width: 46px;
 
    display: block;
 
    background: url("../images/button_home.png");
 
    background-position: 0 0;
 
    margin: 0;
 
    padding: 0;
 
}
 

	
 
#header #header-inner #home a:hover {
 
    background-position: 0 -40px;
 
}
 

	
 
#header #header-inner #logo {
 
    float: left;
 
    position: absolute;
 
}
 

	
 
#header #header-inner #logo h1 {
 
    color: #FFF;
 
    font-size: 20px;
 
    margin: 12px 0 0 13px;
 
    padding: 0;
 
}
 

	
 
#header #header-inner #logo a {
 
    color: #fff;
 
    text-decoration: none;
 
}
 

	
 
#header #header-inner #logo a:hover {
 
    color: #bfe3ff;
 
}
 

	
 
#header #header-inner #quick {
 
    position: relative;
 
    float: right;
 
    list-style-type: none;
 
    list-style-position: outside;
 
    margin: 4px 8px 0 0;
 
    padding: 0;
 
    border-radius: 4px;
 
}
 

	
 
#header #header-inner #quick li span.short {
 
    padding: 9px 6px 8px 6px;
 
}
 

	
 
#header #header-inner #quick li span {
 
    display: inline;
 
    margin: 0;
 
}
 

	
 
#header #header-inner #quick li span.normal {
 
    border: none;
 
    padding: 10px 12px 8px;
 
}
 

	
 
#header #header-inner #quick li span.icon {
 
    border-left: none;
 
    padding-left: 10px;
 
}
 

	
 
#header #header-inner #quick li span.icon_short {
 
    top: 0;
 
    left: 0;
 
    border-left: none;
 
    border-right: 1px solid #2e5c89;
 
    padding: 8px 6px 4px;
 
}
 

	
 
#header #header-inner #quick li span.icon img, #header #header-inner #quick li span.icon_short img {
 
    vertical-align: middle;
 
    margin-bottom: 2px;
 
}
 

	
 
#header #header-inner #quick ul.repo_switcher {
 
    max-height: 275px;
 
    overflow-x: hidden;
 
    overflow-y: auto;
 
}
 

	
 
#header #header-inner #quick ul.repo_switcher li.qfilter_rs {
 
    padding: 2px 3px;
 
    padding-right: 17px;
 
}
 

	
 
#header #header-inner #quick ul.repo_switcher li.qfilter_rs  input {
 
    width: 100%;
 
    border-radius: 10px;
 
    padding: 2px 7px;
 
}
 

	
 
#header #header-inner #quick .repo_switcher_type {
 
    position: absolute;
 
    left: 0;
 
    top: 9px;
 
    margin: 0px 2px 0px 2px;
 
}
 

	
 
#header #header-inner #quick li ul li a.journal, #header #header-inner #quick li ul li a.journal:hover {
 
    background-image: url("../images/icons/book.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.private_repo, #header #header-inner #quick li ul li a.private_repo:hover {
 
    background-image: url("../images/icons/lock.png")
 
}
 

	
 
#header #header-inner #quick li ul li a.public_repo, #header #header-inner #quick li ul li a.public_repo:hover {
 
    background-image: url("../images/icons/lock_open.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.hg, #header #header-inner #quick li ul li a.hg:hover {
 
    background-image: url("../images/icons/hgicon.png");
 
    padding-left: 42px;
 
    background-position: 20px 9px;
 
}
 

	
 
#header #header-inner #quick li ul li a.git, #header #header-inner #quick li ul li a.git:hover {
 
    background-image: url("../images/icons/giticon.png");
 
    padding-left: 42px;
 
    background-position: 20px 9px;
 
}
 

	
 
#header #header-inner #quick li ul li a.repos, #header #header-inner #quick li ul li a.repos:hover {
 
    background-image: url("../images/icons/database_edit.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.repos_groups, #header #header-inner #quick li ul li a.repos_groups:hover {
 
    background-image: url("../images/icons/database_link.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.users, #header #header-inner #quick li ul li a.users:hover {
 
    background-image: url("../images/icons/user_edit.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.groups, #header #header-inner #quick li ul li a.groups:hover {
 
    background-image: url("../images/icons/group_edit.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.defaults, #header #header-inner #quick li ul li a.defaults:hover {
 
    background-image: url("../images/icons/wrench.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.settings, #header #header-inner #quick li ul li a.settings:hover {
 
    background-image: url("../images/icons/cog.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.permissions, #header #header-inner #quick li ul li a.permissions:hover {
 
    background-image: url("../images/icons/key.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.ldap, #header #header-inner #quick li ul li a.ldap:hover {
 
    background-image: url("../images/icons/server_key.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.fork, #header #header-inner #quick li ul li a.fork:hover {
 
    background-image: url("../images/icons/arrow_divide.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.locking_add, #header #header-inner #quick li ul li a.locking_add:hover {
 
    background-image: url("../images/icons/lock_add.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.locking_del, #header #header-inner #quick li ul li a.locking_del:hover {
 
    background-image: url("../images/icons/lock_delete.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.pull_request, #header #header-inner #quick li ul li a.pull_request:hover {
 
    background-image: url("../images/icons/arrow_join.png") ;
 
}
 

	
 
#header #header-inner #quick li ul li a.compare_request, #header #header-inner #quick li ul li a.compare_request:hover {
 
    background-image: url("../images/icons/arrow_inout.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.search, #header #header-inner #quick li ul li a.search:hover {
 
    background-image: url("../images/icons/search_16.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.shortlog, #header #header-inner #quick li ul li a.shortlog:hover {
 
    background-image: url("../images/icons/clock_16.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.delete, #header #header-inner #quick li ul li a.delete:hover {
 
    background-image: url("../images/icons/delete.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.branches, #header #header-inner #quick li ul li a.branches:hover {
 
    background-image: url("../images/icons/arrow_branch.png");
 
}
 

	
 
#header #header-inner #quick li ul li a.tags,
 
#header #header-inner #quick li ul li a.tags:hover {
 
    background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 

	
 
#header #header-inner #quick li ul li a.bookmarks,
 
#header #header-inner #quick li ul li a.bookmarks:hover {
 
    background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 

	
 
#header #header-inner #quick li ul li a.admin,
 
#header #header-inner #quick li ul li a.admin:hover {
 
    background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 

	
 
.groups_breadcrumbs a {
 
    color: #fff;
 
}
 

	
 
.groups_breadcrumbs a:hover {
 
    color: #bfe3ff;
 
    text-decoration: none;
 
}
 

	
 
td.quick_repo_menu {
 
    background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
 
    cursor: pointer;
 
    width: 8px;
 
    border: 1px solid transparent;
 
}
 

	
 
td.quick_repo_menu.active {
 
    background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
 
    border: 1px solid #003367;
 
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
 
    cursor: pointer;
 
}
 

	
 
td.quick_repo_menu .menu_items {
 
    margin-top: 10px;
 
    margin-left: -6px;
 
    width: 150px;
 
    position: absolute;
 
    background-color: #FFF;
 
    background: none repeat scroll 0 0 #FFFFFF;
 
    border-color: #003367 #666666 #666666;
 
    border-right: 1px solid #666666;
 
    border-style: solid;
 
    border-width: 1px;
 
    box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
 
    border-top-style: none;
 
}
 

	
 
td.quick_repo_menu .menu_items li {
 
    padding: 0 !important;
 
}
 

	
 
td.quick_repo_menu .menu_items a {
 
    display: block;
 
    padding: 4px 12px 4px 8px;
 
}
 

	
 
td.quick_repo_menu .menu_items a:hover {
 
    background-color: #EEE;
 
    text-decoration: none;
 
}
 

	
 
td.quick_repo_menu .menu_items .icon img {
 
    margin-bottom: -2px;
 
}
 

	
 
td.quick_repo_menu .menu_items.hidden {
 
    display: none;
 
}
 

	
 
.yui-dt-first th {
 
    text-align: left;
 
}
 

	
 
/*
 
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
 
*/
 
.yui-skin-sam .yui-dt-mask {
 
    position: absolute;
 
    z-index: 9500;
 
}
 
.yui-dt-tmp {
 
    position: absolute;
 
    left: -9000px;
 
}
 
.yui-dt-scrollable .yui-dt-bd { overflow: auto }
 
.yui-dt-scrollable .yui-dt-hd {
 
    overflow: hidden;
 
    position: relative;
 
}
 
.yui-dt-scrollable .yui-dt-bd thead tr,
 
.yui-dt-scrollable .yui-dt-bd thead th {
 
    position: absolute;
 
    left: -1500px;
 
}
 
.yui-dt-scrollable tbody { -moz-outline: 0 }
 
.yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
 
.yui-skin-sam thead .yui-dt-draggable { cursor: move }
 
.yui-dt-coltarget {
 
    position: absolute;
 
    z-index: 999;
 
}
 
.yui-dt-hd { zoom: 1 }
 
th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
 
.yui-dt-resizer {
 
    position: absolute;
 
    right: 0;
 
    bottom: 0;
 
    height: 100%;
 
    cursor: e-resize;
 
    cursor: col-resize;
 
    background-color: #CCC;
 
    opacity: 0;
 
    filter: alpha(opacity=0);
 
}
 
.yui-dt-resizerproxy {
 
    visibility: hidden;
 
    position: absolute;
 
    z-index: 9000;
 
    background-color: #CCC;
 
    opacity: 0;
 
    filter: alpha(opacity=0);
 
}
 
th.yui-dt-hidden .yui-dt-liner,
 
td.yui-dt-hidden .yui-dt-liner,
 
th.yui-dt-hidden .yui-dt-resizer { display: none }
 
.yui-dt-editor,
 
.yui-dt-editor-shim {
 
    position: absolute;
 
    z-index: 9000;
 
}
 
.yui-skin-sam .yui-dt table {
 
    margin: 0;
 
    padding: 0;
 
    font-family: arial;
 
    font-size: inherit;
 
    border-collapse: separate;
 
    *border-collapse: collapse;
 
    border-spacing: 0;
 
    border: 1px solid #7f7f7f;
 
}
 
.yui-skin-sam .yui-dt thead { border-spacing: 0 }
 
.yui-skin-sam .yui-dt caption {
 
    color: #000;
 
    font-size: 85%;
 
    font-weight: normal;
 
    font-style: italic;
 
    line-height: 1;
 
    padding: 1em 0;
 
    text-align: center;
 
}
 
.yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
 
.yui-skin-sam .yui-dt th,
 
.yui-skin-sam .yui-dt th a {
 
    font-weight: normal;
 
    text-decoration: none;
 
    color: #000;
 
    vertical-align: bottom;
 
}
 
.yui-skin-sam .yui-dt th {
 
    margin: 0;
 
    padding: 0;
 
    border: 0;
 
    border-right: 1px solid #cbcbcb;
 
}
 
.yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
 
.yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
 
.yui-skin-sam .yui-dt-liner {
 
    margin: 0;
 
    padding: 0;
 
}
 
.yui-skin-sam .yui-dt-coltarget {
 
    width: 5px;
 
    background-color: red;
 
}
 
.yui-skin-sam .yui-dt td {
 
    margin: 0;
 
    padding: 0;
 
    border: 0;
 
    border-right: 1px solid #cbcbcb;
 
    text-align: left;
 
}
 
.yui-skin-sam .yui-dt-list td { border-right: 0 }
 
.yui-skin-sam .yui-dt-resizer { width: 6px }
 
.yui-skin-sam .yui-dt-mask {
 
    background-color: #000;
 
    opacity: .25;
 
    filter: alpha(opacity=25);
 
}
 
.yui-skin-sam .yui-dt-message { background-color: #FFF }
 
.yui-skin-sam .yui-dt-scrollable table { border: 0 }
 
.yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
 
    border-left: 1px solid #7f7f7f;
 
    border-top: 1px solid #7f7f7f;
 
    border-right: 1px solid #7f7f7f;
 
}
 
.yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
 
    border-left: 1px solid #7f7f7f;
 
    border-bottom: 1px solid #7f7f7f;
 
    border-right: 1px solid #7f7f7f;
 
    background-color: #FFF;
 
}
 
.yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
 
.yui-skin-sam th.yui-dt-asc,
 
.yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
 
.yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
 
.yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
 
.yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
 
tbody .yui-dt-editable { cursor: pointer }
 
.yui-dt-editor {
 
    text-align: left;
 
    background-color: #f2f2f2;
 
    border: 1px solid #808080;
 
    padding: 6px;
 
}
 
.yui-dt-editor label {
 
    padding-left: 4px;
 
    padding-right: 6px;
 
}
 
.yui-dt-editor .yui-dt-button {
 
    padding-top: 6px;
 
    text-align: right;
 
}
 
.yui-dt-editor .yui-dt-button button {
 
    background: url(../images/sprite.png) repeat-x 0 0;
 
    border: 1px solid #999;
 
    width: 4em;
 
    height: 1.8em;
 
    margin-left: 6px;
 
}
 
.yui-dt-editor .yui-dt-button button.yui-dt-default {
 
    background: url(../images/sprite.png) repeat-x 0 -1400px;
 
    background-color: #5584e0;
 
    border: 1px solid #304369;
 
    color: #FFF;
 
}
 
.yui-dt-editor .yui-dt-button button:hover {
 
    background: url(../images/sprite.png) repeat-x 0 -1300px;
 
    color: #000;
 
}
 
.yui-dt-editor .yui-dt-button button:active {
 
    background: url(../images/sprite.png) repeat-x 0 -1700px;
 
    color: #000;
 
}
 
.yui-skin-sam tr.yui-dt-even { background-color: #FFF }
 
.yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
 
.yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
 
.yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
 
.yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
 
.yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
 
.yui-skin-sam th.yui-dt-highlighted,
 
.yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
 
.yui-skin-sam tr.yui-dt-highlighted,
 
.yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
 
.yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
 
.yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
 
.yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
 
    cursor: pointer;
 
    background-color: #b2d2ff;
 
}
 
.yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
 
.yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
 
    cursor: pointer;
 
    background-color: #b2d2ff;
 
}
 
.yui-skin-sam th.yui-dt-selected,
 
.yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
 
.yui-skin-sam tr.yui-dt-selected td,
 
.yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
 
.yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
 
    background-color: #426fd9;
 
    color: #FFF;
 
}
 
.yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
 
.yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
 
    background-color: #446cd7;
 
    color: #FFF;
 
}
 
.yui-skin-sam .yui-dt-list th.yui-dt-selected,
 
.yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
 
    background-color: #426fd9;
 
    color: #FFF;
 
}
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
 
    background-color: #446cd7;
 
    color: #FFF;
 
}
 
.yui-skin-sam .yui-dt-paginator {
 
    display: block;
 
    margin: 6px 0;
 
    white-space: nowrap;
 
}
 
.yui-skin-sam .yui-dt-paginator .yui-dt-first,
 
.yui-skin-sam .yui-dt-paginator .yui-dt-last,
 
.yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
 
.yui-skin-sam .yui-dt-paginator a.yui-dt-first,
 
.yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
 
.yui-skin-sam .yui-dt-paginator .yui-dt-previous,
 
.yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
 
.yui-skin-sam a.yui-dt-page {
 
    border: 1px solid #cbcbcb;
 
    padding: 2px 6px;
 
    text-decoration: none;
 
    background-color: #fff;
 
}
 
.yui-skin-sam .yui-dt-selected {
 
    border: 1px solid #fff;
 
    background-color: #fff;
 
}
 

	
 
#content #left {
 
    left: 0;
 
    width: 280px;
 
    position: absolute;
 
}
 

	
 
#content #right {
 
    margin: 0 60px 10px 290px;
 
}
 

	
 
#content div.box {
 
    clear: both;
 
    background: #fff;
 
    margin: 0 0 10px;
 
    padding: 0 0 10px;
 
    -webkit-border-radius: 4px 4px 4px 4px;
 
    -khtml-border-radius: 4px 4px 4px 4px;
 
    border-radius: 4px 4px 4px 4px;
 
    box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
}
 

	
 
#content div.box-left {
 
    width: 49%;
 
    clear: none;
 
    float: left;
 
    margin: 0 0 10px;
 
}
 

	
 
#content div.box-right {
 
    width: 49%;
 
    clear: none;
 
    float: right;
 
    margin: 0 0 10px;
 
}
 

	
 
#content div.box div.title {
 
    clear: both;
 
    overflow: hidden;
 
    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);
 
    background-image: -ms-linear-gradient(top, #003b76, #00376e);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
 
    background-image: -webkit-linear-gradient(top, #003b76, #00376e);
 
    background-image: -o-linear-gradient(top, #003b76, #00376e);
 
    background-image: linear-gradient(to bottom, #003b76, #00376e);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
 
    margin: 0 0 20px;
 
    padding: 0;
 
    border-radius: 4px 4px 0 0;
 
}
 

	
 
#content div.box div.title h5 {
 
    float: left;
 
    border: none;
 
    color: #fff;
 
    margin: 0;
 
    padding: 11px 0 11px 10px;
 
}
 

	
 
#content div.box div.title .link-white {
 
    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;
 
    margin: 0;
 
    padding: 0;
 
}
 

	
 
#content div.box div.title ul.links li a {
 
    border-left: 1px solid #316293;
 
    color: #FFFFFF;
 
    display: block;
 
    float: left;
 
    font-size: 13px;
 
    font-weight: 700;
 
    height: 1%;
 
    margin: 0;
 
    padding: 11px 22px 12px;
 
    text-decoration: none;
 
}
 

	
 
#content div.box h1, #content div.box h2, #content div.box h3, #content div.box h4, #content div.box h5, #content div.box h6,
 
@@ -3532,1342 +3534,1366 @@ div.gravatar img {
 
    background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
 
    background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
 
    background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
 
    background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
 
    background-image: linear-gradient(to bottom, #F4F4F4, #DADADA);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
 

	
 
    border-top: 1px solid #DDD;
 
    border-left: 1px solid #c6c6c6;
 
    border-right: 1px solid #DDD;
 
    border-bottom: 1px solid #c6c6c6;
 
    color: #515151;
 
    outline: none;
 
    margin: 0px 3px 3px 0px;
 
    -webkit-border-radius: 4px 4px 4px 4px !important;
 
    -khtml-border-radius: 4px 4px 4px 4px !important;
 
    border-radius: 4px 4px 4px 4px !important;
 
    cursor: pointer !important;
 
    padding: 3px 3px 3px 3px;
 
    background-position: 0 -15px;
 

	
 
}
 

	
 
.ui-btn.disabled {
 
    color: #999;
 
}
 

	
 
.ui-btn.xsmall {
 
    padding: 1px 2px 1px 1px;
 
}
 

	
 
.ui-btn.large {
 
    padding: 6px 12px;
 
}
 

	
 
.ui-btn.clone {
 
    padding: 5px 2px 6px 1px;
 
    margin: 0px 0px 3px -4px;
 
    -webkit-border-radius: 0px 4px 4px 0px !important;
 
    -khtml-border-radius: 0px 4px 4px 0px !important;
 
    border-radius: 0px 4px 4px 0px !important;
 
    width: 100px;
 
    text-align: center;
 
    display: inline-block;
 
    position: relative;
 
    top: -2px;
 
}
 
.ui-btn:focus {
 
    outline: none;
 
}
 
.ui-btn:hover {
 
    background-position: 0 -15px;
 
    text-decoration: none;
 
    color: #515151;
 
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
 
}
 

	
 
.ui-btn.disabled:hover {
 
    background-position: 0;
 
    color: #999;
 
    text-decoration: none;
 
    box-shadow: none !important;
 
}
 

	
 
.ui-btn.red {
 
    color: #fff;
 
    background-color: #c43c35;
 
    background-repeat: repeat-x;
 
    background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
 
    background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
 
    background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
 
    background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
 
    background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
 
    background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
 
    border-color: #c43c35 #c43c35 #882a25;
 
    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
 
}
 

	
 

	
 
.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));
 
    background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
 
    background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
 
    background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
 
    background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
 
    background-image: linear-gradient(to bottom, #5bc0de, #339bb9);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
 
    border-color: #339bb9 #339bb9 #22697d;
 
    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
 
}
 

	
 
.ui-btn.green {
 
    background-color: #57a957;
 
    background-repeat: repeat-x;
 
    background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
 
    background-image: -moz-linear-gradient(top, #62c462, #57a957);
 
    background-image: -ms-linear-gradient(top, #62c462, #57a957);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
 
    background-image: -webkit-linear-gradient(top, #62c462, #57a957);
 
    background-image: -o-linear-gradient(top, #62c462, #57a957);
 
    background-image: linear-gradient(to bottom, #62c462, #57a957);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
 
    border-color: #57a957 #57a957 #3d773d;
 
    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
 
}
 

	
 
.ui-btn.blue.hidden {
 
    display: none;
 
}
 

	
 
.ui-btn.active {
 
    font-weight: bold;
 
}
 

	
 
ins, div.options a:hover {
 
    text-decoration: none;
 
}
 

	
 
img,
 
#header #header-inner #quick li a:hover span.normal,
 
#content div.box div.form div.fields div.field div.textarea table td table td a,
 
#clone_url,
 
#clone_url_id
 
{
 
    border: none;
 
}
 

	
 
img.icon, .right .merge img {
 
    vertical-align: bottom;
 
}
 

	
 
#header ul#logged-user, #content div.box div.title ul.links,
 
#content div.box div.message div.dismiss,
 
#content div.box div.traffic div.legend ul {
 
    float: right;
 
    margin: 0;
 
    padding: 0;
 
}
 

	
 
#header #header-inner #home, #header #header-inner #logo,
 
#content div.box ul.left, #content div.box ol.left,
 
div#commit_history,
 
div#legend_data, div#legend_container, div#legend_choices {
 
    float: left;
 
}
 

	
 
#header #header-inner #quick li #quick_login,
 
#header #header-inner #quick li:hover ul ul,
 
#header #header-inner #quick li:hover ul ul ul,
 
#header #header-inner #quick li:hover ul ul ul ul,
 
#content #left #menu ul.closed, #content #left #menu li ul.collapsed, .yui-tt-shadow {
 
    display: none;
 
}
 

	
 
#header #header-inner #quick li:hover #quick_login,
 
#header #header-inner #quick li:hover ul, #header #header-inner #quick li li:hover ul, #header #header-inner #quick li li li:hover ul, #header #header-inner #quick li li li li:hover ul, #content #left #menu ul.opened, #content #left #menu li ul.expanded {
 
    display: block;
 
}
 

	
 
#content div.graph {
 
    padding: 0 10px 10px;
 
}
 

	
 
#content div.box div.title ul.links li a:hover,
 
#content div.box div.title ul.links li.ui-tabs-selected a {
 

	
 
    background: #6388ad; /* Old browsers */
 
    background: -moz-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* FF3.6+ */
 
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
 
    background: -webkit-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Chrome10+,Safari5.1+ */
 
    background: -o-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* Opera 11.10+ */
 
    background: -ms-linear-gradient(top, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* IE10+ */
 
    background: linear-gradient(to bottom, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.1) 100%); /* W3C */
 
    /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#88bfe8', endColorstr='#70b0e0',GradientType=0 ); /* IE6-9 */*/
 
}
 

	
 
#content div.box ol.lower-roman, #content div.box ol.upper-roman, #content div.box ol.lower-alpha, #content div.box ol.upper-alpha, #content div.box ol.decimal {
 
    margin: 10px 24px 10px 44px;
 
}
 

	
 
#content div.box div.form, #content div.box div.table, #content div.box div.traffic {
 
    position: relative;
 
    clear: both;
 
    margin: 0;
 
    padding: 0 20px 10px;
 
}
 

	
 
#content div.box div.form div.fields, #login div.form, #login div.form div.fields, #register div.form, #register div.form div.fields {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0;
 
}
 

	
 
#content div.box div.form div.fields div.field div.label span, #login div.form div.fields div.field div.label span, #register div.form div.fields div.field div.label span {
 
    height: 1%;
 
    display: block;
 
    color: #363636;
 
    margin: 0;
 
    padding: 2px 0 0;
 
}
 

	
 
#content div.box div.form div.fields div.field div.input input.error, #login div.form div.fields div.field div.input input.error, #register div.form div.fields div.field div.input input.error {
 
    background: #FBE3E4;
 
    border-top: 1px solid #e1b2b3;
 
    border-left: 1px solid #e1b2b3;
 
    border-right: 1px solid #FBC2C4;
 
    border-bottom: 1px solid #FBC2C4;
 
}
 

	
 
#content div.box div.form div.fields div.field div.input input.success, #login div.form div.fields div.field div.input input.success, #register div.form div.fields div.field div.input input.success {
 
    background: #E6EFC2;
 
    border-top: 1px solid #cebb98;
 
    border-left: 1px solid #cebb98;
 
    border-right: 1px solid #c6d880;
 
    border-bottom: 1px solid #c6d880;
 
}
 

	
 
#content div.box-left div.form div.fields div.field div.textarea, #content div.box-right div.form div.fields div.field div.textarea, #content div.box div.form div.fields div.field div.select select, #content div.box table th.selected input, #content div.box table td.selected input {
 
    margin: 0;
 
}
 

	
 
#content div.box-left div.form div.fields div.field div.select, #content div.box-left div.form div.fields div.field div.checkboxes, #content div.box-left div.form div.fields div.field div.radios, #content div.box-right div.form div.fields div.field div.select, #content div.box-right div.form div.fields div.field div.checkboxes, #content div.box-right div.form div.fields div.field div.radios {
 
    margin: 0 0 0 0px !important;
 
    padding: 0;
 
}
 

	
 
#content div.box div.form div.fields div.field div.select, #content div.box div.form div.fields div.field div.checkboxes, #content div.box div.form div.fields div.field div.radios {
 
    margin: 0 0 0 200px;
 
    padding: 0;
 
}
 

	
 
#content div.box div.form div.fields div.field div.select a:hover, #content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover, #content div.box div.action a:hover {
 
    color: #000;
 
    text-decoration: none;
 
}
 

	
 
#content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus, #content div.box div.action a.ui-selectmenu-focus {
 
    border: 1px solid #666;
 
}
 

	
 
#content div.box div.form div.fields div.field div.checkboxes div.checkbox, #content div.box div.form div.fields div.field div.radios div.radio {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 8px 0 2px;
 
}
 

	
 
#content div.box div.form div.fields div.field div.checkboxes div.checkbox input, #content div.box div.form div.fields div.field div.radios div.radio input {
 
    float: left;
 
    margin: 0;
 
}
 

	
 
#content div.box div.form div.fields div.field div.checkboxes div.checkbox label, #content div.box div.form div.fields div.field div.radios div.radio label {
 
    height: 1%;
 
    display: block;
 
    float: left;
 
    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 {
 
    font-size: 11px;
 
    font-weight: 700;
 
    margin: 0;
 
}
 

	
 
input.ui-button {
 
    background: #e5e3e3 url("../images/button.png") repeat-x;
 
    border-top: 1px solid #DDD;
 
    border-left: 1px solid #c6c6c6;
 
    border-right: 1px solid #DDD;
 
    border-bottom: 1px solid #c6c6c6;
 
    color: #515151 !important;
 
    outline: none;
 
    margin: 0;
 
    padding: 6px 12px;
 
    -webkit-border-radius: 4px 4px 4px 4px;
 
    -khtml-border-radius: 4px 4px 4px 4px;
 
    border-radius: 4px 4px 4px 4px;
 
    box-shadow: 0 1px 0 #ececec;
 
    cursor: pointer;
 
}
 

	
 
input.ui-button:hover {
 
    background: #b4b4b4 url("../images/button_selected.png") repeat-x;
 
    border-top: 1px solid #ccc;
 
    border-left: 1px solid #bebebe;
 
    border-right: 1px solid #b1b1b1;
 
    border-bottom: 1px solid #afafaf;
 
}
 

	
 
div.form div.fields div.field div.highlight, #content div.box div.form div.fields div.buttons div.highlight {
 
    display: inline;
 
}
 

	
 
#content div.box div.form div.fields div.buttons, div.form div.fields div.buttons {
 
    margin: 10px 0 0 200px;
 
    padding: 0;
 
}
 

	
 
#content div.box-left div.form div.fields div.buttons, #content div.box-right div.form div.fields div.buttons, div.box-left div.form div.fields div.buttons, div.box-right div.form div.fields div.buttons {
 
    margin: 10px 0 0;
 
}
 

	
 
#content div.box table td.user, #content div.box table td.address {
 
    width: 10%;
 
    text-align: center;
 
}
 

	
 
#content div.box div.action div.button, #login div.form div.fields div.field div.input div.link, #register div.form div.fields div.field div.input div.link {
 
    text-align: right;
 
    margin: 6px 0 0;
 
    padding: 0;
 
}
 

	
 
#content div.box div.action div.button input.ui-state-hover, #login div.form div.fields div.buttons input.ui-state-hover, #register div.form div.fields div.buttons input.ui-state-hover {
 
    background: #b4b4b4 url("../images/button_selected.png") repeat-x;
 
    border-top: 1px solid #ccc;
 
    border-left: 1px solid #bebebe;
 
    border-right: 1px solid #b1b1b1;
 
    border-bottom: 1px solid #afafaf;
 
    color: #515151;
 
    margin: 0;
 
    padding: 6px 12px;
 
}
 

	
 
#content div.box div.pagination div.results, #content div.box div.pagination-wh div.results {
 
    text-align: left;
 
    float: left;
 
    margin: 0;
 
    padding: 0;
 
}
 

	
 
#content div.box div.pagination div.results span, #content div.box div.pagination-wh div.results span {
 
    height: 1%;
 
    display: block;
 
    float: left;
 
    background: #ebebeb url("../images/pager.png") repeat-x;
 
    border-top: 1px solid #dedede;
 
    border-left: 1px solid #cfcfcf;
 
    border-right: 1px solid #c4c4c4;
 
    border-bottom: 1px solid #c4c4c4;
 
    color: #4A4A4A;
 
    font-weight: 700;
 
    margin: 0;
 
    padding: 6px 8px;
 
}
 

	
 
#content div.box div.pagination ul.pager li.disabled, #content div.box div.pagination-wh a.disabled {
 
    color: #B4B4B4;
 
    padding: 6px;
 
}
 

	
 
#login, #register {
 
    width: 520px;
 
    margin: 10% auto 0;
 
    padding: 0;
 
}
 

	
 
#login div.color, #register div.color {
 
    clear: both;
 
    overflow: hidden;
 
    background: #FFF;
 
    margin: 10px auto 0;
 
    padding: 3px 3px 3px 0;
 
}
 

	
 
#login div.color a, #register div.color a {
 
    width: 20px;
 
    height: 20px;
 
    display: block;
 
    float: left;
 
    margin: 0 0 0 3px;
 
    padding: 0;
 
}
 

	
 
#login div.title h5, #register div.title h5 {
 
    color: #fff;
 
    margin: 10px;
 
    padding: 0;
 
}
 

	
 
#login div.form div.fields div.field, #register div.form div.fields div.field {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0 0 10px;
 
}
 

	
 
#login div.form div.fields div.field span.error-message, #register div.form div.fields div.field span.error-message {
 
    height: 1%;
 
    display: block;
 
    color: red;
 
    margin: 8px 0 0;
 
    padding: 0;
 
    max-width: 320px;
 
}
 

	
 
#login div.form div.fields div.field div.label label, #register div.form div.fields div.field div.label label {
 
    color: #000;
 
    font-weight: 700;
 
}
 

	
 
#login div.form div.fields div.field div.input, #register div.form div.fields div.field div.input {
 
    float: left;
 
    margin: 0;
 
    padding: 0;
 
}
 

	
 
#login div.form div.fields div.field div.input input.large {
 
    width: 250px;
 
}
 

	
 
#login div.form div.fields div.field div.checkbox, #register div.form div.fields div.field div.checkbox {
 
    margin: 0 0 0 184px;
 
    padding: 0;
 
}
 

	
 
#login div.form div.fields div.field div.checkbox label, #register div.form div.fields div.field div.checkbox label {
 
    color: #565656;
 
    font-weight: 700;
 
}
 

	
 
#login div.form div.fields div.buttons input, #register div.form div.fields div.buttons input {
 
    color: #000;
 
    font-size: 1em;
 
    font-weight: 700;
 
    margin: 0;
 
}
 

	
 
#changeset_content .container .wrapper, #graph_content .container .wrapper {
 
    width: 600px;
 
}
 

	
 
#changeset_content .container .date, .ac .match {
 
    font-weight: 700;
 
    padding-top: 5px;
 
    padding-bottom: 5px;
 
}
 

	
 
div#legend_container table td, div#legend_choices table td {
 
    border: none !important;
 
    height: 20px !important;
 
    padding: 0 !important;
 
}
 

	
 
.q_filter_box {
 
    -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
 
    -webkit-border-radius: 4px;
 
    border-radius: 4px;
 
    border: 0 none;
 
    color: #AAAAAA;
 
    margin-bottom: -4px;
 
    margin-top: -4px;
 
    padding-left: 3px;
 
}
 

	
 
#node_filter {
 
    border: 0px solid #545454;
 
    color: #AAAAAA;
 
    padding-left: 3px;
 
}
 

	
 

	
 
.group_members_wrap {
 
    min-height: 85px;
 
    padding-left: 20px;
 
}
 

	
 
.group_members .group_member {
 
    height: 30px;
 
    padding: 0px 0px 0px 0px;
 
}
 

	
 
.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
 
}
 

	
 
.ips_wrap {
 
    padding: 0px 20px;
 
}
 

	
 
.ips_wrap .ip_entry {
 
    height: 30px;
 
    padding: 0px 0px 0px 10px;
 
}
 
.ips_wrap .ip_entry .ip {
 
    float: left
 
}
 
.ips_wrap .ip_entry .ip_action {
 
    float: left
 
}
 

	
 

	
 
/*README STYLE*/
 

	
 
div.readme {
 
    padding: 0px;
 
}
 

	
 
div.readme h2 {
 
    font-weight: normal;
 
}
 

	
 
div.readme .readme_box {
 
    background-color: #fafafa;
 
}
 

	
 
div.readme .readme_box {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0 20px 10px;
 
}
 

	
 
div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
 
    border-bottom: 0 !important;
 
    margin: 0 !important;
 
    padding: 0 !important;
 
    line-height: 1.5em !important;
 
}
 

	
 

	
 
div.readme .readme_box h1:first-child {
 
    padding-top: .25em !important;
 
}
 

	
 
div.readme .readme_box h2, div.readme .readme_box h3 {
 
    margin: 1em 0 !important;
 
}
 

	
 
div.readme .readme_box h2 {
 
    margin-top: 1.5em !important;
 
    border-top: 4px solid #e0e0e0 !important;
 
    padding-top: .5em !important;
 
}
 

	
 
div.readme .readme_box p {
 
    color: black !important;
 
    margin: 1em 0 !important;
 
    line-height: 1.5em !important;
 
}
 

	
 
div.readme .readme_box ul {
 
    list-style: disc !important;
 
    margin: 1em 0 1em 2em !important;
 
}
 

	
 
div.readme .readme_box ol {
 
    list-style: decimal;
 
    margin: 1em 0 1em 2em !important;
 
}
 

	
 
div.readme .readme_box pre, code {
 
    font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
 
}
 

	
 
div.readme .readme_box code {
 
    font-size: 12px !important;
 
    background-color: ghostWhite !important;
 
    color: #444 !important;
 
    padding: 0 .2em !important;
 
    border: 1px solid #dedede !important;
 
}
 

	
 
div.readme .readme_box pre code {
 
    padding: 0 !important;
 
    font-size: 12px !important;
 
    background-color: #eee !important;
 
    border: none !important;
 
}
 

	
 
div.readme .readme_box pre {
 
    margin: 1em 0;
 
    font-size: 12px;
 
    background-color: #eee;
 
    border: 1px solid #ddd;
 
    padding: 5px;
 
    color: #444;
 
    overflow: auto;
 
    -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
 
    -webkit-border-radius: 3px;
 
    border-radius: 3px;
 
}
 

	
 
div.readme .readme_box table {
 
    display: table;
 
    border-collapse: separate;
 
    border-spacing: 2px;
 
    border-color: gray;
 
    width: auto !important;
 
}
 

	
 

	
 
/** RST STYLE **/
 

	
 

	
 
div.rst-block {
 
    padding: 0px;
 
}
 

	
 
div.rst-block h2 {
 
    font-weight: normal;
 
}
 

	
 
div.rst-block {
 
    background-color: #fafafa;
 
}
 

	
 
div.rst-block {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0 20px 10px;
 
}
 

	
 
div.rst-block  h1, div.rst-block  h2, div.rst-block  h3, div.rst-block  h4, div.rst-block  h5, div.rst-block  h6 {
 
    border-bottom: 0 !important;
 
    margin: 0 !important;
 
    padding: 0 !important;
 
    line-height: 1.5em !important;
 
}
 

	
 

	
 
div.rst-block  h1:first-child {
 
    padding-top: .25em !important;
 
}
 

	
 
div.rst-block  h2, div.rst-block  h3 {
 
    margin: 1em 0 !important;
 
}
 

	
 
div.rst-block  h2 {
 
    margin-top: 1.5em !important;
 
    border-top: 4px solid #e0e0e0 !important;
 
    padding-top: .5em !important;
 
}
 

	
 
div.rst-block  p {
 
    color: black !important;
 
    margin: 1em 0 !important;
 
    line-height: 1.5em !important;
 
}
 

	
 
div.rst-block  ul {
 
    list-style: disc !important;
 
    margin: 1em 0 1em 2em !important;
 
}
 

	
 
div.rst-block  ol {
 
    list-style: decimal;
 
    margin: 1em 0 1em 2em !important;
 
}
 

	
 
div.rst-block  pre, code {
 
    font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
 
}
 

	
 
div.rst-block  code {
 
    font-size: 12px !important;
 
    background-color: ghostWhite !important;
 
    color: #444 !important;
 
    padding: 0 .2em !important;
 
    border: 1px solid #dedede !important;
 
}
 

	
 
div.rst-block  pre code {
 
    padding: 0 !important;
 
    font-size: 12px !important;
 
    background-color: #eee !important;
 
    border: none !important;
 
}
 

	
 
div.rst-block  pre {
 
    margin: 1em 0;
 
    font-size: 12px;
 
    background-color: #eee;
 
    border: 1px solid #ddd;
 
    padding: 5px;
 
    color: #444;
 
    overflow: auto;
 
    -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
 
    -webkit-border-radius: 3px;
 
    border-radius: 3px;
 
}
 

	
 

	
 
/** comment main **/
 
.comments {
 
    padding: 10px 20px;
 
}
 

	
 
.comments .comment {
 
    border: 1px solid #ddd;
 
    margin-top: 10px;
 
    -webkit-border-radius: 4px;
 
    border-radius: 4px;
 
}
 

	
 
.comments .comment .meta {
 
    background: #f8f8f8;
 
    padding: 4px;
 
    border-bottom: 1px solid #ddd;
 
    height: 18px;
 
}
 

	
 
.comments .comment .meta img {
 
    vertical-align: middle;
 
}
 

	
 
.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 {
 
    background-color: #FAFAFA;
 
}
 
.comment .text div.rst-block p {
 
    margin: 0.5em 0px !important;
 
}
 

	
 
.comments .comments-number {
 
    padding: 0px 0px 10px 0px;
 
    font-weight: bold;
 
    color: #666;
 
    font-size: 16px;
 
}
 

	
 
/** comment form **/
 

	
 
.status-block {
 
    min-height: 80px;
 
    clear: both
 
}
 

	
 
.comment-form .clearfix {
 
    background: #EEE;
 
    -webkit-border-radius: 4px;
 
    border-radius: 4px;
 
    padding: 10px;
 
}
 

	
 
div.comment-form {
 
    margin-top: 20px;
 
}
 

	
 
.comment-form strong {
 
    display: block;
 
    margin-bottom: 15px;
 
}
 

	
 
.comment-form textarea {
 
    width: 100%;
 
    height: 100px;
 
    font-family: 'Monaco', 'Courier', 'Courier New', monospace;
 
}
 

	
 
form.comment-form {
 
    margin-top: 10px;
 
    margin-left: 10px;
 
}
 

	
 
.comment-inline-form .comment-block-ta,
 
.comment-form .comment-block-ta {
 
    border: 1px solid #ccc;
 
    border-radius: 3px;
 
    box-sizing: border-box;
 
}
 

	
 
.comment-form-submit {
 
    margin-top: 5px;
 
    margin-left: 525px;
 
}
 

	
 
.file-comments {
 
    display: none;
 
}
 

	
 
.comment-form .comment {
 
    margin-left: 10px;
 
}
 

	
 
.comment-form .comment-help {
 
    padding: 0px 0px 5px 0px;
 
    padding: 5px 5px 5px 5px;
 
    color: #666;
 
}
 
.comment-form .comment-help .preview-btn,
 
.comment-form .comment-help .edit-btn {
 
    float: right;
 
    margin: -6px 0px 0px 0px;
 
}
 

	
 
.comment-form .preview-box.unloaded,
 
.comment-inline-form .preview-box.unloaded {
 
    height: 50px;
 
    text-align: center;
 
    padding: 20px;
 
    background-color: #fafafa;
 
}
 

	
 
.comment-form .comment-button {
 
    padding-top: 5px;
 
}
 

	
 
.add-another-button {
 
    margin-left: 10px;
 
    margin-top: 10px;
 
    margin-bottom: 10px;
 
}
 

	
 
.comment .buttons {
 
    float: right;
 
    padding: 2px 2px 0px 0px;
 
    margin: -1px 0px 0px 0px;
 
}
 

	
 

	
 
.show-inline-comments {
 
    position: relative;
 
    top: 1px
 
}
 

	
 
/** comment inline form **/
 
.comment-inline-form {
 
    margin: 4px;
 
}
 
.comment-inline-form .overlay {
 
    display: none;
 
}
 
.comment-inline-form .overlay.submitting {
 
    display: block;
 
    background: none repeat scroll 0 0 white;
 
    font-size: 16px;
 
    opacity: 0.5;
 
    position: absolute;
 
    text-align: center;
 
    vertical-align: top;
 

	
 
}
 
.comment-inline-form .overlay.submitting .overlay-text {
 
    width: 100%;
 
    margin-top: 5%;
 
}
 

	
 
.comment-inline-form .clearfix {
 
.comment-inline-form .clearfix,
 
.comment-form .clearfix {
 
    background: #EEE;
 
    -webkit-border-radius: 4px;
 
    border-radius: 4px;
 
    padding: 5px;
 
    margin: 0px;
 
}
 

	
 
div.comment-inline-form {
 
    padding: 4px 0px 6px 0px;
 
}
 

	
 
.comment-inline-form strong {
 
    display: block;
 
    margin-bottom: 15px;
 
}
 

	
 
.comment-inline-form textarea {
 
    width: 100%;
 
    height: 100px;
 
    font-family: 'Monaco', 'Courier', 'Courier New', monospace;
 
}
 

	
 
form.comment-inline-form {
 
    margin-top: 10px;
 
    margin-left: 10px;
 
}
 

	
 
.comment-inline-form-submit {
 
    margin-top: 5px;
 
    margin-left: 525px;
 
}
 

	
 
.file-comments {
 
    display: none;
 
}
 

	
 
.comment-inline-form .comment {
 
    margin-left: 10px;
 
}
 

	
 
.comment-inline-form .comment-help {
 
    padding: 0px 0px 2px 0px;
 
    color: #666666;
 
    font-size: 10px;
 
    padding: 5px 5px 5px 5px;
 
    color: #666;
 
}
 

	
 
.comment-inline-form .comment-help .preview-btn,
 
.comment-inline-form .comment-help .edit-btn {
 
    float: right;
 
    margin: -6px 0px 0px 0px;
 
}
 

	
 
.comment-inline-form .comment-button {
 
    padding-top: 5px;
 
}
 

	
 
/** comment inline **/
 
.inline-comments {
 
    padding: 10px 20px;
 
}
 

	
 
.inline-comments div.rst-block {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0 20px 0px;
 
}
 
.inline-comments .comment {
 
    border: 1px solid #ddd;
 
    -webkit-border-radius: 4px;
 
    border-radius: 4px;
 
    margin: 3px 3px 5px 5px;
 
    background-color: #FAFAFA;
 
}
 
.inline-comments .add-comment {
 
    padding: 2px 4px 8px 5px;
 
}
 

	
 
.inline-comments .comment-wrapp {
 
    padding: 1px;
 
}
 
.inline-comments .comment .meta {
 
    background: #f8f8f8;
 
    padding: 4px;
 
    border-bottom: 1px solid #ddd;
 
    height: 20px;
 
}
 

	
 
.inline-comments .comment .meta img {
 
    vertical-align: middle;
 
}
 

	
 
.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 {
 
    background-color: #FAFAFA;
 
}
 

	
 
.inline-comments .comments-number {
 
    padding: 0px 0px 10px 0px;
 
    font-weight: bold;
 
    color: #666;
 
    font-size: 16px;
 
}
 
.inline-comments-button .add-comment {
 
    margin: 2px 0px 8px 5px !important
 
}
 

	
 
.notification-paginator {
 
    padding: 0px 0px 4px 16px;
 
}
 

	
 
#context-pages .pull-request span,
 
.menu_link_notifications {
 
    padding: 4px 4px !important;
 
    text-align: center;
 
    color: #888 !important;
 
    background-color: #DEDEDE !important;
 
    border-radius: 4px !important;
 
    -webkit-border-radius: 4px !important;
 
}
 

	
 
#context-pages .forks span,
 
.menu_link_notifications {
 
    padding: 4px 4px !important;
 
    text-align: center;
 
    color: #888 !important;
 
    background-color: #DEDEDE !important;
 
    border-radius: 4px !important;
 
    -webkit-border-radius: 4px !important;
 
}
 

	
 

	
 
.notification-header {
 
    padding-top: 6px;
 
}
 
.notification-header .desc {
 
    font-size: 16px;
 
    height: 24px;
 
    float: left
 
}
 
.notification-list .container.unread {
 
    background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
 
}
 
.notification-header .gravatar {
 
    background: none repeat scroll 0 0 transparent;
 
    padding: 0px 0px 0px 8px;
 
}
 
.notification-list .container .notification-header .desc {
 
    font-weight: bold;
 
    font-size: 17px;
 
}
 
.notification-table {
 
    border: 1px solid #ccc;
 
    -webkit-border-radius: 6px 6px 6px 6px;
 
    border-radius: 6px 6px 6px 6px;
 
    clear: both;
 
    margin: 0px 20px 0px 20px;
 
}
 
.notification-header .delete-notifications {
 
    float: right;
 
    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;
 
    padding: 5px 0px 5px 38px;
 
}
 

	
 
.notification-body {
 
    clear: both;
 
    margin: 34px 2px 2px 8px
 
}
 

	
 
/****
 
PULL REQUESTS
 
*****/
 
.pullrequests_section_head {
 
    padding: 10px 10px 10px 0px;
 
    font-size: 16px;
 
    font-weight: bold;
 
}
 

	
 
h3.closed,
 
#pullrequests_container li.closed a
 
 {
 
    color: #555;
 
    background: #eee;
 
}
 

	
 
div.pr-title {
 
    font-size: 1.6em;
 
}
 

	
 
div.pr {
 
    border-bottom: 1px solid #DDD;
 
    margin: 0px 20px;
 
    padding: 10px 4px;
 
}
 
div.pr-closed {
 
    background-color: rgba(245,245,245,0.5);
 
}
 

	
 
span.pr-closed-tag {
 
    margin-bottom: 1px;
 
    margin-right: 1px;
 
    padding: 1px 3px;
 
    font-size: 10px;
 
    padding: 1px 3px 1px 3px;
 
    font-size: 10px;
 
    color: #336699;
 
    white-space: nowrap;
 
    -webkit-border-radius: 4px;
 
    border-radius: 4px;
 
    border: 1px solid #d9e8f8;
 
    line-height: 1.5em;
 
}
 

	
 
/****
 
  PERMS
 
*****/
 
#perms .perms_section_head {
 
    padding: 10px 10px 10px 0px;
 
    font-size: 16px;
 
    font-weight: bold;
 
}
 

	
 
#perms .perm_tag {
 
    padding: 1px 3px 1px 3px;
 
    font-size: 10px;
 
    font-weight: bold;
 
    text-transform: uppercase;
 
    white-space: nowrap;
 
    -webkit-border-radius: 3px;
 
    border-radius: 3px;
 
}
 

	
 
#perms .perm_tag.admin {
 
    background-color: #B94A48;
 
    color: #ffffff;
 
}
 

	
 
#perms .perm_tag.write {
 
    background-color: #DB7525;
 
    color: #ffffff;
 
}
 

	
 
#perms .perm_tag.read {
 
    background-color: #468847;
 
    color: #ffffff;
 
}
 

	
 
#perms .perm_tag.none {
 
    background-color: #bfbfbf;
 
    color: #ffffff;
 
}
 

	
 
.perm-gravatar {
 
    vertical-align: middle;
 
    padding: 2px;
 
}
 
.perm-gravatar-ac {
 
    vertical-align: middle;
 
    padding: 2px;
 
    width: 14px;
 
    height: 14px;
 
}
 

	
 
/*****************************************************************************
 
                                  DIFFS CSS
 
******************************************************************************/
 
.diff-collapse {
 
    text-align: center;
 
    margin-bottom: -15px;
 
}
 
.diff-collapse-button {
 
    cursor: pointer;
 
    color: #666;
 
    font-size: 16px;
 
}
 
.diff-container {
 

	
 
}
 

	
 
.diff-container.hidden {
 
    display: none;
 
    overflow: hidden;
 
}
 

	
 

	
 
div.diffblock {
 
    overflow: auto;
 
    padding: 0px;
 
    border: 1px solid #ccc;
 
    background: #f8f8f8;
 
    font-size: 100%;
 
    line-height: 100%;
 
    /* new */
 
    line-height: 125%;
 
    -webkit-border-radius: 6px 6px 0px 0px;
 
    border-radius: 6px 6px 0px 0px;
 
}
 
div.diffblock.margined {
 
    margin: 0px 20px 0px 20px;
 
}
 
div.diffblock .code-header {
 
    border-bottom: 1px solid #CCCCCC;
 
    background: #EEEEEE;
 
    padding: 10px 0 10px 0;
 
    height: 14px;
 
}
 

	
 
div.diffblock .code-header.banner {
 
    border-bottom: 1px solid #CCCCCC;
 
    background: #EEEEEE;
 
    height: 14px;
 
    margin: 0px 95px 0px 95px;
 
    padding: 3px 3px 11px 3px;
 
}
 

	
 
div.diffblock .code-header-title {
 
    padding: 0px 0px 10px 5px !important;
 
    margin: 0 !important;
 
}
 
div.diffblock .code-header .hash {
 
    float: left;
 
    padding: 2px 0 0 2px;
 
}
 
div.diffblock .code-header .date {
 
    float: left;
 
    text-transform: uppercase;
 
    padding: 2px 0px 0px 2px;
 
}
 
div.diffblock .code-header div {
 
    margin-left: 4px;
 
    font-weight: bold;
 
    font-size: 14px;
 
}
 

	
 
div.diffblock .parents {
 
    float: left;
 
    height: 26px;
 
    width: 100px;
 
    font-size: 10px;
 
    font-weight: 400;
 
    vertical-align: middle;
 
    padding: 0px 2px 2px 2px;
 
    background-color: #eeeeee;
 
    border-bottom: 1px solid #CCCCCC;
 
}
 

	
 
div.diffblock .children {
 
    float: right;
 
    height: 26px;
 
    width: 100px;
 
    font-size: 10px;
 
    font-weight: 400;
 
    vertical-align: middle;
 
    text-align: right;
 
    padding: 0px 2px 2px 2px;
 
    background-color: #eeeeee;
 
    border-bottom: 1px solid #CCCCCC;
 
}
 

	
 
div.diffblock .code-body {
 
    background: #FFFFFF;
 
}
 
div.diffblock pre.raw {
 
    background: #FFFFFF;
 
    color: #000000;
 
}
 
table.code-difftable {
 
    border-collapse: collapse;
 
    width: 99%;
 
    border-radius: 0px !important;
 
}
 
table.code-difftable td {
 
    padding: 0 !important;
 
    background: none !important;
 
    border: 0 !important;
 
    vertical-align: baseline !important
 
}
 
table.code-difftable .context {
 
    background: none repeat scroll 0 0 #DDE7EF;
 
}
 
table.code-difftable .add {
 
    background: none repeat scroll 0 0 #DDFFDD;
 
}
 
table.code-difftable .add ins {
 
    background: none repeat scroll 0 0 #AAFFAA;
 
    text-decoration: none;
 
}
 
table.code-difftable .del {
 
    background: none repeat scroll 0 0 #FFDDDD;
 
}
 
table.code-difftable .del del {
 
    background: none repeat scroll 0 0 #FFAAAA;
 
    text-decoration: none;
 
}
 

	
 
/** LINE NUMBERS **/
 
table.code-difftable .lineno {
 

	
 
    padding-left: 2px;
 
    padding-right: 2px;
 
    text-align: right;
 
    width: 32px;
 
    -moz-user-select: none;
 
    -webkit-user-select: none;
 
    border-right: 1px solid #CCC !important;
 
    border-left: 0px solid #CCC !important;
 
    border-top: 0px solid #CCC !important;
 
    border-bottom: none !important;
 
    vertical-align: middle !important;
 

	
 
}
 
table.code-difftable .lineno.new {
 
}
 
table.code-difftable .lineno.old {
 
}
 
table.code-difftable .lineno a {
 
    color: #747474 !important;
 
    font: 11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
 
    letter-spacing: -1px;
 
    text-align: right;
 
    padding-right: 2px;
 
    cursor: pointer;
 
    display: block;
 
    width: 32px;
 
}
 

	
 
table.code-difftable .lineno-inline {
 
    background: none repeat scroll 0 0 #FFF !important;
 
    padding-left: 2px;
 
    padding-right: 2px;
 
    text-align: right;
 
    width: 30px;
 
    -moz-user-select: none;
 
    -webkit-user-select: none;
 
}
 

	
 
/** CODE **/
 
table.code-difftable .code {
 
    display: block;
 
    width: 100%;
 
}
 
table.code-difftable .code td {
 
    margin: 0;
 
    padding: 0;
 
}
 
table.code-difftable .code pre {
 
    margin: 0;
 
    padding: 0;
 
    height: 17px;
 
    line-height: 17px;
 
}
 

	
 

	
 
.diffblock.margined.comm .line .code:hover {
 
    background-color: #FFFFCC !important;
 
    cursor: pointer !important;
 
    background-image: url("../images/icons/comment_add.png") !important;
 
    background-repeat: no-repeat !important;
 
    background-position: right !important;
 
    background-position: 0% 50% !important;
 
}
 
.diffblock.margined.comm .line .code.no-comment:hover {
 
    background-image: none !important;
 
    cursor: auto !important;
 
    background-color: inherit !important;
 
}
 

	
 
div.comment:target>.comment-wrapp {
 
    border: solid 2px #ee0 !important;
 
}
 

	
 
.lineno:target a {
 
    border: solid 2px #ee0 !important;
 
    margin: -2px;
 
}
rhodecode/public/js/rhodecode.js
Show inline comments
 
@@ -101,1559 +101,1585 @@ var ColorGenerator = function(){
 
	this.CURRENT_RATIO = 0.22717784590367374 // this can be random
 
	this.HSV_1 = 0.75;//saturation
 
	this.HSV_2 = 0.95;
 
	this.color;
 
	this.cacheColorMap = {};
 
};
 

	
 
ColorGenerator.prototype = {
 
    getColor:function(key){
 
    	if(this.cacheColorMap[key] !== undefined){
 
    		return this.cacheColorMap[key];
 
    	}
 
    	else{
 
    		this.cacheColorMap[key] = this.generateColor();
 
    		return this.cacheColorMap[key];
 
    	}
 
    },
 
    _hsvToRgb:function(h,s,v){
 
        if (s == 0.0)
 
            return [v, v, v];
 
        i = parseInt(h * 6.0)
 
        f = (h * 6.0) - i
 
        p = v * (1.0 - s)
 
        q = v * (1.0 - s * f)
 
        t = v * (1.0 - s * (1.0 - f))
 
        i = i % 6
 
        if (i == 0) 
 
            return [v, t, p]
 
        if (i == 1) 
 
            return [q, v, p]
 
        if (i == 2) 
 
            return [p, v, t]
 
        if (i == 3)
 
            return [p, q, v]
 
        if (i == 4) 
 
            return [t, p, v]
 
        if (i == 5)
 
            return [v, p, q]            	
 
    },
 
    generateColor:function(){
 
        this.CURRENT_RATIO = this.CURRENT_RATIO+this.GOLDEN_RATIO;
 
        this.CURRENT_RATIO = this.CURRENT_RATIO %= 1;
 
        HSV_tuple = [this.CURRENT_RATIO, this.HSV_1, this.HSV_2]
 
        RGB_tuple = this._hsvToRgb(HSV_tuple[0],HSV_tuple[1],HSV_tuple[2]);
 
        function toRgb(v){
 
        	return ""+parseInt(v*256)
 
        }
 
        return [toRgb(RGB_tuple[0]),toRgb(RGB_tuple[1]),toRgb(RGB_tuple[2])];
 
        
 
    }
 
}
 

	
 
/**
 
 * PyRoutesJS
 
 * 
 
 * Usage pyroutes.url('mark_error_fixed',{"error_id":error_id}) // /mark_error_fixed/<error_id>
 
 */
 
var pyroutes = (function() {
 
	// access global map defined in special file pyroutes
 
    var matchlist = PROUTES_MAP;
 
    var sprintf = (function() {
 
        function get_type(variable) {
 
            return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
 
        }
 
        function str_repeat(input, multiplier) {
 
            for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
 
            return output.join('');
 
        }
 

	
 
        var str_format = function() {
 
            if (!str_format.cache.hasOwnProperty(arguments[0])) {
 
                str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
 
            }
 
            return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
 
        };
 

	
 
        str_format.format = function(parse_tree, argv) {
 
            var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
 
            for (i = 0; i < tree_length; i++) {
 
                node_type = get_type(parse_tree[i]);
 
                if (node_type === 'string') {
 
                    output.push(parse_tree[i]);
 
                }
 
                else if (node_type === 'array') {
 
                    match = parse_tree[i]; // convenience purposes only
 
                    if (match[2]) { // keyword argument
 
                        arg = argv[cursor];
 
                        for (k = 0; k < match[2].length; k++) {
 
                            if (!arg.hasOwnProperty(match[2][k])) {
 
                                throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
 
                            }
 
                            arg = arg[match[2][k]];
 
                        }
 
                    }
 
                    else if (match[1]) { // positional argument (explicit)
 
                        arg = argv[match[1]];
 
                    }
 
                    else { // positional argument (implicit)
 
                        arg = argv[cursor++];
 
                    }
 

	
 
                    if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
 
                        throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
 
                    }
 
                    switch (match[8]) {
 
                        case 'b': arg = arg.toString(2); break;
 
                        case 'c': arg = String.fromCharCode(arg); break;
 
                        case 'd': arg = parseInt(arg, 10); break;
 
                        case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
 
                        case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
 
                        case 'o': arg = arg.toString(8); break;
 
                        case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
 
                        case 'u': arg = Math.abs(arg); break;
 
                        case 'x': arg = arg.toString(16); break;
 
                        case 'X': arg = arg.toString(16).toUpperCase(); break;
 
                    }
 
                    arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
 
                    pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
 
                    pad_length = match[6] - String(arg).length;
 
                    pad = match[6] ? str_repeat(pad_character, pad_length) : '';
 
                    output.push(match[5] ? arg + pad : pad + arg);
 
                }
 
            }
 
            return output.join('');
 
        };
 

	
 
        str_format.cache = {};
 

	
 
        str_format.parse = function(fmt) {
 
            var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
 
            while (_fmt) {
 
                if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
 
                    parse_tree.push(match[0]);
 
                }
 
                else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
 
                    parse_tree.push('%');
 
                }
 
                else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
 
                    if (match[2]) {
 
                        arg_names |= 1;
 
                        var field_list = [], replacement_field = match[2], field_match = [];
 
                        if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
 
                            field_list.push(field_match[1]);
 
                            while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
 
                                if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
 
                                    field_list.push(field_match[1]);
 
                                }
 
                                else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
 
                                    field_list.push(field_match[1]);
 
                                }
 
                                else {
 
                                    throw('[sprintf] huh?');
 
                                }
 
                            }
 
                        }
 
                        else {
 
                            throw('[sprintf] huh?');
 
                        }
 
                        match[2] = field_list;
 
                    }
 
                    else {
 
                        arg_names |= 2;
 
                    }
 
                    if (arg_names === 3) {
 
                        throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
 
                    }
 
                    parse_tree.push(match);
 
                }
 
                else {
 
                    throw('[sprintf] huh?');
 
                }
 
                _fmt = _fmt.substring(match[0].length);
 
            }
 
            return parse_tree;
 
        };
 

	
 
        return str_format;
 
    })();
 

	
 
    var vsprintf = function(fmt, argv) {
 
        argv.unshift(fmt);
 
        return sprintf.apply(null, argv);
 
    };
 
    return {
 
        'url': function(route_name, params) {
 
            var result = route_name;
 
            if (typeof(params) != 'object'){
 
            	params = {};
 
            }
 
            if (matchlist.hasOwnProperty(route_name)) {
 
                var route = matchlist[route_name];
 
                // param substitution
 
                for(var i=0; i < route[1].length; i++) {
 

	
 
                   if (!params.hasOwnProperty(route[1][i]))
 
                        throw new Error(route[1][i] + ' missing in "' + route_name + '" route generation');
 
                }
 
                result = sprintf(route[0], params);
 
                
 
                var ret = [];
 
                //extra params => GET
 
                for(param in params){
 
                	if (route[1].indexOf(param) == -1){
 
                		ret.push(encodeURIComponent(param) + "=" + encodeURIComponent(params[param]));	
 
                	}
 
                }
 
                var _parts = ret.join("&");
 
                if(_parts){
 
                	result = result +'?'+ _parts
 
                }
 
            }
 

	
 
            return result;
 
        },
 
    	'register': function(route_name, route_tmpl, req_params) {
 
    		if (typeof(req_params) != 'object') {
 
    			req_params = [];
 
    		}
 
    		//fix escape
 
    		route_tmpl = unescape(route_tmpl);
 
    		keys = [];
 
    		for (o in req_params){
 
    			keys.push(req_params[o])
 
    		}
 
    		matchlist[route_name] = [
 
    		    route_tmpl,
 
    		    keys
 
    		]
 
    	},
 
    	'_routes': function(){
 
    		return matchlist;
 
    	}
 
    }
 
})();
 

	
 

	
 

	
 
/**
 
 * GLOBAL YUI Shortcuts
 
 */
 
var YUC = YAHOO.util.Connect;
 
var YUD = YAHOO.util.Dom;
 
var YUE = YAHOO.util.Event;
 
var YUQ = YAHOO.util.Selector.query;
 

	
 
// defines if push state is enabled for this browser ?
 
var push_state_enabled = Boolean(
 
		window.history && window.history.pushState && window.history.replaceState
 
		&& !(   /* disable for versions of iOS before version 4.3 (8F190) */
 
				(/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent)
 
				/* disable for the mercury iOS browser, or at least older versions of the webkit engine */
 
				|| (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent)
 
		)
 
);
 

	
 
var _run_callbacks = function(callbacks){
 
	if (callbacks !== undefined){
 
		var _l = callbacks.length;
 
	    for (var i=0;i<_l;i++){
 
	    	var func = callbacks[i];
 
	    	if(typeof(func)=='function'){
 
	            try{
 
	          	    func();
 
	            }catch (err){};            		
 
	    	}
 
	    }
 
	}		
 
}
 

	
 
/**
 
 * Partial Ajax Implementation
 
 * 
 
 * @param url: defines url to make partial request
 
 * @param container: defines id of container to input partial result
 
 * @param s_call: success callback function that takes o as arg
 
 *  o.tId
 
 *  o.status
 
 *  o.statusText
 
 *  o.getResponseHeader[ ]
 
 *  o.getAllResponseHeaders
 
 *  o.responseText
 
 *  o.responseXML
 
 *  o.argument
 
 * @param f_call: failure callback
 
 * @param args arguments 
 
 */
 
function ypjax(url,container,s_call,f_call,args){
 
	var method='GET';
 
	if(args===undefined){
 
		args=null;
 
	}
 
	
 
	// Set special header for partial ajax == HTTP_X_PARTIAL_XHR
 
	YUC.initHeader('X-PARTIAL-XHR',true);
 
	
 
	// wrapper of passed callback
 
	var s_wrapper = (function(o){
 
		return function(o){
 
			YUD.get(container).innerHTML=o.responseText;
 
			YUD.setStyle(container,'opacity','1.0');
 
    		//execute the given original callback
 
    		if (s_call !== undefined){
 
    			s_call(o);
 
    		}
 
		}
 
	})()	
 
	YUD.setStyle(container,'opacity','0.3');
 
	YUC.asyncRequest(method,url,{
 
		success:s_wrapper,
 
		failure:function(o){
 
			console.log(o);
 
			YUD.get(container).innerHTML='<span class="error_red">ERROR: {0}</span>'.format(o.status);
 
			YUD.setStyle(container,'opacity','1.0');
 
		},
 
		cache:false
 
	},args);
 
	
 
};
 

	
 
var ajaxGET = function(url,success) {
 
	// Set special header for ajax == HTTP_X_PARTIAL_XHR
 
	YUC.initHeader('X-PARTIAL-XHR',true);
 

	
 
    var sUrl = url;
 
    var callback = {
 
        success: success,
 
        failure: function (o) {
 
            if (o.status != 0) {
 
                alert("error: " + o.statusText);
 
            };
 
        },
 
    };
 

	
 
    var request = YAHOO.util.Connect.asyncRequest('GET', sUrl, callback);
 
    return request;
 
};
 

	
 

	
 

	
 
var ajaxPOST = function(url,postData,success) {
 
	// Set special header for ajax == HTTP_X_PARTIAL_XHR
 
	YUC.initHeader('X-PARTIAL-XHR',true);
 
	
 
	var toQueryString = function(o) {
 
	    if(typeof o !== 'object') {
 
	        return false;
 
	    }
 
	    var _p, _qs = [];
 
	    for(_p in o) {
 
	        _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
 
	    }
 
	    return _qs.join('&');
 
	};
 
	
 
    var sUrl = url;
 
    var callback = {
 
        success: success,
 
        failure: function (o) {
 
            alert("error");
 
        },
 
    };
 
    var postData = toQueryString(postData);
 
    var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
 
    return request;
 
};
 

	
 

	
 
/**
 
 * tooltip activate
 
 */
 
var tooltip_activate = function(){
 
	yt = YAHOO.yuitip.main;
 
	YUE.onDOMReady(yt.init);
 
};
 

	
 
/**
 
 * show more
 
 */
 
var show_more_event = function(){
 
    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');
 
    });
 
};
 

	
 
/**
 
 * show changeset tooltip
 
 */
 
var show_changeset_tooltip = function(){
 
	YUE.on(YUD.getElementsByClassName('lazy-cs'), 'mouseover', function(e){
 
		var target = e.currentTarget;
 
		var rid = YUD.getAttribute(target,'raw_id');
 
		var repo_name = YUD.getAttribute(target,'repo_name');
 
		var ttid = 'tt-'+rid;
 
		var success = function(o){
 
			var json = JSON.parse(o.responseText);
 
			YUD.addClass(target,'tooltip')
 
			YUD.setAttribute(target, 'title',json['message']);
 
			YAHOO.yuitip.main.show_yuitip(e, target);
 
		}
 
		if(rid && !YUD.hasClass(target, 'tooltip')){
 
			YUD.setAttribute(target,'id',ttid);
 
			YUD.setAttribute(target, 'title',_TM['loading...']);
 
			YAHOO.yuitip.main.set_listeners(target);
 
			YAHOO.yuitip.main.show_yuitip(e, target);
 
			var url = pyroutes.url('changeset_info', {"repo_name":repo_name, "revision": rid});
 
			ajaxGET(url, success)
 
		}
 
	});
 
};
 

	
 
var onSuccessFollow = function(target){
 
    var f = YUD.get(target);
 
    var f_cnt = YUD.get('current_followers_count');
 

	
 
    if(YUD.hasClass(f, 'follow')){
 
        f.setAttribute('class','following');
 
        f.setAttribute('title',_TM['Stop following this repository']);
 

	
 
        if(f_cnt){
 
            var cnt = Number(f_cnt.innerHTML)+1;
 
            f_cnt.innerHTML = cnt;
 
        }
 
    }
 
    else{
 
        f.setAttribute('class','follow');
 
        f.setAttribute('title',_TM['Start following this repository']);
 
        if(f_cnt){
 
            var cnt = Number(f_cnt.innerHTML)-1;
 
            f_cnt.innerHTML = cnt;
 
        }
 
    }
 
}
 

	
 
var toggleFollowingUser = function(target,fallows_user_id,token,user_id){
 
    args = 'follows_user_id='+fallows_user_id;
 
    args+= '&amp;auth_token='+token;
 
    if(user_id != undefined){
 
        args+="&amp;user_id="+user_id;
 
    }
 
    YUC.asyncRequest('POST',TOGGLE_FOLLOW_URL,{
 
        success:function(o){
 
        	onSuccessFollow(target);
 
        }
 
    },args);
 
    return false;
 
}
 

	
 
var toggleFollowingRepo = function(target,fallows_repo_id,token,user_id){
 

	
 
    args = 'follows_repo_id='+fallows_repo_id;
 
    args+= '&amp;auth_token='+token;
 
    if(user_id != undefined){
 
        args+="&amp;user_id="+user_id;
 
    }
 
    YUC.asyncRequest('POST',TOGGLE_FOLLOW_URL,{
 
        success:function(o){
 
        	onSuccessFollow(target);
 
        }
 
    },args);
 
    return false;
 
}
 

	
 
var showRepoSize = function(target, repo_name, token){
 
    var args= 'auth_token='+token;
 
    
 
    if(!YUD.hasClass(target, 'loaded')){
 
        YUD.get(target).innerHTML = _TM['Loading ...'];
 
        var url = pyroutes.url('repo_size', {"repo_name":repo_name});
 
        YUC.asyncRequest('POST',url,{
 
            success:function(o){
 
            	YUD.get(target).innerHTML = JSON.parse(o.responseText);
 
            	YUD.addClass(target, 'loaded');
 
            }
 
        },args);    	
 
    }
 
    return false;	
 
}
 

	
 
/**
 
 * TOOLTIP IMPL.
 
 */
 
YAHOO.namespace('yuitip');
 
YAHOO.yuitip.main = {
 

	
 
	$:			YAHOO.util.Dom.get,
 

	
 
	bgColor:	'#000',
 
	speed:		0.3,
 
	opacity:	0.9,
 
	offset:		[15,15],
 
	useAnim:	false,
 
	maxWidth:	600,
 
	add_links:	false,
 
	yuitips:    [],
 

	
 
	set_listeners: function(tt){
 
		YUE.on(tt, 'mouseover', yt.show_yuitip,  tt);
 
		YUE.on(tt, 'mousemove', yt.move_yuitip,  tt);
 
		YUE.on(tt, 'mouseout',  yt.close_yuitip, tt);		
 
	},
 

	
 
	init: function(){
 
		yt.tipBox = yt.$('tip-box');
 
		if(!yt.tipBox){
 
			yt.tipBox = document.createElement('div');
 
			document.body.appendChild(yt.tipBox);
 
			yt.tipBox.id = 'tip-box';
 
		}
 

	
 
		YUD.setStyle(yt.tipBox, 'display', 'none');
 
		YUD.setStyle(yt.tipBox, 'position', 'absolute');
 
		if(yt.maxWidth !== null){
 
			YUD.setStyle(yt.tipBox, 'max-width', yt.maxWidth+'px');
 
		}
 

	
 
		var yuitips = YUD.getElementsByClassName('tooltip');
 

	
 
		if(yt.add_links === true){
 
			var links = document.getElementsByTagName('a');
 
			var linkLen = links.length;
 
			for(i=0;i<linkLen;i++){
 
				yuitips.push(links[i]);
 
			}
 
		}
 

	
 
		var yuiLen = yuitips.length;
 

	
 
		for(i=0;i<yuiLen;i++){
 
			yt.set_listeners(yuitips[i]);
 
		}
 
	},
 

	
 
	show_yuitip: function(e, el){
 
		YUE.stopEvent(e);
 
		if(el.tagName.toLowerCase() === 'img'){
 
			yt.tipText = el.alt ? el.alt : '';
 
		} else {
 
			yt.tipText = el.title ? el.title : '';
 
		}
 

	
 
		if(yt.tipText !== ''){
 
			// save org title
 
			YUD.setAttribute(el, 'tt_title', yt.tipText);
 
			// reset title to not show org tooltips
 
			YUD.setAttribute(el, 'title', '');
 

	
 
			yt.tipBox.innerHTML = yt.tipText;
 
			YUD.setStyle(yt.tipBox, 'display', 'block');
 
			if(yt.useAnim === true){
 
				YUD.setStyle(yt.tipBox, 'opacity', '0');
 
				var newAnim = new YAHOO.util.Anim(yt.tipBox,
 
					{
 
						opacity: { to: yt.opacity }
 
					}, yt.speed, YAHOO.util.Easing.easeOut
 
				);
 
				newAnim.animate();
 
			}
 
		}
 
	},
 

	
 
	move_yuitip: function(e, el){
 
		YUE.stopEvent(e);
 
		var movePos = YUE.getXY(e);
 
		YUD.setStyle(yt.tipBox, 'top', (movePos[1] + yt.offset[1]) + 'px');
 
		YUD.setStyle(yt.tipBox, 'left', (movePos[0] + yt.offset[0]) + 'px');
 
	},
 

	
 
	close_yuitip: function(e, el){
 
		YUE.stopEvent(e);
 
	
 
		if(yt.useAnim === true){
 
			var newAnim = new YAHOO.util.Anim(yt.tipBox,
 
				{
 
					opacity: { to: 0 }
 
				}, yt.speed, YAHOO.util.Easing.easeOut
 
			);
 
			newAnim.animate();
 
		} else {
 
			YUD.setStyle(yt.tipBox, 'display', 'none');
 
		}
 
		YUD.setAttribute(el,'title', YUD.getAttribute(el, 'tt_title'));
 
	}
 
}
 

	
 
/**
 
 * Quick filter widget
 
 * 
 
 * @param target: filter input target
 
 * @param nodes: list of nodes in html we want to filter.
 
 * @param display_element function that takes current node from nodes and
 
 *    does hide or show based on the node
 
 * 
 
 */
 
var q_filter = function(target,nodes,display_element){
 
	
 
	var nodes = nodes;
 
	var q_filter_field = YUD.get(target);
 
	var F = YAHOO.namespace(target);
 

	
 
	YUE.on(q_filter_field,'keyup',function(e){
 
	    clearTimeout(F.filterTimeout); 
 
	    F.filterTimeout = setTimeout(F.updateFilter,600); 
 
	});
 

	
 
	F.filterTimeout = null;
 

	
 
	var show_node = function(node){
 
		YUD.setStyle(node,'display','')
 
	}
 
	var hide_node = function(node){
 
		YUD.setStyle(node,'display','none');
 
	}
 
	
 
	F.updateFilter  = function() { 
 
	   // Reset timeout 
 
	   F.filterTimeout = null;
 
	   
 
	   var obsolete = [];
 
	   
 
	   var req = q_filter_field.value.toLowerCase();
 
	   
 
	   var l = nodes.length;
 
	   var i;
 
	   var showing = 0;
 
	   
 
       for (i=0;i<l;i++ ){
 
    	   var n = nodes[i];
 
    	   var target_element = display_element(n)
 
    	   if(req && n.innerHTML.toLowerCase().indexOf(req) == -1){
 
    		   hide_node(target_element);
 
    	   }
 
    	   else{
 
    		   show_node(target_element);
 
    		   showing+=1;
 
    	   }
 
       }	  	   
 

	
 
	   // if repo_count is set update the number
 
	   var cnt = YUD.get('repo_count');
 
	   if(cnt){
 
		   YUD.get('repo_count').innerHTML = showing;
 
	   }       
 
       
 
	}	
 
};
 

	
 
var tableTr = function(cls, body){
 
	var _el = document.createElement('div');
 
	var cont = new YAHOO.util.Element(body);
 
	var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
 
	var id = 'comment-tr-{0}'.format(comment_id);
 
	var _html = ('<table><tbody><tr id="{0}" class="{1}">'+
 
	              '<td class="lineno-inline new-inline"></td>'+
 
    			  '<td class="lineno-inline old-inline"></td>'+ 
 
                  '<td>{2}</td>'+
 
                 '</tr></tbody></table>').format(id, cls, body);
 
	_el.innerHTML = _html;
 
	return _el.children[0].children[0].children[0];
 
};
 

	
 
/** comments **/
 
var removeInlineForm = function(form) {
 
	form.parentNode.removeChild(form);
 
};
 

	
 
var createInlineForm = function(parent_tr, f_path, line) {
 
	var tmpl = YUD.get('comment-inline-form-template').innerHTML;
 
	tmpl = tmpl.format(f_path, line);
 
	var form = tableTr('comment-form-inline',tmpl)
 

	
 
	// create event for hide button
 
	form = new YAHOO.util.Element(form);
 
	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')){
 
			YUD.setStyle(newtr.nextElementSibling,'display','');
 
		}
 
		removeInlineForm(newtr);
 
		YUD.removeClass(parent_tr, 'form-open');
 
		YUD.removeClass(parent_tr, 'hl-comment');
 
		
 
	});
 
	
 
	return form
 
};
 

	
 
/**
 
 * Inject inline comment for on given TR this tr should be always an .line
 
 * tr containing the line. Code will detect comment, and always put the comment
 
 * block at the very bottom
 
 */
 
var injectInlineForm = function(tr){
 
	  if(!YUD.hasClass(tr, 'line')){
 
		  return
 
	  }
 
	  var submit_url = AJAX_COMMENT_URL;
 
	  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');
 
	  YUD.addClass(tr,'hl-comment');
 
	  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);
 
	  
 
	  var parent = tr;
 
	  while (1){
 
		  var n = parent.nextElementSibling;
 
		  // next element are comments !
 
		  if(YUD.hasClass(n,'inline-comments')){
 
			  parent = n;
 
		  }
 
		  else{
 
			  break;
 
		  }
 
	  }	  
 
	  YUD.insertAfter(form,parent);
 
	  var f = YUD.get(form);
 
	  var overlay = YUD.getElementsByClassName('overlay',null,f)[0];
 
	  var _form = YUD.getElementsByClassName('inline-form',null,f)[0];
 
	  
 
	  YUE.on(YUD.get(_form), 'submit',function(e){
 
		  YUE.preventDefault(e);
 
		  
 
		  //ajax submit
 
		  var text = YUD.get('text_'+lineno).value;
 
		  var postData = {
 
	            'text':text,
 
	            'f_path':f_path,
 
	            'line':lineno
 
		  };
 
		  
 
		  if(lineno === undefined){
 
			  alert('missing line !');
 
			  return
 
		  }
 
		  if(f_path === undefined){
 
			  alert('missing file path !');
 
			  return
 
		  }
 
		  
 
		  if(text == ""){
 
			  return
 
		  }
 
		  
 
		  var success = function(o){
 
			  YUD.removeClass(tr, 'form-open');
 
			  removeInlineForm(f);			  
 
			  var json_data = JSON.parse(o.responseText);
 
	          renderInlineComment(json_data);
 
		  };
 

	
 
		  if (YUD.hasClass(overlay,'overlay')){
 
			  var w = _form.offsetWidth;
 
			  var h = _form.offsetHeight;
 
			  YUD.setStyle(overlay,'width',w+'px');
 
			  YUD.setStyle(overlay,'height',h+'px');
 
		  }		  
 
		  YUD.addClass(overlay, 'submitting');		  
 
		  
 
		  ajaxPOST(submit_url, postData, success);
 
	  });
 
	  
 
	  YUE.on('preview-btn_'+lineno, 'click', function(e){
 
	       var _text = YUD.get('text_'+lineno).value;
 
	       if(!_text){
 
	           return
 
	       }
 
	       var post_data = {'text': _text};
 
	       YUD.addClass('preview-box_'+lineno, 'unloaded');
 
	       YUD.get('preview-box_'+lineno).innerHTML = _TM['Loading ...'];	       
 
	       YUD.setStyle('edit-container_'+lineno, 'display', 'none');
 
	       YUD.setStyle('preview-container_'+lineno, 'display', '');
 

	
 
	       var url = pyroutes.url('changeset_comment_preview', {'repo_name': REPO_NAME});
 
	       ajaxPOST(url,post_data,function(o){
 
	           YUD.get('preview-box_'+lineno).innerHTML = o.responseText;
 
	           YUD.removeClass('preview-box_'+lineno, 'unloaded');
 
	       })
 
	   })
 
	   YUE.on('edit-btn_'+lineno, 'click', function(e){
 
	       YUD.setStyle('edit-container_'+lineno, 'display', '');
 
	       YUD.setStyle('preview-container_'+lineno, 'display', 'none');
 
	   })	  
 
	  
 
	  
 
	  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){
 
	var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__',comment_id);
 
    var postData = {'_method':'delete'};
 
    var success = function(o){
 
        var n = YUD.get('comment-tr-'+comment_id);
 
        var root = prevElementSibling(prevElementSibling(n));
 
        n.parentNode.removeChild(n);
 

	
 
        // scann nodes, and attach add button to last one
 
        // scann nodes, and attach add button to last one only for TR
 
        // which are the inline comments
 
        if(root && root.tagName == 'TR'){
 
        placeAddButton(root);
 
    }
 
    }
 
    ajaxPOST(url,postData,success);
 
}
 

	
 
var createInlineAddButton = function(tr){
 

	
 
	var label = TRANSLATION_MAP['Add another comment'];
 
	
 
	var html_el = document.createElement('div');
 
	YUD.addClass(html_el, 'add-comment');
 
	html_el.innerHTML = '<span class="ui-btn">{0}</span>'.format(label);
 
	
 
	var add = new YAHOO.util.Element(html_el);
 
	add.on('click', function(e) {
 
		injectInlineForm(tr);
 
	});
 
	return add;
 
};
 

	
 
var getLineNo = function(tr) {
 
	var line;
 
	var o = tr.children[0].id.split('_');
 
	var n = tr.children[1].id.split('_');
 

	
 
	if (n.length >= 2) {
 
		line = n[n.length-1];
 
	} else if (o.length >= 2) {
 
		line = o[o.length-1];
 
	}
 

	
 
	return line
 
};
 

	
 
var placeAddButton = function(target_tr){
 
	if(!target_tr){
 
		return
 
	}
 
	var last_node = target_tr;
 
    //scann	
 
	  while (1){
 
		  var n = last_node.nextElementSibling;
 
		  // next element are comments !
 
		  if(YUD.hasClass(n,'inline-comments')){
 
			  last_node = n;
 
			  //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);
 
			  }
 
		  }
 
		  else{
 
			  break;
 
		  }
 
	  }
 
	  
 
    var add = createInlineAddButton(target_tr);
 
    // get the comment div
 
    var comment_block = YUD.getElementsByClassName('comment',null,last_node)[0];
 
    // attach add button
 
    YUD.insertAfter(add,comment_block);	
 
}
 

	
 
/**
 
 * Places the inline comment into the changeset block in proper line position
 
 */
 
var placeInline = function(target_container,lineno,html){
 
	  var lineid = "{0}_{1}".format(target_container,lineno);
 
	  var target_line = YUD.get(lineid);
 
	  var comment = new YAHOO.util.Element(tableTr('inline-comments',html))
 
	  
 
	  // check if there are comments already !
 
	  var parent = target_line.parentNode;
 
	  var root_parent = parent;
 
	  while (1){
 
		  var n = parent.nextElementSibling;
 
		  // next element are comments !
 
		  if(YUD.hasClass(n,'inline-comments')){
 
			  parent = n;
 
		  }
 
		  else{
 
			  break;
 
		  }
 
	  }
 
	  // put in the comment at the bottom
 
	  YUD.insertAfter(comment,parent);
 
	  
 
	  // scann nodes, and attach add button to last one
 
      placeAddButton(root_parent);
 

	
 
	  return target_line;
 
}
 

	
 
/**
 
 * make a single inline comment and place it inside
 
 */
 
var renderInlineComment = function(json_data){
 
    try{
 
	  var html =  json_data['rendered_text'];
 
	  var lineno = json_data['line_no'];
 
	  var target_id = json_data['target_id'];
 
	  placeInline(target_id, lineno, html);
 

	
 
    }catch(e){
 
  	  console.log(e);
 
    }
 
}
 

	
 
/**
 
 * Iterates over all the inlines, and places them inside proper blocks of data
 
 */
 
var renderInlineComments = function(file_comments){
 
	for (f in file_comments){
 
        // holding all comments for a FILE
 
		var box = file_comments[f];
 

	
 
		var target_id = YUD.getAttribute(box,'target_id');
 
		// actually comments with line numbers
 
        var comments = box.children;
 
        for(var i=0; i<comments.length; i++){
 
        	var data = {
 
        		'rendered_text': comments[i].outerHTML,
 
        		'line_no': YUD.getAttribute(comments[i],'line'),
 
        		'target_id': target_id
 
        	}
 
        	renderInlineComment(data);
 
        }
 
    }	
 
}
 

	
 
var fileBrowserListeners = function(current_url, node_list_url, url_base){
 
	var current_url_branch = +"?branch=__BRANCH__";
 

	
 
	YUE.on('stay_at_branch','click',function(e){
 
	    if(e.target.checked){
 
	        var uri = current_url_branch;
 
	        uri = uri.replace('__BRANCH__',e.target.value);
 
	        window.location = uri;
 
	    }
 
	    else{
 
	        window.location = current_url;
 
	    }
 
	})            
 

	
 
	var n_filter = YUD.get('node_filter');
 
	var F = YAHOO.namespace('node_filter');
 
	
 
	F.filterTimeout = null;
 
	var nodes = null;
 

	
 
	F.initFilter = function(){
 
	  YUD.setStyle('node_filter_box_loading','display','');
 
	  YUD.setStyle('search_activate_id','display','none');
 
	  YUD.setStyle('add_node_id','display','none');
 
	  YUC.initHeader('X-PARTIAL-XHR',true);
 
	  YUC.asyncRequest('GET', node_list_url, {
 
	      success:function(o){
 
	        nodes = JSON.parse(o.responseText).nodes;
 
	        YUD.setStyle('node_filter_box_loading','display','none');
 
	        YUD.setStyle('node_filter_box','display','');
 
	        n_filter.focus();
 
			if(YUD.hasClass(n_filter,'init')){
 
				n_filter.value = '';
 
				YUD.removeClass(n_filter,'init');
 
			}   
 
	      },
 
	      failure:function(o){
 
	          console.log('failed to load');
 
	      }
 
	  },null);            
 
	}
 

	
 
	F.updateFilter  = function(e) {
 
	    
 
	    return function(){
 
	        // Reset timeout 
 
	        F.filterTimeout = null;
 
	        var query = e.target.value.toLowerCase();
 
	        var match = [];
 
	        var matches = 0;
 
	        var matches_max = 20;
 
	        if (query != ""){
 
	            for(var i=0;i<nodes.length;i++){
 
	            	
 
	                var pos = nodes[i].name.toLowerCase().indexOf(query)
 
	                if(query && pos != -1){
 
	                    
 
	                    matches++
 
	                    //show only certain amount to not kill browser 
 
	                    if (matches > matches_max){
 
	                        break;
 
	                    }
 
	                    
 
	                    var n = nodes[i].name;
 
	                    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)
 
	                    var new_url = url_base.replace('__FPATH__',n);
 
	                    match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,new_url,n_hl));
 
	                }
 
	                if(match.length >= matches_max){
 
	                    match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['Search truncated']));
 
	                }
 
	            }                       
 
	        }
 
	        if(query != ""){
 
	            YUD.setStyle('tbody','display','none');
 
	            YUD.setStyle('tbody_filtered','display','');
 
	            
 
	            if (match.length==0){
 
	              match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
 
	            }                           
 
	            
 
	            YUD.get('tbody_filtered').innerHTML = match.join("");   
 
	        }
 
	        else{
 
	            YUD.setStyle('tbody','display','');
 
	            YUD.setStyle('tbody_filtered','display','none');
 
	        }
 
	        
 
	    }
 
	};
 

	
 
	YUE.on(YUD.get('filter_activate'),'click',function(){
 
	    F.initFilter();
 
	})
 
	YUE.on(n_filter,'click',function(){
 
		if(YUD.hasClass(n_filter,'init')){
 
			n_filter.value = '';
 
			YUD.removeClass(n_filter,'init');
 
		}
 
	 });
 
	YUE.on(n_filter,'keyup',function(e){
 
	    clearTimeout(F.filterTimeout); 
 
	    F.filterTimeout = setTimeout(F.updateFilter(e),600);
 
	});
 
};
 

	
 

	
 
var initCodeMirror = function(textAreadId,resetUrl){  
 
    var myCodeMirror = CodeMirror.fromTextArea(YUD.get(textAreadId),{
 
           mode:  "null",
 
           lineNumbers:true
 
         });
 
    YUE.on('reset','click',function(e){
 
        window.location=resetUrl
 
    });
 
    
 
    YUE.on('file_enable','click',function(){
 
        YUD.setStyle('editor_container','display','');
 
        YUD.setStyle('upload_file_container','display','none');
 
        YUD.setStyle('filename_container','display','');
 
    });
 
    
 
    YUE.on('upload_file_enable','click',function(){
 
        YUD.setStyle('editor_container','display','none');
 
        YUD.setStyle('upload_file_container','display','');
 
        YUD.setStyle('filename_container','display','none');
 
    });	
 
};
 

	
 

	
 

	
 
var getIdentNode = function(n){
 
	//iterate thru nodes untill matched interesting node !
 
	
 
	if (typeof n == 'undefined'){
 
		return -1
 
	}
 
	
 
	if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
 
			return n
 
		}
 
	else{
 
		return getIdentNode(n.parentNode);
 
	}
 
};
 

	
 
var  getSelectionLink = function(e) {
 

	
 
	//get selection from start/to nodes    	
 
	if (typeof window.getSelection != "undefined") {
 
		s = window.getSelection();
 
	
 
	   	from = getIdentNode(s.anchorNode);
 
	   	till = getIdentNode(s.focusNode);
 
	   	
 
	    f_int = parseInt(from.id.replace('L',''));
 
	    t_int = parseInt(till.id.replace('L',''));
 
	    
 
	    if (f_int > t_int){
 
	    	//highlight from bottom 
 
	    	offset = -35;
 
	    	ranges = [t_int,f_int];
 
	    	
 
	    }
 
	    else{
 
	    	//highligth from top 
 
	    	offset = 35;
 
	    	ranges = [f_int,t_int];
 
	    }
 
	    // if we select more than 2 lines
 
	    if (ranges[0] != ranges[1]){
 
	        if(YUD.get('linktt') == null){
 
	            hl_div = document.createElement('div');
 
	            hl_div.id = 'linktt';
 
	        }
 
	        hl_div.innerHTML = '';
 

	
 
	        anchor = '#L'+ranges[0]+'-'+ranges[1];
 
	        var link = document.createElement('a');
 
	        link.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
 
	        link.innerHTML = _TM['Selection link'];
 
	        hl_div.appendChild(link);
 
	        YUD.get('body').appendChild(hl_div);
 
	        
 
	        xy = YUD.getXY(till.id);
 

	
 
	        YUD.addClass('linktt', 'hl-tip-box');
 
	        YUD.setStyle('linktt','top',xy[1]+offset+'px');
 
	        YUD.setStyle('linktt','left',xy[0]+'px');
 
	        YUD.setStyle('linktt','visibility','visible');
 

	
 
	    }
 
	    else{
 
	    	YUD.setStyle('linktt','visibility','hidden');
 
	    }
 
	}
 
};
 

	
 
var deleteNotification = function(url, notification_id,callbacks){
 
    var callback = { 
 
		success:function(o){
 
		    var obj = YUD.get(String("notification_"+notification_id));
 
		    if(obj.parentNode !== undefined){
 
				obj.parentNode.removeChild(obj);
 
			}
 
			_run_callbacks(callbacks);
 
		},
 
	    failure:function(o){
 
	        alert("error");
 
	    },
 
	};
 
    var postData = '_method=delete';
 
    var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
 
    var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, 
 
    											  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 (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 userGroups
 
    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);
 
            g = matchGroups(sQuery);
 
            return u.concat(g);
 
        };
 

	
 
    // DataScheme for members
 
    var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
 
    memberDS.responseSchema = {
 
        fields: ["id", "fname", "lname", "nname", "grname", "grmembers", "gravatar_lnk"]
 
    };
 

	
 
    // DataScheme for owner
 
    var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
 
    ownerDS.responseSchema = {
 
        fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
 
    };
 

	
 
    // Instantiate AutoComplete for perms
 
    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) {
 
            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
 
    var custom_formatter = function (oResultData, sQuery, sResultMatch) {
 
            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)
 
            }
 
            // group
 
            if (oResultData.grname != undefined) {
 
                var grname = oResultData.grname;
 
                var grmembers = oResultData.grmembers;
 
                var grnameMatchIndex = grname.toLowerCase().indexOf(query);
 
                var grprefix = "{0}: ".format(_TM['Group']);
 
                var grsuffix = " (" + grmembers + "  )";
 
                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.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 '';
 
            }
 
        };
 
    membersAC.formatResult = custom_formatter;
 
    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
 
            //fill the autocomplete with value
 
            if (oData.nname != undefined) {
 
                //users
 
                myAC.getInputEl().value = oData.nname;
 
                YUD.get('perm_new_member_type_'+nextId).value = 'user';
 
            } else {
 
                //groups
 
                myAC.getInputEl().value = oData.grname;
 
                YUD.get('perm_new_member_type_'+nextId).value = 'users_group';
 
            }
 
        };
 

	
 
    membersAC.itemSelectEvent.subscribe(myHandler);
 
    if(ownerAC.itemSelectEvent){
 
    	ownerAC.itemSelectEvent.subscribe(myHandler);
 
    }
 

	
 
    return {
 
        memberDS: memberDS,
 
        ownerDS: ownerDS,
 
        membersAC: membersAC,
 
        ownerAC: ownerAC,
 
    };
 
}
 

	
 

	
 
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 addReviewMember = function(id,fname,lname,nname,gravatar_link){
 
	var members  = YUD.get('review_members');
 
	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="removeReviewMember({2})"></span>'+
 
    '</div>'+
 
    '</li>'	;
 
    var displayname = "{0} {1} ({2})".format(fname,lname,nname);
 
	var element = tmpl.format(gravatar_link,displayname,id);
 
	// check if we don't have this ID already in
 
	var ids = [];
 
	var _els = YUQ('#review_members li');
 
	for (el in _els){
 
		ids.push(_els[el].id)
 
	}
 
	if(ids.indexOf('reviewer_'+id) == -1){
 
		//only add if it's not there
 
		members.innerHTML += element;
 
	}
 
	    
 
}
 

	
 
var removeReviewMember = function(reviewer_id, repo_name, pull_request_id){
 
	var el = YUD.get('reviewer_{0}'.format(reviewer_id));
 
	if (el.parentNode !== undefined){
rhodecode/templates/base/root.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<!DOCTYPE html>
 
<html xmlns="http://www.w3.org/1999/xhtml">
 
    <head>
 
        <title>${self.title()}</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" />
 

	
 
        ## CSS ###
 
        <%def name="css()">
 
            <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css', ver=c.rhodecode_version)}" media="screen"/>
 
            <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css', ver=c.rhodecode_version)}"/>
 
            <link rel="stylesheet" type="text/css" href="${h.url('/css/contextbar.css', ver=c.rhodecode_version)}"/>
 
            ## EXTRA FOR CSS
 
            ${self.css_extra()}
 
        </%def>
 
        <%def name="css_extra()">
 
        </%def>
 

	
 
        ${self.css()}
 

	
 
        %if c.ga_code:
 
        <!-- Analytics -->
 
        <script type="text/javascript">
 
            var _gaq = _gaq || [];
 
            _gaq.push(['_setAccount', '${c.ga_code}']);
 
            _gaq.push(['_trackPageview']);
 

	
 
            (function() {
 
                var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 
                ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 
                var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 
                })();
 
        </script>
 
        %endif
 

	
 
        ## 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')}",
 
                'Loading ...':"${_('Loading ...')}",
 
                'Search truncated': "${_('Search truncated')}",
 
                'No matching files': "${_('No matching files')}",
 
                'Open new pull request': "${_('Open new pull request')}",
 
                'Open new pull request for selected changesets':  "${_('Open new pull request for selected changesets')}",
 
                'Show selected changesets __S -> __E': "${_('Show selected changesets __S -> __E')}",
 
                'Show selected changeset __S': "${_('Show selected changeset __S')}",
 
                'Selection link': "${_('Selection link')}",
 
                'Collapse diff': "${_('Collapse diff')}",
 
                'Expand diff': "${_('Expand diff')}"
 
            };
 
            var _TM = TRANSLATION_MAP;
 

	
 
            var TOGGLE_FOLLOW_URL  = "${h.url('toggle_following')}";
 

	
 
            var REPO_NAME = "";
 
            %if hasattr(c, 'repo_name'):
 
                var REPO_NAME = "${c.repo_name}";
 
            %endif
 
            </script>
 
            <script type="text/javascript" src="${h.url('/js/yui.2.9.js', ver=c.rhodecode_version)}"></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', ver=c.rhodecode_version)}"></script>
 
            <script type="text/javascript" src="${h.url('/js/native.history.js', ver=c.rhodecode_version)}"></script>
 
            <script type="text/javascript" src="${h.url('/js/pyroutes_map.js', ver=c.rhodecode_version)}"></script>
 
            <script type="text/javascript" src="${h.url('/js/rhodecode.js', ver=c.rhodecode_version)}"></script>
 
           ## EXTRA FOR JS
 
           ${self.js_extra()}
 
            <script type="text/javascript">
 
            (function(window,undefined){
 
                // 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);
 

	
 
            YUE.onDOMReady(function(){
 
              tooltip_activate();
 
              show_more_event();
 
              show_changeset_tooltip();
 
              // routes registration
 
              pyroutes.register('toggle_following', "${h.url('toggle_following')}");
 
              pyroutes.register('changeset_info', "${h.url('changeset_info', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']);
 
              pyroutes.register('repo_size', "${h.url('repo_size', repo_name='%(repo_name)s')}", ['repo_name']);
 
              pyroutes.register('changeset_comment_preview', "${h.url('changeset_comment_preview', repo_name='%(repo_name)s')}", ['repo_name']);
 
           })
 
            </script>
 
        </%def>
 
        <%def name="js_extra()"></%def>
 
        ${self.js()}
 
        <%def name="head_extra()"></%def>
 
        ${self.head_extra()}
 
    </head>
 
    <body id="body">
 
     ## IE hacks
 
      <!--[if IE 7]>
 
      <script>YUD.addClass(document.body,'ie7')</script>
 
      <![endif]-->
 
      <!--[if IE 8]>
 
      <script>YUD.addClass(document.body,'ie8')</script>
 
      <![endif]-->
 
      <!--[if IE 9]>
 
      <script>YUD.addClass(document.body,'ie9')</script>
 
      <![endif]-->
 

	
 
      ${next.body()}
 
    </body>
 
</html>
rhodecode/templates/changeset/changeset_file_comment.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
## usage:
 
## <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
 
## ${comment.comment_block(co)}
 
##
 
<%def name="comment_block(co)">
 
  <div class="comment" id="comment-${co.comment_id}" line="${co.line_no}">
 
    <div class="comment-wrapp">
 
      <div class="meta">
 
        <div style="float:left"> <img src="${h.gravatar_url(co.author.email, 20)}" /> </div>
 
          <div class="user">
 
              ${co.author.username}
 
          </div>
 
          <div class="date">
 
              ${h.age(co.modified_at)} <a class="permalink" href="#comment-${co.comment_id}">&para;</a>
 
              ${h.age(co.modified_at)}
 
          </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
 

	
 
       <div style="float:left;padding:3px 0px 0px 5px">
 
       <div style="float:left;padding:4px 0px 0px 5px">
 
        <span class="">
 
         %if co.pull_request:
 
            <a href="${h.url('pullrequest_show',repo_name=co.pull_request.other_repo.repo_name,pull_request_id=co.pull_request.pull_request_id)}">
 
            %if co.status_change:
 
              ${_('Status change on pull request #%s') % co.pull_request.pull_request_id}
 
            %else:
 
              ${_('Comment on pull request #%s') % co.pull_request.pull_request_id}
 
            %endif
 
            </a>
 
         %endif
 
        </span>
 
       </div>
 

	
 
      <a class="permalink" href="#comment-${co.comment_id}">&para;</a>
 
      %if h.HasPermissionAny('hg.admin', 'repository.admin')() or co.author.user_id == c.rhodecode_user.user_id:
 
        <div class="buttons">
 
          <span onClick="deleteComment(${co.comment_id})" class="delete-comment ui-btn">${_('Delete')}</span>
 
        </div>
 
          <div onClick="deleteComment(${co.comment_id})" class="buttons delete-comment ui-btn small">${_('Delete')}</div>
 
      %endif
 
      </div>
 
      <div class="text">
 
          ${h.rst_w_mentions(co.text)|n}
 
      </div>
 
    </div>
 
  </div>
 
</%def>
 

	
 

	
 
<%def name="comment_inline_form()">
 
<div id='comment-inline-form-template' style="display:none">
 
  <div class="comment-inline-form ac">
 
  %if c.rhodecode_user.username != 'default':
 
    <div class="overlay"><div class="overlay-text">${_('Submitting...')}</div></div>
 
      ${h.form('#', class_='inline-form')}
 
      <div class="clearfix">
 
      <div id="edit-container_{1}" class="clearfix">
 
          <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 id="preview-btn_{1}" class="preview-btn ui-btn small">${_('preview')}</div>
 
          </div>
 
            <div class="mentions-container" id="mentions_container_{1}"></div>
 
            <textarea id="text_{1}" name="text" class="yui-ac-input"></textarea>
 
            <textarea id="text_{1}" name="text" class="comment-block-ta yui-ac-input"></textarea>
 
      </div>
 
      <div id="preview-container_{1}" class="clearfix" style="display:none">
 
         <div class="comment-help">
 
              ${_('Comment Preview')}
 
            <div id="edit-btn_{1}" class="edit-btn ui-btn small">${_('edit')}</div>
 
          </div>
 
          <div id="preview-box_{1}" class="preview-box"></div>
 
      </div>
 
      <div class="comment-button">
 
      <input type="hidden" name="f_path" value="{0}">
 
      <input type="hidden" name="line" value="{1}">
 
      ${h.submit('save', _('Comment'), class_='ui-btn save-inline-form')}
 
      ${h.reset('hide-inline-form', _('Cancel'), class_='ui-btn hide-inline-form')}
 
      </div>
 
      ${h.end_form()}
 
  %else:
 
      ${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>
 
          </div>
 
      </div>
 
      <div class="comment-button">
 
      ${h.reset('hide-inline-form', _('Hide'), class_='ui-btn hide-inline-form')}
 
      </div>
 
      ${h.end_form()}
 
  %endif
 
  </div>
 
</div>
 
</%def>
 

	
 

	
 
## 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))}">
 
            %for co in comments:
 
                ${comment_block(co)}
 
            %endfor
 
            </div>
 
        %endfor
 
    %endfor
 

	
 
</%def>
 

	
 
## generate inline comments and the main ones
 
<%def name="generate_comments(include_pr=False)">
 
<div class="comments">
 
    <div id="inline-comments-container">
 
    ## generate inlines for this changeset
 
     ${inlines()}
 
    </div>
 

	
 
    %for co in c.comments:
 
        <div id="comment-tr-${co.comment_id}">
 
          ## only render comments that are not from pull request, or from
 
          ## pull request and a status change
 
          %if not co.pull_request or (co.pull_request and co.status_change) or include_pr:
 
          ${comment_block(co)}
 
          %endif
 
        </div>
 
    %endfor
 
</div>
 
</%def>
 

	
 
## MAIN COMMENT FORM
 
<%def name="comments(post_url, cur_status, close_btn=False, change_status=True)">
 

	
 
<div class="comments">
 
    %if c.rhodecode_user.username != 'default':
 
    <div class="comment-form ac">
 
        ${h.form(post_url)}
 
        <div class="clearfix">
 
        <div id="edit-container" class="clearfix">
 
            <div class="comment-help">
 
                ${(_('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}
 
              %if change_status:
 
                | <a id="show_changeset_link" onClick="change_status_show();"> ${_('Change status')}</a>
 
                  <input id="show_changeset_status_box" type="checkbox" name="change_changeset_status" style="display: none;" />
 
              %endif
 
              <div id="preview-btn" class="preview-btn ui-btn small">${_('preview')}</div>
 
            </div>
 
            %if change_status:
 
            <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" class="status_change_radio" name="changeset_status" id="${status}" value="${status}">
 
                        <label for="${status}">${lbl}</label>
 
                    </div>
 
                %endfor
 
            </div>
 
            %endif
 
            <div class="mentions-container" id="mentions_container"></div>
 
             ${h.textarea('text')}
 
             ${h.textarea('text', class_="comment-block-ta")}
 
        </div>
 

	
 
        <div id="preview-container" class="clearfix" style="display:none">
 
           <div class="comment-help">
 
                ${_('Comment Preview')}
 
              <div id="edit-btn" class="edit-btn ui-btn small">${_('edit')}</div>
 
            </div>
 
            <div id="preview-box" class="preview-box"></div>
 
        </div>
 

	
 
        <div class="comment-button">
 
        ${h.submit('save', _('Comment'), class_="ui-btn large")}
 
        %if close_btn and change_status:
 
           ${h.submit('save_close', _('Comment and close'), class_='ui-btn blue large %s' % ('hidden' if cur_status in ['not_reviewed','under_review'] else ''))}
 
        %endif
 
        </div>
 
        ${h.end_form()}
 
    </div>
 
    %endif
 
</div>
 
<script>
 
var change_status_show = function(){
 
    var show = ! YUD.get('show_changeset_status_box').checked;
 
    YUD.get('show_changeset_status_box').checked = show;
 
    YUD.setStyle('status_block_container', 'display', show?'':'none');
 
};
 

	
 
YUE.onDOMReady(function () {
 
   MentionsAutoComplete('text', 'mentions_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
 

	
 
   YUE.on(YUQ('.status_change_radio'), 'change',function(e){
 
       var val = e.currentTarget.value;
 
       if (val == 'approved' || val == 'rejected') {
 
           YUD.removeClass('save_close', 'hidden');
 
       }else{
 
           YUD.addClass('save_close', 'hidden');
 
       }
 
   })
 
   YUE.on('preview-btn', 'click', function(e){
 
       var _text = YUD.get('text').value;
 
       if(!_text){
 
           return
 
       }
 
       var post_data = {'text': _text};
 
       YUD.addClass('preview-box', 'unloaded');
 
       YUD.get('preview-box').innerHTML = _TM['Loading ...'];
 
       YUD.setStyle('edit-container', 'display', 'none');
 
       YUD.setStyle('preview-container', 'display', '');
 

	
 
       var url = pyroutes.url('changeset_comment_preview', {'repo_name': '${c.repo_name}'});
 
       ajaxPOST(url,post_data,function(o){
 
           YUD.get('preview-box').innerHTML = o.responseText;
 
           YUD.removeClass('preview-box', 'unloaded');
 
       })
 
   })
 
   YUE.on('edit-btn', 'click', function(e){
 
       YUD.setStyle('edit-container', 'display', '');
 
       YUD.setStyle('preview-container', 'display', 'none');
 
   })
 

	
 
});
 
</script>
 
</%def>
0 comments (0 inline, 0 general)