Cloned DMOJ

This commit is contained in:
thanhluong 2020-01-21 15:35:58 +09:00
parent f623974b58
commit 49dc9ff10c
513 changed files with 132349 additions and 39 deletions

View file

@ -0,0 +1,32 @@
<thead>
<tr>
<th class="header rank">{{ rank_header or _("Rank") }}</th>
{% block after_rank_head %}{% endblock %}
<th class="header username">{{ _('Username') }}</th>
{% block before_point_head %}{% endblock %}
<th class="header points">
{% if sort_links %}<a href="{{ sort_links.performance_points }}">{% endif %}
{{ _('Points') }}
{%- if sort_links %}{{ sort_order.performance_points }}</a>{% endif %}
</th>
{% block after_point_head %}{% endblock %}
</tr>
</thead>
<tbody>
{% for rank, user in users %}
<tr id="user-{{ user.user.username }}" {% block row_extra scoped %}{% endblock %}>
<td>{{ rank }}</td>
{% block after_rank scoped %}{% endblock %}
<td class="user-name">{{ link_user(user) }} {% block user_data scoped %}{% endblock %}</td>
{% block before_point scoped %}{% endblock %}
{% block point scoped %}
<td title="{{ user.performance_points|floatformat(2) }}" class="user-points">
{{ user.performance_points|floatformat(0) }}
</td>
{% endblock %}
{% block after_point scoped %}{% endblock %}
</tr>
{% endfor %}
</tbody>

View file

