Changeset - 7276b170ce8b
[Not reviewed]
beta
0 8 0
Marcin Kuzminski - 14 years ago 2011-11-13 01:16:12
marcin@python-works.com
#71 code-review
- simple inline comments
8 files changed with 202 insertions and 21 deletions:
0 comments (0 inline, 0 general)
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) 2009-2011 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 pylons import tmpl_context as c, url, request, response
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 
from pylons.decorators import jsonify
 

	
 
import rhodecode.lib.helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
 
    NotAnonymous
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import EmptyChangeset
 
from rhodecode.lib.compat import OrderedDict
 
from rhodecode.model.db import ChangesetComment
 
from rhodecode.model.comment import ChangesetCommentsModel
 

	
 
from vcs.exceptions import RepositoryError, ChangesetError, \
 
    ChangesetDoesNotExistError
 
from vcs.nodes import FileNode
 
from vcs.utils import diffs as differ
 
from webob.exc import HTTPForbidden
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ChangesetController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        super(ChangesetController, self).__before__()
 
        c.affected_files_cut_off = 60
 

	
 
    def index(self, revision):
 

	
 
        def wrap_to_table(str):
 

	
 
            return '''<table class="code-difftable">
 
                        <tr class="line">
 
                        <td class="lineno new"></td>
 
                        <td class="code"><pre>%s</pre></td>
 
                        </tr>
 
                      </table>''' % str
 

	
 
        #get ranges of revisions if preset
 
        rev_range = revision.split('...')[:2]
 

	
 
        try:
 
            if len(rev_range) == 2:
 
                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='warning')
 
            return redirect(url('home'))
 

	
 
        c.changes = OrderedDict()
 
        c.sum_added = 0
 
        c.sum_removed = 0
 
        c.lines_added = 0
 
        c.lines_deleted = 0
 
        c.cut_off = False  # defines if cut off limit is reached
 

	
 
        c.comments = []
 

	
 
        c.inline_comments = []
 
        c.inline_cnt = 0
 
        # Iterate over ranges (default changeset view is always one changeset)
 
        for changeset in c.cs_ranges:
 
            c.comments.extend(ChangesetCommentsModel()\
 
                              .get_comments(c.rhodecode_db_repo.repo_id,
 
                                            changeset.raw_id))
 

	
 
            inlines = ChangesetCommentsModel()\
 
                        .get_inline_comments(c.rhodecode_db_repo.repo_id,
 
                                             changeset.raw_id)
 
            c.inline_comments.extend(inlines)
 
            c.changes[changeset.raw_id] = []
 
            try:
 
                changeset_parent = changeset.parents[0]
 
            except IndexError:
 
                changeset_parent = None
 

	
 
            #==================================================================
 
            # ADDED FILES
 
            #==================================================================
 
            for node in changeset.added:
 

	
 
                filenode_old = FileNode(node.path, '', EmptyChangeset())
 
                if filenode_old.is_binary or node.is_binary:
 
                    diff = wrap_to_table(_('binary file'))
 
                    st = (0, 0)
 
                else:
 
                    # in this case node.size is good parameter since those are
 
                    # added nodes and their size defines how many changes were
 
                    # made
 
                    c.sum_added += node.size
 
                    if c.sum_added < self.cut_off_limit:
 
                        f_gitdiff = differ.get_gitdiff(filenode_old, node)
 
                        d = differ.DiffProcessor(f_gitdiff, format='gitdiff')
 

	
 
                        st = d.stat()
 
                        diff = d.as_html()
 

	
 
                    else:
 
                        diff = wrap_to_table(_('Changeset is to big and '
 
                                               'was cut off, see raw '
 
                                               'changeset instead'))
 
                        c.cut_off = True
 
                        break
 

	
 
                cs1 = None
 
                cs2 = node.last_changeset.raw_id
 
                c.lines_added += st[0]
 
                c.lines_deleted += st[1]
 
                c.changes[changeset.raw_id].append(('added', node, diff,
 
                                                    cs1, cs2, st))
 

	
 
            #==================================================================
 
            # CHANGED FILES
 
            #==================================================================
 
            if not c.cut_off:
 
                for node in changeset.changed:
 
                    try:
 
                        filenode_old = changeset_parent.get_node(node.path)
 
                    except ChangesetError:
 
                        log.warning('Unable to fetch parent node for diff')
 
                        filenode_old = FileNode(node.path, '',
 
                                                EmptyChangeset())
 

	
 
                    if filenode_old.is_binary or node.is_binary:
 
                        diff = wrap_to_table(_('binary file'))
 
                        st = (0, 0)
 
                    else:
 

	
 
                        if c.sum_removed < self.cut_off_limit:
 
                            f_gitdiff = differ.get_gitdiff(filenode_old, node)
 
                            d = differ.DiffProcessor(f_gitdiff,
 
                                                     format='gitdiff')
 
                            st = d.stat()
 
                            if (st[0] + st[1]) * 256 > self.cut_off_limit:
 
                                diff = wrap_to_table(_('Diff is to big '
 
                                                       'and was cut off, see '
 
                                                       'raw diff instead'))
 
                            else:
 
                                diff = d.as_html()
 

	
 
                            if diff:
 
                                c.sum_removed += len(diff)
 
                        else:
 
                            diff = wrap_to_table(_('Changeset is to big and '
 
                                                   'was cut off, see raw '
 
                                                   'changeset instead'))
 
                            c.cut_off = True
 
                            break
 

	
 
                    cs1 = filenode_old.last_changeset.raw_id
 
                    cs2 = node.last_changeset.raw_id
 
                    c.lines_added += st[0]
 
                    c.lines_deleted += st[1]
 
                    c.changes[changeset.raw_id].append(('changed', node, diff,
 
                                                        cs1, cs2, st))
 

	
 
            #==================================================================
 
            # REMOVED FILES
 
            #==================================================================
 
            if not c.cut_off:
 
                for node in changeset.removed:
 
                    c.changes[changeset.raw_id].append(('removed', node, None,
 
                                                        None, None, (0, 0)))
 

	
 
        # count inline comments
 
        for path, 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.changes = c.changes[c.changeset.raw_id]
 

	
 
            return render('changeset/changeset.html')
 
        else:
 
            return render('changeset/changeset_range.html')
 

	
 
    def raw_changeset(self, revision):
 

	
 
        method = request.GET.get('diff', 'show')
 
        try:
 
            c.scm_type = c.rhodecode_repo.alias
 
            c.changeset = c.rhodecode_repo.get_changeset(revision)
 
        except RepositoryError:
 
            log.error(traceback.format_exc())
 
            return redirect(url('home'))
 
        else:
 
            try:
 
                c.changeset_parent = c.changeset.parents[0]
 
            except IndexError:
 
                c.changeset_parent = None
 
            c.changes = []
 

	
 
            for node in c.changeset.added:
 
                filenode_old = FileNode(node.path, '')
 
                if filenode_old.is_binary or node.is_binary:
 
                    diff = _('binary file') + '\n'
 
                else:
 
                    f_gitdiff = differ.get_gitdiff(filenode_old, node)
 
                    diff = differ.DiffProcessor(f_gitdiff,
 
                                                format='gitdiff').raw_diff()
 

	
 
                cs1 = None
 
                cs2 = node.last_changeset.raw_id
 
                c.changes.append(('added', node, diff, cs1, cs2))
 

	
 
            for node in c.changeset.changed:
 
                filenode_old = c.changeset_parent.get_node(node.path)
 
                if filenode_old.is_binary or node.is_binary:
 
                    diff = _('binary file')
 
                else:
 
                    f_gitdiff = differ.get_gitdiff(filenode_old, node)
 
                    diff = differ.DiffProcessor(f_gitdiff,
 
                                                format='gitdiff').raw_diff()
 

	
 
                cs1 = filenode_old.last_changeset.raw_id
 
                cs2 = node.last_changeset.raw_id
 
                c.changes.append(('changed', node, diff, cs1, cs2))
 

	
 
        response.content_type = 'text/plain'
 

	
 
        if method == 'download':
 
            response.content_disposition = 'attachment; filename=%s.patch' \
 
                                            % revision
 

	
 
        c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id for x in
 
                                                 c.changeset.parents])
 

	
 
        c.diffs = ''
 
        for x in c.changes:
 
            c.diffs += x[2]
 

	
 
        return render('changeset/raw_changeset.html')
 

	
 
    def comment(self, repo_name, revision):
 
        ccmodel = ChangesetCommentsModel()
 

	
 
        ccmodel.create(text=request.POST.get('text'),
 
                       repo_id=c.rhodecode_db_repo.repo_id,
 
                       user_id=c.rhodecode_user.user_id,
 
                       revision=revision, f_path=request.POST.get('f_path'),
 
                       line_no=request.POST.get('line'))
 

	
 
        return redirect(h.url('changeset_home', repo_name=repo_name,
 
                              revision=revision))
 

	
 
    @jsonify
 
    def delete_comment(self, comment_id):
 
        co = ChangesetComment.get(comment_id)
 
        if (h.HasPermissionAny('hg.admin', 'repository.admin')() or
 
            co.author.user_id == c.rhodecode_user.user_id):
 
            ccmodel = ChangesetCommentsModel()
 
            ccmodel.delete(comment_id=comment_id)
 
            return True
 
        else:
 
            raise HTTPForbidden()
 

	
rhodecode/model/comment.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.comment
 
    ~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    comments model for RhodeCode
 
    
 
    :created_on: Nov 11, 2011
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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 rhodecode.model import BaseModel
 
from rhodecode.model.db import ChangesetComment
 
from sqlalchemy.util.compat import defaultdict
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ChangesetCommentsModel(BaseModel):
 

	
 

	
 
    def create(self, text, repo_id, user_id, revision, f_path=None,
 
               line_no=None):
 
        """
 
        Creates new comment for changeset
 
        
 
        :param text:
 
        :param repo_id:
 
        :param user_id:
 
        :param revision:
 
        :param f_path:
 
        :param line_no:
 
        """
 

	
 
        if text:
 
        comment = ChangesetComment()
 
        comment.repo_id = repo_id
 
        comment.user_id = user_id
 
        comment.revision = revision
 
        comment.text = text
 
        comment.f_path = f_path
 
        comment.line_no = line_no
 

	
 
        self.sa.add(comment)
 
        self.sa.commit()
 
        return comment
 

	
 
    def delete(self, comment_id):
 
        """
 
        Deletes given comment
 
        
 
        :param comment_id:
 
        """
 
        comment = ChangesetComment.get(comment_id)
 
        self.sa.delete(comment)
 
        self.sa.commit()
 
        return comment
 

	
 

	
 
    def get_comments(self, repo_id, revision):
 
        return ChangesetComment.query()\
 
                .filter(ChangesetComment.repo_id == repo_id)\
 
                .filter(ChangesetComment.revision == revision)\
 
                .filter(ChangesetComment.line_no == None)\
 
                .filter(ChangesetComment.f_path == None).all()
 

	
 
    def get_comments_for_file(self, repo_id, f_path, raw_id):
 
    def get_inline_comments(self, repo_id, revision):
 
        comments = self.sa.query(ChangesetComment)\
 
            .filter(ChangesetComment.repo_id == repo_id)\
 
            .filter(ChangesetComment.commit_id == raw_id)\
 
            .filter(ChangesetComment.f_path == f_path).all()
 
            .filter(ChangesetComment.revision == revision).all()
 

	
 
        paths = defaultdict(lambda:defaultdict(list))
 

	
 
        d = defaultdict(list)
 
        for co in comments:
 
            d[co.line_no].append(co)
 
        return d.items()
 
            paths[co.f_path][co.line_no].append(co)
 
        return paths.items()
