This commit is contained in:
hohoTT 2015-09-16 21:24:16 +08:00
commit 5011861ee5
32 changed files with 277 additions and 137 deletions

3
.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
static/src/js/lib/* linguist-vendored
static/src/js/require.js linguist-vendored
static/src/js/r.js linguist-vendored

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Qingdao 青岛大学信息工程学院创新实验室
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,33 @@
# OnlineJudge
基于 Python 和 Django的在线评测平台。
文档https://www.zybuluo.com/virusdefender/note/171932
TODO
- 完善文档,目前还差很多
- 完善测试
- 搭建 demo 站点
![oj_previewindex.png][1]
![preview.jpeg][2]
![oj_preview_submission.png][3]
![contest][4]
![contest_rank_edit][5]
![admin_problem][6]
![admin_contest][7]
[1]: https://dn-virusdefender-blog-cdn.qbox.me/oj_previewindex.png
[2]: https://dn-virusdefender-blog-cdn.qbox.me/oj_previewproblem.png
[3]: https://dn-virusdefender-blog-cdn.qbox.me/oj_previewsubmission.png
[4]: https://dn-virusdefender-blog-cdn.qbox.me/oj_previewcontest.png
[5]: https://dn-virusdefender-blog-cdn.qbox.me/oj_previewcontest_rank.png?edit
[6]: https://dn-virusdefender-blog-cdn.qbox.me/oj_previewadmin_problem.png
[7]: https://dn-virusdefender-blog-cdn.qbox.me/oj_previewadmin_contest.png

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='user',
name='problems_status',
field=models.TextField(blank=True),
),
]

View File

@ -30,6 +30,9 @@ class User(AbstractBaseUser):
create_time = models.DateTimeField(auto_now_add=True) create_time = models.DateTimeField(auto_now_add=True)
# 0代表不是管理员 1是普通管理员 2是超级管理员 # 0代表不是管理员 1是普通管理员 2是超级管理员
admin_type = models.IntegerField(default=0) admin_type = models.IntegerField(default=0)
# JSON字典用来表示该用户的问题的解决状态 1为ac2为正在进行
problems_status = models.TextField(blank=True)
USERNAME_FIELD = 'username' USERNAME_FIELD = 'username'
REQUIRED_FIELDS = [] REQUIRED_FIELDS = []

View File

@ -433,7 +433,9 @@ def contest_rank_page(request, contest_id):
except ContestSubmission.DoesNotExist: except ContestSubmission.DoesNotExist:
result[i]["problems"].append({}) result[i]["problems"].append({})
result[i]["total_ac"] = submissions.filter(ac=True).count() result[i]["total_ac"] = submissions.filter(ac=True).count()
result[i]["username"] = User.objects.get(id=result[i]["user_id"]).username user= User.objects.get(id=result[i]["user_id"])
result[i]["username"] = user.username
result[i]["real_name"] = user.real_name
result[i]["total_time"] = get_the_time_format(submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"]) result[i]["total_time"] = get_the_time_format(submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"])
result = sorted(result, cmp=_cmp, reverse=True) result = sorted(result, cmp=_cmp, reverse=True)
r.set("contest_rank_" + contest_id, json.dumps(list(result))) r.set("contest_rank_" + contest_id, json.dumps(list(result)))
@ -449,4 +451,5 @@ def contest_rank_page(request, contest_id):
{"contest": contest, "contest_problems": contest_problems, {"contest": contest, "contest_problems": contest_problems,
"result": result, "result": result,
"auto_refresh": request.GET.get("auto_refresh", None) == "true", "auto_refresh": request.GET.get("auto_refresh", None) == "true",
"show_real_name": result.GET.get("show_real_name", None) == "true",
"real_time_rank": contest.real_time_rank}) "real_time_rank": contest.real_time_rank})

View File

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,23 +0,0 @@
# coding=utf-8
from django.shortcuts import render
from django.http import HttpResponse
from account.models import User
from group.models import Group, UserGroupRelation, JoinGroupRequest
def install(request):
for i in range(10):
user = User.objects.create(username="root" + str(i), admin_type=2, real_name="real_name", email="11111@qq.com")
user.set_password("root")
user.save()
for i in range(10):
group = Group.objects.create(name="group" + str(i),
description="description",
admin=User.objects.get(username="root0"))
for i in range(7):
UserGroupRelation.objects.create(user=User.objects.get(username="root" + str(i)), group=group)
for i in range(7, 10):
JoinGroupRequest.objects.create(user=User.objects.get(username="root" + str(i)),
group=group, message=u"你好啊")
return HttpResponse("success")

View File

@ -1,3 +0,0 @@
/usr/bin/docker run -t -i --privileged -v /var/test_case/:/var/judger/test_case/ -v /var/code/:/var/judger/code/ judger /bin/bash
python judge/judger/run.py -solution_id 1 -max_cpu_time 1 -max_memory 1 -test_case_id 1

View File

@ -1,7 +1,12 @@
# coding=utf-8 # coding=utf-8
"""
注意
此文件包含 celery 的部分配置但是 celery 并不是运行在docker 中的所以本配置文件中的 redis和 MySQL 的地址就应该是
运行 redis MySQL docker 容器的地址了怎么获取这个地址见帮助文档测试用例的路径和源代码路径同理
"""
# 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息 # 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息
redis_config = { redis_config = {
"host": "121.42.32.129", "host": "192.168.42.23",
"port": 6379, "port": 6379,
"db": 0 "db": 0
} }
@ -9,23 +14,23 @@ redis_config = {
# 判题的 docker 容器的配置参数 # 判题的 docker 容器的配置参数
docker_config = { docker_config = {
"image_name": "3da0e526934e", "image_name": "judger",
"docker_path": "docker", "docker_path": "docker",
"shell": True "shell": True
} }
# 测试用例的路径,是主机上的实际路径 # 测试用例的路径,是主机上的实际路径
test_case_dir = "/var/mnt/source/test_case/" test_case_dir = "/root/test_case/"
# 源代码路径,也就是 manage.py 所在的实际路径 # 源代码路径,也就是 manage.py 所在的实际路径
source_code_dir = "/var/mnt/source/OnlineJudge/" source_code_dir = "/root/qduoj/"
# 日志文件夹路径 # 日志文件夹路径
log_dir = "/var/log/" log_dir = "/root/log/"
# 存储提交信息的数据库,是 celery 使用的,与 oj.settings/local_settings 等区分,那是 web 服务器访问的地址 # 存储提交信息的数据库,是 celery 使用的,与 oj.settings/local_settings 等区分,那是 web 服务器访问的地址
submission_db = { submission_db = {
"host": "127.0.0.1", "host": "192.168.42.32",
"port": 3306, "port": 3306,
"db": "oj_submission", "db": "oj_submission",
"user": "root", "user": "root",

View File

@ -11,7 +11,8 @@ from settings import docker_config, source_code_dir, test_case_dir, log_dir, sub
@app.task @app.task
def judge(submission_id, time_limit, memory_limit, test_case_id): def judge(submission_id, time_limit, memory_limit, test_case_id):
try: try:
command = "%s run -t -i --privileged --rm=true " \ command = "%s run -t -i --privileged --rm " \
"--link mysql " \
"-v %s:/var/judger/test_case/ " \ "-v %s:/var/judger/test_case/ " \
"-v %s:/var/judger/code/ " \ "-v %s:/var/judger/code/ " \
"-v %s:/var/judger/code/log/ " \ "-v %s:/var/judger/code/log/ " \

View File

@ -2,6 +2,9 @@
import logging import logging
import redis import redis
import json
from django.db import transaction
from judge.judger_controller.settings import redis_config from judge.judger_controller.settings import redis_config
from judge.judger.result import result from judge.judger.result import result
@ -9,6 +12,7 @@ from submission.models import Submission
from problem.models import Problem from problem.models import Problem
from contest.models import ContestProblem, Contest, ContestSubmission from contest.models import ContestProblem, Contest, ContestSubmission
from account.models import User from account.models import User
logger = logging.getLogger("app_info") logger = logging.getLogger("app_info")
@ -35,6 +39,21 @@ class MessageQueue(object):
problem.save() problem.save()
except Problem.DoesNotExist: except Problem.DoesNotExist:
logger.warning("Submission problem does not exist, submission_id: " + submission_id) logger.warning("Submission problem does not exist, submission_id: " + submission_id)
continue
# 更新该用户的解题状态
try:
user = User.objects.get(pk=submission.user_id)
except User.DoesNotExist:
logger.warning("Submission user does not exist, submission_id: " + submission_id)
continue
if user.problems_status:
problems_status = json.loads(user.problems_status)
else:
problems_status = {}
problems_status[str(problem.id)] = 1
user.problems_status = json.dumps(problems_status)
user.save()
# 普通题目的话,到这里就结束了 # 普通题目的话,到这里就结束了
continue continue
@ -53,15 +72,11 @@ class MessageQueue(object):
contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest, contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest,
problem_id=contest_problem.id) problem_id=contest_problem.id)
# 提交次数加1 # 提交次数加1
with transaction.atomic():
if submission.result == result["accepted"]: if submission.result == result["accepted"]:
# 避免这道题已经 ac 了,但是又重新提交了一遍 # 避免这道题已经 ac 了,但是又重新提交了一遍
if not contest_submission.ac: if not contest_submission.ac:
# 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时 # 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时
# logger.debug(contest.start_time)
# logger.debug(submission.create_time)
# logger.debug((submission.create_time - contest.start_time).total_seconds())
# logger.debug(int((submission.create_time - contest.start_time).total_seconds() / 60))
contest_submission.ac_time = int((submission.create_time - contest.start_time).total_seconds()) contest_submission.ac_time = int((submission.create_time - contest.start_time).total_seconds())
contest_submission.total_time += contest_submission.ac_time contest_submission.total_time += contest_submission.ac_time
contest_submission.total_submission_number += 1 contest_submission.total_submission_number += 1
@ -79,6 +94,7 @@ class MessageQueue(object):
contest_problem.save() contest_problem.save()
except ContestSubmission.DoesNotExist: except ContestSubmission.DoesNotExist:
# 第一次提交 # 第一次提交
with transaction.atomic():
is_ac = submission.result == result["accepted"] is_ac = submission.result == result["accepted"]
first_achieved = False first_achieved = False
ac_time = 0 ac_time = 0
@ -97,6 +113,5 @@ class MessageQueue(object):
ac=is_ac, total_time=total_time, first_achieved=first_achieved, ac=is_ac, total_time=total_time, first_achieved=first_achieved,
ac_time=ac_time) ac_time=ac_time)
logger.debug("Start message queue") logger.debug("Start message queue")
MessageQueue().listen_task() MessageQueue().listen_task()

View File

@ -282,11 +282,15 @@ def problem_list_page(request, page=1):
except Exception: except Exception:
pass pass
if request.user.is_authenticated() and request.user.problems_status:
problems_status = json.loads(request.user.problems_status)
else:
problems_status = {}
# 右侧标签列表 按照关联的题目的数量排序 排除题目数量为0的 # 右侧标签列表 按照关联的题目的数量排序 排除题目数量为0的
tags = ProblemTag.objects.annotate(problem_number=Count("problem")).filter(problem_number__gt=0).order_by("-problem_number") tags = ProblemTag.objects.annotate(problem_number=Count("problem")).filter(problem_number__gt=0).order_by("-problem_number")
return render(request, "oj/problem/problem_list.html", return render(request, "oj/problem/problem_list.html",
{"problems": current_page, "page": int(page), {"problems": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "previous_page": previous_page, "next_page": next_page,
"keyword": keyword, "tag": tag_text, "keyword": keyword, "tag": tag_text,"problems_status": problems_status,
"tags": tags, "difficulty_order": difficulty_order}) "tags": tags, "difficulty_order": difficulty_order})

View File

@ -1,4 +1,3 @@
@import url("global.css");
@import url("bootstrap/bootstrap.min.css"); @import url("bootstrap/bootstrap.min.css");
@import url("bootstrap/todc-bootstrap.min.css"); @import url("bootstrap/todc-bootstrap.min.css");
@import url("codeMirror/codemirror.css"); @import url("codeMirror/codemirror.css");
@ -6,6 +5,7 @@
@import url("webuploader/webuploader.css"); @import url("webuploader/webuploader.css");
@import url("datetime_picker/bootstrap-datetimepicker.css"); @import url("datetime_picker/bootstrap-datetimepicker.css");
@import url("tagEditor/jquery.tag-editor.css"); @import url("tagEditor/jquery.tag-editor.css");
@import url("global.css");
#loading-gif { #loading-gif {
width: 40px; width: 40px;

View File

@ -1,13 +1,17 @@
html{ body, button, input, select, textarea, h1, h2, h3, h4, h5, h6 {
font-family: Georgia, STHeiti, "Microsoft Yahei", SimSun, "Droid Sans";
}
html {
height: 100%; height: 100%;
} }
body{ body {
height:100%; /*使内容高度和body一样*/ height: 100%; /*使内容高度和body一样*/
margin-bottom:-80px;/*向上缩减80像素不至于footer超出屏幕可视范围*/ margin-bottom: -80px; /*向上缩减80像素不至于footer超出屏幕可视范围*/
} }
.main{ .main {
padding-bottom: 120px; padding-bottom: 120px;
} }
@ -30,10 +34,11 @@ label {
display: none display: none
} }
.right{ .right {
float: right; float: right;
} }
.CodeMirror pre {
font-family: "Consolas","Bitstream Vera Sans Mono","Courier New", Courier, monospace !important; pre {
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
} }