@ -0,0 +1,83 @@
{% extends "common-content.html" %}
{% block js_media %}
{% block users_js_media %}{% endblock %}
<script>
$(function () {
$('#search-handle').replaceWith($('<select>').attr({
id: 'search-handle',
name: 'handle',
onchange: 'form.submit()'
}));
var in_user_redirect = false;
$('#search-handle').select2({
placeholder: '{{ _('Search by handle...') }}',
ajax: {
url: '{{ url('user_search_select2_ajax') }}'
},
minimumInputLength: 1,
escapeMarkup: function (markup) {
return markup;
},
templateResult: function (data, container) {
return $('<span>')
.append($('<img>', {
'class': 'user-search-image', src: data.gravatar_url,
width: 24, height: 24
}))
.append($('<span>', {'class': data.display_rank + ' user-search-name'}).text(data.text))
.append($('<a>', {href: '/user/' + data.text, 'class': 'user-redirect'})
.append($('<i>', {'class': 'fa fa-mail-forward'}))
.mouseover(function () {
in_user_redirect = true;
}).mouseout(function () {
in_user_redirect = false;
}));
}
}).on('select2:selecting', function () {
return !in_user_redirect;
});
var $last = null;
$(window).on('hashchange', function () {
var hash = window.location.hash;
if (hash.startsWith('#!')) {
var $user = $('#user-' + hash.substring(2)).addClass('highlight');
if ($user) {
$(document).scrollTop($user.position().top - 50);
if ($last !== null) $last.removeClass('highlight');
$last = $user;
}
}
}).trigger('hashchange');
});
</script>
{% endblock %}
{% block media %}
{% block users_media %}{% endblock %}
{% endblock %}
{% block body %}
<div id="common-content">
<div id="content-left" class="users">
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-bottom: 7px; margin-top: 3px;">
{% include "list-pages.html" %}
<form id="search-form" name="form" action="{{ url('user_ranking_redirect') }}" method="get">
<input id="search-handle" type="text" name="search"
placeholder="{{ _('Search by handle...') }}">
</form>
</div>
{% endif %}
<table id="users-table" class="table">
{% block users_table %}{% endblock %}
</table>
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,188 @@
{% extends "user/user-base.html" %}
{% block user_media %}
{% include "timezone/media-css.html" %}
{{ form.media.css }}
<style>
.sortedm2m-container, .sortedm2m-container p.selector-filter {
width: 300px;
}
.sortedm2m-container p.selector-filter input {
width: 262px;
}
ul.sortedm2m {
width: 284px;
min-height: 70px;
max-height: 200px;
height: 70px
}
.grayed {
color: #666;
}
.inline-header {
float: left;
font-size: 1.1em;
padding: 4px 8px;
padding-left: 0;
}
.block-header {
color: #666;
font-size: 1.1em;
}
.fullwidth {
display: block;
overflow: hidden;
}
#edit-form {
border: unset;
background: unset;
max-width: 700px;
}
#center-float {
position: relative;
margin: 0 auto auto -28.5em;
left: 50%;
width: 700px;
}
</style>
{% endblock %}
{% block js_media %}
{% include "timezone/media-js.html" %}
{{ form.media.js }}
<script type="text/javascript">
$(function () {
$('#ace_user_script').on('ace_load', function (e, editor) {
editor.getSession().setMode("ace/mode/javascript");
});
});
</script>
<script type="text/javascript">
$(function () {
$('#disable-2fa-button').click(function () {
alert("The administrators for this site require all the staff to have two-factor authentication enabled, so it may not be disabled at this time.");
});
});
</script>
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% set tab = 'edit' %}
{% set user = request.profile %}
{% include "user/user-tabs.html" %}
{% endblock %}
{% block body %}
<div id="center-float">
<form id="edit-form" action="" method="post" class="form-area">
{% if form.errors %}
<div class="alert alert-danger alert-dismissable">
<a href="#" class="close">x</a>
{{ form.non_field_errors() }}
</div>
{% endif %}
{% csrf_token %}
<div style="padding-top:0.5em" class="block-header">{{ _('Self-description') }}:</div>
{{ form.about }}
<hr>
<table border="0" style="padding-top:0.7em">
<tr>
<td style="vertical-align:top;">
<table style="padding-right:0.8em">
<tr title="{{ _('Select your closest major city') }}">
<td><label class="inline-header grayed">{{ _('Timezone') }}:</label></td>
<td><span class="fullwidth">{{ form.timezone }}</span></td>
</tr>
<tr>
<td><label class="inline-header grayed">{{ _('Preferred language') }}:</label></td>
<td><span class="fullwidth">{{ form.language }}</span></td>
</tr>
<tr>
<td><label class="inline-header grayed">{{ _('Editor theme') }}:</label></td>
<td><span class="fullwidth">{{ form.ace_theme }}</span></td>
</tr>
{% if has_math_config %}
<tr>
<td><label class="inline-header grayed">{{ _('Math engine') }}:</label></td>
<td><span class="fullwidth">{{ form.math_engine }}</span></td>
</tr>
{% endif %}
{% if form.newsletter %}
<tr>
<td colspan="2">
{{ form.newsletter }}
<label for="id_newsletter" style="float: unset" class="inline-header grayed">
{{- _('Notify me about upcoming contests') -}}
</label>
</td>
</tr>
{% endif %}
<tr>
<td colspan="2">
{{ form.test_site }}
<label for="id_test_site" style="float: unset" class="inline-header grayed">
{{- form.test_site.label -}}
</label>
</td>
</tr>
<tr>
<td colspan="2">
<a href="http://www.gravatar.com/" title="{{ _('Change your avatar') }}"
target="_blank" class="inline-header">{{ _('Change your avatar') }}</a>
</td>
</tr>
<tr>
<td colspan="2">
<a href="{{ url('password_change') }}" class="inline-header">
{{ _('Change your password') }}
</a>
</td>
</tr>
<tr>
<td colspan="2"><span class="inline-header">
{% if profile.is_totp_enabled %}
{{ _('Two Factor Authentication is enabled.') }}
{% if require_staff_2fa and request.user.is_staff %}
<a id="disable-2fa-button" class="button inline-button">Disable</a>
{% else %}
<a href="{{ url('disable_2fa') }}" class="button inline-button">Disable</a>
{% endif %}
{% else %}
{{ _('Two Factor Authentication is disabled.') }}
<a href="{{ url('enable_2fa') }}" class="button inline-button">Enable</a>
{% endif %}
</span></td>
</tr>
</table>
</td>
<td>
<div style="padding-bottom:0.4em;margin-top:-2em" class="block-header">
{{ _('Affiliated organizations') }}:
</div>
{{ form.organizations }}
</td>
</tr>
</table>
<hr>
<div class="block-header">{{ _('User-script') }}:</div>
{{ form.user_script }}
<hr>
<input type="submit" style="float:right" value="{{ _('Update profile') }}">
</form>
</div>
{% endblock %}

