@@ -379,548 +379,548 @@ def person(author):
# Maybe it's a username?
_author = author_name(author)
user = User.get_by_username(_author, case_insensitive=True,
cache=True)
if user is not None:
return person_getter(user)
# Still nothing? Just pass back the author name then
return _author
def bool2icon(value):
"""Returns True/False values represented as small html image of true/false
icons
:param value: bool value
"""
if value is True:
return HTML.tag('img', src=url("/images/icons/accept.png"),
alt=_('True'))
if value is False:
return HTML.tag('img', src=url("/images/icons/cancel.png"),
alt=_('False'))
return value
def action_parser(user_log, feed=False):
This helper will action_map the specified string action into translated
fancy names with icons and links
:param user_log: user log instance
:param feed: use output for feeds (no html and fancy icons)
action = user_log.action
action_params = ' '
x = action.split(':')
if len(x) > 1:
action, action_params = x
def get_cs_links():
revs_limit = 3 # display this amount always
revs_top_limit = 50 # show upto this amount of changesets hidden
revs_ids = action_params.split(',')
deleted = user_log.repository is None
if deleted:
return ','.join(revs_ids)
repo_name = user_log.repository.repo_name
repo = user_log.repository.scm_instance
message = lambda rev: rev.message
lnk = lambda rev, repo_name: (
link_to('r%s:%s' % (rev.revision, rev.short_id),
url('changeset_home', repo_name=repo_name,
revision=rev.raw_id),
title=tooltip(message(rev)), class_='tooltip')
)
# get only max revs_top_limit of changeset for performance/ui reasons
revs = [
x for x in repo.get_changesets(revs_ids[0],
revs_ids[:revs_top_limit][-1])
]
cs_links = []
cs_links.append(" " + ', '.join(
[lnk(rev, repo_name) for rev in revs[:revs_limit]]
compare_view = (
' <div class="compare_view tooltip" title="%s">'
'<a href="%s">%s</a> </div>' % (
_('Show all combined changesets %s->%s') % (
revs_ids[0], revs_ids[-1]
),
revision='%s...%s' % (revs_ids[0], revs_ids[-1])
_('compare view')
# if we have exactly one more than normally displayed
# just display it, takes less space than displaying
# "and 1 more revisions"
if len(revs_ids) == revs_limit + 1:
rev = revs[revs_limit]
cs_links.append(", " + lnk(rev, repo_name))
# hidden-by-default ones
if len(revs_ids) > revs_limit + 1:
uniq_id = revs_ids[0]
html_tmpl = (
'<span> %s <a class="show_more" id="_%s" '
'href="#more">%s</a> %s</span>'
if not feed:
cs_links.append(html_tmpl % (
_('and'),
uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
_('revisions')
html_tmpl = '<span id="%s" style="display:none">, %s </span>'
else:
html_tmpl = '<span id="%s"> %s </span>'
morelinks = ', '.join(
[lnk(rev, repo_name) for rev in revs[revs_limit:]]
if len(revs_ids) > revs_top_limit:
morelinks += ', ...'
cs_links.append(html_tmpl % (uniq_id, morelinks))
if len(revs) > 1:
cs_links.append(compare_view)
return ''.join(cs_links)
def get_fork_name():
repo_name = action_params
return _('fork name ') + str(link_to(action_params, url('summary_home',
repo_name=repo_name,)))
action_map = {'user_deleted_repo': (_('[deleted] repository'), None),
'user_created_repo': (_('[created] repository'), None),
'user_created_fork': (_('[created] repository as fork'), None),
'user_forked_repo': (_('[forked] repository'), get_fork_name),
'user_updated_repo': (_('[updated] repository'), None),
'admin_deleted_repo': (_('[delete] repository'), None),
'admin_created_repo': (_('[created] repository'), None),
'admin_forked_repo': (_('[forked] repository'), None),
'admin_updated_repo': (_('[updated] repository'), None),
'push': (_('[pushed] into'), get_cs_links),
'push_local': (_('[committed via RhodeCode] into'), get_cs_links),
'push_remote': (_('[pulled from remote] into'), get_cs_links),
'pull': (_('[pulled] from'), None),
'started_following_repo': (_('[started following] repository'), None),
'stopped_following_repo': (_('[stopped following] repository'), None),
}
action_str = action_map.get(action, action)
if feed:
action = action_str[0].replace('[', '').replace(']', '')
action = action_str[0]\
.replace('[', '<span class="journal_highlight">')\
.replace(']', '</span>')
action_params_func = lambda: ""
if callable(action_str[1]):
action_params_func = action_str[1]
return [literal(action), action_params_func]
def action_parser_icon(user_log):
action_params = None
tmpl = """<img src="%s%s" alt="%s"/>"""
map = {'user_deleted_repo':'database_delete.png',
'user_created_repo':'database_add.png',
'user_created_fork':'arrow_divide.png',
'user_forked_repo':'arrow_divide.png',
'user_updated_repo':'database_edit.png',
'admin_deleted_repo':'database_delete.png',
'admin_created_repo':'database_add.png',
'admin_forked_repo':'arrow_divide.png',
'admin_updated_repo':'database_edit.png',
'push':'script_add.png',
'push_local':'script_edit.png',
'push_remote':'connect.png',
'pull':'down_16.png',
'started_following_repo':'heart_add.png',
'stopped_following_repo':'heart_delete.png',
return literal(tmpl % ((url('/images/icons/')),
map.get(action, action), action))
#==============================================================================
# PERMS
from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
HasRepoPermissionAny, HasRepoPermissionAll
# GRAVATAR URL
def gravatar_url(email_address, size=30):
if (not str2bool(config['app_conf'].get('use_gravatar')) or
not email_address or email_address == 'anonymous@rhodecode.org'):
f = lambda a, l: min(l, key=lambda x: abs(x - a))
return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
default = 'identicon'
baseurl_nossl = "http://www.gravatar.com/avatar/"
baseurl_ssl = "https://secure.gravatar.com/avatar/"
baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
if isinstance(email_address, unicode):
#hashlib crashes on unicode items
email_address = safe_str(email_address)
# construct the url
gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
return gravatar_url
# REPO PAGER, PAGER FOR REPOSITORY
class RepoPage(Page):
def __init__(self, collection, page=1, items_per_page=20,
item_count=None, url=None, **kwargs):
"""Create a "RepoPage" instance. special pager for paging
repository
self._url_generator = url
# Safe the kwargs class-wide so they can be used in the pager() method
self.kwargs = kwargs
# Save a reference to the collection
self.original_collection = collection
self.collection = collection
# The self.page is the number of the current page.
# The first page has the number 1!
try:
self.page = int(page) # make it int() if we get it as a string
except (ValueError, TypeError):
self.page = 1
self.items_per_page = items_per_page
# Unless the user tells us how many items the collections has
# we calculate that ourselves.
if item_count is not None:
self.item_count = item_count
self.item_count = len(self.collection)
# Compute the number of the first and last available page
if self.item_count > 0:
self.first_page = 1
self.page_count = int(math.ceil(float(self.item_count) /
self.items_per_page))
self.last_page = self.first_page + self.page_count - 1
# Make sure that the requested page number is the range of
# valid pages
if self.page > self.last_page:
self.page = self.last_page
elif self.page < self.first_page:
self.page = self.first_page
# Note: the number of items on this page can be less than
# items_per_page if the last page is not full
self.first_item = max(0, (self.item_count) - (self.page *
items_per_page))
self.last_item = ((self.item_count - 1) - items_per_page *
(self.page - 1))
self.items = list(self.collection[self.first_item:self.last_item + 1])
# Links to previous and next page
if self.page > self.first_page:
self.previous_page = self.page - 1
self.previous_page = None
if self.page < self.last_page:
self.next_page = self.page + 1
self.next_page = None
# No items available
self.first_page = None
self.page_count = 0
self.last_page = None
self.first_item = None
self.last_item = None
self.items = []
# This is a subclass of the 'list' type. Initialise the list now.
list.__init__(self, reversed(self.items))
def changed_tooltip(nodes):
Generates a html string for changed nodes in changeset page.
It limits the output to 30 entries
:param nodes: LazyNodesGenerator
if nodes:
pref = ': <br/> '
suf = ''
if len(nodes) > 30:
suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
return literal(pref + '<br/> '.join([safe_unicode(x.path)
for x in nodes[:30]]) + suf)
return ': ' + _('No Files')
def repo_link(groups_and_repos):
Makes a breadcrumbs link to repo within a group
joins » on each group to create a fancy link
ex::
group >> subgroup >> repo
:param groups_and_repos:
groups, repo_name = groups_and_repos
if not groups:
return repo_name
def make_link(group):
return link_to(group.name, url('repos_group_home',
group_name=group.group_name))
return literal(' » '.join(map(make_link, groups)) + \
" » " + repo_name)
def fancy_file_stats(stats):
Displays a fancy two colored bar for number of added/deleted
lines of code on file
:param stats: two element list of added/deleted lines of code
a, d, t = stats[0], stats[1], stats[0] + stats[1]
width = 100
unit = float(width) / (t or 1)
# needs > 9% of width to be visible or 0 to be hidden
a_p = max(9, unit * a) if a > 0 else 0
d_p = max(9, unit * d) if d > 0 else 0
p_sum = a_p + d_p
if p_sum > width:
#adjust the percentage to be == 100% since we adjusted to 9
if a_p > d_p:
a_p = a_p - (p_sum - width)
d_p = d_p - (p_sum - width)
a_v = a if a > 0 else ''
d_v = d if d > 0 else ''
def cgen(l_type):
mapping = {'tr': 'top-right-rounded-corner',
'tl': 'top-left-rounded-corner',
'br': 'bottom-right-rounded-corner',
'bl': 'bottom-left-rounded-corner'}
mapping = {'tr': 'top-right-rounded-corner-mid',
'tl': 'top-left-rounded-corner-mid',
'br': 'bottom-right-rounded-corner-mid',
'bl': 'bottom-left-rounded-corner-mid'}
map_getter = lambda x: mapping[x]
if l_type == 'a' and d_v:
#case when added and deleted are present
return ' '.join(map(map_getter, ['tl', 'bl']))
if l_type == 'a' and not d_v:
return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
if l_type == 'd' and a_v:
return ' '.join(map(map_getter, ['tr', 'br']))
if l_type == 'd' and not a_v:
d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
cgen('a'), a_p, a_v
d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
cgen('d'), d_p, d_v
return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
def urlify_text(text_):
import re
url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
'''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
def url_func(match_obj):
url_full = match_obj.groups()[0]
return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
return literal(url_pat.sub(url_func, text_))
def urlify_changesets(text_, repository):
Extract revision ids from changeset and make link from them
:param text_:
:param repository:
URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
rev = match_obj.groups()[0]
pref = ''
if match_obj.group().startswith(' '):
pref = ' '
tmpl = (
'%(pref)s<a class="%(cls)s" href="%(url)s">'
'%(rev)s'
'</a>'
return tmpl % {
'pref': pref,
'cls': 'revision-link',
'url': url('changeset_home', repo_name=repository, revision=rev),
'rev': rev,
newtext = URL_PAT.sub(url_func, text_)
return newtext
def urlify_commit(text_, repository=None, link_=None):
Parses given text message and makes proper links.
issues are linked to given issue-server, and rest is a changeset link
if link_ is given, in other case it's a plain text
:param link_: changeset link
import traceback
def escaper(string):
return string.replace('<', '<').replace('>', '>')
def linkify_others(t, l):
urls = re.compile(r'(\<a.*?\<\/a\>)',)
links = []
for e in urls.split(t):
if not urls.match(e):
links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
links.append(e)
return ''.join(links)
# urlify changesets - extrac revisions and make link out of them
text_ = urlify_changesets(escaper(text_), repository)
conf = config['app_conf']
URL_PAT = re.compile(r'%s' % conf.get('issue_pat'))
if URL_PAT:
ISSUE_SERVER_LNK = conf.get('issue_server_link')
ISSUE_PREFIX = conf.get('issue_prefix')
issue_id = ''.join(match_obj.groups())
'%(issue-prefix)s%(id-repr)s'
url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
if repository:
url = url.replace('{repo}', repository)
'cls': 'issue-tracker-link',
'url': url,
'id-repr': issue_id,
'issue-prefix': ISSUE_PREFIX,
'serv': ISSUE_SERVER_LNK,
if link_:
# wrap not links into final link => link_
newtext = linkify_others(newtext, link_)
return literal(newtext)
except:
log.error(traceback.format_exc())
pass
return text_
def rst(source):
return literal('<div class="rst-block">%s</div>' %
MarkupRenderer.rst(source))
def rst_w_mentions(source):
Wrapped rst renderer with @mention highlighting
:param source:
MarkupRenderer.rst_with_mentions(source))
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td
{
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
margin: 0;
padding: 0;
body {
line-height: 1;
height: 100%;
background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
font-family: Lucida Grande, Verdana, Lucida Sans Regular,
Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
color: #000;
font-size: 12px;
ol,ul {
list-style: none;
blockquote,q {
quotes: none;
blockquote:before,blockquote:after,q:before,q:after {
content: none;
:focus {
del {
text-decoration: line-through;
table {
border-collapse: collapse;
border-spacing: 0;
html {
a {
color: #003367;
text-decoration: none;
cursor: pointer;
a:hover {
color: #316293;
text-decoration: underline;
h1,h2,h3,h4,h5,h6 {
color: #292929;
font-weight: 700;
h1 {
font-size: 22px;
h2 {
font-size: 20px;
h3 {
font-size: 18px;
h4 {
font-size: 16px;
h5 {
font-size: 14px;
h6 {
font-size: 11px;
ul.circle {
list-style-type: circle;
ul.disc {
list-style-type: disc;
ul.square {
list-style-type: square;
ol.lower-roman {
list-style-type: lower-roman;
ol.upper-roman {
list-style-type: upper-roman;
ol.lower-alpha {
list-style-type: lower-alpha;
ol.upper-alpha {
list-style-type: upper-alpha;
ol.decimal {
list-style-type: decimal;
div.color {
clear: both;
overflow: hidden;
position: absolute;
background: #FFF;
margin: 7px 0 0 60px;
padding: 1px 1px 1px 0;
div.color a {
width: 15px;
height: 15px;
display: block;
float: left;
margin: 0 0 0 1px;
div.options {
margin: 7px 0 0 162px;
div.options a {
height: 1%;
padding: 3px 8px;
.top-left-rounded-corner {
-webkit-border-top-left-radius: 8px;
-khtml-border-radius-topleft: 8px;
-moz-border-radius-topleft: 8px;
border-top-left-radius: 8px;
.top-right-rounded-corner {
-webkit-border-top-right-radius: 8px;
-khtml-border-radius-topright: 8px;
-moz-border-radius-topright: 8px;
border-top-right-radius: 8px;
.bottom-left-rounded-corner {
-webkit-border-bottom-left-radius: 8px;
-khtml-border-radius-bottomleft: 8px;
-moz-border-radius-bottomleft: 8px;
border-bottom-left-radius: 8px;
.bottom-right-rounded-corner {
-webkit-border-bottom-right-radius: 8px;
-khtml-border-radius-bottomright: 8px;
-moz-border-radius-bottomright: 8px;
border-bottom-right-radius: 8px;
.top-left-rounded-corner-mid {
-webkit-border-top-left-radius: 4px;
-khtml-border-radius-topleft: 4px;
-moz-border-radius-topleft: 4px;
border-top-left-radius: 4px;
.top-right-rounded-corner-mid {
-webkit-border-top-right-radius: 4px;
-khtml-border-radius-topright: 4px;
-moz-border-radius-topright: 4px;
border-top-right-radius: 4px;
.bottom-left-rounded-corner-mid {
-webkit-border-bottom-left-radius: 4px;
-khtml-border-radius-bottomleft: 4px;
-moz-border-radius-bottomleft: 4px;
border-bottom-left-radius: 4px;
.bottom-right-rounded-corner-mid {
-webkit-border-bottom-right-radius: 4px;
-khtml-border-radius-bottomright: 4px;
-moz-border-radius-bottomright: 4px;
border-bottom-right-radius: 4px;
.help-block {
color: #999999;
margin-bottom: 0;
margin-top: 5px;
#header {
padding: 0 10px;
#header ul#logged-user {
margin-bottom: 5px !important;
-webkit-border-radius: 0px 0px 8px 8px;
-khtml-border-radius: 0px 0px 8px 8px;
-moz-border-radius: 0px 0px 8px 8px;
border-radius: 0px 0px 8px 8px;
height: 37px;
background-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);
#header ul#logged-user li {
margin: 8px 0 0;
padding: 4px 12px;
border-left: 1px solid #316293;
#header ul#logged-user li.first {
border-left: none;
margin: 4px;
#header ul#logged-user li.first div.gravatar {
margin-top: -2px;
#header ul#logged-user li.first div.account {
padding-top: 4px;
#header ul#logged-user li.last {
border-right: none;
#header ul#logged-user li a {
color: #fff;
#header ul#logged-user li a:hover {
#header ul#logged-user li.highlight a {
#header ul#logged-user li.highlight a:hover {
color: #FFF;
#header #header-inner {
min-height: 44px;
position: relative;
background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1),to(#eedc94) );
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
-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;
#header #header-inner.hover{
position: fixed !important;
width: 100% !important;
margin-left: -10px !important;
z-index: 10000;
-webkit-border-radius: 0px 0px 0px 0px;
-khtml-border-radius: 0px 0px 0px 0px;
-moz-border-radius: 0px 0px 0px 0px;
border-radius: 0px 0px 0px 0px;
#header #header-inner #home a {
height: 40px;
width: 46px;
background: url("../images/button_home.png");
background-position: 0 0;
#header #header-inner #home a:hover {
background-position: 0 -40px;
#header #header-inner #logo {
#header #header-inner #logo h1 {
margin: 12px 0 0 13px;
#header #header-inner #logo a {
#header #header-inner #logo a:hover {
color: #bfe3ff;
#header #header-inner #quick,#header #header-inner #quick ul {
float: right;
list-style-type: none;
list-style-position: outside;
margin: 8px 8px 0 0;
#header #header-inner #quick li {
margin: 0 5px 0 0;
#header #header-inner #quick li a.menu_link {
top: 0;
left: 0;
background: #369;
#header #header-inner #quick li span.short {
padding: 9px 6px 8px 6px;
#header #header-inner #quick li span {
right: 0;
border-left: 1px solid #3f6f9f;
padding: 10px 12px 8px 10px;
#header #header-inner #quick li span.normal {
border: none;
padding: 10px 12px 8px;
#header #header-inner #quick li span.icon {
border-right: 1px solid #2e5c89;
padding: 8px 6px 4px;
#header #header-inner #quick li span.icon_short {
#header #header-inner #quick li span.icon img,#header #header-inner #quick li span.icon_short img
margin: 0px -2px 0px 0px;
#header #header-inner #quick li a:hover {
background: #4e4e4e no-repeat top left;
#header #header-inner #quick li a:hover span {
border-left: 1px solid #545454;
#header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short
border-right: 1px solid #464646;
#header #header-inner #quick ul {
top: 29px;
min-width: 200px;
display: none;
border: 1px solid #666;
border-top: 1px solid #003367;
z-index: 100;
margin: 0px 0px 0px 0px;
#header #header-inner #quick ul.repo_switcher {
max-height: 275px;
overflow-x: hidden;
overflow-y: auto;
#header #header-inner #quick ul.repo_switcher li.qfilter_rs {
float: none;
border-bottom: 2px solid #003367;
#header #header-inner #quick .repo_switcher_type {
top: 9px;
#header #header-inner #quick li ul li {
border-bottom: 1px solid #ddd;
#header #header-inner #quick li ul li a {
width: 182px;
height: auto;
font-weight: 400;
padding: 7px 9px;
#header #header-inner #quick li ul li a:hover {
#header #header-inner #quick ul ul {
top: auto;
#header #header-inner #quick li ul ul {
right: 200px;
overflow: auto;
white-space: normal;
#header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover
background: url("../images/icons/book.png") no-repeat scroll 4px 9px
#FFF;
width: 167px;
padding: 12px 9px 7px 24px;
#header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover
background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
min-width: 167px;
#header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover
background: url("../images/icons/lock_open.png") no-repeat scroll 4px
9px #FFF;
#header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover
background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
margin: 0 0 0 14px;
#header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover
background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
#header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover
background: url("../images/icons/database_edit.png") no-repeat scroll
4px 9px #FFF;
#header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover
background: url("../images/icons/database_link.png") no-repeat scroll
#header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover
background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
#header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover
background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
#header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover
background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
Status change: