搭建与二次开发自己的OJ

· · 个人记录

因为洛谷博客代码中吃 \$ ,所以 PHP 的变量前的 \$ 在这篇博客里全部被删除。

如果想要原版文章,请访问 https://oi-master.gitee.io/2020/12/30/%E6%90%AD%E5%BB%BA%E5%92%8C%E4%BA%8C%E6%AC%A1%E5%BC%80%E5%8F%91%E6%82%A8%E7%9A%84OJ/

以下是加工后的内容。

欢迎阅读 OI-Master 的博客!本文将会介绍如何搭建您自己的 Online Judge。若您想要 Online Judge 功能更多或者前端更好看,我们也会初步介绍二次开发。

我希望大家的搭建过程不枯燥,并且二次开发、配置的过程尽可能十分舒服。所以,我们选用刚开始默认前端并不太好看的 HustOJ,稍后会更改前端。

如果您想搭建前段默认很好的 qduoj,推荐阅读 Steve George 的日报。

很好!让我们开始吧!

服务器准备

我们需要准备一台 Ubuntu18.04 服务器。OI-Master 推荐您使用 腾讯云 的服务器。这个平台的账号是可以用 QQ、微信账号的,并且对于新用户优惠较多,也有便宜的学生机。如果您真的没有钱来购买,您可以使用 Ubuntu 18.04 Server 虚拟机。

如果您需要使用虚拟机,您可以在 清华大学开源镜像站 进行下载 Ubuntu 18.04 系统。点击右侧 \color{white}\colorbox{lightblue}{获取下载链接} 按钮。左侧选择 \color{blue}\text{Ubuntu} ,然后下载 \color{blue}\text{18.04.5 (amd64, Server)}

打开您的虚拟机软件(如 VMware),安装这个系统。安装过程因软件而定。如果您没有虚拟机软件,推荐 VMware 的虚拟机,支持简易安装,对于新手是很好的事。

更换源

如果您是阿里云用户,可以跳过本段。其他用户需要更换您的 Ubuntu 源。

修改 Ubuntu 源的指令是有些复杂的,但是 HustOJ 官方给出一个更简单的脚本,只有 2 行代码。请在终端中输入:

wget http://dl.hustoj.com/update-sources-ubuntu.sh
sudo bash update-sources-ubuntu.sh

此处会需要输入密码。密码不会显示,请您不要认为没有输入进去。

出错可能

如果您看到这些文字:

E: Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable)
E: Unable to lock directory /var/lib/apt/lists/

就说明您过于着急,您的系统还未准备好。请重新运行这行指令。

sudo bash update-sources-ubuntu.sh

完成

如果您看到这样(或类似)的文字:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
142 packages can be upgraded. Run 'apt list --upgradable' to see them.

那么恭喜!您已经成功更换源!

安装 HustOJ

HustOJ 的开发者们是十分良心的。他们又提供了一份智能化代码来一键安装 HustOJ。为了方便,我们使用这个代码。

首先您需要下载代码。为了节约您的生命,我们选择 Gitee 上的镜像。

wget https://gitee.com/zhblue/hustoj/raw/master/trunk/install/install-ubuntu18-gitee.sh

下载完成后,运行这份代码。

sudo bash install-ubuntu18-gitee.sh

等!注意可能中间会弹出几个 Warning,不用管。正常等待时间是 10 分钟左右。在这一段时间里,您可以先写一个 LCA 模板来玩玩。

p.s.: 其实 OI-Master 的服务器在这里出问题了,不过这不重要(bushi。 ## 后台 ### 警告! 接下来的内容因为稍微复杂,所以即将出现多张大图! ### 进入 打开您服务器的公网 IP 或用服务器访问 127.0.0.1,即可看到您的 HustOJ! OI-Master 将会用自己的服务器给大家演示。 首先,让我们注册一个账号。 打开您的 OJ,然后点击注册。 ![注册](https://i.loli.net/2020/12/30/jxJ3K81lovcpFHg.png) 注册一个学号为 `admin` 的用户。 ![注册](https://i.loli.net/2020/12/30/czn2TGP34L8yuNR.png) p.s. OI-Master 其实现在真的是小学生( 完成了吗?现在,您的账号自动就有了管理权限! 接下来,我们进入后台看看。 ![后台](https://i.loli.net/2020/12/30/7asTJQYmBi9LRwt.png) 后台左侧的样子应该是这样的。 ![后台](https://i.loli.net/2020/12/30/73CuAWUNhEXod6V.png) ## 删除广告 HustOJ 也有几处有些恶心的东西。例如——广告。 ![这顶上是啥](https://i.loli.net/2020/12/30/Ycu5C4bGeRM97LP.png) 还有底部: ![底部](https://i.loli.net/2020/12/30/YFrqbSZkaC3JGsO.png) 那么如何才能去掉这些呢? ### 顶部去除 进入后台,然后点击 $\color{white}\colorbox{lightblue}{新闻-设置公告}$,或进入左下链接。另外,鼠标真的不好写字…… ![新闻](https://i.loli.net/2020/12/30/7VsIghiK1OQyXkB.png) 直接对着框一顿 `Backspace` 就行了。 ![后台](https://i.loli.net/2020/12/30/BpWAXS8yaNrGwHV.png) ### 尾部广告 这个……稍后讲二次开发的时候再说吧。 ## 高级后台功能 普通的后台功能就在这里了,十分清楚。接下来,我们来讲讲高级的后台功能。 ### 修改帮助 ![帮助页面](https://i.loli.net/2020/12/30/LbCmrqnIYlsoPEF.png) 你看,是不是格式十分难看?丑的要命? 后台呢?看起来没有这个功能?不!我们可以改! 进入后台,按下 $\color{white}\colorbox{lightblue}{新闻-添加}$ 按钮。 ![image.png](https://i.loli.net/2020/12/30/57LxEZRNMOybKQ6.png) 输入以下内容,然后保存。注意,标题一定要为 `faqs.cn`! ![保存](https://i.loli.net/2020/12/30/yg3jHrLt2XhzCxA.png) 再看看前台? ![改了](https://i.loli.net/2020/12/30/4fi3ML6j2ChryBs.png) Yes! 现在,您可以把 `test` 在后台改成任意内容,然后编写您自己的 FAQ! ### 克隆题目 想用用别的 OJ 的好题?不想重新输入题面?克隆题目功能可以帮助你! 注意,本功能只能复制题面,无法克隆数据! 因为这个功能并没有淦完,所以 HustOJ 把这个功能做得非常不起眼。看看它的后台入口! ![左侧](https://i.loli.net/2020/12/30/x91UyXgTivMCuoH.png) 看这个后台的左侧!看见了吗?看见了吗?非常浅的一行! 那么我们将会打开,出现几个链接。发现这个功能支持很多 OJ,包括洛谷 3.0(现在是 4.0 了,前端有变化,所以会出点问题),现在您只要有数据,就可以复制题面了! ## 二次开发 ### 宝塔 这一段为了更好地使用,可以下载 [宝塔](https://www.bt.cn/)。 进入终端,然后输入安装指令: ```shell wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh ``` 然后输入密码,这时候出现了一个情况: ```shell 已有Web环境,安装宝塔可能影响现有站点 Web service is alreday installed,Can't install panel ---------------------------------------------------- 输入yes强制安装/Enter yes to force installation (yes/n): ``` 这里的现有站点应该是 HustOJ,不过没事,安装宝塔不会干扰这个。输入 `yes`。 然后等待约 $9$ 分钟,大佬可以写个 [侦探推理](https://www.luogu.com.cn/problem/P1039)。 接下来,千万不要关闭终端!看末尾的几串字符(为了安全在这里我们强制打了码): ![用户密码](https://i.loli.net/2020/12/30/TfK8pVNUCBzL4Qs.png) 我们访问这个链接,登录后接受这个协议。您一定要翻到底部! ### db_info.inc.php ![面板](https://i.loli.net/2020/12/30/KA7JaVrhtWLm4dB.png) 我们不要管这个窗口,叉掉即可。然后点击 $\color{lightgray}\colorbox{black}{文件}$ 按钮。 在上方输入 `/home/judge/src/web/include`,然后您应该可以看到一些 `.php` 文件。 往下翻,找到 `db_info.inc.php`,鼠标右击编辑。 ```php <?php @session_start(); //ini_set("display_errors", "Off"); //set this to "On" for debugging ,especially when no reason blank shows up. //header('X-Frame-Options:SAMEORIGIN'); //for people using hustoj out of China , be careful of the last two line of this file ! // connect db static DB_HOST="localhost"; //数据库服务器ip或域名 static DB_NAME="jol"; //数据库名 static DB_USER="debian-sys-maint"; //数据库账户 static DB_PASS="tSIqUCnBNiuByEOp"; //数据库密码 static OJ_NAME="HUSTOJ"; //左上角显示的系统名称 static OJ_HOME="./"; //主页目录 static OJ_ADMIN="root@localhost"; //管理员email static OJ_DATA="/home/judge/data"; //测试数据目录 static OJ_BBS=false; //设为"discuss3" 启用, "bbs" for phpBB3 bridge or "discuss" for mini-forum or false for close any static OJ_ONLINE=false; //是否记录在线情况 static OJ_LANG="en"; //默认语言 static OJ_SIM=false; //显示相似度 static OJ_DICT=false; //显示在线翻译 static OJ_LANGMASK=1637684; //TIOBE index top 10, calculator : https://pigeon-developer.github.io/hustoj-langmask/ static OJ_EDITE_AREA=true; //true: syntax highlighting is active static OJ_ACE_EDITOR=true; static OJ_AUTO_SHARE=false; //true: One can view all AC submit if he/she has ACed it onece. static OJ_CSS="white.css"; static OJ_SAE=false; //using sina application engine static OJ_VCODE=false; //验证码 static OJ_APPENDCODE=false; // 代码预定模板 if (!OJ_APPENDCODE) ini_set("session.cookie_httponly", 1); // APPENDCODE模式需要允许javascript操作cookie保存当前语言。 static OJ_CE_PENALTY=false; // 编译错误是否罚时 static OJ_PRINTER=false; //启用打印服务 static OJ_MAIL=false; //内邮 static OJ_MARK="mark"; // "mark" for right "percent" for WA static OJ_MEMCACHE=false; //使用内存缓存 static OJ_MEMSERVER="127.0.0.1"; static OJ_MEMPORT=11211; static OJ_UDP=true; //使用UDP通知 static OJ_UDPSERVER="127.0.0.1"; static OJ_UDPPORT=1536; static OJ_REDIS=false; //使用REDIS队列 static OJ_REDISSERVER="127.0.0.1"; static OJ_REDISPORT=6379; static OJ_REDISQNAME="hustoj"; static SAE_STORAGE_ROOT="http://hustoj-web.stor.sinaapp.com/"; static OJ_CDN_URL=""; // http://cdn.hustoj.com/ https://raw.githubusercontent.com/zhblue/hustoj/master/trunk/web/ static OJ_TEMPLATE="bs3"; //使用的默认模板, [bs3 ie ace sweet sae mario] work with discuss3, [classic bs] work with discuss //if(isset(_GET['tp'])) OJ_TEMPLATE=_GET['tp']; if (OJ_TEMPLATE == "classic") OJ_CSS="hoj.css"; static OJ_LOGIN_MOD="hustoj"; static OJ_REGISTER=true; //允许注册新用户 static OJ_REG_NEED_CONFIRM=false; //新注册用户需要审核 static OJ_NEED_LOGIN=false; //需要登录才能访问 static OJ_LONG_LOGIN=false; //启用长时间登录信息保留 static OJ_KEEP_TIME="30"; //登录Cookie有效时间(单位:天(day),仅在上一行为true时生效) static OJ_RANK_LOCK_PERCENT=0; //比赛封榜时间比例 static OJ_SHOW_DIFF=false; //是否显示WA的对比说明 static OJ_DOWNLOAD=false; //是否允许下载WA的测试数据 static OJ_TEST_RUN=false; //提交界面是否允许测试运行 static OJ_MATHJAX=false; // 激活mathjax static OJ_BLOCKLY=false; //是否启用Blockly界面 static OJ_ENCODE_SUBMIT=false; //是否启用base64编码提交的功能,用来回避WAF防火墙误拦截。 static OJ_OI_1_SOLUTION_ONLY=false; //比赛是否采用noip中的仅保留最后一次提交的规则。true则在新提交发生时,将本场比赛该题老的提交删除。 static OJ_OI_MODE=false; //是否开启OI比赛模式,禁用排名、状态、统计、用户信息、内邮、论坛等。 static OJ_SHOW_METAL=true; //榜单上是否按比例显示奖牌 static OJ_RANK_LOCK_DELAY=3600; //赛后封榜持续时间,单位秒。根据实际情况调整,在闭幕式颁奖结束后设为0即可立即解封。 static OJ_BENCHMARK_MODE=false; //此选项将影响代码提交,不再有提交间隔限制,提交后会返回solution id static OJ_CONTEST_RANK_FIX_HEADER=false; //比赛排名水平滚动时固定名单 static OJ_NOIP_KEYWORD="noip"; // 标题包含此关键词,激活noip模式,赛中不显示结果,仅保留最后一次提交。 static OJ_BEIAN=false; // 如果有备案号,填写备案号 //static OJ_EXAM_CONTEST_ID=1000; // 启用考试状态,填写考试比赛ID //static OJ_ON_SITE_CONTEST_ID=1000; //启用现场赛状态,填写现场赛比赛ID /* share code */ static OJ_SHARE_CODE=false; // 代码分享功能 /* recent contest */ static OJ_RECENT_CONTEST=true; // "http://algcontest.rainng.com/contests.json" ; // 名校联赛 //OJ_ON_SITE_TEAM_TOTAL用于根据比例的计算奖牌的队伍总数 //CCPC比赛的一种做法是比赛结束后导出终榜看AC至少1题的不打星的队伍数,现场修改此值即可正确计算奖牌 //0表示根据榜单上的出现的队伍总数计算(包含了AC0题的队伍和打星队伍) static OJ_ON_SITE_TEAM_TOTAL=0; static OJ_OPENID_PWD='8a367fe87b1e406ea8e94d7d508dcf01'; /* weibo config here */ static OJ_WEIBO_AUTH=false; static OJ_WEIBO_AKEY='1124518951'; static OJ_WEIBO_ASEC='df709a1253ef8878548920718085e84b'; static OJ_WEIBO_CBURL='http://192.168.0.108/JudgeOnline/login_weibo.php'; /* renren config here */ static OJ_RR_AUTH=false; static OJ_RR_AKEY='d066ad780742404d85d0955ac05654df'; static OJ_RR_ASEC='c4d2988cf5c149fabf8098f32f9b49ed'; static OJ_RR_CBURL='http://192.168.0.108/JudgeOnline/login_renren.php'; /* qq config here */ static OJ_QQ_AUTH=false; static OJ_QQ_AKEY='1124518951'; static OJ_QQ_ASEC='df709a1253ef8878548920718085e84b'; static OJ_QQ_CBURL='192.168.0.108'; /* log */ OJ_LOG_FILE="/var/log/hustoj/{OJ_NAME}.log"; static OJ_LOG_ENABLED=false; static OJ_LOG_DATETIME_FORMAT="Y-m-d H:i:s"; static OJ_LOG_PID_ENABLED=false; static OJ_LOG_USER_ENABLED=false; static OJ_LOG_URL_ENABLED=false; static OJ_LOG_URL_HOST_ENABLED=false; static OJ_LOG_URL_PARAM_ENABLED=false; static OJ_LOG_TRACE_ENABLED=false; //if(date('H')<5||date('H')>21||isset(_GET['dark'])) OJ_CSS="dark.css"; if (isset(_SESSION[OJ_NAME . '_' . 'OJ_LANG'])) { OJ_LANG=_SESSION[OJ_NAME . '_' . 'OJ_LANG']; } else if (isset(_COOKIE['lang']) && in_array(_COOKIE['lang'], array("cn", "ug", "en", 'fa', 'ko', 'th'))) { OJ_LANG=_COOKIE['lang']; } else if (isset(_GET['lang']) && in_array(_GET['lang'], array("cn", "ug", "en", 'fa', 'ko', 'th'))) { OJ_LANG=_GET['lang']; } else if (isset(_SERVER['HTTP_ACCEPT_LANGUAGE']) && strstr(_SERVER['HTTP_ACCEPT_LANGUAGE'], "zh-CN")) { OJ_LANG="cn"; } require_once(dirname(__FILE__) . "/pdo.php"); // use db //pdo_query("set names utf8"); //sychronize php and mysql server with timezone settings, dafault setting for China //if you are not from China, comment out these two lines or modify them. //date_default_timezone_set("PRC"); //pdo_query("SET time_zone ='+8:00'"); require_once(dirname(__FILE__) . "/logger.php"); logger=new Logger(_SESSION[OJ_NAME . '_' . 'user_id'], OJ_LOG_FILE, OJ_LOG_DATETIME_FORMAT, OJ_LOG_ENABLED, OJ_LOG_PID_ENABLED, OJ_LOG_USER_ENABLED, OJ_LOG_URL_ENABLED, OJ_LOG_URL_HOST_ENABLED, OJ_LOG_URL_PARAM_ENABLED, OJ_LOG_TRACE_ENABLED); logger->info(); ``` 您会看到这样子的内容。上面的注释写得很清楚,您可以个性化修改。 如果出现问题,您可以来本博客复制上方内容恢复。 注意第 47 行。下面我们将会详细介绍主题问题。 ### 主题 我们的主题默认是 `bs3` 主题。看看 HustOJ 还有哪些主题。 打开 `/home/judge/src/web/template`,看见这些文件夹。 ![template](https://i.loli.net/2020/12/30/4XmxiGYWCqQBVN8.png) 看到了吗?这些是我们的主题。 + bs3 + bshark + mario + sweet > p.s. OI-Master 写完本文后又突然更新了一个 syzoj 主题,大家可以试试qwq,这里太颓了不改了 我们来做个实验试试。我们把上面的 47 行改成 `static OJ_TEMPLATE="sweet";` 保存后,来到前台看看!哇! ![sweet](https://i.loli.net/2020/12/30/B6bMC92tOksTQXz.png) 是不是酷很多!这个界面目前是绝大多数用户认为 HustOJ 最好看的主题。目前,[JZOJ](http://www.jzoj.cn/index.php)、现在已经消失的小白菜OJ 等 OJ 都在使用此主题。 若果您觉得这些主题都太丑了,您也可以自己新建一个文件夹,用 `PHP` 等语言写一个主题。 ### 广告去除(二次开发前端) 以 `bs3` 为例。之前我们讲过上方的广告如何去除,现在我们来看看下方。 我们查看 `bs3` 主题目录下的 `index.php` 文件,看看下方的页脚是怎么实现的。 ```php <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <link rel="icon" href="../../favicon.ico"> <title> <?php echo OJ_NAME?> </title> <?php include("template/OJ_TEMPLATE/css.php");?> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> <script src="http://cdn.bootcss.com/html5shiv/3.7.0/html5shiv.js"></script> <script src="http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <?php include("template/OJ_TEMPLATE/nav.php");?> <!-- Main component for a primary marketing message or call to action --> <div class="jumbotron"> <p> <center> Recent submission : <?php echo speed?> . <div id=submission style="width:80%;height:300px"></div> </center> </p> <?php echo view_news?> </div> </div> <!-- /container --> <!-- Bootstrap core JavaScript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <?php include("template/OJ_TEMPLATE/js.php");?> <script language="javascript" type="text/javascript" src="<?php echo OJ_CDN_URL?>include/jquery.flot.js"></script> <script type="text/javascript"> ( function () { var d1 = <?php echo json_encode(chart_data_all)?>; var d2 = <?php echo json_encode(chart_data_ac)?>; .plot( ( "#submission" ), [ { label: "<?php echo MSG_SUBMIT?>", data: d1, lines: { show: true } }, { label: "<?php echo MSG_SOVLED?>", data: d2, bars: { show: true } } ], { grid: { backgroundColor: { colors: [ "#fff", "#eee" ] } }, xaxis: { mode: "time" //, //max:(new Date()).getTime(), //min:(new Date()).getTime()-100*24*3600*1000 } } ); } ); //alert((new Date()).getTime()); </script> </body> </html> ``` 注意 46 行,这里内嵌了一个 `PHP` 文件,这应该是我们需要的页脚等信息。我们打开 `js.php`。 ```php <!-- jQuery文件。务必在bootstrap.min.js 之前引入 --> <script src="<?php echo OJ_CDN_URL.path_fix."template/OJ_TEMPLATE/"?>jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="<?php echo OJ_CDN_URL.path_fix."template/OJ_TEMPLATE/"?>bootstrap.min.js"></script> <?php if(file_exists("./admin/msg.txt")) view_marquee_msg=file_get_contents(OJ_SAE?"saestor://web/msg.txt":"./admin/msg.txt"); if(file_exists("../admin/msg.txt")) view_marquee_msg=file_get_contents(OJ_SAE?"saestor://web/msg.txt":"../admin/msg.txt"); /* <!-- to enable mathjax in hustoj: svn export http://github.com/mathjax/MathJax/trunk /home/judge/src/web/mathjax <script type="text/javascript" src="mathjax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script> or <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script> --> */ ?> <script> (document).ready(function(){ <?php if(view_marquee_msg!="") { ?> var msg="<marquee style='margin-top:10px' direction='left' scrollamount=3 scrolldelay=50 onMouseOver='this.stop()'"+ " onMouseOut='this.start()' class=toprow>"+<?php echo json_encode(view_marquee_msg); ?>+"</marquee>"; (".jumbotron").prepend(msg); <?php } ?> ("form").append("<div id='csrf' />"); ("#csrf").load("<?php echo path_fix?>csrf.php"); ("body").append("<div id=footer class=center >GPLv2 licensed by <a href='https://github.com/zhblue/hustoj' >HUSTOJ</a> "+(new Date()).getFullYear()+" </div>"); ("body").append("<center><?php echo MSG_HELP_HUSTOJ?></center>"); ("body").append("<div class=center > <img src='http://hustoj.com/wx.jpg' width='120px'><img src='http://hustoj.com/alipay.png' width='120px'><br> 欢迎关注微信公众号onlinejudge</div>"); <?php if(isset(OJ_BEIAN)&&OJ_BEIAN){ ?> ("body").append("<br><center><a href='http://beian.miit.gov.cn/' target='_blank'><?php echo OJ_BEIAN?></a></center>"); <?php } ?> <?php if(isset(_SESSION[OJ_NAME."_administrator"])) echo "admin_mod();"; ?> }); (".hint pre").each(function(){ var plus="<span class='glyphicon glyphicon-plus'>Click</span>"; var content=(this); (this).before(plus); (this).prev().click(function(){ content.toggle(); }); }); console.log("If you want to change the appearance of the web pages, make a copy of bs3 under template directory.\nRename it to whatever you like, and change the OJ_TEMPLATE value in db_info.inc.php\nAfter that modify files under your own directory .\n"); console.log("To enable mathjax in hustoj, check line 15 in /home/judge/src/web/template/bs3/js.php"); function admin_mod(){ ("div[fd=source]").each(function(){ let pid=(this).attr('pid'); (this).append("<span><span class='label label-success' pid='"+pid+"' onclick='problem_add_source(this,"+pid+");'>+</span></span>"); }); ("span[fd=time_limit]").each(function(){ let sp=(this); let pid=(this).attr('pid'); (this).dblclick(function(){ let time=sp.text(); console.log("pid:"+pid+" time_limit:"+time); sp.html("<form onsubmit='return false;'><input type=hidden name='m' value='problem_update_time'><input type='hidden' name='pid' value='"+pid+"'><input type='text' name='t' value='"+time+"' selected='true' class='input-mini' size=2 ></form>"); let ipt=sp.find("input[name=t]"); ipt.focus(); ipt[0].select(); sp.find("input").change(function(){ let newtime=sp.find("input[name=t]").val(); .post("admin/ajax.php",sp.find("form").serialize()).done(function(){ console.log("new time_limit:"+time); sp.html(newtime); }); }); }); }); } function problem_add_source(sp,pid){ console.log("pid:"+pid); let p=(sp).parent(); p.html("<form onsubmit='return false;'><input type='hidden' name='m' value='problem_add_source'><input type='hidden' name='pid' value='"+pid+"'><input type='text' class='input input-large' name='ns'></form>"); p.find("input").focus(); p.find("input").change(function(){ console.log(p.find("form").serialize()); let ns=p.find("input[name=ns]").val(); console.log("new source:"+ns); .post("admin/ajax.php",p.find("form").serialize()); p.parent().append("<span class='label label-success'>"+ns+"</span>"); p.html("<span class='label label-success' pid='"+pid+"' onclick='problem_add_source(this,"+pid+");'>+</span>"); }); } </script> ``` 看到 42,43 行,就是我们的页脚最后的二维码和爱心代码!注释掉即可。保存刷新,看看前端。 ![页脚](https://i.loli.net/2020/12/30/upDEt4hfTU7bxVy.png) 消失了!现在我们已经成功修改前端了! ## 评测机 HustOJ 的评测系统也是十分完善的。 不过,有些时候,我们还是可以自定义评测集的设置。 我们使用宝塔进入 `/home/judge/etc`,然后修改 judge.conf。 ```php #Database Config OJ_HOST_NAME=127.0.0.1 OJ_USER_NAME= #这里是数据库用户名 OJ_PASSWORD= #这里是数据库密码 #以上两行我已删除账号密码,防止被 Hack OJ_DB_NAME=jol OJ_PORT_NUMBER=3306 #CPU cores Config OJ_RUNNING=1 #Query Interval/UDP timeout OJ_SLEEP_TIME=1 #Multi-Judger Task Divider OJ_TOTAL=1 OJ_MOD=0 #Java and Other VM language bonus OJ_JAVA_TIME_BONUS=2 OJ_JAVA_MEMORY_BONUS=64 #JVM Compiler Settings OJ_JAVA_XMS=-Xms64M OJ_JAVA_XMX=-Xmx128M #Similarity Tester from Dick Grune OJ_SIM_ENABLE=0 #Using HTTP for distributed judgers OJ_HTTP_JUDGE=0 OJ_HTTP_BASEURL=http://127.0.0.1/JudgeOnline OJ_HTTP_USERNAME=admin OJ_HTTP_PASSWORD=admin OJ_HTTP_DOWNLOAD=1 #Using Redis for solutions queue OJ_REDISENABLE=0 OJ_REDISSERVER=127.0.0.1 OJ_REDISPORT=6379 OJ_REDISAUTH=123456 OJ_REDISQNAME=hustoj #Judge all test data even solution fails OJ_OI_MODE=1 #Using /dev/shm as working directory OJ_SHM_RUN=0 #Using the longest case of test as final time OJ_USE_MAX_TIME=0 #Judge TLE by total time OJ_TIME_LIMIT_TO_TOTAL=0 #Judge only listed languages OJ_LANG_SET=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 #Using Chroot to prevent compile time attack (#include</dev/random>) OJ_COMPILE_CHROOT=0 #Jump some middle status update for faster judge OJ_TURBO_MODE=0 #Bigger setting Slow down time on fast CPU, smaller setting Speed up time on slow CPU OJ_CPU_COMPENSATION=1.04 #Using UDP for submission notification OJ_UDP_ENABLE=1 OJ_UDP_SERVER=127.0.0.1 OJ_UDP_PORT=1536 #Let Python Free OJ_PYTHON_FREE=0 #allow NOIP using data.in as input file OJ_COPY_DATA=0 ``` 评测机的二次开发就可以看此文件了。 ## FPS 题目 HustOJ 支持 `fps.xml` 存储的题目。您可以使用 [EasyFPSViewer](https://github.com/zhblue/freeproblemset/tree/master/EasyFPSViewer) 编辑 FPS 题目。同时,FPS 也支持 [Hydro](https://hydro.js.org/)、[OpenJudger](https://github.com/Azure99/OpenJudger)、[QDUOJ](https://github.com/QingdaoU/OnlineJudge)。这意味着,FPS 可以实现不同 OJ 系统的交换题目。 FPS 的仓库为 <https://github.com/zhblue/freeproblemset>,同时,HustOJ 又一次良心地为我们提供了 [TK 题库](http://tk.hustoj.com/)。这是一个支持下载数据、FPS 题目的网站,提供免费与付费题目。 近期 NOIP、CSP 等竞赛题目基本都在免费题库支持下载。大家想把这些题目导入时可以使用。 免费专区链接:<http://tk.hustoj.com/problemset.php?search=free> ## Vjudge HustOJ 可以与 Vjudge 配合,自己的 VJ 抓自己的题目,也评测别的 OJ 的题目。 它的 GitHub 库为 <https://github.com/zhblue/vjudge>,暂时没有官方的 Gitee 镜像。 ```shell wget https://github.com/zhblue/vjudge/raw/master/install.sh sudo bash install.sh ``` 运行这些命令即可安装。这次会使用 tomcat8,所以要下载仓库中 vjudge.war。目前 OI-Master 尝试过搭建,不过出现了一点小问题(例如网络与无法解析),所以暂时不提供详细的安装教程。 ## HustOJ+Vjudge 套餐 如果您是使用虚拟机或者手中的服务器、电脑,那么您可以下载 LiveCD。 您需要关注 HustOJ 官方 `onlinejudge` 公众号,发送 `livecd`,获取百度云下载链接。 详细的可以点击:<https://gitee.com/zhblue/hustoj#livecd%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85> ## 结语 如果大家搭建时出现一些问题,欢迎用洛谷私信我或 QQ 202367038。 如果需要,我也会将视频传至哔哩哔哩。