View file

@ -0,0 +1,3 @@
{% for user in users -%}
{{ link_user(user) }}{% if not loop.last %}, {% endif %}
{%- endfor %}

1
templates/user/link.html Normal file
View file

@ -0,0 +1 @@
<span class="{{ profile.css_class }}"><a href="{{ url('user_page', user.username) }}">{{ user.username }}</a></span>

26
templates/user/list.html Normal file
View file

@ -0,0 +1,26 @@
{% extends "user/base-users.html" %}
{% block users_media %}
<style>
#users-table td:nth-child(2), #users-table th:nth-child(2) {
border-right: none;
text-align: left;
}
#users-table th a {
color: white;
}
</style>
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% set tab = 'list' %}
{% set title = 'Leaderboard' %}
{% include "user/user-list-tabs.html" %}
{% endblock %}
{% block users_table %}
{% include "user/users-table.html" %}
{% endblock %}

View file

@ -0,0 +1,32 @@
<div class="sub-result {{ breakdown.sub_result_class }}">
<div class="score">{{ breakdown.sub_points|floatformat(0) }} / {{ breakdown.sub_total|floatformat(0) }}</div>
<div class="state">
<span title="{{ breakdown.sub_long_status }}" class="status">{{ breakdown.sub_short_status }}</span>
|
<span class="language">{{ breakdown.sub_lang }}</span>
</div>
</div>
<div class="sub-info">
<div class="name">
<a href="{{ url('problem_detail', breakdown.problem_code) }}">{{ breakdown.problem_name }}</a>
</div>
<div class="time">{{ relative_time(breakdown.sub_date) }}</div>
</div>
<div class="sub-pp sub-usage">
<div class="pp">
<a href="{{ url('submission_status', breakdown.sub_id) }}">{{ breakdown.points|floatformat(0) }}pp</a>
</div>
<div class="pp-weighted">
{% trans weight=breakdown.weight|floatformat(0) %}
weighted <b>{{ weight }}%</b>
{% endtrans %}
{% if breakdown.scaled_points < 10 %}
({{ _('%(pp).1fpp', pp=breakdown.scaled_points) }})
{% else %}
({{ _('%(pp).0fpp', pp=breakdown.scaled_points) }})
{% endif %}
</div>
</div>

View file

@ -0,0 +1,3 @@
{% for breakdown in pp_breakdown %}
<div class="submission-row">{% include "user/pp-row.html" %}</div>
{% endfor %}

View file

@ -0,0 +1,4 @@
{{ preview_data|markdown('self-description', MATH_ENGINE)|reference|str|safe }}
{% if REQUIRE_JAX %}
<div data-config="{{ static('mathjax_config.js') }}" class="require-mathjax-support"></div>
{% endif %}

View file

@ -0,0 +1,17 @@
{% spaceless %}
<span class="rate-group">
{% if rating_class(rating) == 'rate-target' %}
<svg class="rate-box rate-target" viewBox="0 0 16 16">
<circle cx="8" cy="8" r="7"></circle>
<circle cx="8" cy="8" r="3"></circle>
</svg>
{% else %}
<svg class="rate-box {{ rating_class(rating) }}" viewBox="0 0 16 16">
<circle cx="8" cy="8" r="7"></circle>
<path clip-path="url(#rating-clip)"
d="M0 16v-{{ (rating_progress(rating) * 16)|round(2) }}h16 0v16z"></path>
</svg>
{% endif %}
<span class="rating {{ rating_class(rating) }}">{{ rating.rating|default(rating) }}</span>
</span>
{% endspaceless %}

View file