View File

@ -1,8 +1,7 @@
@import url("global.css");
@import url("bootstrap/bootstrap.min.css"); @import url("bootstrap/bootstrap.min.css");
@import url("bootstrap/todc-bootstrap.min.css"); @import url("bootstrap/todc-bootstrap.min.css");
@import url("codeMirror/codemirror.css"); @import url("codeMirror/codemirror.css");
@import url("global.css");
#language-selector { #language-selector {
width: 130px; width: 130px;

BIN
static/src/img/chrome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
static/src/img/firefox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
static/src/img/ie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>不支持的浏览器</title>
<style>
body{
padding-top: 50px;;
}
div {
margin: 20px;
display: inline;
}
</style>
</head>
<body>
很抱歉,我们无法完全兼容低版本的 IE 浏览器,您可以
<a href="http://down.tech.sina.com.cn/page/40975.html">
<div>
<img src="/static/img/chrome.png">使用Chrome
</div>
</a>
<a href="https://www.mozilla.org/zh-CN/firefox/new/?scene=2#download-fx">
<div>
<img src="/static/img/firefox.png">使用FireFox
</div>
</a>
<a href="http://windows.microsoft.com/en-us/internet-explorer/download-ie">
<div>
<img src="/static/img/ie.png">升级IE
</div>
</a>
</body>
</html>