rhodecode/model/db.py
Show inline comments
 
@@ -336,785 +336,785 @@ class User(Base, BaseModel):
 

	
 
class UserLog(Base, BaseModel):
 
    __tablename__ = 'user_logs'
 
    __table_args__ = {'extend_existing':True}
 
    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
    repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
 

	
 
    @property
 
    def action_as_day(self):
 
        return date(*self.action_date.timetuple()[:3])
 

	
 
    user = relationship('User')
 
    repository = relationship('Repository')
 

	
 

	
 
class UsersGroup(Base, BaseModel):
 
    __tablename__ = 'users_groups'
 
    __table_args__ = {'extend_existing':True}
 

	
 
    users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
 

	
 
    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
 

	
 
    def __repr__(self):
 
        return '<userGroup(%s)>' % (self.users_group_name)
 

	
 
    @classmethod
 
    def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
 
        if case_insensitive:
 
            gr = cls.query()\
 
                .filter(cls.users_group_name.ilike(group_name))
 
        else:
 
            gr = cls.query()\
 
                .filter(cls.users_group_name == group_name)
 
        if cache:
 
            gr = gr.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % group_name))
 
        return gr.scalar()
 

	
 

	
 
    @classmethod
 
    def get(cls, users_group_id, cache=False):
 
        users_group = cls.query()
 
        if cache:
 
            users_group = users_group.options(FromCache("sql_cache_short",
 
                                    "get_users_group_%s" % users_group_id))
 
        return users_group.get(users_group_id)
 

	
 
    @classmethod
 
    def create(cls, form_data):
 
        try:
 
            new_users_group = cls()
 
            for k, v in form_data.items():
 
                setattr(new_users_group, k, v)
 

	
 
            Session.add(new_users_group)
 
            Session.commit()
 
            return new_users_group
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
    @classmethod
 
    def update(cls, users_group_id, form_data):
 

	
 
        try:
 
            users_group = cls.get(users_group_id, cache=False)
 

	
 
            for k, v in form_data.items():
 
                if k == 'users_group_members':
 
                    users_group.members = []
 
                    Session.flush()
 
                    members_list = []
 
                    if v:
 
                        v = [v] if isinstance(v, basestring) else v
 
                        for u_id in set(v):
 
                            member = UsersGroupMember(users_group_id, u_id)
 
                            members_list.append(member)
 
                    setattr(users_group, 'members', members_list)
 
                setattr(users_group, k, v)
 

	
 
            Session.add(users_group)
 
            Session.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
    @classmethod
 
    def delete(cls, users_group_id):
 
        try:
 

	
 
            # check if this group is not assigned to repo
 
            assigned_groups = UsersGroupRepoToPerm.query()\
 
                .filter(UsersGroupRepoToPerm.users_group_id ==
 
                        users_group_id).all()
 

	
 
            if assigned_groups:
 
                raise UsersGroupsAssignedException('RepoGroup assigned to %s' %
 
                                                   assigned_groups)
 

	
 
            users_group = cls.get(users_group_id, cache=False)
 
            Session.delete(users_group)
 
            Session.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 
            raise
 

	
 
class UsersGroupMember(Base, BaseModel):
 
    __tablename__ = 'users_groups_members'
 
    __table_args__ = {'extend_existing':True}
 

	
 
    users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User', lazy='joined')
 
    users_group = relationship('UsersGroup')
 

	
 
    def __init__(self, gr_id='', u_id=''):
 
        self.users_group_id = gr_id
 
        self.user_id = u_id
 

	
 
    @staticmethod
 
    def add_user_to_group(group, user):
 
        ugm = UsersGroupMember()
 
        ugm.users_group = group
 
        ugm.user = user
 
        Session.add(ugm)
 
        Session.commit()
 
        return ugm
 

	
 
class Repository(Base, BaseModel):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
 

	
 
    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
 
    repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
 
    private = Column("private", Boolean(), nullable=True, unique=None, default=None)
 
    enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
 
    enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
 
    description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
 

	
 
    fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
 

	
 

	
 
    user = relationship('User')
 
    fork = relationship('Repository', remote_side=repo_id)
 
    group = relationship('RepoGroup')
 
    repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
 
    users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
 
    stats = relationship('Statistics', cascade='all', uselist=False)
 

	
 
    followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
 

	
 
    logs = relationship('UserLog', cascade='all')
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.repo_id, self.repo_name)
 

	
 
    @classmethod
 
    def url_sep(cls):
 
        return '/'
 

	
 
    @classmethod
 
    def get_by_repo_name(cls, repo_name):
 
        q = Session.query(cls).filter(cls.repo_name == repo_name)
 
        q = q.options(joinedload(Repository.fork))\
 
                .options(joinedload(Repository.user))\
 
                .options(joinedload(Repository.group))
 
        return q.one()
 

	
 
    @classmethod
 
    def get_repo_forks(cls, repo_id):
 
        return cls.query().filter(Repository.fork_id == repo_id)
 

	
 
    @classmethod
 
    def base_path(cls):
 
        """
 
        Returns base path when all repos are stored
 

	
 
        :param cls:
 
        """
 
        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
 
                                              cls.url_sep())
 
        q.options(FromCache("sql_cache_short", "repository_repo_path"))
 
        return q.one().ui_value
 

	
 
    @property
 
    def just_name(self):
 
        return self.repo_name.split(Repository.url_sep())[-1]
 

	
 
    @property
 
    def groups_with_parents(self):
 
        groups = []
 
        if self.group is None:
 
            return groups
 

	
 
        cur_gr = self.group
 
        groups.insert(0, cur_gr)
 
        while 1:
 
            gr = getattr(cur_gr, 'parent_group', None)
 
            cur_gr = cur_gr.parent_group
 
            if gr is None:
 
                break
 
            groups.insert(0, gr)
 

	
 
        return groups
 

	
 
    @property
 
    def groups_and_repo(self):
 
        return self.groups_with_parents, self.just_name
 

	
 
    @LazyProperty
 
    def repo_path(self):
 
        """
 
        Returns base full path for that repository means where it actually
 
        exists on a filesystem
 
        """
 
        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
 
                                              Repository.url_sep())
 
        q.options(FromCache("sql_cache_short", "repository_repo_path"))
 
        return q.one().ui_value
 

	
 
    @property
 
    def repo_full_path(self):
 
        p = [self.repo_path]
 
        # we need to split the name by / since this is how we store the
 
        # names in the database, but that eventually needs to be converted
 
        # into a valid system path
 
        p += self.repo_name.split(Repository.url_sep())
 
        return os.path.join(*p)
 

	
 
    def get_new_name(self, repo_name):
 
        """
 
        returns new full repository name based on assigned group and new new
 

	
 
        :param group_name:
 
        """
 
        path_prefix = self.group.full_path_splitted if self.group else []
 
        return Repository.url_sep().join(path_prefix + [repo_name])
 

	
 
    @property
 
    def _ui(self):
 
        """
 
        Creates an db based ui object for this repository
 
        """
 
        from mercurial import ui
 
        from mercurial import config
 
        baseui = ui.ui()
 

	
 
        #clean the baseui object
 
        baseui._ocfg = config.config()
 
        baseui._ucfg = config.config()
 
        baseui._tcfg = config.config()
 

	
 

	
 
        ret = RhodeCodeUi.query()\
 
            .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
 

	
 
        hg_ui = ret
 
        for ui_ in hg_ui:
 
            if ui_.ui_active:
 
                log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
 
                          ui_.ui_key, ui_.ui_value)
 
                baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
 

	
 
        return baseui
 

	
 
    @classmethod
 
    def is_valid(cls, repo_name):
 
        """
 
        returns True if given repo name is a valid filesystem repository
 

	
 
        @param cls:
 
        @param repo_name:
 
        """
 
        from rhodecode.lib.utils import is_valid_repo
 

	
 
        return is_valid_repo(repo_name, cls.base_path())
 

	
 

	
 
    #==========================================================================
 
    # SCM PROPERTIES
 
    #==========================================================================
 

	
 
    def get_changeset(self, rev):
 
        return get_changeset_safe(self.scm_instance, rev)
 

	
 
    @property
 
    def tip(self):
 
        return self.get_changeset('tip')
 

	
 
    @property
 
    def author(self):
 
        return self.tip.author
 

	
 
    @property
 
    def last_change(self):
 
        return self.scm_instance.last_change
 

	
 
    #==========================================================================
 
    # SCM CACHE INSTANCE
 
    #==========================================================================
 

	
 
    @property
 
    def invalidate(self):
 
        return CacheInvalidation.invalidate(self.repo_name)
 

	
 
    def set_invalidate(self):
 
        """
 
        set a cache for invalidation for this instance
 
        """
 
        CacheInvalidation.set_invalidate(self.repo_name)
 

	
 
    @LazyProperty
 
    def scm_instance(self):
 
        return self.__get_instance()
 

	
 
    @property
 
    def scm_instance_cached(self):
 
        @cache_region('long_term')
 
        def _c(repo_name):
 
            return self.__get_instance()
 
        rn = self.repo_name
 

	
 
        inv = self.invalidate
 
        if inv is not None:
 
            region_invalidate(_c, None, rn)
 
            # update our cache
 
            CacheInvalidation.set_valid(inv.cache_key)
 
        return _c(rn)
 

	
 
    def __get_instance(self):
 

	
 
        repo_full_path = self.repo_full_path
 

	
 
        try:
 
            alias = get_scm(repo_full_path)[0]
 
            log.debug('Creating instance of %s repository', alias)
 
            backend = get_backend(alias)
 
        except VCSError:
 
            log.error(traceback.format_exc())
 
            log.error('Perhaps this repository is in db and not in '
 
                      'filesystem run rescan repositories with '
 
                      '"destroy old data " option from admin panel')
 
            return
 

	
 
        if alias == 'hg':
 

	
 
            repo = backend(safe_str(repo_full_path), create=False,
 
                           baseui=self._ui)
 
            # skip hidden web repository
 
            if repo._get_hidden():
 
                return
 
        else:
 
            repo = backend(repo_full_path, create=False)
 

	
 
        return repo
 

	
 

	
 