@ -0,0 +1,186 @@
{% extends "user/user-base.html" %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% set tab = 'about' %}
{% include "user/user-tabs.html" %}
{% endblock %}
{% block user_content %}
<div class="content-description">
{% with orgs=user.organizations.all() %}
{% if orgs %}
<p style="margin-top: 0"><b>{{ _('From') }}</b>
{% for org in orgs -%}
<a href="{{ org.get_absolute_url() }}">{{ org.name }}</a>
{%- if not loop.last %}, {% endif %}
{% endfor %}
</p>
{% endif %}
{% endwith %}
{% if perms.judge.change_profile %}
{% with notes=user.notes %}
{% if notes %}
<p style="margin-top: 0"><b>{{ _('Admin Notes') }}: </b>
{{ notes }}
</p>
{% endif %}
{% endwith %}
{% endif%}
{% if user.about %}
<h4>{{ _('About') }}</h4>
{% cache 86400 'user_about' user.id MATH_ENGINE %}
{{ user.about|markdown('self-description', MATH_ENGINE)|reference|str|safe }}
{% endcache %}
{% else %}
<i>
{% if user.user == request.user %}
{{ _('You have not shared any information.') }}
{% else %}
{{ _('This user has not shared any information.') }}
{% endif %}
</i>
<br>
{% endif %}
{% if rating %}
<h4>Rating History</h4>
<div id="rating-chart">
<canvas></canvas>
</div>
<div id="rating-tooltip">
<div class="contest"></div>
<div class="date"></div>
<div class="rate-group">
<span class="rate-box"><span></span></span>
<span class="rating"></span>, #<span class="rank"></span>
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% block bodyend %}
{% if REQUIRE_JAX %}
{% include "mathjax-load.html" %}
{% endif %}
{% if ratings %}
<script type="text/javascript" src="{{ static('libs/chart.js/Chart.js') }}"></script>
<script type="text/javascript">
var rating_history = {{rating_data}};
$.each(rating_history, function (index, item) {
item.x = new Date(item.timestamp);
item.y = item.rating;
});
$(function () {
var $canvas = $('#rating-chart').find('canvas');
var ctx = $canvas.get(0).getContext('2d');
var getItem = function (index) {
return rating_history[index];
};
window.rating_chart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
label: 'rating',
backgroundColor: 'rgb(0,0,0,0)',
borderColor: '#A31515',
pointBackgroundColor: '#A31515',
pointHoverBackgroundColor: '#FFF',
pointRadius: 5,
pointHoverRadius: 5,
showLine: true,
data: rating_history,
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
elements: {
line: {
tension: 0,
},
},
legend: {
display: false,
},
layout: {
padding: {
right: 10,
},
},
scales: {
xAxes: [{
type: 'time',
distribution: 'linear',
}],
yAxes: [{
ticks: {
precision: 0,
},
}],
},
tooltips: {
enabled: false,
custom: function (tooltipModel) {
var $tooltip = $('#rating-tooltip');
if (tooltipModel.opacity == 0) {
$tooltip.hide();
return;
}
var element = tooltipModel.dataPoints[0]
var item = getItem(element.index);
$tooltip.find('.contest').text(item.label);
$tooltip.find('.date').text(item.date);
$tooltip.find('.rate-box').attr('class', 'rate-box ' + item.class)
.find('span').css('height', item.height);
$tooltip.find('.rating').text(item.rating).attr('class', 'rating ' + item.class);
$tooltip.find('.rank').text(item.ranking);
$tooltip.removeClass('above below');
$tooltip.addClass(element.y < $tooltip.height() ? 'below' : 'above');
var position = $canvas.offset();
var container = $('#page-container').offset();
$tooltip.css({
left: position.left - container.left + element.x + $tooltip.width() / 2,
top: position.top - container.top + element.y - $tooltip.height() - 13,
fontFamily: tooltipModel._bodyFontFamily,
fontSize: tooltipModel._bodyFontSize,
fontStyle: tooltipModel._bodyFontStyle,
}).show();
},
}
}
});
$canvas.click(function (evt) {
var elements = window.rating_chart.getElementsAtEvent(evt);
if (elements.length > 0) {
var item = getItem(elements[0]._index);
window.location.href = item.link;
}
});
$canvas.mousemove(function (evt) {
var elements = window.rating_chart.getElementsAtEvent(evt);
if (elements.length > 0) {
$canvas.css('cursor', 'pointer');
} else {
$canvas.css('cursor', '');
}
});
});
</script>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,78 @@
{% extends "base.html" %}
{% block media %}
{% block user_media %}{% endblock %}
<style>
.user-gravatar {
display: block;
padding-right: 15px;
width: 135px;
}
.user-gravatar img {
width: 135px;
height: 135px;
display: block;
border-radius: 6px;
}
.page-title {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
</style>
{% endblock %}
{% block js_media %}
{% block user_js_media %}{% endblock %}
{% endblock %}
{% block body %}
<div class="user-info-page">
<div class="user-sidebar">
<div class="user-gravatar">
<img src="{{ gravatar(user, 135) }}" width="135px" height="135px">
</div>
<br>
<div><b>
{%- trans trimmed counter=user.problem_count %}
{{ counter }} problem solved
{% pluralize %}
{{ counter }} problems solved
{% endtrans -%}
</b></div>
{% if not user.is_unlisted %}
<div><b class="semibold">{{ _('Rank by points:') }}</b> #{{ rank }}</div>
{% endif %}
<div>
<b class="semibold">{{ _('Total points:') }}</b>
<span title="{{ user.performance_points|floatformat(2) }}">
{{ user.performance_points|floatformat(0) }}
</span>
</div>
<br>
<div>
<a href="{{ url('all_user_submissions', user.user.username) }}">{{ _('View submissions') }}</a>
</div>
{% if ratings %}
<br>
<div><b>{{ ratings|length }} contests written</b></div>
{% if not user.is_unlisted %}
<div><b class="semibold">{{ _('Rank by rating:') }}</b> #{{ rating_rank }}</div>
{% endif %}
<div><b class="semibold">{{ _('Rating:') }}</b> {{ rating_number(rating) }}</div>
<div><b class="semibold">{{ _('Volatility:') }}</b> {{ rating.volatility }}</div>
<div><b class="semibold">{{ _('Min. rating:') }}</b> {{ rating_number(min_rating) }}</div>
<div><b class="semibold">{{ _('Max rating:') }}</b> {{ rating_number(max_rating) }}</div>
{% endif %}
</div>
<div class="user-content">{% block user_content %}{% endblock %}</div>
</div>
{% endblock %}

View file

@ -0,0 +1,6 @@
{% extends "tabs-base.html" %}
{% block tabs %}
{{ make_tab('list', 'fa-users', url('user_list'), _('Leaderboard')) }}
{{ make_tab('organizations', 'fa-university', url('organization_list'), _('Organizations')) }}
{% endblock %}

View file

@ -0,0 +1,119 @@
{% extends "user/user-base.html" %}
{% block user_js_media %}
<script type="text/javascript">
window.show_pp_base = 1;
window.currently_requesting_pp = false;
window.load_more_pp = function () {
if (window.currently_requesting_pp) return;
window.currently_requesting_pp = true;
$.get('{{ url('user_pp_ajax', user.user.username) }}', {
start: window.show_pp_base * 10,
end: (window.show_pp_base + 1) * 10
}).done(function (data) {
$('.pp-table').append(data['results']);
window.show_pp_base++;
if (!data['has_more']) {
$("#pp-load-link-wrapper").hide();
}
window.currently_requesting_pp = false;
});
};
</script>
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% set tab = 'problems' %}
{% include "user/user-tabs.html" %}
{% endblock %}
{% block user_content %}
{% if pp_breakdown %}
<h3 class="pp-breakdown-header">{{ _('Points Breakdown') }}</h3>
<div id="submissions-table" class="pp-table table">
{% include "user/pp-table-body.html" %}
</div>
{% if pp_has_more %}
<div id="pp-load-link-wrapper">
<a id="pp-load-more-link" href="javascript:load_more_pp()">{{ _('Load more...') }}</a>
</div>
{% endif %}
{% else %}
<i>{{ _('This user has not yet solved any problems.') }}</i>
{% endif %}
{% if authored %}
<div class="user-problem-group">
<h3 class="unselectable toggle closed">
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Authored Problems') }} ({{ authored|length }})
</h3>
<table style="display: none" class="table toggled">
<thead>
<tr>
<th>{{ _('Problem') }}</th>
<th>{{ _('Category') }}</th>
<th>{{ _('Points') }}</th>
</tr>
</thead>
<tbody>
{% for problem in authored %}
<tr>
<td class="problem-name">
<a href="{{ url('problem_detail', problem.code) }}">{{ problem.name }}</a>
</td>
<td class="problem-category">{{ problem.group.full_name }}</td>
<td class="problem-score"><a href="{{ url('ranked_submissions', problem.code) }}">
{{ problem.points|floatformat }}{% if problem.partial %}p{% endif %}
</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% if request.user.is_authenticated and request.user != user.user %}
<div class="hide-solved-problems"><span>
<form name="form" action="" method="get">
<input id="hide_solved" style="vertical-align:middle" onclick="form.submit()" type="checkbox"
name="hide_solved"{% if hide_solved %} checked{% endif %} value="1">
<label style="vertical-align:middle" for="hide_solved">{{ _("Hide problems I've solved") }}</label>
</form>
</span></div>
{% else %}
<hr>
{% endif %}
{% for group in best_submissions %}
<div class="user-problem-group">
<h3 class="unselectable toggle closed"><span class="fa fa-chevron-right fa-fw"></span>
{{ group.name }} ({{ _('%(points).1f points', points=group.points) }})
</h3>
<table style="display: none" class="table toggled">
<thead>
<tr>
<th>{{ _('Problem') }}</th>
<th>{{ _('Score') }}</th>
</tr>
</thead>
<tbody>
{% for entry in group.problems %}
<tr>
<td class="problem-name">
<a href="{{ url('problem_detail', entry.code) }}">{{ entry.name }}</a>
</td>
<td class="problem-score">
<a href="{{ url('user_submissions', entry.code, user.user.username) }}">
{{ _('%(points)s / %(total)s', points=entry.points, total=entry.total) }}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
{% endblock %}