View File

@ -46,7 +46,14 @@ class SubmissionAPIView(APIView):
judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception: except Exception:
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")
# 修改用户解题状态
if request.user.problems_status:
problems_status = json.loads(request.user.problems_status)
else:
problems_status = {}
problems_status[str(data["problem_id"])] = 2
request.user.problems_status = json.dumps(problems_status)
request.user.save()
# 增加redis 中判题队列长度的计数器 # 增加redis 中判题队列长度的计数器
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
r.incr("judge_queue_length") r.incr("judge_queue_length")

View File

@ -54,13 +54,11 @@
</nav> </nav>
<!-- nav end --> <!-- nav end -->
<!--browser happy begin --> <script>
<!--[if lt IE 9]> if(navigator.userAgent.indexOf("MSIE") > -1){
<div class="alert alert-danger text-center" role="alert"> location.href = "/static/img/unsupported_browser.html";
当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>. }
</div> </script>
<![endif]-->
<!-- browser happy end -->
<div class="container main"> <div class="container main">
<div class="row"> <div class="row">

View File

@ -45,7 +45,12 @@
{% for item in result %} {% for item in result %}
<tr> <tr>
<th scope="row">{{ forloop.counter }}</th> <th scope="row">{{ forloop.counter }}</th>
<td>{{ item.username }}</td> <td>
{{ item.username }}
{% if show_real_name %}
{{ item.real_name }}
{% endif %}
</td>
<td>{{ item.total_ac }} / {{ item.total_submit }}</td> <td>{{ item.total_ac }} / {{ item.total_submit }}</td>
<td>{% if item.total_time %}{{ item.total_time }}{% else %}--{% endif %}</td> <td>{% if item.total_time %}{{ item.total_time }}{% else %}--{% endif %}</td>
{% for problem in item.problems %} {% for problem in item.problems %}