class RepoGroup(Base, BaseModel):
 
    __tablename__ = 'groups'
 
    __table_args__ = (UniqueConstraint('group_name', 'group_parent_id'),
 
                      CheckConstraint('group_id != group_parent_id'), {'extend_existing':True},)
 
    __mapper_args__ = {'order_by':'group_name'}
 

	
 
    group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
 
    group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    parent_group = relationship('RepoGroup', remote_side=group_id)
 

	
 

	
 
    def __init__(self, group_name='', parent_group=None):
 
        self.group_name = group_name
 
        self.parent_group = parent_group
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
 
                                  self.group_name)
 

	
 
    @classmethod
 
    def groups_choices(cls):
 
        from webhelpers.html import literal as _literal
 
        repo_groups = [('', '')]
 
        sep = ' &raquo; '
 
        _name = lambda k: _literal(sep.join(k))
 

	
 
        repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
 
                              for x in cls.query().all()])
 

	
 
        repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
 
        return repo_groups
 

	
 
    @classmethod
 
    def url_sep(cls):
 
        return '/'
 

	
 
    @classmethod
 
    def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
 
        if case_insensitive:
 
            gr = cls.query()\
 
                .filter(cls.group_name.ilike(group_name))
 
        else:
 
            gr = cls.query()\
 
                .filter(cls.group_name == group_name)
 
        if cache:
 
            gr = gr.options(FromCache("sql_cache_short",
 
                                          "get_group_%s" % group_name))
 
        return gr.scalar()
 

	
 
    @property
 
    def parents(self):
 
        parents_recursion_limit = 5
 
        groups = []
 
        if self.parent_group is None:
 
            return groups
 
        cur_gr = self.parent_group
 
        groups.insert(0, cur_gr)
 
        cnt = 0
 
        while 1:
 
            cnt += 1
 
            gr = getattr(cur_gr, 'parent_group', None)
 
            cur_gr = cur_gr.parent_group
 
            if gr is None:
 
                break
 
            if cnt == parents_recursion_limit:
 
                # this will prevent accidental infinit loops
 
                log.error('group nested more than %s' %
 
                          parents_recursion_limit)
 
                break
 

	
 
            groups.insert(0, gr)
 
        return groups
 

	
 
    @property
 
    def children(self):
 
        return RepoGroup.query().filter(RepoGroup.parent_group == self)
 

	
 
    @property
 
    def name(self):
 
        return self.group_name.split(RepoGroup.url_sep())[-1]
 

	
 
    @property
 
    def full_path(self):
 
        return self.group_name
 

	
 
    @property
 
    def full_path_splitted(self):
 
        return self.group_name.split(RepoGroup.url_sep())
 

	
 
    @property
 
    def repositories(self):
 
        return Repository.query().filter(Repository.group == self)
 

	
 
    @property
 
    def repositories_recursive_count(self):
 
        cnt = self.repositories.count()
 

	
 
        def children_count(group):
 
            cnt = 0
 
            for child in group.children:
 
                cnt += child.repositories.count()
 
                cnt += children_count(child)
 
            return cnt
 

	
 
        return cnt + children_count(self)
 

	
 

	
 
    def get_new_name(self, group_name):
 
        """
 
        returns new full group name based on parent and new name
 

	
 
        :param group_name:
 
        """
 
        path_prefix = (self.parent_group.full_path_splitted if
 
                       self.parent_group else [])
 
        return RepoGroup.url_sep().join(path_prefix + [group_name])
 

	
 

	
 
class Permission(Base, BaseModel):
 
    __tablename__ = 'permissions'
 
    __table_args__ = {'extend_existing':True}
 
    permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.permission_id, self.permission_name)
 

	
 
    @classmethod
 
    def get_by_key(cls, key):
 
        return cls.query().filter(cls.permission_name == key).scalar()
 

	
 
class UserRepoToPerm(Base, BaseModel):
 
    __tablename__ = 'repo_to_perm'
 
    __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'extend_existing':True})
 
    repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 
    repository = relationship('Repository')
 

	
 
class UserToPerm(Base, BaseModel):
 
    __tablename__ = 'user_to_perm'
 
    __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'extend_existing':True})
 
    user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 

	
 
    @classmethod
 
    def has_perm(cls, user_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        return cls.query().filter(cls.user_id == user_id)\
 
            .filter(cls.permission == perm).scalar() is not None
 

	
 
    @classmethod
 
    def grant_perm(cls, user_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        new = cls()
 
        new.user_id = user_id
 
        new.permission = perm
 
        try:
 
            Session.add(new)
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 

	
 
    @classmethod
 
    def revoke_perm(cls, user_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        try:
 
            cls.query().filter(cls.user_id == user_id)\
 
                .filter(cls.permission == perm).delete()
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 
class UsersGroupRepoToPerm(Base, BaseModel):
 
    __tablename__ = 'users_group_repo_to_perm'
 
    __table_args__ = (UniqueConstraint('repository_id', 'users_group_id', 'permission_id'), {'extend_existing':True})
 
    users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 

	
 
    users_group = relationship('UsersGroup')
 
    permission = relationship('Permission')
 
    repository = relationship('Repository')
 

	
 
    def __repr__(self):
 
        return '<userGroup:%s => %s >' % (self.users_group, self.repository)
 

	
 
class UsersGroupToPerm(Base, BaseModel):
 
    __tablename__ = 'users_group_to_perm'
 
    users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 

	
 
    users_group = relationship('UsersGroup')
 
    permission = relationship('Permission')
 

	
 

	
 
    @classmethod
 
    def has_perm(cls, users_group_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        return cls.query().filter(cls.users_group_id ==
 
                                         users_group_id)\
 
                                         .filter(cls.permission == perm)\
 
                                         .scalar() is not None
 

	
 
    @classmethod
 
    def grant_perm(cls, users_group_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        new = cls()
 
        new.users_group_id = users_group_id
 
        new.permission = perm
 
        try:
 
            Session.add(new)
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 

	
 
    @classmethod
 
    def revoke_perm(cls, users_group_id, perm):
 
        if not isinstance(perm, Permission):
 
            raise Exception('perm needs to be an instance of Permission class')
 

	
 
        try:
 
            cls.query().filter(cls.users_group_id == users_group_id)\
 
                .filter(cls.permission == perm).delete()
 
            Session.commit()
 
        except:
 
            Session.rollback()
 

	
 

	
 
class UserRepoGroupToPerm(Base, BaseModel):
 
    __tablename__ = 'group_to_perm'
 
    __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
 

	
 
    group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User')
 
    permission = relationship('Permission')
 
    group = relationship('RepoGroup')
 

	
 
class UsersGroupRepoGroupToPerm(Base, BaseModel):
 
    __tablename__ = 'users_group_repo_group_to_perm'
 
    __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'extend_existing':True})
 

	
 
    users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
 

	
 
    users_group = relationship('UsersGroup')
 
    permission = relationship('Permission')
 
    group = relationship('RepoGroup')
 

	
 
class Statistics(Base, BaseModel):
 
    __tablename__ = 'statistics'
 
    __table_args__ = (UniqueConstraint('repository_id'), {'extend_existing':True})
 
    stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
 
    stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
 
    commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
 
    commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
 
    languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
 

	
 
    repository = relationship('Repository', single_parent=True)
 

	
 
class UserFollowing(Base, BaseModel):
 
    __tablename__ = 'user_followings'
 
    __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
 
                      UniqueConstraint('user_id', 'follows_user_id')
 
                      , {'extend_existing':True})
 

	
 
    user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
 
    follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
 
    follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
 

	
 
    user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
 

	
 
    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
 
    follows_repository = relationship('Repository', order_by='Repository.repo_name')
 

	
 

	
 
    @classmethod
 
    def get_repo_followers(cls, repo_id):
 
        return cls.query().filter(cls.follows_repo_id == repo_id)
 

	
 
class CacheInvalidation(Base, BaseModel):
 
    __tablename__ = 'cache_invalidation'
 
    __table_args__ = (UniqueConstraint('cache_key'), {'extend_existing':True})
 
    cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
 

	
 

	
 
    def __init__(self, cache_key, cache_args=''):
 
        self.cache_key = cache_key
 
        self.cache_args = cache_args
 
        self.cache_active = False
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.cache_id, self.cache_key)
 

	
 
    @classmethod
 
    def invalidate(cls, key):
 
        """
 
        Returns Invalidation object if this given key should be invalidated
 
        None otherwise. `cache_active = False` means that this cache
 
        state is not valid and needs to be invalidated
 
        
 
        :param key:
 
        """
 
        return cls.query()\
 
                .filter(CacheInvalidation.cache_key == key)\
 
                .filter(CacheInvalidation.cache_active == False)\
 
                .scalar()
 

	
 
    @classmethod
 
    def set_invalidate(cls, key):
 
        """
 
        Mark this Cache key for invalidation
 
        
 
        :param key:
 
        """
 

	
 
        log.debug('marking %s for invalidation' % key)
 
        inv_obj = Session().query(cls)\
 
            .filter(cls.cache_key == key).scalar()
 
        if inv_obj:
 
            inv_obj.cache_active = False
 
        else:
 
            log.debug('cache key not found in invalidation db -> creating one')
 
            inv_obj = CacheInvalidation(key)
 

	
 
        try:
 
            Session.add(inv_obj)
 
            Session.commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            Session.rollback()
 

	
 
    @classmethod
 
    def set_valid(cls, key):
 
        """
 
        Mark this cache key as active and currently cached
 
        
 
        :param key:
 
        """
 
        inv_obj = Session().query(CacheInvalidation)\
 
            .filter(CacheInvalidation.cache_key == key).scalar()
 
        inv_obj.cache_active = True
 
        Session.add(inv_obj)
 
        Session.commit()
 

	
 

	
 
class ChangesetComment(Base, BaseModel):
 
    __tablename__ = 'changeset_comments'
 
    __table_args__ = ({'extend_existing':True},)
 
    comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
 
    repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
 
    revision = Column('revision', String(40), nullable=False)
 
    line_no = Column('line_no', Integer(), nullable=True)
 
    f_path = Column('f_path', String(1000), nullable=True)
 
    line_no = Column('line_no', Unicode(10), nullable=True)
 
    f_path = Column('f_path', Unicode(1000), nullable=True)
 
    user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
 
    text = Column('text', String(25000), nullable=False)
 
    modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
    text = Column('text', Unicode(25000), nullable=False)
 
    modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
 

	
 
    author = relationship('User')
 
    repo = relationship('Repository')
 

	
 

	
 
class DbMigrateVersion(Base, BaseModel):
 
    __tablename__ = 'db_migrate_version'
 
    __table_args__ = {'extend_existing':True}
 
    repository_id = Column('repository_id', String(250), primary_key=True)
 
    repository_path = Column('repository_path', Text)
 
    version = Column('version', Integer)
 

	
rhodecode/public/css/diff.css
Show inline comments
 
div.diffblock {
 
    overflow: auto;
 
    padding: 0px;
 
    border: 1px solid #ccc;
 
    background: #f8f8f8;
 
    font-size: 100%;
 
    line-height: 100%;
 
    /* new */
 
    line-height: 125%;
 
}
 

	
 
div.diffblock.margined{
 
	margin: 0px 20px 0px 20px;
 
}
 

	
 
div.diffblock .code-header{
 
	border-bottom: 1px solid #CCCCCC;
 
	background: #EEEEEE;
 
	padding:10px 0 10px 0;
 
}
 
div.diffblock .code-header div{
 
	margin-left:25px;
 
	font-weight: bold;
 
}
 
div.diffblock .code-body{
 
	background: #FFFFFF;
 
}
 
div.diffblock pre.raw{
 
	background: #FFFFFF;
 
	color:#000000;
 
}
 

	
 
table.code-difftable{
 
	border-collapse: collapse;
 
	width: 99%;
 
}
 

	
 
table.code-difftable td {
 
    padding: 0 !important; 
 
    background: none !important; 
 
    border:0 !important;    
 
}
 

	
 

	
 
.code-difftable .context{
 
	background:none repeat scroll 0 0 #DDE7EF;
 
}
 
.code-difftable .add{
 
	background:none repeat scroll 0 0 #DDFFDD;
 
}
 
.code-difftable .add ins{
 
	background:none repeat scroll 0 0 #AAFFAA;
 
	text-decoration:none;
 
}
 

	
 
.code-difftable .del{
 
	background:none repeat scroll 0 0 #FFDDDD;
 
}
 
.code-difftable .del del{
 
	background:none repeat scroll 0 0 #FFAAAA;
 
	text-decoration:none;
 
}
 

	
 
.code-difftable .lineno{
 
	background:none repeat scroll 0 0 #EEEEEE !important;
 
	padding-left:2px;
 
	padding-right:2px;
 
	text-align:right;
 
	width:30px;
 
	-moz-user-select:none;
 
	-webkit-user-select: none;
 
}
 
.code-difftable .new {
 
	border-right: 1px solid #CCC !important;
 
}
 
.code-difftable .old {
 
    border-right: 1px solid #CCC !important;
 
}
 
.code-difftable .lineno pre{
 
	color:#747474 !important;
 
	font:11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
 
	letter-spacing:-1px;
 
	text-align:right;
 
	width:20px;
 
}
 
.code-difftable .lineno a{
 
font-weight: 700;
 
cursor: pointer;
 
}
 
.code-difftable .code td{
 
	margin:0;
 
	padding: 0;
 
}
 
.code-difftable .code pre{
 
	margin:0;
 
	padding:0;
 
}
 

	
 
.code { 
 
	display: block;
 
	width: 100%;
 
}
 
.code-diff {
 
    padding: 0px;
 
    margin-top: 5px;
 
    margin-bottom: 5px;
 
    border-left: 2px solid #ccc;
 
}
 
.code-diff pre, .line pre { 
 
	padding: 3px;
 
    margin: 0;
 
}
 
.lineno a { 
 
	text-decoration: none; 
 
}
 

	
 
.line{
 
	padding:0;
 
	margin:0;
 
}
 
\ No newline at end of file
 
}
 

	
 