View file

@ -0,0 +1,19 @@
{% extends "tabs-base.html" %}
{% block tabs %}
{{ make_tab('about', 'fa-info-circle', url('user_page', user.user.username), _('About')) }}
{{ make_tab('problems', 'fa-puzzle-piece', url('user_problems', user.user.username), _('Problems')) }}
{% if request.user.is_superuser and user.user != request.user and not user.user.is_superuser %}
{{ make_tab('impersonate', 'fa-eye', url('impersonate-start', user.user.id), _('Impersonate')) }}
{% endif %}
{% if user.user == request.user %}
{{ make_tab('edit', 'fa-edit', url('user_edit_profile'), _('Edit profile')) }}
{% else %}
{% if perms.auth.change_user %}
{{ make_tab('edit', 'fa-edit', url('admin:auth_user_change', user.user.id), _('Admin User')) }}
{% endif %}
{% if perms.judge.change_profile %}
{{ make_tab('edit', 'fa-edit', url('admin:judge_profile_change', user.id), _('Admin Profile')) }}
{% endif %}
{% endif %}
{% endblock %}

View file

@ -0,0 +1,30 @@
{% extends "user/base-users-table.html" %}
{% block after_rank_head %}
<th class="header rank">
{% if sort_links %}<a href="{{ sort_links.rating }}">{% endif %}
<span class="rate-group">
<svg class="rate-box" viewBox="0 0 16 16">
<circle cx="8" cy="8" r="7" stroke="white"></circle>
<path clip-path="url(#rating-clip)" d="M0 16v-4.8h16 0v16z" fill="white"></path>
</svg>
</span>
{%- if sort_links %}{{ sort_order.rating }}</a>{% endif %}
</th>
{% endblock %}
{% block after_rank %}
<td>{% if user.rating %}{{ rating_number(user) }}{% endif %}</td>
{% endblock %}
{% block after_point_head %}
<th class="problems">
{% if sort_links %}<a href="{{ sort_links.problem_count }}">{% endif %}
{{ _('Problems') }}
{%- if sort_links %}{{ sort_order.problem_count }}</a>{% endif %}
</th>
{% endblock %}
{% block after_point %}
<td>{{ user.problem_count }}</td>
{% endblock %}