View File

@ -59,6 +59,12 @@
{% endfor %} {% endfor %}
</p> </p>
</div> </div>
{% if problem.source %}
<div class="problem-section hide">
<label class="problem-label">来源</label>
<div class="problem-detail">{{ problem.source }}</div>
</div>
{% endif %}
<div> <div>
<label>选择语言</label> <label>选择语言</label>
<div> <div>

View File

@ -28,7 +28,7 @@
<tbody> <tbody>
{% for item in problems %} {% for item in problems %}
<tr> <tr>
<th><span class="glyphicon glyphicon-ok ac-flag"></span></th> <th><span class="{% get_problem_status problems_status item.id %}"></span></th>
<th scope="row"><a href="/problem/{{ item.id }}/">{{ item.id }}</a></th> <th scope="row"><a href="/problem/{{ item.id }}/">{{ item.id }}</a></th>
<td><a href="/problem/{{ item.id }}/">{{ item.title }}</a></td> <td><a href="/problem/{{ item.id }}/">{{ item.title }}</a></td>
<td> <td>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="zh-cn">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -21,13 +21,11 @@
<body> <body>
<!--browser happy begin --> <script>
<!--[if lt IE 9]> if(navigator.userAgent.indexOf("MSIE") > -1){
<div class="alert alert-danger text-center" role="alert"> location.href = "/static/img/unsupported_browser.html";
当前网页 <strong>不支持</strong> 你正在使用的浏览器. 为了正常的访问, 请 <a href="http://browsehappy.com/">升级你的浏览器</a>. }
</div> </script>
<![endif]-->
<!-- browser happy end -->
<!-- nav begin --> <!-- nav begin -->
<nav class="navbar navbar-masthead navbar-default navbar-static-top"> <nav class="navbar navbar-masthead navbar-default navbar-static-top">