.line.highlight{
 
	background-color:#FFFFCC;
 
	cursor: pointer;
 
	background-image:url("../images/icons/comment_add.png");
 
	background-repeat:no-repeat;
 
	background-position: right;
 
	background-position: 100% 50%;
 
}
rhodecode/public/css/style.css
Show inline comments
 
@@ -1088,2247 +1088,2310 @@ div.options a {
 
	color: #000;
 
	margin: 0;
 
	padding: 4px 8px;
 
}
 
 
#content div.box div.form div.fields div.field div.textarea {
 
	border-top: 1px solid #b3b3b3;
 
	border-left: 1px solid #b3b3b3;
 
	border-right: 1px solid #eaeaea;
 
	border-bottom: 1px solid #eaeaea;
 
	margin: 0 0 0 200px;
 
	padding: 10px;
 
}
 
 
#content div.box div.form div.fields div.field div.textarea-editor {
 
	border: 1px solid #ddd;
 
	padding: 0;
 
}
 
 
#content div.box div.form div.fields div.field div.textarea textarea {
 
	width: 100%;
 
	height: 220px;
 
	overflow: hidden;
 
	background: #FFF;
 
	color: #000;
 
	font-size: 11px;
 
	outline: none;
 
	border-width: 0;
 
	margin: 0;
 
	padding: 0;
 
}
 
 
#content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea
 
	{
 
	width: 100%;
 
	height: 100px;
 
}
 
 
#content div.box div.form div.fields div.field div.textarea table {
 
	width: 100%;
 
	border: none;
 
	margin: 0;
 
	padding: 0;
 
}
 
 
#content div.box div.form div.fields div.field div.textarea table td {
 
	background: #DDD;
 
	border: none;
 
	padding: 0;
 
}
 
 
#content div.box div.form div.fields div.field div.textarea table td table
 
	{
 
	width: auto;
 
	border: none;
 
	margin: 0;
 
	padding: 0;
 
}
 
 
#content div.box div.form div.fields div.field div.textarea table td table td
 
	{
 
	font-size: 11px;
 
	padding: 5px 5px 5px 0;
 
}
 
 
#content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus
 
	{
 
	background: #f6f6f6;
 
	border-color: #666;
 
}
 
 
div.form div.fields div.field div.button {
 
	margin: 0;
 
	padding: 0 0 0 8px;
 
}
 
