diff --git a/judge/admin/contest.py b/judge/admin/contest.py
index 3ccad04..3a57793 100644
--- a/judge/admin/contest.py
+++ b/judge/admin/contest.py
@@ -158,7 +158,10 @@ class ContestAdmin(CompareVersionAdmin):
)
},
),
- (_("Scheduling"), {"fields": ("start_time", "end_time", "time_limit")}),
+ (
+ _("Scheduling"),
+ {"fields": ("start_time", "end_time", "time_limit", "freeze_after")},
+ ),
(
_("Details"),
{
@@ -274,7 +277,8 @@ class ContestAdmin(CompareVersionAdmin):
# We need this flag because `save_related` deals with the inlines, but does not know if we have already rescored
self._rescored = False
if form.changed_data and any(
- f in form.changed_data for f in ("format_config", "format_name")
+ f in form.changed_data
+ for f in ("format_config", "format_name", "freeze_after")
):
self._rescore(obj.key)
self._rescored = True
diff --git a/judge/contest_format/atcoder.py b/judge/contest_format/atcoder.py
index 64e0749..db42b73 100644
--- a/judge/contest_format/atcoder.py
+++ b/judge/contest_format/atcoder.py
@@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy
from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
-from judge.timezone import from_database_time
+from judge.timezone import from_database_time, to_database_time
from judge.utils.timedelta import nice_repr
@@ -54,6 +54,10 @@ class AtCoderContestFormat(DefaultContestFormat):
points = 0
format_data = {}
+ frozen_time = self.contest.end_time
+ if self.contest.freeze_after:
+ frozen_time = participation.start + self.contest.freeze_after
+
with connection.cursor() as cursor:
cursor.execute(
"""
@@ -66,9 +70,10 @@ class AtCoderContestFormat(DefaultContestFormat):
FROM judge_contestproblem cp INNER JOIN
judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN
judge_submission sub ON (sub.id = cs.submission_id)
+ WHERE sub.date < %s
GROUP BY cp.id
""",
- (participation.id, participation.id),
+ (participation.id, participation.id, to_database_time(frozen_time)),
)
for score, time, prob in cursor.fetchall():
@@ -100,6 +105,7 @@ class AtCoderContestFormat(DefaultContestFormat):
format_data[str(prob)] = {"time": dt, "points": score, "penalty": prev}
points += score
+ self.handle_frozen_state(participation, format_data)
participation.cumtime = cumtime + penalty
participation.score = points
participation.tiebreaker = 0
@@ -114,7 +120,7 @@ class AtCoderContestFormat(DefaultContestFormat):
' ({penalty})',
penalty=floatformat(format_data["penalty"]),
)
- if format_data["penalty"]
+ if format_data.get("penalty")
else ""
)
return format_html(
@@ -129,6 +135,7 @@ class AtCoderContestFormat(DefaultContestFormat):
+ self.best_solution_state(
format_data["points"], contest_problem.points
)
+ + (" frozen" if format_data.get("frozen") else "")
),
url=reverse(
"contest_user_submissions_ajax",
diff --git a/judge/contest_format/base.py b/judge/contest_format/base.py
index f27f2ac..848d81d 100644
--- a/judge/contest_format/base.py
+++ b/judge/contest_format/base.py
@@ -1,4 +1,5 @@
from abc import ABCMeta, abstractmethod, abstractproperty
+from django.db.models import Max
class abstractclassmethod(classmethod):
@@ -95,3 +96,17 @@ class BaseContestFormat(metaclass=ABCMeta):
if points == total:
return "full-score"
return "partial-score"
+
+ def handle_frozen_state(self, participation, format_data):
+ if not self.contest.freeze_after:
+ return
+ queryset = participation.submissions.values("problem_id").annotate(
+ time=Max("submission__date")
+ )
+ for result in queryset:
+ problem = str(result["problem_id"])
+ if format_data.get(problem):
+ if result["time"] >= self.contest.freeze_after + participation.start:
+ format_data[problem]["frozen"] = True
+ else:
+ format_data[problem] = {"time": 0, "points": 0, "frozen": True}
diff --git a/judge/contest_format/default.py b/judge/contest_format/default.py
index 0c053e0..d8dd848 100644
--- a/judge/contest_format/default.py
+++ b/judge/contest_format/default.py
@@ -32,10 +32,19 @@ class DefaultContestFormat(BaseContestFormat):
points = 0
format_data = {}
- for result in participation.submissions.values("problem_id").annotate(
+ queryset = participation.submissions
+
+ if self.contest.freeze_after:
+ queryset = queryset.filter(
+ submission__date__lt=participation.start + self.contest.freeze_after
+ )
+
+ queryset = queryset.values("problem_id").annotate(
time=Max("submission__date"),
points=Max("points"),
- ):
+ )
+
+ for result in queryset:
dt = (result["time"] - participation.start).total_seconds()
if result["points"]:
cumtime += dt
@@ -45,6 +54,7 @@ class DefaultContestFormat(BaseContestFormat):
}
points += result["points"]
+ self.handle_frozen_state(participation, format_data)
participation.cumtime = max(cumtime, 0)
participation.score = points
participation.tiebreaker = 0
@@ -66,6 +76,7 @@ class DefaultContestFormat(BaseContestFormat):
+ self.best_solution_state(
format_data["points"], contest_problem.points
)
+ + (" frozen" if format_data.get("frozen") else "")
),
url=reverse(
"contest_user_submissions_ajax",
diff --git a/judge/contest_format/ecoo.py b/judge/contest_format/ecoo.py
index 007498c..149d00a 100644
--- a/judge/contest_format/ecoo.py
+++ b/judge/contest_format/ecoo.py
@@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy
from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
-from judge.timezone import from_database_time
+from judge.timezone import from_database_time, to_database_time
from judge.utils.timedelta import nice_repr
@@ -60,6 +60,10 @@ class ECOOContestFormat(DefaultContestFormat):
points = 0
format_data = {}
+ frozen_time = self.contest.end_time
+ if self.contest.freeze_after:
+ frozen_time = participation.start + self.contest.freeze_after
+
with connection.cursor() as cursor:
cursor.execute(
"""
@@ -77,9 +81,15 @@ class ECOOContestFormat(DefaultContestFormat):
FROM judge_contestproblem cp INNER JOIN
judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN
judge_submission sub ON (sub.id = cs.submission_id)
+ WHERE sub.date < %s
GROUP BY cp.id
""",
- (participation.id, participation.id, participation.id),
+ (
+ participation.id,
+ participation.id,
+ participation.id,
+ to_database_time(frozen_time),
+ ),
)
for score, time, prob, subs, max_score in cursor.fetchall():
@@ -105,6 +115,7 @@ class ECOOContestFormat(DefaultContestFormat):
format_data[str(prob)] = {"time": dt, "points": score, "bonus": bonus}
points += score
+ self.handle_frozen_state(participation, format_data)
participation.cumtime = cumtime
participation.score = points
participation.tiebreaker = 0
@@ -134,6 +145,7 @@ class ECOOContestFormat(DefaultContestFormat):
+ self.best_solution_state(
format_data["points"], contest_problem.points
)
+ + (" frozen" if format_data.get("frozen") else "")
),
url=reverse(
"contest_user_submissions_ajax",
diff --git a/judge/contest_format/icpc.py b/judge/contest_format/icpc.py
index aa76484..b366b01 100644
--- a/judge/contest_format/icpc.py
+++ b/judge/contest_format/icpc.py
@@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy
from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
-from judge.timezone import from_database_time
+from judge.timezone import from_database_time, to_database_time
from judge.utils.timedelta import nice_repr
@@ -55,6 +55,10 @@ class ICPCContestFormat(DefaultContestFormat):
score = 0
format_data = {}
+ frozen_time = self.contest.end_time
+ if self.contest.freeze_after:
+ frozen_time = participation.start + self.contest.freeze_after
+
with connection.cursor() as cursor:
cursor.execute(
"""
@@ -67,9 +71,10 @@ class ICPCContestFormat(DefaultContestFormat):
FROM judge_contestproblem cp INNER JOIN
judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN
judge_submission sub ON (sub.id = cs.submission_id)
+ WHERE sub.date < %s
GROUP BY cp.id
""",
- (participation.id, participation.id),
+ (participation.id, participation.id, to_database_time(frozen_time)),
)
for points, time, prob in cursor.fetchall():
@@ -102,6 +107,7 @@ class ICPCContestFormat(DefaultContestFormat):
format_data[str(prob)] = {"time": dt, "points": points, "penalty": prev}
score += points
+ self.handle_frozen_state(participation, format_data)
participation.cumtime = max(0, cumtime + penalty)
participation.score = score
participation.tiebreaker = last # field is sorted from least to greatest
@@ -116,7 +122,7 @@ class ICPCContestFormat(DefaultContestFormat):
' +{penalty}',
penalty=floatformat(format_data["penalty"]),
)
- if format_data["penalty"]
+ if format_data.get("penalty")
else ""
)
return format_html(
@@ -131,6 +137,7 @@ class ICPCContestFormat(DefaultContestFormat):
+ self.best_solution_state(
format_data["points"], contest_problem.points
)
+ + (" frozen" if format_data.get("frozen") else "")
),
url=reverse(
"contest_user_submissions_ajax",
diff --git a/judge/contest_format/ioi.py b/judge/contest_format/ioi.py
index 9275f78..bcd18c3 100644
--- a/judge/contest_format/ioi.py
+++ b/judge/contest_format/ioi.py
@@ -12,6 +12,7 @@ from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
from judge.timezone import from_database_time
from judge.utils.timedelta import nice_repr
+from django.db.models import Min, OuterRef, Subquery
@register_contest_format("ioi")
@@ -45,41 +46,42 @@ class IOIContestFormat(DefaultContestFormat):
def update_participation(self, participation):
cumtime = 0
- points = 0
+ score = 0
format_data = {}
- with connection.cursor() as cursor:
- cursor.execute(
- """
- SELECT MAX(cs.points) as `score`, (
- SELECT MIN(csub.date)
- FROM judge_contestsubmission ccs LEFT OUTER JOIN
- judge_submission csub ON (csub.id = ccs.submission_id)
- WHERE ccs.problem_id = cp.id AND ccs.participation_id = %s AND ccs.points = MAX(cs.points)
- ) AS `time`, cp.id AS `prob`
- FROM judge_contestproblem cp INNER JOIN
- judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN
- judge_submission sub ON (sub.id = cs.submission_id)
- GROUP BY cp.id
- """,
- (participation.id, participation.id),
+ queryset = participation.submissions
+ if self.contest.freeze_after:
+ queryset = queryset.filter(
+ submission__date__lt=participation.start + self.contest.freeze_after
)
- for score, time, prob in cursor.fetchall():
- if self.config["cumtime"]:
- dt = (
- from_database_time(time) - participation.start
- ).total_seconds()
- if score:
- cumtime += dt
- else:
- dt = 0
+ queryset = (
+ queryset.values("problem_id")
+ .filter(
+ points=Subquery(
+ queryset.filter(problem_id=OuterRef("problem_id"))
+ .order_by("-points")
+ .values("points")[:1]
+ )
+ )
+ .annotate(time=Min("submission__date"))
+ .values_list("problem_id", "time", "points")
+ )
- format_data[str(prob)] = {"time": dt, "points": score}
- points += score
+ for problem_id, time, points in queryset:
+ if self.config["cumtime"]:
+ dt = (time - participation.start).total_seconds()
+ if points:
+ cumtime += dt
+ else:
+ dt = 0
+ format_data[str(problem_id)] = {"points": points, "time": dt}
+ score += points
+
+ self.handle_frozen_state(participation, format_data)
participation.cumtime = max(cumtime, 0)
- participation.score = points
+ participation.score = score
participation.tiebreaker = 0
participation.format_data = format_data
participation.save()
@@ -99,6 +101,7 @@ class IOIContestFormat(DefaultContestFormat):
+ self.best_solution_state(
format_data["points"], contest_problem.points
)
+ + (" frozen" if format_data.get("frozen") else "")
),
url=reverse(
"contest_user_submissions_ajax",
diff --git a/judge/migrations/0139_contest_freeze_after.py b/judge/migrations/0139_contest_freeze_after.py
new file mode 100644
index 0000000..97e4a25
--- /dev/null
+++ b/judge/migrations/0139_contest_freeze_after.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.16 on 2022-11-18 06:11
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("judge", "0138_bookmark_makebookmark"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="contest",
+ name="freeze_after",
+ field=models.DurationField(
+ blank=True,
+ help_text="Format hh:mm:ss. For example, if you want to freeze contest after 2 hours, enter 02:00:00",
+ null=True,
+ verbose_name="freeze after",
+ ),
+ ),
+ ]
diff --git a/judge/models/contest.py b/judge/models/contest.py
index 1cd5795..0a7389b 100644
--- a/judge/models/contest.py
+++ b/judge/models/contest.py
@@ -128,6 +128,14 @@ class Contest(models.Model):
"Format hh:mm:ss. For example, if you want a 2-hour contest, enter 02:00:00"
),
)
+ freeze_after = models.DurationField(
+ verbose_name=_("freeze after"),
+ blank=True,
+ null=True,
+ help_text=_(
+ "Format hh:mm:ss. For example, if you want to freeze contest after 2 hours, enter 02:00:00"
+ ),
+ )
is_visible = models.BooleanField(
verbose_name=_("publicly visible"),
default=False,
diff --git a/judge/timezone.py b/judge/timezone.py
index c3b5b04..c609649 100644
--- a/judge/timezone.py
+++ b/judge/timezone.py
@@ -2,7 +2,7 @@ import pytz
from django.conf import settings
from django.db import connection
from django.utils import timezone
-from django.utils.timezone import make_aware
+from django.utils.timezone import make_aware, make_naive
class TimezoneMiddleware(object):
@@ -25,3 +25,10 @@ def from_database_time(datetime):
if tz is None:
return datetime
return make_aware(datetime, tz)
+
+
+def to_database_time(datetime):
+ tz = connection.timezone
+ if tz is None:
+ return datetime
+ return make_naive(datetime, tz)
diff --git a/judge/views/submission.py b/judge/views/submission.py
index 13b4651..3b22820 100644
--- a/judge/views/submission.py
+++ b/judge/views/submission.py
@@ -301,6 +301,7 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
template_name = "submission/list.html"
context_object_name = "submissions"
first_page_href = None
+ include_frozen = False
def get_result_data(self):
result = self._get_result_data()
@@ -344,6 +345,10 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
queryset = queryset.filter(contest_object=self.contest)
if not self.contest.can_see_full_scoreboard(self.request.user):
queryset = queryset.filter(user=self.request.profile)
+ if self.contest.freeze_after and not self.include_frozen:
+ queryset = queryset.exclude(
+ date__gte=self.contest.freeze_after + self.contest.start_time
+ )
else:
queryset = queryset.select_related("contest_object").defer(
"contest_object__description"
@@ -456,6 +461,9 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
self.selected_languages = set(request.GET.getlist("language"))
self.selected_statuses = set(request.GET.getlist("status"))
+ if request.user.is_superuser:
+ self.include_frozen = True
+
if "results" in request.GET:
return JsonResponse(self.get_result_data())
@@ -468,6 +476,8 @@ class UserMixin(object):
raise ImproperlyConfigured("Must pass a user")
self.profile = get_object_or_404(Profile, user__username=kwargs["user"])
self.username = kwargs["user"]
+ if self.profile == request.profile:
+ self.include_frozen = True
return super(UserMixin, self).get(request, *args, **kwargs)
@@ -837,8 +847,8 @@ class UserContestSubmissionsAjax(UserContestSubmissions):
s.contest_time = nice_repr(contest_time, "noday")
else:
s.contest_time = None
- points = floatformat(s.contest.points, -self.contest.points_precision)
total = floatformat(contest_problem.points, -self.contest.points_precision)
+ points = floatformat(s.contest.points, -self.contest.points_precision)
s.display_point = f"{points} / {total}"
filtered_submissions.append(s)
context["submissions"] = filtered_submissions
diff --git a/locale/vi/LC_MESSAGES/django.po b/locale/vi/LC_MESSAGES/django.po
index c9b34f3..800e099 100644
--- a/locale/vi/LC_MESSAGES/django.po
+++ b/locale/vi/LC_MESSAGES/django.po
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: lqdoj2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-11-18 05:10+0700\n"
+"POT-Creation-Date: 2022-11-19 03:12+0700\n"
"PO-Revision-Date: 2021-07-20 03:44\n"
"Last-Translator: Icyene\n"
"Language-Team: Vietnamese\n"
@@ -19,8 +19,8 @@ msgstr ""
"X-Crowdin-File-ID: 5\n"
#: chat_box/models.py:31 chat_box/models.py:51 chat_box/models.py:65
-#: judge/admin/interface.py:150 judge/models/contest.py:622
-#: judge/models/contest.py:815 judge/models/profile.py:354
+#: judge/admin/interface.py:150 judge/models/contest.py:630
+#: judge/models/contest.py:823 judge/models/profile.py:354
#: judge/models/profile.py:430
msgid "user"
msgstr "người dùng"
@@ -99,72 +99,72 @@ msgstr "Bài tập"
msgid "Settings"
msgstr "Cài đặt"
-#: judge/admin/contest.py:161
+#: judge/admin/contest.py:162
msgid "Scheduling"
msgstr ""
-#: judge/admin/contest.py:163
+#: judge/admin/contest.py:166
msgid "Details"
msgstr "Chi tiết"
-#: judge/admin/contest.py:175
+#: judge/admin/contest.py:178
msgid "Format"
msgstr "Thể thức"
-#: judge/admin/contest.py:179 templates/contest/ranking-table.html:7
+#: judge/admin/contest.py:182 templates/contest/ranking-table.html:7
#: templates/user/user-about.html:15 templates/user/user-about.html:45
msgid "Rating"
msgstr ""
-#: judge/admin/contest.py:191
+#: judge/admin/contest.py:194
msgid "Access"
msgstr "Truy cập"
-#: judge/admin/contest.py:201 judge/admin/problem.py:219
+#: judge/admin/contest.py:204 judge/admin/problem.py:219
msgid "Justice"
msgstr "Xử phạt"
-#: judge/admin/contest.py:313
+#: judge/admin/contest.py:317
#, python-format
msgid "%d contest successfully marked as visible."
msgid_plural "%d contests successfully marked as visible."
msgstr[0] "%d kỳ thi đã được đánh dấu hiển thị."
-#: judge/admin/contest.py:320
+#: judge/admin/contest.py:324
msgid "Mark contests as visible"
msgstr "Đánh dấu hiển thị các kỳ thi"
-#: judge/admin/contest.py:331
+#: judge/admin/contest.py:335
#, python-format
msgid "%d contest successfully marked as hidden."
msgid_plural "%d contests successfully marked as hidden."
msgstr[0] "%d kỳ thi đã được đánh dấu ẩn."
-#: judge/admin/contest.py:338
+#: judge/admin/contest.py:342
msgid "Mark contests as hidden"
msgstr "Ẩn các kỳ thi"
-#: judge/admin/contest.py:359 judge/admin/submission.py:243
+#: judge/admin/contest.py:363 judge/admin/submission.py:243
#, python-format
msgid "%d submission was successfully scheduled for rejudging."
msgid_plural "%d submissions were successfully scheduled for rejudging."
msgstr[0] "%d bài nộp đã được lên lịch thành công để chấm lại."
-#: judge/admin/contest.py:467
+#: judge/admin/contest.py:471
#, python-format
msgid "%d participation recalculated."
msgid_plural "%d participations recalculated."
msgstr[0] "%d thí sinh đã được tính điểm lại."
-#: judge/admin/contest.py:474
+#: judge/admin/contest.py:478
msgid "Recalculate results"
msgstr "Tính toán lại kết quả"
-#: judge/admin/contest.py:479 judge/admin/organization.py:99
+#: judge/admin/contest.py:483 judge/admin/organization.py:99
msgid "username"
msgstr "tên đăng nhập"
-#: judge/admin/contest.py:485 templates/base.html:315
+#: judge/admin/contest.py:489 templates/base.html:315
msgid "virtual"
msgstr "ảo"
@@ -567,13 +567,13 @@ msgstr "Lưu"
msgid "bookmarks"
msgstr "Lưu"
-#: judge/models/bookmark.py:56
+#: judge/models/bookmark.py:59
#, fuzzy
#| msgid "Bookmark"
msgid "make bookmark"
msgstr "Lưu"
-#: judge/models/bookmark.py:57
+#: judge/models/bookmark.py:60
#, fuzzy
#| msgid "Bookmark"
msgid "make bookmarks"
@@ -696,7 +696,7 @@ msgstr ""
msgid "contest tag"
msgstr ""
-#: judge/models/contest.py:74 judge/models/contest.py:234
+#: judge/models/contest.py:74 judge/models/contest.py:242
msgid "contest tags"
msgstr "nhãn kỳ thi"
@@ -751,7 +751,7 @@ msgstr "mô tả"
msgid "problems"
msgstr "bài tập"
-#: judge/models/contest.py:121 judge/models/contest.py:627
+#: judge/models/contest.py:121 judge/models/contest.py:635
msgid "start time"
msgstr "thời gian bắt đầu"
@@ -771,11 +771,23 @@ msgstr ""
"Định dạng hh:mm:ss (giờ:phút:giây). Ví dụ, nếu muốn tạo kỳ thi dài 2h, hãy "
"nhập 02:00:00"
-#: judge/models/contest.py:132 judge/models/problem.py:222
+#: judge/models/contest.py:132
+msgid "freeze after"
+msgstr "đóng băng sau"
+
+#: judge/models/contest.py:136
+msgid ""
+"Format hh:mm:ss. For example, if you want to freeze contest after 2 hours, "
+"enter 02:00:00"
+msgstr ""
+"Định dạng hh:mm:ss (giờ:phút:giây). Ví dụ, nếu muốn đóng băng kỳ thi sau 2h, hãy "
+"nhập 02:00:00"
+
+#: judge/models/contest.py:140 judge/models/problem.py:222
msgid "publicly visible"
msgstr "công khai"
-#: judge/models/contest.py:135
+#: judge/models/contest.py:143
msgid ""
"Should be set even for organization-private contests, where it determines "
"whether the contest is visible to members of the specified organizations."
@@ -783,84 +795,84 @@ msgstr ""
"Đánh dấu ngay cả với các kỳ thi riêng tư của nhóm, quyết định việc kỳ thi có "
"được hiển thị với các thành viên hay không."
-#: judge/models/contest.py:141
+#: judge/models/contest.py:149
msgid "contest rated"
msgstr "kỳ thi được xếp hạng"
-#: judge/models/contest.py:142
+#: judge/models/contest.py:150
msgid "Whether this contest can be rated."
msgstr "Quyết định kỳ thi có được xếp hạng không."
-#: judge/models/contest.py:146
+#: judge/models/contest.py:154
msgid "scoreboard visibility"
msgstr "khả năng hiển thị của bảng điểm"
-#: judge/models/contest.py:149
+#: judge/models/contest.py:157
msgid "Scoreboard visibility through the duration of the contest"
msgstr "Khả năng hiển thị của bảng điểm trong thời gian kỳ thi"
-#: judge/models/contest.py:154
+#: judge/models/contest.py:162
msgid "view contest scoreboard"
msgstr "xem bảng điểm kỳ thi"
-#: judge/models/contest.py:157
+#: judge/models/contest.py:165
msgid "These users will be able to view the scoreboard."
msgstr "Những người dùng này được phép xem bảng điểm."
-#: judge/models/contest.py:160
+#: judge/models/contest.py:168
msgid "no comments"
msgstr "không bình luận"
-#: judge/models/contest.py:161
+#: judge/models/contest.py:169
msgid "Use clarification system instead of comments."
msgstr "Dùng hệ thống thông báo thay vì bình luận."
-#: judge/models/contest.py:166
+#: judge/models/contest.py:174
msgid "Rating floor for contest"
msgstr "Cận dưới rating được xếp hạng trong kỳ thi"
-#: judge/models/contest.py:172
+#: judge/models/contest.py:180
msgid "Rating ceiling for contest"
msgstr "Cận trên rating được xếp hạng trong kỳ thi"
-#: judge/models/contest.py:177
+#: judge/models/contest.py:185
msgid "rate all"
msgstr "xếp hạng tất cả"
-#: judge/models/contest.py:178
+#: judge/models/contest.py:186
msgid "Rate all users who joined."
msgstr "Xếp hạng tất cả người dùng đã tham gia (kể cả không nộp)."
-#: judge/models/contest.py:183
+#: judge/models/contest.py:191
msgid "exclude from ratings"
msgstr "không xếp hạng"
-#: judge/models/contest.py:188
+#: judge/models/contest.py:196
msgid "private to specific users"
msgstr "riêng tư với các người dùng này"
-#: judge/models/contest.py:193
+#: judge/models/contest.py:201
msgid "private contestants"
msgstr "thí sinh riêng tư"
-#: judge/models/contest.py:194
+#: judge/models/contest.py:202
msgid "If private, only these users may see the contest"
msgstr "Nếu riêng tư, chỉ những người dùng này mới thấy kỳ thi"
-#: judge/models/contest.py:198
+#: judge/models/contest.py:206
msgid "hide problem tags"
msgstr "ẩn nhãn kỳ thi"
-#: judge/models/contest.py:199
+#: judge/models/contest.py:207
msgid "Whether problem tags should be hidden by default."
msgstr ""
"Quyết định việc nhãn bài tập (DP, Tham lam, ...) được ẩn trong kỳ thi không."
-#: judge/models/contest.py:203
+#: judge/models/contest.py:211
msgid "run pretests only"
msgstr "chỉ chạy pretests"
-#: judge/models/contest.py:205
+#: judge/models/contest.py:213
msgid ""
"Whether judges should grade pretests only, versus all testcases. Commonly "
"set during a contest, then unset prior to rejudging user submissions when "
@@ -869,50 +881,50 @@ msgstr ""
"Quyết định việc các máy chấm chỉ chấm pretests thay vì tất cả các test. Sau "
"kỳ thi, hãy bỏ đánh dấu ô này và chấm lại tất cả các bài."
-#: judge/models/contest.py:212 judge/models/interface.py:92
+#: judge/models/contest.py:220 judge/models/interface.py:92
#: judge/models/problem.py:279
msgid "private to organizations"
msgstr "riêng tư với các tổ chức"
-#: judge/models/contest.py:217 judge/models/interface.py:88
+#: judge/models/contest.py:225 judge/models/interface.py:88
#: judge/models/problem.py:275 judge/models/profile.py:126
msgid "organizations"
msgstr "tổ chức"
-#: judge/models/contest.py:218
+#: judge/models/contest.py:226
msgid "If private, only these organizations may see the contest"
msgstr "Nếu riêng tư, chỉ những tổ chức này thấy được kỳ thi"
-#: judge/models/contest.py:221 judge/models/problem.py:253
+#: judge/models/contest.py:229 judge/models/problem.py:253
msgid "OpenGraph image"
msgstr "Hình ảnh OpenGraph"
-#: judge/models/contest.py:224 judge/models/profile.py:81
+#: judge/models/contest.py:232 judge/models/profile.py:81
msgid "Logo override image"
msgstr "Hình ảnh ghi đè logo"
-#: judge/models/contest.py:229
+#: judge/models/contest.py:237
msgid ""
"This image will replace the default site logo for users inside the contest."
msgstr "Ảnh này sẽ thay thế cho logo mặc định trong kỳ thi."
-#: judge/models/contest.py:237
+#: judge/models/contest.py:245
msgid "the amount of live participants"
msgstr "số lượng thí sinh thi trực tiếp"
-#: judge/models/contest.py:241
+#: judge/models/contest.py:249
msgid "contest summary"
msgstr "tổng kết kỳ thi"
-#: judge/models/contest.py:243 judge/models/problem.py:259
+#: judge/models/contest.py:251 judge/models/problem.py:259
msgid "Plain-text, shown in meta description tag, e.g. for social media."
msgstr ""
-#: judge/models/contest.py:247 judge/models/profile.py:76
+#: judge/models/contest.py:255 judge/models/profile.py:76
msgid "access code"
msgstr "mật khẩu truy cập"
-#: judge/models/contest.py:252
+#: judge/models/contest.py:260
msgid ""
"An optional code to prompt contestants before they are allowed to join the "
"contest. Leave it blank to disable."
@@ -920,267 +932,267 @@ msgstr ""
"Mật khẩu truy cập cho các thí sinh muốn tham gia kỳ thi. Để trống nếu không "
"dùng."
-#: judge/models/contest.py:258 judge/models/problem.py:241
+#: judge/models/contest.py:266 judge/models/problem.py:241
msgid "personae non gratae"
msgstr "Chặn tham gia"
-#: judge/models/contest.py:260
+#: judge/models/contest.py:268
msgid "Bans the selected users from joining this contest."
msgstr "Cấm những người dùng được chọn tham gia kỳ thi."
-#: judge/models/contest.py:263
+#: judge/models/contest.py:271
msgid "contest format"
msgstr "format kỳ thi"
-#: judge/models/contest.py:267
+#: judge/models/contest.py:275
msgid "The contest format module to use."
msgstr "Format kỳ thi sử dụng."
-#: judge/models/contest.py:270
+#: judge/models/contest.py:278
msgid "contest format configuration"
msgstr "Tùy chỉnh format kỳ thi"
-#: judge/models/contest.py:274
+#: judge/models/contest.py:282
msgid ""
"A JSON object to serve as the configuration for the chosen contest format "
"module. Leave empty to use None. Exact format depends on the contest format "
"selected."
msgstr ""
-#: judge/models/contest.py:287
+#: judge/models/contest.py:295
msgid "precision points"
msgstr "Hiển thị điểm"
-#: judge/models/contest.py:290
+#: judge/models/contest.py:298
msgid "Number of digits to round points to."
msgstr "Số chữ số thập phân trên bảng điểm."
-#: judge/models/contest.py:595
+#: judge/models/contest.py:603
msgid "See private contests"
msgstr ""
-#: judge/models/contest.py:596
+#: judge/models/contest.py:604
msgid "Edit own contests"
msgstr ""
-#: judge/models/contest.py:597
+#: judge/models/contest.py:605
msgid "Edit all contests"
msgstr ""
-#: judge/models/contest.py:598
+#: judge/models/contest.py:606
msgid "Clone contest"
msgstr ""
-#: judge/models/contest.py:599 templates/contest/moss.html:74
+#: judge/models/contest.py:607 templates/contest/moss.html:74
msgid "MOSS contest"
msgstr ""
-#: judge/models/contest.py:600
+#: judge/models/contest.py:608
msgid "Rate contests"
msgstr ""
-#: judge/models/contest.py:601
+#: judge/models/contest.py:609
msgid "Contest access codes"
msgstr ""
-#: judge/models/contest.py:602
+#: judge/models/contest.py:610
msgid "Create private contests"
msgstr ""
-#: judge/models/contest.py:603
+#: judge/models/contest.py:611
msgid "Change contest visibility"
msgstr ""
-#: judge/models/contest.py:604
+#: judge/models/contest.py:612
msgid "Edit contest problem label script"
msgstr "Cách hiển thị thứ tự bài tập"
-#: judge/models/contest.py:606 judge/models/contest.py:744
-#: judge/models/contest.py:818 judge/models/contest.py:848
+#: judge/models/contest.py:614 judge/models/contest.py:752
+#: judge/models/contest.py:826 judge/models/contest.py:856
#: judge/models/submission.py:116
msgid "contest"
msgstr "kỳ thi"
-#: judge/models/contest.py:607
+#: judge/models/contest.py:615
msgid "contests"
msgstr "kỳ thi"
-#: judge/models/contest.py:616
+#: judge/models/contest.py:624
msgid "associated contest"
msgstr ""
-#: judge/models/contest.py:629
+#: judge/models/contest.py:637
msgid "score"
msgstr "điểm"
-#: judge/models/contest.py:630
+#: judge/models/contest.py:638
msgid "cumulative time"
msgstr "tổng thời gian"
-#: judge/models/contest.py:632
+#: judge/models/contest.py:640
msgid "is disqualified"
msgstr "đã bị loại"
-#: judge/models/contest.py:634
+#: judge/models/contest.py:642
msgid "Whether this participation is disqualified."
msgstr "Quyết định thí sinh có bị loại không."
-#: judge/models/contest.py:636
+#: judge/models/contest.py:644
msgid "tie-breaking field"
msgstr ""
-#: judge/models/contest.py:638
+#: judge/models/contest.py:646
msgid "virtual participation id"
msgstr "id lần tham gia ảo"
-#: judge/models/contest.py:640
+#: judge/models/contest.py:648
msgid "0 means non-virtual, otherwise the n-th virtual participation."
msgstr "0 nghĩa là tham gia chính thức, ngược lại là lần tham gia ảo thứ n."
-#: judge/models/contest.py:643
+#: judge/models/contest.py:651
msgid "contest format specific data"
msgstr ""
-#: judge/models/contest.py:719
+#: judge/models/contest.py:727
#, python-format
msgid "%s spectating in %s"
msgstr "%s đang theo dõi trong %s"
-#: judge/models/contest.py:724
+#: judge/models/contest.py:732
#, python-format
msgid "%s in %s, v%d"
msgstr "%s trong %s, v%d"
-#: judge/models/contest.py:729
+#: judge/models/contest.py:737
#, python-format
msgid "%s in %s"
msgstr "%s trong %s"
-#: judge/models/contest.py:732
+#: judge/models/contest.py:740
msgid "contest participation"
msgstr "lần tham gia kỳ thi"
-#: judge/models/contest.py:733
+#: judge/models/contest.py:741
msgid "contest participations"
msgstr "lần tham gia kỳ thi"
-#: judge/models/contest.py:740 judge/models/contest.py:789
-#: judge/models/contest.py:851 judge/models/problem.py:558
+#: judge/models/contest.py:748 judge/models/contest.py:797
+#: judge/models/contest.py:859 judge/models/problem.py:558
#: judge/models/problem.py:565 judge/models/problem.py:586
#: judge/models/problem.py:617 judge/models/problem_data.py:50
msgid "problem"
msgstr "bài tập"
-#: judge/models/contest.py:748 judge/models/contest.py:801
+#: judge/models/contest.py:756 judge/models/contest.py:809
#: judge/models/problem.py:206
msgid "points"
msgstr "điểm"
-#: judge/models/contest.py:749
+#: judge/models/contest.py:757
msgid "partial"
msgstr "thành phần"
-#: judge/models/contest.py:750 judge/models/contest.py:803
+#: judge/models/contest.py:758 judge/models/contest.py:811
msgid "is pretested"
msgstr "dùng pretest"
-#: judge/models/contest.py:751 judge/models/interface.py:43
+#: judge/models/contest.py:759 judge/models/interface.py:43
msgid "order"
msgstr "thứ tự"
-#: judge/models/contest.py:753
+#: judge/models/contest.py:761
msgid "0 to not show testcases, 1 to show"
msgstr "0 để ẩn test, 1 để hiện"
-#: judge/models/contest.py:754
+#: judge/models/contest.py:762
msgid "visible testcases"
msgstr "hiển thị test"
-#: judge/models/contest.py:761
+#: judge/models/contest.py:769
msgid "Maximum number of submissions for this problem, or 0 for no limit."
msgstr "Số lần nộp tối đa, đặt là 0 nếu không có giới hạn."
-#: judge/models/contest.py:763
+#: judge/models/contest.py:771
msgid "max submissions"
msgstr "số lần nộp tối đa"
-#: judge/models/contest.py:766
+#: judge/models/contest.py:774
msgid "Why include a problem you can't submit to?"
msgstr ""
-#: judge/models/contest.py:776
+#: judge/models/contest.py:784
msgid "contest problem"
msgstr "bài trong kỳ thi"
-#: judge/models/contest.py:777
+#: judge/models/contest.py:785
msgid "contest problems"
msgstr "bài trong kỳ thi"
-#: judge/models/contest.py:783 judge/models/submission.py:233
+#: judge/models/contest.py:791 judge/models/submission.py:233
msgid "submission"
msgstr "bài nộp"
-#: judge/models/contest.py:796 judge/models/contest.py:822
+#: judge/models/contest.py:804 judge/models/contest.py:830
msgid "participation"
msgstr "lần tham gia"
-#: judge/models/contest.py:804
+#: judge/models/contest.py:812
msgid "Whether this submission was ran only on pretests."
msgstr "Quyết định bài nộp chỉ được chạy trên pretest không."
-#: judge/models/contest.py:809
+#: judge/models/contest.py:817
msgid "contest submission"
msgstr "bài nộp kỳ thi"
-#: judge/models/contest.py:810
+#: judge/models/contest.py:818
msgid "contest submissions"
msgstr "bài nộp kỳ thi"
-#: judge/models/contest.py:826
+#: judge/models/contest.py:834
msgid "rank"
msgstr "rank"
-#: judge/models/contest.py:827
+#: judge/models/contest.py:835
msgid "rating"
msgstr "rating"
-#: judge/models/contest.py:828
+#: judge/models/contest.py:836
msgid "raw rating"
msgstr "rating thật"
-#: judge/models/contest.py:829
+#: judge/models/contest.py:837
msgid "contest performance"
msgstr ""
-#: judge/models/contest.py:830
+#: judge/models/contest.py:838
msgid "last rated"
msgstr "lần cuối được xếp hạng"
-#: judge/models/contest.py:834
+#: judge/models/contest.py:842
msgid "contest rating"
msgstr "rating kỳ thi"
-#: judge/models/contest.py:835
+#: judge/models/contest.py:843
msgid "contest ratings"
msgstr "rating kỳ thi"
-#: judge/models/contest.py:859
+#: judge/models/contest.py:867
msgid "contest moss result"
msgstr "kết quả MOSS kỳ thi"
-#: judge/models/contest.py:860
+#: judge/models/contest.py:868
msgid "contest moss results"
msgstr "kết quả MOSS kỳ thi"
-#: judge/models/contest.py:865
+#: judge/models/contest.py:873
msgid "clarified problem"
msgstr ""
-#: judge/models/contest.py:867
+#: judge/models/contest.py:875
msgid "clarification body"
msgstr ""
-#: judge/models/contest.py:869
+#: judge/models/contest.py:877
msgid "clarification timestamp"
msgstr ""
@@ -2554,7 +2566,7 @@ msgid "Editing comment"
msgstr "Chỉnh sửa bình luận"
#: judge/views/contests.py:119 judge/views/contests.py:367
-#: judge/views/contests.py:372 judge/views/contests.py:613
+#: judge/views/contests.py:372 judge/views/contests.py:619
msgid "No such contest"
msgstr "Không có contest nào như vậy"
@@ -2578,113 +2590,113 @@ msgstr "Không tìm thấy kỳ thi nào như vậy."
msgid "Access to contest \"%s\" denied"
msgstr "Truy cập tới kỳ thi \"%s\" bị từ chối"
-#: judge/views/contests.py:418
+#: judge/views/contests.py:424
msgid "Clone Contest"
msgstr "Nhân bản kỳ thi"
-#: judge/views/contests.py:487
+#: judge/views/contests.py:493
msgid "Contest not ongoing"
msgstr "Kỳ thi đang không diễn ra"
-#: judge/views/contests.py:488
+#: judge/views/contests.py:494
#, python-format
msgid "\"%s\" is not currently ongoing."
msgstr "\"%s\" kỳ thi đang không diễn ra."
-#: judge/views/contests.py:495
+#: judge/views/contests.py:501
msgid "Already in contest"
msgstr "Đã ở trong kỳ thi"
-#: judge/views/contests.py:496
+#: judge/views/contests.py:502
#, python-format
msgid "You are already in a contest: \"%s\"."
msgstr "Bạn đã ở trong kỳ thi: \"%s\"."
-#: judge/views/contests.py:506
+#: judge/views/contests.py:512
msgid "Banned from joining"
msgstr "Bị cấm tham gia"
-#: judge/views/contests.py:508
+#: judge/views/contests.py:514
msgid ""
"You have been declared persona non grata for this contest. You are "
"permanently barred from joining this contest."
msgstr "Bạn không được phép tham gia kỳ thi này."
-#: judge/views/contests.py:597
+#: judge/views/contests.py:603
#, python-format
msgid "Enter access code for \"%s\""
msgstr "Nhập mật khẩu truy cập cho \"%s\""
-#: judge/views/contests.py:614
+#: judge/views/contests.py:620
#, python-format
msgid "You are not in contest \"%s\"."
msgstr "Bạn không ở trong kỳ thi \"%s\"."
-#: judge/views/contests.py:637
+#: judge/views/contests.py:643
msgid "ContestCalendar requires integer year and month"
msgstr "Lịch thi yêu cầu giá trị cho năm và tháng là số nguyên"
-#: judge/views/contests.py:695
+#: judge/views/contests.py:701
#, python-format
msgid "Contests in %(month)s"
msgstr "Các kỳ thi trong %(month)s"
-#: judge/views/contests.py:696
+#: judge/views/contests.py:702
msgid "F Y"
msgstr "F Y"
-#: judge/views/contests.py:756
+#: judge/views/contests.py:762
#, python-format
msgid "%s Statistics"
msgstr "%s Thống kê"
-#: judge/views/contests.py:1013
+#: judge/views/contests.py:1019
#, python-format
msgid "%s Rankings"
msgstr "%s Bảng điểm"
-#: judge/views/contests.py:1024
+#: judge/views/contests.py:1030
msgid "???"
msgstr "???"
-#: judge/views/contests.py:1040
+#: judge/views/contests.py:1046
#, python-format
msgid "Your participation in %s"
msgstr "Lần tham gia trong %s"
-#: judge/views/contests.py:1041
+#: judge/views/contests.py:1047
#, python-format
msgid "%s's participation in %s"
msgstr "Lần tham gia của %s trong %s"
-#: judge/views/contests.py:1055
+#: judge/views/contests.py:1061
msgid "Live"
msgstr "Trực tiếp"
-#: judge/views/contests.py:1074 templates/contest/contest-tabs.html:13
+#: judge/views/contests.py:1080 templates/contest/contest-tabs.html:13
msgid "Participation"
msgstr "Lần tham gia"
-#: judge/views/contests.py:1123
+#: judge/views/contests.py:1129
#, python-format
msgid "%s MOSS Results"
msgstr "%s Kết quả MOSS"
-#: judge/views/contests.py:1159
+#: judge/views/contests.py:1165
#, python-format
msgid "Running MOSS for %s..."
msgstr "Đang chạy MOSS cho %s..."
-#: judge/views/contests.py:1182
+#: judge/views/contests.py:1188
#, python-format
msgid "Contest tag: %s"
msgstr "Nhãn kỳ thi: %s"
-#: judge/views/contests.py:1197 judge/views/ticket.py:72
+#: judge/views/contests.py:1203 judge/views/ticket.py:72
msgid "Issue description"
msgstr "Mô tả vấn đề"
-#: judge/views/contests.py:1244
+#: judge/views/contests.py:1250
#, python-format
msgid "New clarification for %s"
msgstr "Thông báo mới cho %s"
@@ -2930,41 +2942,41 @@ msgstr "Hướng dẫn cho {0}"
msgid "Editorial for {0}"
msgstr "Hướng dẫn cho {0}"
-#: judge/views/problem.py:443 templates/contest/contest.html:81
+#: judge/views/problem.py:447 templates/contest/contest.html:81
#: templates/organization/org-left-sidebar.html:4
#: templates/user/user-about.html:28 templates/user/user-bookmarks.html:32
#: templates/user/user-tabs.html:5 templates/user/users-table.html:19
msgid "Problems"
msgstr "Bài tập"
-#: judge/views/problem.py:823
+#: judge/views/problem.py:827
msgid "Problem feed"
msgstr "Bài tập"
-#: judge/views/problem.py:1061
+#: judge/views/problem.py:1065
msgid "Banned from submitting"
msgstr "Bị cấm nộp bài"
-#: judge/views/problem.py:1063
+#: judge/views/problem.py:1067
msgid ""
"You have been declared persona non grata for this problem. You are "
"permanently barred from submitting this problem."
msgstr "Bạn đã bị cấm nộp bài này."
-#: judge/views/problem.py:1086
+#: judge/views/problem.py:1090
msgid "Too many submissions"
msgstr "Quá nhiều lần nộp"
-#: judge/views/problem.py:1088
+#: judge/views/problem.py:1092
msgid "You have exceeded the submission limit for this problem."
msgstr "Bạn đã vượt quá số lần nộp cho bài này."
-#: judge/views/problem.py:1167 judge/views/problem.py:1172
+#: judge/views/problem.py:1171 judge/views/problem.py:1176
#, python-format
msgid "Submit to %(problem)s"
msgstr "Nộp bài cho %(problem)s"
-#: judge/views/problem.py:1195
+#: judge/views/problem.py:1199
msgid "Clone Problem"
msgstr "Nhân bản bài tập"
@@ -3138,39 +3150,39 @@ msgstr "Bài nộp của %(user)s cho bài %(problem)s"
msgid "All submissions"
msgstr "Tất cả bài nộp"
-#: judge/views/submission.py:495
+#: judge/views/submission.py:505
msgid "All my submissions"
msgstr "Tất cả bài nộp của tôi"
-#: judge/views/submission.py:496
+#: judge/views/submission.py:506
#, python-format
msgid "All submissions by %s"
msgstr "Tất cả bài nộp của %s"
-#: judge/views/submission.py:541
+#: judge/views/submission.py:551
#, python-format
msgid "All submissions for %s"
msgstr "Tất cả bài nộp cho %s"
-#: judge/views/submission.py:569
+#: judge/views/submission.py:579
msgid "Must pass a problem"
msgstr "Phải làm được một bài"
-#: judge/views/submission.py:627
+#: judge/views/submission.py:637
#, python-format
msgid "My submissions for %(problem)s"
msgstr "Bài nộp của tôi cho %(problem)s"
-#: judge/views/submission.py:628
+#: judge/views/submission.py:638
#, python-format
msgid "%(user)s's submissions for %(problem)s"
msgstr "Các bài nộp của %(user)s cho %(problem)s"
-#: judge/views/submission.py:758
+#: judge/views/submission.py:768
msgid "Must pass a contest"
msgstr "Phải qua một kỳ thi"
-#: judge/views/submission.py:788
+#: judge/views/submission.py:798
#, python-brace-format
msgid ""
"{0}'s submissions for {2} in {0} cho {2} trong {4}"
-#: judge/views/submission.py:800
+#: judge/views/submission.py:810
#, python-brace-format
msgid ""
"{0}'s submissions for problem {2} in {3}"
@@ -3188,7 +3200,7 @@ msgstr ""
"Các bài nộp của {0} cho bài {2} trong {3}"
""
-#: judge/views/submission.py:851
+#: judge/views/submission.py:861
#, fuzzy
#| msgid "You do not have the permission to rejudge submissions."
msgid "You don't have permission to access."
@@ -3248,48 +3260,48 @@ msgstr "Hủy kích hoạt Two Factor Authentication"
msgid "Perform Two Factor Authentication"
msgstr "Thực hiện Two Factor Authentication"
-#: judge/views/user.py:90
+#: judge/views/user.py:97
msgid "No such user"
msgstr "Không người dùng nào như vậy"
-#: judge/views/user.py:91
+#: judge/views/user.py:98
#, python-format
msgid "No user handle \"%s\"."
msgstr "Không tồn tại tên người dùng \"%s\"."
-#: judge/views/user.py:96
+#: judge/views/user.py:103
msgid "My account"
msgstr "Tài khoản của tôi"
-#: judge/views/user.py:98
+#: judge/views/user.py:105
#, python-format
msgid "User %s"
msgstr "Thành viên %s"
-#: judge/views/user.py:196
+#: judge/views/user.py:203
msgid "M j, Y"
msgstr "j M, Y"
-#: judge/views/user.py:231
+#: judge/views/user.py:238
msgid "M j, Y, G:i"
msgstr "j M, Y, G:i"
-#: judge/views/user.py:409
+#: judge/views/user.py:417
msgid "Updated on site"
msgstr "Được cập nhật trên web"
-#: judge/views/user.py:464 templates/admin/auth/user/change_form.html:14
+#: judge/views/user.py:472 templates/admin/auth/user/change_form.html:14
#: templates/admin/auth/user/change_form.html:17 templates/base.html:280
#: templates/user/user-tabs.html:11
msgid "Edit profile"
msgstr "Chỉnh sửa thông tin"
-#: judge/views/user.py:475 templates/user/user-left-sidebar.html:2
+#: judge/views/user.py:483 templates/user/user-left-sidebar.html:2
#: templates/user/user-list-tabs.html:4
msgid "Leaderboard"
msgstr "Xếp hạng"
-#: judge/views/user.py:574
+#: judge/views/user.py:582
msgid "Import Users"
msgstr ""
diff --git a/templates/contest/ranking-css.html b/templates/contest/ranking-css.html
index 43215f0..54fd018 100644
--- a/templates/contest/ranking-css.html
+++ b/templates/contest/ranking-css.html
@@ -35,6 +35,10 @@
background: #00f9a1;
}
+ .frozen {
+ background: #a5c5d9 !important;
+ }
+
.rank {
min-width: 2.5em
}