View File

@ -22,37 +22,29 @@
<li>System Error: 判题系统发生故障,请等待重判</li> <li>System Error: 判题系统发生故障,请等待重判</li>
<li>Waiting: 你的提交正在等待处理</li> <li>Waiting: 你的提交正在等待处理</li>
</ul> </ul>
<h4>支持的语言</h4>
<ul>
<li>C (GCC 4.8)</li>
<li>C++ (G++ 4.3)</li>
<li>Java (Oracle JDK 1.7)</li>
</ul>
<h4>编译参数</h4> <h4>编译参数</h4>
<ul> <ul>
<li>C</li> <li>CGCC 4.8</li>
<p>gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}main</p> <pre>gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}main</pre>
<li>C++</li> <li>C++G++ 4.3</li>
<p>g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}main</p> <pre>g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}main</pre>
<li>Java</li> <li>JavaOracle JDK 1.7</li>
<p>javac {src_path} -d {exe_path}</p> <pre>
<p>java -cp {exe_path} Main</p> //编译
</ul> javac {src_path} -d {exe_path}
//运行
java -cp {exe_path} Main</pre>
</ul>
<h2 class="text-center">常见问题</h2> <h2 class="text-center">常见问题</h2>
<ul> <ul>
<li>输入输出</li> <li>无特殊说明,请使用标准输入输出。</li>
<p>无特殊说明,请使用标准输入输出</p> <li>Java 代码需使用 Main 作为主类名。C/C++代码使用<code>int main()</code>,并且需要<code>return 0;</code></li>
<li>C/C++的64位整数类型</li> <li>C/C++ 的64位整数类型请使用 <code>long long</code> 声明,使用 <code>cin/cout</code><code>%lld</code> 输入输出。
<p>请使用long long声明使用cin/cout或 %lld输入输出</p> 使用<code>__int64</code>会导致编译错误。</li>
<li>判题结果与本地执行结果不一致</li> <li>程序执行时间指CPU时间占用内存按执行过程中内存消耗的峰值计有多组测试数据时以最大的时间和内存消耗为准</li>
<p>是否使用了不同版本的编译器VC和TC并不完全符合C/C++标准)</p>
<p>判题时可能使用了与您测试时不同的测试数据(不仅限于样例中展示的数据)</p>
<li>程序执行时间和占用的内存如何计算</li>
<p>执行时间指CPU时间占用内存按执行过程中内存消耗的峰值计有多组测试数据时以最大的时间和内存消耗为准</p>
</ul> </ul>
</div> </div>