#content div.box table.noborder {
 
	border: 1px solid transparent;
 
}
 
 
#content div.box table {
 
	width: 100%;
 
	border-collapse: separate;
 
	margin: 0;
 
	padding: 0;
 
	border: 1px solid #eee;
 
    -webkit-border-radius: 4px;
 
    -moz-border-radius: 4px;
 
    border-radius: 4px;	
 
}
 
 
#content div.box table th {
 
	background: #eee;
 
	border-bottom: 1px solid #ddd;
 
	padding: 5px 0px 5px 5px;
 
}
 
 
#content div.box table th.left {
 
	text-align: left;
 
}
 
 
#content div.box table th.right {
 
	text-align: right;
 
}
 
 
#content div.box table th.center {
 
	text-align: center;
 
}
 
 
#content div.box table th.selected {
 
	vertical-align: middle;
 
	padding: 0;
 
}
 
 
#content div.box table td {
 
	background: #fff;
 
	border-bottom: 1px solid #cdcdcd;
 
	vertical-align: middle;
 
	padding: 5px;
 
}
 
 
#content div.box table tr.selected td {
 
	background: #FFC;
 
}
 
 
#content div.box table td.selected {
 
	width: 3%;
 
	text-align: center;
 
	vertical-align: middle;
 
	padding: 0;
 
}
 
 
#content div.box table td.action {
 
	width: 45%;
 
	text-align: left;
 
}
 
 
#content div.box table td.date {
 
	width: 33%;
 
	text-align: center;
 
}
 
 
#content div.box div.action {
 
	float: right;
 
	background: #FFF;
 
	text-align: right;
 
	margin: 10px 0 0;
 
	padding: 0;
 
}
 
 
#content div.box div.action select {
 
	font-size: 11px;
 
	margin: 0;
 
}
 
 
#content div.box div.action .ui-selectmenu {
 
	margin: 0;
 
	padding: 0;
 
}
 
 
#content div.box div.pagination {
 
	height: 1%;
 
	clear: both;
 
	overflow: hidden;
 
	margin: 10px 0 0;
 
	padding: 0;
 
}
 
 
#content div.box div.pagination ul.pager {
 
	float: right;
 
	text-align: right;
 
	margin: 0;
 
	padding: 0;
 
}
 
 
#content div.box div.pagination ul.pager li {
 
	height: 1%;
 
	float: left;
 
	list-style: none;
 
	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 0 0 4px;
 
	padding: 0;
 
}
 
 
#content div.box div.pagination ul.pager li.separator {
 
	padding: 6px;
 
}
 
 
#content div.box div.pagination ul.pager li.current {
 
	background: #b4b4b4 url("../images/pager_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;
 
	padding: 6px;
 
}
 
 
#content div.box div.pagination ul.pager li a {
 
	height: 1%;
 
	display: block;
 
	float: left;
 
	color: #515151;
 
	text-decoration: none;
 
	margin: 0;
 
	padding: 6px;
 
}
 
 
#content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active
 
	{
 
	background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
 
	border-top: 1px solid #ccc;
 
	border-left: 1px solid #bebebe;
 
	border-right: 1px solid #b1b1b1;
 
	border-bottom: 1px solid #afafaf;
 
	margin: -1px;
 
}
 
 
#content div.box div.pagination-wh {
 
	height: 1%;
 
	clear: both;
 
	overflow: hidden;
 
	text-align: right;
 
	margin: 10px 0 0;
 
	padding: 0;
 
}
 
 
#content div.box div.pagination-right {
 
	float: right;
 
}
 
 
#content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot
 
	{
 
	height: 1%;
 
	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 0 0 4px;
 
	padding: 6px;
 
}
 
 
#content div.box div.pagination-wh span.pager_curpage {
 
	height: 1%;
 
	float: left;
 
	background: #b4b4b4 url("../images/pager_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;
 
	font-weight: 700;
 
	margin: 0 0 0 4px;
 
	padding: 6px;
 
}
 
 
#content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active
 
	{
 
	background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
 
	border-top: 1px solid #ccc;
 
	border-left: 1px solid #bebebe;
 
	border-right: 1px solid #b1b1b1;
 
	border-bottom: 1px solid #afafaf;
 
	text-decoration: none;
 
}
 
 
#content div.box div.traffic div.legend {
 
	clear: both;
 
	overflow: hidden;
 
	border-bottom: 1px solid #ddd;
 
	margin: 0 0 10px;
 
	padding: 0 0 10px;
 
}
 
 
#content div.box div.traffic div.legend h6 {
 
	float: left;
 
	border: none;
 
	margin: 0;
 
	padding: 0;
 
}
 
 
#content div.box div.traffic div.legend li {
 
	list-style: none;
 
	float: left;
 
	font-size: 11px;
 
	margin: 0;
 
	padding: 0 8px 0 4px;
 
}
 
 
#content div.box div.traffic div.legend li.visits {
 
	border-left: 12px solid #edc240;
 
}
 
 
#content div.box div.traffic div.legend li.pageviews {
 
	border-left: 12px solid #afd8f8;
 
}
 
 
#content div.box div.traffic table {
 
	width: auto;
 
}
 
 
#content div.box div.traffic table td {
 
	background: transparent;
 
	border: none;
 
	padding: 2px 3px 3px;
 
}
 
 
#content div.box div.traffic table td.legendLabel {
 
	padding: 0 3px 2px;
 
}
 
 
#summary {
 
	
 
}
 
 
#summary .desc {
 
	white-space: pre;
 
	width: 100%;
 
}
 
 
#summary .repo_name {
 
	font-size: 1.6em;
 
	font-weight: bold;
 
	vertical-align: baseline;
 
	clear: right
 
}
 
 
#footer {
 
	clear: both;
 
	overflow: hidden;
 
	text-align: right;
 
	margin: 0;
 
	padding: 0 10px 4px;
 
	margin: -10px 0 0;
 
}
 
 
#footer div#footer-inner {
 
	background-color: #eedc94; background-repeat : repeat-x;
 
	background-image : -khtml-gradient( linear, left top, left bottom,
 
	from( #fceec1), to( #eedc94)); 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( top, #003b76, #00376e); filter :
 
	progid : DXImageTransform.Microsoft.gradient ( startColorstr =
 
	'#003b76', endColorstr = '#00376e', GradientType = 0);
 
	box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
	-webkit-border-radius: 4px 4px 4px 4px;
 
	-khtml-border-radius: 4px 4px 4px 4px;
 
	-moz-border-radius: 4px 4px 4px 4px;
 
	border-radius: 4px 4px 4px 4px;
 
	background-repeat: repeat-x;
 
	background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1),
 
		to(#eedc94) );
 
	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(top, #003b76, #00376e);
 
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
 
		endColorstr='#00376e', GradientType=0 );
 
}
 
 
#footer div#footer-inner p {
 
	padding: 15px 25px 15px 0;
 
	color: #FFF;
 
	font-weight: 700;
 
}
 
 
#footer div#footer-inner .footer-link {
 
	float: left;
 
	padding-left: 10px;
 
}
 
 
#footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a
 
	{
 
	color: #FFF;
 
}
 
 
#login div.title {
 
	width: 420px;
 
	clear: both;
 
	overflow: hidden;
 
	position: relative;
 
	background-color: #eedc94; background-repeat : repeat-x;
 
	background-image : -khtml-gradient( linear, left top, left bottom,
 
	from( #fceec1), to( #eedc94)); 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( top, #003b76, #00376e); filter :
 
	progid : DXImageTransform.Microsoft.gradient ( startColorstr =
 
	'#003b76', endColorstr = '#00376e', GradientType = 0);
 
	margin: 0 auto;
 
	padding: 0;
 
	background-repeat: repeat-x;
 
	background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1),
 
		to(#eedc94) );
 
	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(top, #003b76, #00376e);
 
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
 
		endColorstr='#00376e', GradientType=0 );
 
}
 
 
#login div.inner {
 
	width: 380px;
 
	background: #FFF url("../images/login.png") no-repeat top left;
 
	border-top: none;
 
	border-bottom: none;
 
	margin: 0 auto;
 
	padding: 20px;
 
}
 
 
#login div.form div.fields div.field div.label {
 
	width: 173px;
 
	float: left;
 
	text-align: right;
 
	margin: 2px 10px 0 0;
 
	padding: 5px 0 0 5px;
 
}
 
 
#login div.form div.fields div.field div.input input {
 
	width: 176px;
 
	background: #FFF;
 
	border-top: 1px solid #b3b3b3;
 
	border-left: 1px solid #b3b3b3;
 
	border-right: 1px solid #eaeaea;
 
	border-bottom: 1px solid #eaeaea;
 
	color: #000;
 
	font-size: 11px;
 
	margin: 0;
 
	padding: 7px 7px 6px;
 
}
 
 
#login div.form div.fields div.buttons {
 
	clear: both;
 
	overflow: hidden;
 
	border-top: 1px solid #DDD;
 
	text-align: right;
 
	margin: 0;
 
	padding: 10px 0 0;
 
}
 
 
#login div.form div.links {
 
	clear: both;
 
	overflow: hidden;
 
	margin: 10px 0 0;
 
	padding: 0 0 2px;
 
}
 
 
#quick_login {
 
	top: 31px;
 
	background-color: rgb(0, 51, 103);
 
	z-index: 999;
 
	height: 150px;
 
	position: absolute;
 
	margin-left: -16px;
 
	width: 281px;
 
	-webkit-border-radius: 0px 0px 4px 4px;
 
	-khtml-border-radius: 0px 0px 4px 4px;
 
	-moz-border-radius: 0px 0px 4px 4px;
 
	border-radius: 0px 0px 4px 4px;
 
	box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
}
 
 
#quick_login .password_forgoten {
 
	padding-right: 10px;
 
	padding-top: 0px;
 
	float: left;
 
}
 
 
#quick_login .password_forgoten a {
 
	font-size: 10px
 
}
 
 
#quick_login .register {
 
	padding-right: 10px;
 
	padding-top: 5px;
 
	float: left;
 
}
 
 
#quick_login .register a {
 
	font-size: 10px
 
}
 
 
#quick_login div.form div.fields {
 
	padding-top: 2px;
 
	padding-left: 10px;
 
}
 
 
#quick_login div.form div.fields div.field {
 
	padding: 5px;
 
}
 
 
#quick_login div.form div.fields div.field div.label label {
 
	color: #fff;
 
	padding-bottom: 3px;
 
}
 
 
#quick_login div.form div.fields div.field div.input input {
 
	width: 236px;
 
	background: #FFF;
 
	border-top: 1px solid #b3b3b3;
 
	border-left: 1px solid #b3b3b3;
 
	border-right: 1px solid #eaeaea;
 
	border-bottom: 1px solid #eaeaea;
 
	color: #000;
 
	font-size: 11px;
 
	margin: 0;
 
	padding: 5px 7px 4px;
 
}
 
 
#quick_login div.form div.fields div.buttons {
 
	clear: both;
 
	overflow: hidden;
 
	text-align: right;
 
	margin: 0;
 
	padding: 10px 14px 0px 5px;
 
}
 
 
#quick_login div.form div.links {
 
	clear: both;
 
	overflow: hidden;
 
	margin: 10px 0 0;
 
	padding: 0 0 2px;
 
}
 
 
#register div.title {
 
	clear: both;
 
	overflow: hidden;
 
	position: relative;
 
    background-color: #eedc94;
 
    background-repeat: repeat-x;
 
    background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1),
 
        to(#eedc94) );
 
    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(top, #003b76, #00376e);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
 
        endColorstr='#00376e', GradientType=0 );
 
	margin: 0 auto;
 
	padding: 0;
 
}
 
 
#register div.inner {
 
	background: #FFF;
 
	border-top: none;
 
	border-bottom: none;
 
	margin: 0 auto;
 
	padding: 20px;
 
}
 
 
#register div.form div.fields div.field div.label {
 
	width: 135px;
 
	float: left;
 
	text-align: right;
 
	margin: 2px 10px 0 0;
 
	padding: 5px 0 0 5px;
 
}
 
 
#register div.form div.fields div.field div.input input {
 
	width: 300px;
 
	background: #FFF;
 
	border-top: 1px solid #b3b3b3;
 
	border-left: 1px solid #b3b3b3;
 
	border-right: 1px solid #eaeaea;
 
	border-bottom: 1px solid #eaeaea;
 
	color: #000;
 
	font-size: 11px;
 
	margin: 0;
 
	padding: 7px 7px 6px;
 
}
 
 
#register div.form div.fields div.buttons {
 
	clear: both;
 
	overflow: hidden;
 
	border-top: 1px solid #DDD;
 
	text-align: left;
 
	margin: 0;
 
	padding: 10px 0 0 150px;
 
}
 
 
#register div.form div.activation_msg {
 
	padding-top: 4px;
 
	padding-bottom: 4px;
 
}
 
 
#journal .journal_day {
 
	font-size: 20px;
 
	padding: 10px 0px;
 
	border-bottom: 2px solid #DDD;
 
	margin-left: 10px;
 
	margin-right: 10px;
 
}
 
 
#journal .journal_container {
 
	padding: 5px;
 
	clear: both;
 
	margin: 0px 5px 0px 10px;
 
}
 
 
#journal .journal_action_container {
 
	padding-left: 38px;
 
}
 
 
#journal .journal_user {
 
	color: #747474;
 
	font-size: 14px;
 
	font-weight: bold;
 
	height: 30px;
 
}
 
 
#journal .journal_icon {
 
	clear: both;
 
	float: left;
 
	padding-right: 4px;
 
	padding-top: 3px;
 
}
 
 
#journal .journal_action {
 
	padding-top: 4px;
 
	min-height: 2px;
 
	float: left
 
}
 
 
#journal .journal_action_params {
 
	clear: left;
 
	padding-left: 22px;
 
}
 
 
#journal .journal_repo {
 
	float: left;
 
	margin-left: 6px;
 
	padding-top: 3px;
 
}
 
 
#journal .date {
 
	clear: both;
 
	color: #777777;
 
	font-size: 11px;
 
	padding-left: 22px;
 
}
 
 
#journal .journal_repo .journal_repo_name {
 
	font-weight: bold;
 
	font-size: 1.1em;
 
}
 
 
#journal .compare_view {
 
	padding: 5px 0px 5px 0px;
 
	width: 95px;
 
}
 
 
.journal_highlight {
 
	font-weight: bold;
 
	padding: 0 2px;
 
	vertical-align: bottom;
 
}
 
 
.trending_language_tbl,.trending_language_tbl td {
 
	border: 0 !important;
 
	margin: 0 !important;
 
	padding: 0 !important;
 
}
 
 
.trending_language {
 
	background-color: #003367;
 
	color: #FFF;
 
	display: block;
 
	min-width: 20px;
 
	text-decoration: none;
 
	height: 12px;
 
	margin-bottom: 4px;
 
	margin-left: 5px;
 
	white-space: pre;
 
	padding: 3px;
 
}
 
 
h3.files_location {
 
	font-size: 1.8em;
 
	font-weight: 700;
 
	border-bottom: none !important;
 
	margin: 10px 0 !important;
 
}
 
 
#files_data dl dt {
 
	float: left;
 
	width: 115px;
 
	margin: 0 !important;
 
	padding: 5px;
 
}
 
 
#files_data dl dd {
 
	margin: 0 !important;
 
	padding: 5px !important;
 
}
 
 
#changeset_content {
 
	border: 1px solid #CCC;
 
	padding: 5px;
 
}
 
 
#changeset_compare_view_content {
 
	border: 1px solid #CCC;
 
	padding: 5px;
 
}
 
 
#changeset_content .container {
 
	min-height: 120px;
 
	font-size: 1.2em;
 
	overflow: hidden;
 
}
 
 
#changeset_compare_view_content .compare_view_commits {
 
	width: auto !important;
 
}
 
 
#changeset_compare_view_content .compare_view_commits td {
 
	padding: 0px 0px 0px 12px !important;
 
}
 
 
#changeset_content .container .right {
 
	float: right;
 
	width: 25%;
 
	text-align: right;
 
}
 
 
#changeset_content .container .left .message {
 
	font-style: italic;
 
	color: #556CB5;
 
	white-space: pre-wrap;
 
}
 
 
.cs_files .cur_cs {
 
	margin: 10px 2px;
 
	font-weight: bold;
 
}
 
 
.cs_files .node {
 
	float: left;
 
}
 
 
.cs_files .changes {
 
	float: right;
 
	color:#003367;
 
	
 
}
 
 
.cs_files .changes .added {
 
	background-color: #BBFFBB;
 
	float: left;
 
	text-align: center;
 
	font-size: 90%;
 
	font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
 
.cs_files .changes .deleted {
 
	background-color: #FF8888;
 
	float: left;
 
	text-align: center;
 
	font-size: 90%;
 
	font-size: 9px;
 
    padding: 2px 0px 2px 0px;
 
}
 
 
.cs_files .cs_added {
 
	background: url("../images/icons/page_white_add.png") no-repeat scroll
 
		3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	margin-top: 7px;
 
	text-align: left;
 
}
 
 
.cs_files .cs_changed {
 
	background: url("../images/icons/page_white_edit.png") no-repeat scroll
 
		3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	margin-top: 7px;
 
	text-align: left;
 
}
 
 
.cs_files .cs_removed {
 
	background: url("../images/icons/page_white_delete.png") no-repeat
 
		scroll 3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	margin-top: 7px;
 
	text-align: left;
 
}
 
 
#graph {
 
	overflow: hidden;
 
}
 
 
#graph_nodes {
 
	float: left;
 
	margin-right: -6px;
 
	margin-top: 0px;
 
}
 
 
#graph_content {
 
	width: 800px;
 
	float: left;
 
}
 
 
#graph_content .container_header {
 
	border: 1px solid #CCC;
 
	padding: 10px;
 
	height: 45px;
 
}
 
 
#graph_content #rev_range_container {
 
	padding: 10px 0px;
 
	clear: both;
 
}
 
 
#graph_content .container {
 
	border-bottom: 1px solid #CCC;
 
	border-left: 1px solid #CCC;
 
	border-right: 1px solid #CCC;
 
	min-height: 70px;
 
	overflow: hidden;
 
	font-size: 1.2em;
 
}
 
 
#graph_content .container .right {
 
	float: right;
 
	width: 28%;
 
	text-align: right;
 
	padding-bottom: 5px;
 
}
 
 
#graph_content .container .left .date {
 
	font-weight: 700;
 
	padding-bottom: 5px;
 
}
 
 
#graph_content .container .left .date span {
 
	vertical-align: text-top;
 
}
 
 
#graph_content .container .left .author {
 
	height: 22px;
 
}
 
 
#graph_content .container .left .author .user {
 
	color: #444444;
 
	float: left;
 
	font-size: 12px;
 
	margin-left: -4px;
 
	margin-top: 4px;
 
}
 
 
#graph_content .container .left .message {
 
	font-size: 100%;
 
	padding-top: 3px;
 
	white-space: pre-wrap;
 
}
 
 
#graph_content .container .left .message a:hover{
 
	text-decoration: none;
 
}
 
 
.right div {
 
	clear: both;
 
}
 
 
.right .changes .changed_total {
 
	border: 1px solid #DDD;
 
	display: block;
 
	float: right;
 
	text-align: center;
 
	min-width: 45px;
 
	cursor: pointer;
 
	background: #FD8;
 
	font-weight: bold;
 
}
 
 
.right .changes .added,.changed,.removed {
 
	border: 1px solid #DDD;
 
	display: block;
 
	float: right;
 
	text-align: center;
 
	min-width: 15px;
 
	cursor: help;
 
}
 
 
.right .changes .large {
 
	border: 1px solid #DDD;
 
	display: block;
 
	float: right;
 
	text-align: center;
 
	min-width: 45px;
 
	cursor: help;
 
	background: #54A9F7;
 
}
 
 
.right .changes .added {
 
	background: #BFB;
 
}
 
 
.right .changes .changed {
 
	background: #FD8;
 
}
 
 
.right .changes .removed {
 
	background: #F88;
 
}
 
 
.right .merge {
 
	vertical-align: top;
 
	font-size: 0.75em;
 
	font-weight: 700;
 
}
 
 
.right .parent {
 
	font-size: 90%;
 
	font-family: monospace;
 
	padding: 2px 2px 2px 2px;
 
}
 
.right .logtags{
 
	padding: 2px 2px 2px 2px;
 
}
 
.right .logtags .branchtag,.logtags .branchtag {
 
  padding: 1px 3px 2px;
 
  background-color: #bfbfbf;
 
  font-size: 9.75px;
 
  font-weight: bold;
 
  color: #ffffff;
 
  text-transform: uppercase;
 
  white-space: nowrap;
 
  -webkit-border-radius: 3px;
 
  -moz-border-radius: 3px;
 
  border-radius: 3px;
 
  padding-left:4px;
 
}
 
.right .logtags .branchtag a:hover,.logtags .branchtag a:hover{
 
	text-decoration: none;
 
}
 
.right .logtags .tagtag,.logtags .tagtag {
 
  padding: 1px 3px 2px;
 
  background-color: #62cffc;
 
  font-size: 9.75px;
 
  font-weight: bold;
 
  color: #ffffff;
 
  text-transform: uppercase;
 
  white-space: nowrap;
 
  -webkit-border-radius: 3px;
 
  -moz-border-radius: 3px;
 
  border-radius: 3px;
 
}
 
.right .logtags .tagtag a:hover,.logtags .tagtag a:hover{
 
    text-decoration: none;
 
}
 
div.browserblock {
 
	overflow: hidden;
 
	border: 1px solid #ccc;
 
	background: #f8f8f8;
 
	font-size: 100%;
 
	line-height: 125%;
 
	padding: 0;
 
}
 
 
div.browserblock .browser-header {
 
	background: #FFF;
 
	padding: 10px 0px 15px 0px;
 
	width: 100%;
 
}
 
 
div.browserblock .browser-nav {
 
	float: left
 
}
 
 
div.browserblock .browser-branch {
 
	float: left;
 
}
 
 
div.browserblock .browser-branch label {
 
	color: #4A4A4A;
 
	vertical-align: text-top;
 
}
 
 
div.browserblock .browser-header span {
 
	margin-left: 5px;
 
	font-weight: 700;
 
}
 
 
div.browserblock .browser-search {
 
	clear: both;
 
	padding: 8px 8px 0px 5px;
 
	height: 20px;
 
}
 
 
div.browserblock #node_filter_box {
 
	
 
}
 
 
div.browserblock .search_activate {
 
	float: left
 
}
 
 
div.browserblock .add_node {
 
	float: left;
 
	padding-left: 5px;
 
}
 
 
div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover
 
	{
 
	text-decoration: none !important;
 
}
 
 
div.browserblock .browser-body {
 
	background: #EEE;
 
	border-top: 1px solid #CCC;
 
}
 
 
table.code-browser {
 
	border-collapse: collapse;
 
	width: 100%;
 
}
 
 
table.code-browser tr {
 
	margin: 3px;
 
}
 
 
table.code-browser thead th {
 
	background-color: #EEE;
 
	height: 20px;
 
	font-size: 1.1em;
 
	font-weight: 700;
 
	text-align: left;
 
	padding-left: 10px;
 
}
 
 
table.code-browser tbody td {
 
	padding-left: 10px;
 
	height: 20px;
 
}
 
 
table.code-browser .browser-file {
 
	background: url("../images/icons/document_16.png") no-repeat scroll 3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	text-align: left;
 
}
 
 
.diffblock .changeset_file {
 
	background: url("../images/icons/file.png") no-repeat scroll 3px;
 
	height: 16px;
 
	padding-left: 22px;
 
	text-align: left;
 
	font-size: 14px;
 
}
 
 
.diffblock .changeset_header {
 
	margin-left: 6px !important;
 
}
 
 
table.code-browser .browser-dir {
 
	background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
 
	height: 16px;
 
	padding-left: 20px;
 
	text-align: left;
 
}
 
 
.box .search {
 
	clear: both;
 
	overflow: hidden;
 
	margin: 0;
 
	padding: 0 20px 10px;
 
}
 
 
.box .search div.search_path {
 
	background: none repeat scroll 0 0 #EEE;
 
	border: 1px solid #CCC;
 
	color: blue;
 
	margin-bottom: 10px;
 
	padding: 10px 0;
 
}
 
 
.box .search div.search_path div.link {
 
	font-weight: 700;
 
	margin-left: 25px;
 
}
 
 
.box .search div.search_path div.link a {
 
	color: #003367;
 
	cursor: pointer;
 
	text-decoration: none;
 
}
 
 
#path_unlock {
 
	color: red;
 
	font-size: 1.2em;
 
	padding-left: 4px;
 
}
 
 
.info_box span {
 
	margin-left: 3px;
 
	margin-right: 3px;
 
}
 
 
.info_box .rev {
 
	color: #003367;
 
	font-size: 1.6em;
 
	font-weight: bold;
 
	vertical-align: sub;
 
}
 
 
.info_box input#at_rev,.info_box input#size {
 
	background: #FFF;
 
	border-top: 1px solid #b3b3b3;
 
	border-left: 1px solid #b3b3b3;
 
	border-right: 1px solid #eaeaea;
 
	border-bottom: 1px solid #eaeaea;
 
	color: #000;
 
	font-size: 12px;
 
	margin: 0;
 
	padding: 1px 5px 1px;
 
}
 
 
.info_box input#view {
 
	text-align: center;
 
	padding: 4px 3px 2px 2px;
 
}
 
 
.yui-overlay,.yui-panel-container {
 
	visibility: hidden;
 
	position: absolute;
 
	z-index: 2;
 
}
 
 
.yui-tt {
 
	visibility: hidden;
 
	position: absolute;
 
	color: #666;
 
	background-color: #FFF;
 
	border: 2px solid #003367;
 
	font: 100% sans-serif;
 
	width: auto;
 
	opacity: 1px;
 
	padding: 8px;
 
	white-space: pre-wrap;
 
	-webkit-border-radius: 8px 8px 8px 8px;
 
	-khtml-border-radius: 8px 8px 8px 8px;
 
	-moz-border-radius: 8px 8px 8px 8px;
 
	border-radius: 8px 8px 8px 8px;
 
	box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
}
 
 
.ac {
 
	vertical-align: top;
 
}
 
 
.ac .yui-ac {
 
	position: relative;
 
	font-size: 100%;
 
}
 
 
.ac .perm_ac {
 
	width: 15em;
 
}
 
 
.ac .yui-ac-input {
 
	width: 100%;
 
}
 
 
.ac .yui-ac-container {
 
	position: absolute;
 
	top: 1.6em;
 
	width: 100%;
 
}
 
 
.ac .yui-ac-content {
 
	position: absolute;
 
	width: 100%;
 
	border: 1px solid gray;
 
	background: #fff;
 
	overflow: hidden;
 
	z-index: 9050;
 
}
 
 
.ac .yui-ac-shadow {
 
	position: absolute;
 
	width: 100%;
 
	background: #000;
 
	-moz-opacity: 0.1px;
 
	opacity: .10;
 
	filter: alpha(opacity =     10);
 
	z-index: 9049;
 
	margin: .3em;
 
}
 
 
.ac .yui-ac-content ul {
 
	width: 100%;
 
	margin: 0;
 
	padding: 0;
 
}
 
 
.ac .yui-ac-content li {
 
	cursor: default;
 
	white-space: nowrap;
 
	margin: 0;
 
	padding: 2px 5px;
 
}
 
 
.ac .yui-ac-content li.yui-ac-prehighlight {
 
	background: #B3D4FF;
 
}
 
 
.ac .yui-ac-content li.yui-ac-highlight {
 
	background: #556CB5;
 
	color: #FFF;
 
}
 
 
.follow {
 
	background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
 
	height: 16px;
 
	width: 20px;
 
	cursor: pointer;
 
	display: block;
 
	float: right;
 
	margin-top: 2px;
 
}
 
 
.following {
 
	background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
 
	height: 16px;
 
	width: 20px;
 
	cursor: pointer;
 
	display: block;
 
	float: right;
 
	margin-top: 2px;
 
}
 
 
.currently_following {
 
	padding-left: 10px;
 
	padding-bottom: 5px;
 
}
 
 
.add_icon {
 
	background: url("../images/icons/add.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	padding-top: 0px;
 
	text-align: left;
 
}
 
 
.edit_icon {
 
	background: url("../images/icons/folder_edit.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	padding-top: 0px;
 
	text-align: left;
 
}
 
 
.delete_icon {
 
	background: url("../images/icons/delete.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	padding-top: 0px;
 
	text-align: left;
 
}
 
 
.refresh_icon {
 
	background: url("../images/icons/arrow_refresh.png") no-repeat scroll
 
		3px;
 
	padding-left: 20px;
 
	padding-top: 0px;
 
	text-align: left;
 
}
 
 
.pull_icon {
 
	background: url("../images/icons/connect.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	padding-top: 0px;
 
	text-align: left;
 
}
 
 
.rss_icon {
 
	background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	padding-top: 0px;
 
	text-align: left;
 
}
 
 
.atom_icon {
 
	background: url("../images/icons/atom.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	padding-top: 0px;
 
	text-align: left;
 
}
 
 
.archive_icon {
 
	background: url("../images/icons/compress.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	text-align: left;
 
	padding-top: 1px;
 
}
 
 
.start_following_icon {
 
	background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	text-align: left;
 
	padding-top: 0px;
 
}
 
 
.stop_following_icon {
 
	background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
 
	padding-left: 20px;
 
	text-align: left;
 
	padding-top: 0px;
 
}
 
 
.action_button {
 
	border: 0;
 
	display: inline;
 
}
 
 
.action_button:hover {
 
	border: 0;
 
	text-decoration: underline;
 
	cursor: pointer;
 
}
 
 
#switch_repos {
 
	position: absolute;
 
	height: 25px;
 
	z-index: 1;
 
}
 
 
#switch_repos select {
 
	min-width: 150px;
 
	max-height: 250px;
 
	z-index: 1;
 
}
 
 
.breadcrumbs {
 
	border: medium none;
 
	color: #FFF;
 
	float: left;
 
	text-transform: uppercase;
 
	font-weight: 700;
 
	font-size: 14px;
 
	margin: 0;
 
	padding: 11px 0 11px 10px;
 
}
 
 
.breadcrumbs a {
 
	color: #FFF;
 
}
 
 
.flash_msg {
 
	
 
}
 
 
.flash_msg ul {
 
	
 
}
 
 
.error_msg {
 
	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(top, #ee5f5b, #c43c35);
 
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',
 
		endColorstr='#c43c35', GradientType=0 );
 
	border-color: #c43c35 #c43c35 #882a25;
 
}
 
 
.warning_msg {
 
	color: #404040 !important;
 
	background-color: #eedc94;
 
	background-repeat: repeat-x;
 
	background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1),
 
		to(#eedc94) );
 
	background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
 
	background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
 
	background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1),
 
		color-stop(100%, #eedc94) );
 
	background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
 
	background-image: -o-linear-gradient(top, #fceec1, #eedc94);
 
	background-image: linear-gradient(top, #fceec1, #eedc94);
 
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1',
 
		endColorstr='#eedc94', GradientType=0 );
 
	border-color: #eedc94 #eedc94 #e4c652;
 
}
 
 
.success_msg {
 
	background-color: #57a957;
 
	background-repeat: repeat-x !important;
 
	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(top, #62c462, #57a957);
 
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462',
 
		endColorstr='#57a957', GradientType=0 );
 
	border-color: #57a957 #57a957 #3d773d;
 
}
 
 
.notice_msg {
 
	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(top, #5bc0de, #339bb9);
 
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de',
 
		endColorstr='#339bb9', GradientType=0 );
 
	border-color: #339bb9 #339bb9 #22697d;
 
}
 
 
.success_msg,.error_msg,.notice_msg,.warning_msg {
 
	font-size: 12px;
 
	font-weight: 700;
 
	min-height: 14px;
 
	line-height: 14px;
 
	margin-bottom: 10px;
 
	margin-top: 0;
 
	display: block;
 
	overflow: auto;
 
	padding: 6px 10px 6px 10px;
 
	border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
 
	position: relative;
 
	color: #FFF;
 
	border-width: 1px;
 
	border-style: solid;
 
	-webkit-border-radius: 4px;
 
	-moz-border-radius: 4px;
 
	border-radius: 4px;
 
	-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
 
	-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
 
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
 
}
 
 
#msg_close {
 
	background: transparent url("../icons/cross_grey_small.png") no-repeat
 
		scroll 0 0;
 
	cursor: pointer;
 
	height: 16px;
 
	position: absolute;
 
	right: 5px;
 
	top: 5px;
 
	width: 16px;
 
}
 
 
div#legend_container table,div#legend_choices table {
 
	width: auto !important;
 
}
 
 
table#permissions_manage {
 
	width: 0 !important;
 
}
 
 
table#permissions_manage span.private_repo_msg {
 
	font-size: 0.8em;
 
	opacity: 0.6px;
 
}
 
 
table#permissions_manage td.private_repo_msg {
 
	font-size: 0.8em;
 
}
 
 
table#permissions_manage tr#add_perm_input td {
 
	vertical-align: middle;
 
}
 
 
div.gravatar {
 
	background-color: #FFF;
 
	border: 1px solid #D0D0D0;
 
	float: left;
 
	margin-right: 0.7em;
 
	padding: 2px 2px 0;
 
	-webkit-border-radius: 6px;
 
	-khtml-border-radius: 6px;
 
	-moz-border-radius: 6px;
 
	border-radius: 6px;
 
}
 
 
div.gravatar img {
 
	-webkit-border-radius: 4px;
 
	-khtml-border-radius: 4px;
 
	-moz-border-radius: 4px;
 
	border-radius: 4px;
 
}
 
 
#header,#content,#footer {
 
	min-width: 978px;
 
}
 
 
#content {
 
	clear: both;
 
	overflow: hidden;
 
	padding: 14px 10px;
 
}
 
 
#content div.box div.title div.search {
 
	
 
	border-left: 1px solid #316293;
 
}
 
 
#content div.box div.title div.search div.input input {
 
	border: 1px solid #316293;
 
}
 
 
.ui-button-small a:hover {
 
	
 
}
 
 
input.ui-button-small,.ui-button-small {
 
	background: #e5e3e3 url("../images/button.png") repeat-x !important;
 
	border-top: 1px solid #DDD !important;
 
	border-left: 1px solid #c6c6c6 !important;
 
	border-right: 1px solid #DDD !important;
 
	border-bottom: 1px solid #c6c6c6 !important;
 
	color: #515151 !important;
 
	outline: none !important;
 
	margin: 0 !important;
 
	-webkit-border-radius: 4px 4px 4px 4px !important;
 
	-khtml-border-radius: 4px 4px 4px 4px !important;
 
	-moz-border-radius: 4px 4px 4px 4px !important;
 
	border-radius: 4px 4px 4px 4px !important;
 
	box-shadow: 0 1px 0 #ececec !important;
 
	cursor: pointer !important;
 
	padding: 0px 2px 1px 2px;
 
}
 
 
input.ui-button-small:hover,.ui-button-small:hover {
 
	background: #b4b4b4 url("../images/button_selected.png") repeat-x
 
		!important;
 
	border-top: 1px solid #ccc !important;
 
	border-left: 1px solid #bebebe !important;
 
	border-right: 1px solid #b1b1b1 !important;
 
	border-bottom: 1px solid #afafaf !important;
 
	text-decoration: none;
 
}
 
 
input.ui-button-small-blue,.ui-button-small-blue {
 
	background: #4e85bb url("../images/button_highlight.png") repeat-x;
 
	border-top: 1px solid #5c91a4;
 
	border-left: 1px solid #2a6f89;
 
	border-right: 1px solid #2b7089;
 
	border-bottom: 1px solid #1a6480;
 
	color: #fff;
 
	-webkit-border-radius: 4px 4px 4px 4px;
 
	-khtml-border-radius: 4px 4px 4px 4px;
 
	-moz-border-radius: 4px 4px 4px 4px;
 
	border-radius: 4px 4px 4px 4px;
 
	box-shadow: 0 1px 0 #ececec;
 
	cursor: pointer;
 
	padding: 0px 2px 1px 2px;
 
}
 
 
input.ui-button-small-blue:hover {
 
	
 
}
 
 
ins,div.options a:hover {
 
	text-decoration: none;
 
}
 
 
img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url
 
	{
 
	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,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices
 
	{
 
	float: left;
 
}
 
 
#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 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
 
	{
 
	color: #bfe3ff;
 
}
 
 
#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
 
	{
 
	clear: both;
 
	overflow: hidden;
 
	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
 
	{
 
	color: #000;
 
	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;
 
	-moz-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.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 .left,#graph_content .container .left {
 
	float: left;
 
	width: 70%;
 
	padding-left: 5px;
 
}
 
 
#changeset_content .container .left .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;
 
	-moz-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;
 
}
 
 
/*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;
 
	-moz-border-radius: 3px;
 
	border-radius: 3px;
 
}
 
 
 
/** 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;
 
    -moz-border-radius: 3px;
 
    border-radius: 3px;
 
}
 
 
 
 
.comments {
 
    padding:10px 20px;
 
}
 
 
.comments .comment {
 
    border: 1px solid #ddd;
 
    margin-top: 10px;
 
    -webkit-border-radius: 4px;
 
    -moz-border-radius: 4px;
 
    border-radius: 4px;    
 
}
 
 
.comments .comment .meta {
 
    background: #f8f8f8;
 
    padding: 6px;
 
    border-bottom: 1px solid #ddd;
 
}
 
 
.comments .comment .meta img {
 
    vertical-align: middle;
 
}
 
 
.comments .comment .meta .user {
 
    font-weight: bold;
 
}
 
 
.comments .comment .meta .date {
 
    float: right;
 
}
 
 
.comments .comment .text {
 
    padding: 8px 6px 6px 14px;
 
    background-color: #FAFAFA;
 
}
 
 
.comments .comments-number{
 
	padding:0px 0px 10px 0px;
 
	font-weight: bold;
 
}
 
	color: #666;
 
	font-size: 16px;
 
}
 
/** comment form **/
 
 
.comment-form .clearfix{
 
	background: #EEE;
 
    -webkit-border-radius: 4px;
 
    -moz-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-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;
 
    color: #666;
 
}
 
 
.comment-form .comment-button{
 
	padding-top:5px;
 
}
 
 
.add-another-button {
 
    margin-left: 10px;
 
    margin-top: 10px;
 
    margin-bottom: 10px;
 
}
 
 
.comment .buttons {
 
    position: absolute;
 
    right:40px;
 
}
 
 
 
 
/** comment inline form **/
 
 
.comment-inline-form .clearfix{
 
    background: #EEE;
 
    -webkit-border-radius: 4px;
 
    -moz-border-radius: 4px;
 
    border-radius: 4px;
 
    padding: 5px;
 
}
 
 
div.comment-inline-form {
 
    margin-top: 5px;
 
    padding:2px 6px 8px 6px;
 
}
 
 
.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;
 
}
 
 
.comment-inline-form .comment-button{
 
    padding-top:5px;
 
}
 