View File

@ -9,6 +9,12 @@ template_release_path = "template/release/"
static_src_path = "static/src/" static_src_path = "static/src/"
static_release_path = "static/release/" static_release_path = "static/release/"
print "Begin to compress js"
if os.system("node static/src/js/r.js -o static/src/js/build.js"):
print "Failed to compress js, exit"
exit()
try: try:
# 删除模板的 release 文件夹 # 删除模板的 release 文件夹
shutil.rmtree(template_release_path) shutil.rmtree(template_release_path)
@ -30,7 +36,6 @@ name_map = {}
def process(match): def process(match):
file_path = match.group(1).replace("/static/", "") file_path = match.group(1).replace("/static/", "")
# print file_path, match.group(), match.group(1)
if not os.path.exists(static_release_path + file_path): if not os.path.exists(static_release_path + file_path):
return match.group(0) return match.group(0)
@ -49,9 +54,11 @@ def process(match):
return match.group(0) return match.group(0)
print "Begin to add md5 stamp in html"
for root, dirs, files in os.walk(template_release_path): for root, dirs, files in os.walk(template_release_path):
for name in files: for name in files:
html_path = os.path.join(root, name) html_path = os.path.join(root, name)
print "Processing: " + html_path
html_content = open(html_path, "r").read() html_content = open(html_path, "r").read()
js_replaced_html_content = re.sub(js_re, process, html_content) js_replaced_html_content = re.sub(js_re, process, html_content)
css_replaced_html_content = re.sub(css_re, process, js_replaced_html_content) css_replaced_html_content = re.sub(css_re, process, js_replaced_html_content)
@ -59,3 +66,5 @@ for root, dirs, files in os.walk(template_release_path):
f = open(html_path, "w") f = open(html_path, "w")
f.write(css_replaced_html_content) f.write(css_replaced_html_content)
f.close() f.close()
print "Done"

View File

@ -8,7 +8,16 @@ def get_problem_accepted_radio(problem):
return "0%" return "0%"
def get_problem_status(problems_status, problem_id):
if str(problem_id) in problems_status:
if problems_status[str(problem_id)] == 1:
return "glyphicon glyphicon-ok ac-flag"
return "glyphicon glyphicon-minus dealing-flag"
return ""
from django import template from django import template
register = template.Library() register = template.Library()
register.filter("accepted_radio", get_problem_accepted_radio) register.filter("accepted_radio", get_problem_accepted_radio)
register.simple_tag(get_problem_status, name="get_problem_status")