\ No newline at end of file
rhodecode/public/js/rhodecode.js
Show inline comments
 
/**
 
RhodeCode JS Files
 
**/
 

	
 
if (typeof console == "undefined" || typeof console.log == "undefined"){
 
	console = { log: function() {} }
 
}
 

	
 

	
 
function str_repeat(i, m) {
 
	for (var o = []; m > 0; o[--m] = i);
 
	return o.join('');
 
}
 

	
 
/**
 
 * INJECT .format function into String
 
 * Usage: "My name is {0} {1}".format("Johny","Bravo")
 
 * Return "My name is Johny Bravo"
 
 * Inspired by https://gist.github.com/1049426
 
 */
 
String.prototype.format = function() {
 
	  
 
	  function format() {
 
	    var str = this;
 
	    var len = arguments.length+1;
 
	    var safe = undefined;
 
	    var arg = undefined;
 
	    
 
	    // For each {0} {1} {n...} replace with the argument in that position.  If 
 
	    // the argument is an object or an array it will be stringified to JSON.
 
	    for (var i=0; i < len; arg = arguments[i++]) {
 
	      safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
 
	      str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
 
	    }
 
	    return str;
 
	  }
 

	
 
	  // Save a reference of what may already exist under the property native.  
 
	  // Allows for doing something like: if("".format.native) { /* use native */ }
 
	  format.native = String.prototype.format;
 

	
 
	  // Replace the prototype property
 
	  return format;
 

	
 
}();
 

	
 

	
 
/**
 
 * SmartColorGenerator
 
 *
 
 *usage::
 
 *	var CG = new ColorGenerator();
 
 *  var col = CG.getColor(key); //returns array of RGB
 
 *  'rgb({0})'.format(col.join(',')
 
 * 
 
 * @returns {ColorGenerator}
 
 */
 
function ColorGenerator(){
 
	this.GOLDEN_RATIO = 0.618033988749895;
 
	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])];
 
        
 
    }
 
}
 

	
 

	
 

	
 

	
 

	
 
/**
 
 * 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)
 
		)
 
)
 

	
 
/**
 
 * 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='ERROR';
 
			YUD.setStyle(container,'opacity','1.0');
 
			YUD.setStyle(container,'color','red');
 
		}
 
	},args);
 
	
 
}
 

	
 
/**
 
 * tooltip activate
 
 */
 
var tooltip_activate = function(){
 
    function toolTipsId(){
 
        var ids = [];
 
        var tts = YUQ('.tooltip');
 
        for (var i = 0; i < tts.length; i++) {
 
            // if element doesn't not have and id 
 
        	//  autogenerate one for tooltip 
 
            if (!tts[i].id){
 
                tts[i].id='tt'+((i*100)+tts.length);
 
            }
 
            ids.push(tts[i].id);
 
        }
 
        return ids
 
    };
 
    var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
 
        context: [[toolTipsId()],"tl","bl",null,[0,5]],
 
        monitorresize:false,
 
        xyoffset :[0,0],
 
        autodismissdelay:300000,
 
        hidedelay:5,
 
        showdelay:20,
 
    });
 
}
 

	
 
/**
 
 * 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');
 
    });
 
}
 

	
 

	
 
/**
 
 * 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,'click',function(){
 
	   q_filter_field.value = '';
 
	});
 

	
 
	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 ajaxPOST = function(url,postData,success) {
 
    var sUrl = url;
 
    var callback = {
 
        success: success,
 
        failure: function (o) {
 
            alert("error");
 
        },
 
    };
 
    var postData = postData;
 
    var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
 
};
 

	
 

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

	
 
var createInlineForm = function(parent_tr, f_path, line) {
 
	var form = document.createElement('tr');
 
	YUD.addClass(form, 'comment-form-inline');
 
	var tmpl = YUD.get('comment-inline-form-template').innerHTML;
 
	tmpl = tmpl.format(f_path, line);
 
	form.innerHTML = '<td class="lineno new"></td>'+
 
		             '<td class="lineno old"></td>'+ 
 
			         '<td>{0}</td>'.format(tmpl);
 

	
 
	// create event for hide button
 
	form = new YAHOO.util.Element(form);
 
	var form_hide_button = new YAHOO.util.Element(form.getElementsByClassName('hide-inline-form')[0]);
 
	form_hide_button.on('click', function(e) {
 
		var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
 
		removeInlineForm(newtr);
 
		YUD.removeClass(parent_tr, 'form-open');
 
	});
 
	return form
 
}
 
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[1];
 
	} else if (o.length == 2) {
 
		line = o[1];
 
	}
 

	
 
	return line
 
}
 
\ No newline at end of file
rhodecode/templates/changeset/changeset.html
Show inline comments
 
## -*- coding: utf-8 -*-
 

	
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(u'Home',h.url('/'))}
 
    &raquo;
 
    ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('changelog')}     
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <div class="table">
 
		<div class="diffblock">
 
			<div class="code-header">
 
				<div>
 
				${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
 
				 &raquo; <span>${h.link_to(_('raw diff'),
 
				h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span>
 
				 &raquo; <span>${h.link_to(_('download diff'),
 
				h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span>
 
				</div>
 
			</div>
 
		</div>
 
	    <div id="changeset_content">
 
			<div class="container">
 
	             <div class="left">
 
	                 <div class="date">${_('commit')} ${c.changeset.revision}: ${h.short_id(c.changeset.raw_id)}@${c.changeset.date}</div>
 
	                 <div class="author">
 
	                     <div class="gravatar">
 
	                         <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
 
	                     </div>
 
	                     <span>${h.person(c.changeset.author)}</span><br/>
 
	                     <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
 
	                 </div>
 
	                 <div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</div>
 
	             </div>
 
	             <div class="right">
 
		             <div class="changes">
 
                        % if len(c.changeset.affected_files) <= c.affected_files_cut_off:	             
 
		                 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
 
		                 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
 
		                 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
 
	                    % else:
 
                         <span class="removed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
 
                         <span class="changed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
 
                         <span class="added"   title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>	                    
 
	                    % endif		                 
 
		             </div>                  
 
		                 %if len(c.changeset.parents)>1:
 
		                 <div class="merge">
 
		                     ${_('merge')}<img alt="merge" src="${h.url('/images/icons/arrow_join.png')}"/>
 
		                 </div>
 
		                 %endif
 
		                 
 
		            %if c.changeset.parents:
 
		             %for p_cs in reversed(c.changeset.parents):
 
		                 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(h.short_id(p_cs.raw_id),
 
		                     h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
 
		                 </div>
 
		             %endfor
 
                    %else: 
 
                        <div class="parent">${_('No parents')}</div>   
 
                    %endif		             
 
		         <span class="logtags">
 
		             <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
 
		             ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
 
		             %for tag in c.changeset.tags:
 
		                 <span class="tagtag"  title="${'%s %s' % (_('tag'),tag)}">
 
		                 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
 
		             %endfor
 
		         </span>                                                                 
 
	                </div>              
 
	        </div>
 
	        <span style="font-size:1.1em;font-weight: bold">
 
	        ${_('%s files affected with %s additions and %s deletions.') % (len(c.changeset.affected_files),c.lines_added,c.lines_deleted)}
 
	        </span>
 
	        <div class="cs_files">
 
	                %for change,filenode,diff,cs1,cs2,stat in c.changes:
 
	                    <div class="cs_${change}">
 
		                    <div class="node">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor='C-%s-%s' % (h.short_id(filenode.changeset.raw_id),h.safeid(h.safe_unicode(filenode.path)))))}</div>
 
		                    <div class="changes">${h.fancy_file_stats(stat)}</div>
 
	                    </div>
 
	                %endfor
 
	                % if c.cut_off:
 
	                  ${_('Changeset was too big and was cut off...')}
 
	                % endif
 
	        </div>         
 
	    </div>
 
	    
 
    </div>
 
    	
 
	%for change,filenode,diff,cs1,cs2,stat in c.changes:
 
		%if change !='removed':
 
		<div style="clear:both;height:10px"></div>
 
		<div class="diffblock  margined">
 
			<div id="${'C-%s-%s' % (h.short_id(filenode.changeset.raw_id),h.safeid(h.safe_unicode(filenode.path)))}" class="code-header">
 
				<div class="changeset_header">
 
					<span class="changeset_file">
 
						${h.link_to_if(change!='removed',h.safe_unicode(filenode.path),h.url('files_home',repo_name=c.repo_name,
 
						revision=filenode.changeset.raw_id,f_path=h.safe_unicode(filenode.path)))}
 
					</span>
 
					%if 1:
 
					&raquo; <span>${h.link_to(_('diff'),
 
					h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff'))}</span>
 
					&raquo; <span>${h.link_to(_('raw diff'),
 
					h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw'))}</span>
 
					&raquo; <span>${h.link_to(_('download diff'),
 
					h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download'))}</span>
 
					%endif
 
				</div>
 
			</div>
 
			<div class="code-body">        
 
                <div class="full_f_path" path="${filenode.path}"></div>        
 
					%if diff:
 
						${diff|n}
 
					%else:
 
						${_('No changes in this file')}
 
					%endif
 
			</div>
 
		</div>
 
		%endif
 
	%endfor
 
  
 
    <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
 
    ## template for inline comment form
 
    ${comment.comment_inline_form()}
 
    
 
    <div class="comments">
 
        <div class="comments-number">${len(c.comments)} comment(s)</div>
 
        <div class="comments-number">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
 
        
 
        %for path, lines in c.inline_comments:
 
            <div class="inline-comment-placeholder" path="${path} ">
 
            % for line,comments in lines.iteritems():
 
                <div class="inline-comment-placeholder-line" line="${line}"> 
 
                %for co in comments:
 
                    ${comment.comment_block(co)}
 
                %endfor
 
                </div>
 
            %endfor
 
            </div>
 
        %endfor        
 
        
 
        %for co in c.comments:
 
            ${comment.comment_block(co)}
 
        %endfor
 
        %if c.rhodecode_user.username != 'default':
 
        <div class="comment-form">
 
            ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id))}
 
            <strong>Leave a comment</strong>
 
            <strong>${_('Leave a comment')}</strong>
 
            <div class="clearfix">
 
                <div class="comment-help">${_('Comments parsed using RST syntax')}</div>
 
                    ${h.textarea('text')}
 
            </div>
 
            <div class="comment-button">
 
            ${h.submit('save', _('Comment'), class_='ui-button')}
 
            </div>
 
            ${h.end_form()}
 
        </div>
 
        %endif
 
    </div>
 
    <script type="text/javascript">
 
      var deleteComment = function(comment_id){
 

	
 
          var url = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}".replace('__COMMENT_ID__',comment_id);
 
          var postData = '_method=delete';
 
          var success = function(o){
 
              var n = YUD.get('comment-'+comment_id);
 
              n.parentNode.removeChild(n);
 
          }
 
          ajaxPOST(url,postData,success);
 
      } 
 

	
 
      YUE.onDOMReady(function(){
 
    	  YUE.on(YUQ('.line'),'mouseenter',function(e){
 
    		  var tr = e.currentTarget;
 
              if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context')){
 
                  return
 
              }    		  
 
    		  YUD.addClass(tr,'highlight');
 
    	  });
 
          YUE.on(YUQ('.line'),'mouseleave',function(e){
 
              YUD.removeClass(e.currentTarget,'highlight');
 
          });
 
          
 
          YUE.on(YUQ('.line'),'click',function(e){
 
        	  var tr = e.currentTarget;
 
        	  if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context')){
 
        		  return
 
        	  }
 
        	  YUD.addClass(tr,'form-open');
 
        	  var node = tr.parentNode.parentNode.parentNode.getElementsByClassName('full_f_path')[0];
 
        	  var f_path = YUD.getAttribute(node,'path');
 
        	  var lineno = getLineNo(tr);
 
        	  var form = createInlineForm(tr, f_path, lineno);
 
        	  YUD.insertAfter(form,tr);
 
          })
 
      })
 
      
 
    </script> 
 
  </div>	
 
</%def>
rhodecode/templates/changeset/changeset_file_comment.html
Show inline comments
 
##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}">
 
  	<div class="meta">
 
  		<span class="user">
 
  			<img src="${h.gravatar_url(co.author.email, 20)}" />
 
  			${co.author.username}
 
  		</span>
 
  		<a href="${h.url.current(anchor='comment-%s' % co.comment_id)}"> ${_('commented on')} </a>
 
  		${h.short_id(co.revision)}
 
  		%if co.f_path:
 
  			${_(' in file ')}
 
  			${co.f_path}:L${co.line_no}
 
  		%endif
 
  		<span class="date">
 
  			${h.age(co.modified_at)}
 
  		</span>
 
  	</div>
 
  	<div class="text">
 
  		%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-button-small">${_('Delete')}</span>
 
  			</div>
 
  		%endif
 
  		${h.rst(co.text)|n}
 
  	</div>
 
  </div>
 
</%def>
 
 
 
 
<%def name="comment_inline_form()">
 
<div id='comment-inline-form-template' style="display:none">
 
  <div class="comment-inline-form">
 
      ${h.form(h.url('changeset_comment', repo_name=c.repo_name, revision=c.changeset.raw_id))}
 
      <div class="clearfix">
 
          <div class="comment-help">${_('Commenting on line')} {1} ${_('comments parsed using RST syntax')}</div>
 
              ${h.textarea('text')}
 
      </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-button-small')}
 
      ${h.reset('hide-inline-form', _('Hide'), class_='ui-button-small hide-inline-form')}
 
      </div>
 
      ${h.end_form()}
 
  </div>
 
</div>  
 
</%def>
 
\ No newline at end of file
0 comments (0 inline, 0 general)