diff --git a/.gitignore b/.gitignore
index 7b43edc..6b170ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ config.json
yarn.lock
*.db
.git.*
+package-lock.json
# Logs
logs
@@ -62,4 +63,4 @@ Session.vim
# auto-generated tag files
tags
-# End of https://www.gitignore.io/api/vim
\ No newline at end of file
+# End of https://www.gitignore.io/api/vim
diff --git a/README.en.md b/README.en.md
new file mode 100644
index 0000000..b37d6ee
--- /dev/null
+++ b/README.en.md
@@ -0,0 +1,39 @@
+# SYZOJ 2
+[中文](README.md) | English
+
+An online judge system for algorithm competition.
+
+This project is the **official** successor and rewritten version of the original Python/Flask version of SYZOJ, which is authorized by the original author [@Chenyao2333](https://github.com/Chenyao2333).
+
+Currently maintained by [LibreOJ](https://loj.ac).
+
+# Deploying
+Currently, the tutorial for deploying is only available in Chinese. It's [部署指南](https://github.com/syzoj/syzoj/wiki/%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97) in this project's wiki.
+
+Join QQ group [565280992](https://jq.qq.com/?_wv=1027&k=5JQZWwd) or Telegram group [@lojdev](https://t.me/lojdev) for help.
+
+# Upgrading
+Because of updates to the database structure, users who upgrade from a commit BEFORE [d5bcbe8fb79e80f9d603b764ac787295cceffa34](https://github.com/syzoj/syzoj/commit/d5bcbe8fb79e80f9d603b764ac787295cceffa34) (Feb 21, 2018) **MUST** perform the following SQL on the database.
+
+```sql
+ALTER TABLE `judge_state` ADD `is_public` TINYINT(1) NOT NULL AFTER `compilation`;
+UPDATE `judge_state` JOIN `problem` ON `problem`.`id` = `judge_state`.`problem_id` SET `judge_state`.`is_public` = `problem`.`is_public`;
+ALTER TABLE `syzoj`.`judge_state` ADD INDEX `judge_state_is_public` (`id`, `is_public`, `type_info`, `type`);
+```
+
+Who upgrade from a commit BEFORE [26d66ceef24fbb35481317453bcb89ead6c69076](https://github.com/syzoj/syzoj/commit/26d66ceef24fbb35481317453bcb89ead6c69076) (Nov 5, 2018) **MUST** perform the following SQL on the database.
+
+```sql
+ALTER TABLE `contest_player` CHANGE `score_details` `score_details` JSON NOT NULL;
+ALTER TABLE `contest_ranklist` CHANGE `ranking_params` `ranking_params` JSON NOT NULL;
+ALTER TABLE `contest_ranklist` CHANGE `ranklist` `ranklist` JSON NOT NULL;
+ALTER TABLE `custom_test` CHANGE `result` `result` JSON NOT NULL;
+ALTER TABLE `judge_state` CHANGE `compilation` `compilation` JSON NOT NULL;
+ALTER TABLE `judge_state` CHANGE `result` `result` JSON NOT NULL;
+```
+
+Who upgraded from a commit BEFORE [84b9e2d7b51e4ed3ab426621b66cf5ae9e1e1c23](https://github.com/syzoj/syzoj/commit/84b9e2d7b51e4ed3ab426621b66cf5ae9e1e1c23) (Nov 6, 2018) **MUST** perform the following SQL on the database.
+
+```sql
+ALTER TABLE `problem` ADD `publicize_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `type`;
+```
diff --git a/README.md b/README.md
index ce95eb7..68ee5c4 100644
--- a/README.md
+++ b/README.md
@@ -1,174 +1,39 @@
# SYZOJ 2
-An OnlineJudge System for OI.
+中文 | [English](README.en.md)
-The UI is powered by [Semantic UI](http://semantic-ui.com/).
-Template designed & coded by [Sengxian](https://www.sengxian.com) and [Menci](https://men.ci).
+一个用于算法竞赛的在线评测系统。
-# Upgrading
-Because of an update to the database structure, users who upgrade from a commit BEFORE 4c673956959532d61b8f9ba0be3191a054b4371a **MUST** perform the following SQL on the database:
-```sql
-ALTER TABLE `judge_state` ADD `is_public` TINYINT(1) NOT NULL AFTER `compilation`;
-UPDATE `judge_state` JOIN `problem` ON `problem`.`id` = `judge_state`.`problem_id` SET `judge_state`.`is_public` = `problem`.`is_public`;
-ALTER TABLE `syzoj`.`judge_state` ADD INDEX `judge_state_is_public` (`id`, `is_public`, `type_info`, `type`);
-```
-
-# Deploying
-**Warning** The following content is **outdated**. Please refer to https://syzoj-demo.t123yh.xyz:20170/article/1 for a detailed guide and a demo server.
-
-There's currently *no* stable version of SYZOJ 2, but you can use the unstable version from git.
-
-```
-git clone https://github.com/syzoj/syzoj
-cd syzoj
-```
+此项目为重写过的、原 Python/Flask 版 SYZOJ 的**官方**后继版本,由原作者 [@Chenyao2333](https://github.com/Chenyao2333) 授权。
-Install dependencies with `npm install` or `yarn`. Also, follow the instructions [here](https://www.npmjs.com/package/node-7z#installation) to install `7z` executable used by the `node-7z` package.
+目前由 [LibreOJ](https://loj.ac) 维护。
-Copy `config-example.json` to `config.json`, and make necessary changes.
+# 部署
+见本项目 Wiki 中的 [部署指南](https://github.com/syzoj/syzoj/wiki/%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97)。
-## Database
-SYZOJ 2 uses [Sequelize](http://sequelizejs.com), which supports many database systems, including MySQL and Sqlite.
+加入 QQ 群 [565280992](https://jq.qq.com/?_wv=1027&k=5JQZWwd) 或 Telegram 群 [@lojdev](https://t.me/lojdev) 以取得帮助。
-By default it use the Sqlite database `syzoj.db`, you can change it in `config.json`
+# 升级须知
+因为一些数据库结构的更新,从该 commit [d5bcbe8fb79e80f9d603b764ac787295cceffa34](https://github.com/syzoj/syzoj/commit/d5bcbe8fb79e80f9d603b764ac787295cceffa34)(2018 年 4 月 21 日)前更新的用户**必须**在其数据库上执行以下 SQL 语句。
-## Security
-You should change the `session_secret` and `judge_token` in `config.json`.
-
-# Administration
-In the database, the `is_admin` field in `user` table describes whether a user is admin or not.
-
-To make a user be an admin, the only way is via database.
-
-# Judge
-SYZOJ 2 uses a Docker-based sandboxed judger. Please go to [syzoj-judge](https://github.com/syzoj/syzoj-judge).
-
-# Advanced
-## System Service
-### Run SYZOJ 2
-Add SYZOJ 2 to system services.
-``` bash
-vim [syzoj2 path]/runsyzoj
-```
-Edit `runsyzoj` as as follows.
-``` bash
-#!/bin/bash
-cd [syzoj2 path]
-npm start > log.txt 2>&1
-```
-**Please change `[syzoj2 path]`.**
-### Run SYZOJ-JUDGE
-Add SYZOJ-JUDGE to system services.
-``` bash
-vim [syzoj-judge path]/runjudge
-```
-Edit `runjudge` as as follows.
-``` bash
-#!/bin/bash
-cd [syzoj-judge path]
-npm start > jlog.txt 2>&1
-```
-**Please change `[syzoj-judge path]`.**
-### Add To System Service
-``` bash
-vim /etc/systemd/system/syzoj.service
-```
-Edit `/etc/systemd/system/syzoj.service` as as follows.
-``` bash
-[Unit]
-Description=SYZOJ Online Judge
-After=network.target
-
-[Service]
-Type=simple
-PIDFile=/run/syzoj.pid
-WorkingDirectory=[syzoj2 path]
-ExecStart=[syzoj2 path]/runsyzoj
-StandardOutput=null
-StandardError=null
-
-[Install]
-WantedBy=multi-user.target
-```
-**Please change `[syzoj2 path]`.**
-
-``` bash
-vim /etc/systemd/system/syzoj-judge.service
-```
-Edit `/etc/systemd/system/syzoj-judge.service` as as follows.
-``` bash
-[Unit]
-Description=SYZOJ Judge Daemon
-After=network.target
-
-[Service]
-Type=simple
-PIDFile=/run/syzoj-judge.pid
-WorkingDirectory=[syzoj-judge path]
-ExecStart=[syzoj-judge path]/runjudge
-StandardOutput=null
-StandardError=null
-
-[Install]
-WantedBy=multi-user.target
-```
-**Please change `[syzoj-judge path]`.**
-### Usage
-#### Start
-``` bash
-systemctl start syzoj
-systemctl start syzoj-judge
-```
-#### Stop
-``` bash
-systemctl stop syzoj
-systemctl stop syzoj-judge
-```
-#### Restart
-``` bash
-systemctl restart syzoj
-systemctl restart syzoj-judge
+```sql
+ALTER TABLE `judge_state` ADD `is_public` TINYINT(1) NOT NULL AFTER `compilation`;
+UPDATE `judge_state` JOIN `problem` ON `problem`.`id` = `judge_state`.`problem_id` SET `judge_state`.`is_public` = `problem`.`is_public`;
+ALTER TABLE `syzoj`.`judge_state` ADD INDEX `judge_state_is_public` (`id`, `is_public`, `type_info`, `type`);
```
-## 邮件配置
-### register_mail
-是否启用注册邮件验证。
+从该 commit [26d66ceef24fbb35481317453bcb89ead6c69076](https://github.com/syzoj/syzoj/commit/26d66ceef24fbb35481317453bcb89ead6c69076)(2018 年 11 月 5 日)前更新的用户**必须**在其数据库上执行以下 SQL 语句。
-### email\_jwt\_secret
-用于 Email Token 签名的 secret,脸滚键盘随意填写即可。
-
-### email
-#### Sendmail 直接发送(成功率低,不推荐)
-```js
- "email": {
- "method": "sendmail",
- "options": {
- "address": "xxxx", // 发件人地址
- }
- },
+```sql
+ALTER TABLE `contest_player` CHANGE `score_details` `score_details` JSON NOT NULL;
+ALTER TABLE `contest_ranklist` CHANGE `ranking_params` `ranking_params` JSON NOT NULL;
+ALTER TABLE `contest_ranklist` CHANGE `ranklist` `ranklist` JSON NOT NULL;
+ALTER TABLE `custom_test` CHANGE `result` `result` JSON NOT NULL;
+ALTER TABLE `judge_state` CHANGE `compilation` `compilation` JSON NOT NULL;
+ALTER TABLE `judge_state` CHANGE `result` `result` JSON NOT NULL;
```
-#### 阿里云邮件推送服务(成功率较高)
-```js
- "email": {
- "method": "aliyundm",
- "options": {
- "AccessKeyId": "xxxx",
- "AccessKeySecret": "xxxx",
- "AccountName": "xxxx" // 发件邮箱
- }
- },
-```
+从该 commit [84b9e2d7b51e4ed3ab426621b66cf5ae9e1e1c23](https://github.com/syzoj/syzoj/commit/84b9e2d7b51e4ed3ab426621b66cf5ae9e1e1c23)(2018 年 11 月 6 日)前更新的用户**必须**在其数据库上执行以下 SQL 语句。
-#### SMTP 服务
-```js
- "email": {
- "method": "smtp",
- "options": {
- "host": "smtp.163.com",
- "port": 465,
- "username": "xxx@163.com",
- "password": "xxx",
- "allowUnauthorizedTls": false
- }
- },
+```sql
+ALTER TABLE `problem` ADD `publicize_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `type`;
```
diff --git a/app.js b/app.js
index e9e99fa..4b9eb6e 100644
--- a/app.js
+++ b/app.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let fs = require('fs'),
path = require('path');
@@ -31,7 +10,7 @@ const options = commandLineArgs(optionDefinitions);
global.syzoj = {
rootDir: __dirname,
- config: require(options.config),
+ config: require('object-assign-deep')({}, require('./config-example.json'), require(options.config)),
configDir: options.config,
models: [],
modules: [],
@@ -53,7 +32,7 @@ global.syzoj = {
});
// Set assets dir
- app.use(Express.static(__dirname + '/static'));
+ app.use(Express.static(__dirname + '/static', { maxAge: syzoj.production ? '1y' : 0 }));
// Set template engine ejs
app.set('view engine', 'ejs');
@@ -88,11 +67,50 @@ global.syzoj = {
},
async connectDatabase() {
let Sequelize = require('sequelize');
+ let Op = Sequelize.Op;
+ let operatorsAliases = {
+ $eq: Op.eq,
+ $ne: Op.ne,
+ $gte: Op.gte,
+ $gt: Op.gt,
+ $lte: Op.lte,
+ $lt: Op.lt,
+ $not: Op.not,
+ $in: Op.in,
+ $notIn: Op.notIn,
+ $is: Op.is,
+ $like: Op.like,
+ $notLike: Op.notLike,
+ $iLike: Op.iLike,
+ $notILike: Op.notILike,
+ $regexp: Op.regexp,
+ $notRegexp: Op.notRegexp,
+ $iRegexp: Op.iRegexp,
+ $notIRegexp: Op.notIRegexp,
+ $between: Op.between,
+ $notBetween: Op.notBetween,
+ $overlap: Op.overlap,
+ $contains: Op.contains,
+ $contained: Op.contained,
+ $adjacent: Op.adjacent,
+ $strictLeft: Op.strictLeft,
+ $strictRight: Op.strictRight,
+ $noExtendRight: Op.noExtendRight,
+ $noExtendLeft: Op.noExtendLeft,
+ $and: Op.and,
+ $or: Op.or,
+ $any: Op.any,
+ $all: Op.all,
+ $values: Op.values,
+ $col: Op.col
+ };
+
this.db = new Sequelize(this.config.db.database, this.config.db.username, this.config.db.password, {
host: this.config.db.host,
- dialect: this.config.db.dialect,
- storage: this.config.db.storage ? this.utils.resolvePath(this.config.db.storage) : null,
- logging: syzoj.production ? false : syzoj.log
+ dialect: 'mysql',
+ logging: syzoj.production ? false : syzoj.log,
+ timezone: require('moment')().format('Z'),
+ operatorsAliases: operatorsAliases
});
global.Promise = Sequelize.Promise;
this.db.countQuery = async (sql, options) => (await this.db.query(`SELECT COUNT(*) FROM (${sql}) AS \`__tmp_table\``, options))[0][0]['COUNT(*)'];
@@ -132,7 +150,7 @@ global.syzoj = {
let FileStore = require('session-file-store')(Session);
let sessionConfig = {
secret: this.config.session_secret,
- cookie: {},
+ cookie: { httpOnly: false },
rolling: true,
saveUninitialized: true,
resave: true,
@@ -140,7 +158,7 @@ global.syzoj = {
};
if (syzoj.production) {
app.set('trust proxy', 1);
- sessionConfig.cookie.secure = true;
+ sessionConfig.cookie.secure = false;
}
app.use(Session(sessionConfig));
diff --git a/bin/unzip b/bin/unzip
new file mode 100755
index 0000000..581ff8e
Binary files /dev/null and b/bin/unzip differ
diff --git a/config-example.json b/config-example.json
index 276cfa7..f0d3019 100644
--- a/config-example.json
+++ b/config-example.json
@@ -3,12 +3,15 @@
"hostname": "127.0.0.1",
"port": "5283",
"db": {
- "database": null,
- "username": null,
+ "database": "syzoj",
+ "username": "syzoj",
"password": null,
- "host": null,
- "dialect": "sqlite",
- "storage": "syzoj.db"
+ "host": "127.0.0.1"
+ },
+ "logo": {
+ "url": null,
+ "width": null,
+ "height": null
},
"register_mail": false,
"email": {
@@ -54,7 +57,8 @@
"problem": 50,
"problem_statistics": 10,
"judge_state": 10,
- "ranklist": 20,
+ "ranklist_index": 20,
+ "ranklist": 50,
"discussion": 10,
"article_comment": 10,
"contest": 10,
diff --git a/libs/highlight.js b/libs/highlight.js
new file mode 100644
index 0000000..43a8760
--- /dev/null
+++ b/libs/highlight.js
@@ -0,0 +1,44 @@
+/*
+ * This file is part of moemark-renderer.
+ *
+ * Copyright (c) 2016 Menci
+ *
+ * moemark-renderer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * moemark-renderer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with moemark-renderer. If not, see .
+ */
+
+const pygmentize = require('pygmentize-bundled-cached');
+
+function escapeHTML(s) {
+ // Code from http://stackoverflow.com/questions/5251520/how-do-i-escape-some-html-in-javascript/5251551
+ return s.replace(/[^0-9A-Za-z ]/g, (c) => {
+ return "" + c.charCodeAt(0) + ";";
+ });
+}
+
+module.exports = (code, lang, cb) => {
+ pygmentize({
+ lang: lang,
+ format: 'html',
+ options: {
+ nowrap: true,
+ classprefix: 'pl-'
+ }
+ }, code, (err, res) => {
+ if (err || res.toString() === 'undefined') {
+ cb(escapeHTML(code));
+ } else {
+ cb(res);
+ }
+ });
+}
diff --git a/libs/markdown.js b/libs/markdown.js
new file mode 100644
index 0000000..19b3519
--- /dev/null
+++ b/libs/markdown.js
@@ -0,0 +1,131 @@
+/*
+ * This file is part of moemark-renderer.
+ *
+ * Copyright (c) 2016 Menci
+ *
+ * moemark-renderer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * moemark-renderer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with moemark-renderer. If not, see .
+ */
+
+const MoeMark = require('moemark');
+const katex = require('katex');
+const mj = require('mathjax-node');
+
+let defaultCache = {
+ data: {},
+ get(key) {
+ return this.data[key];
+ },
+ set(key, val) {
+ this.data[key] = val;
+ }
+};
+
+let config = {
+ highlight: require('./highlight')
+};
+
+function render(s, cb) {
+ if (!s.trim()) return cb('');
+
+ let mathCnt = 0, mathPending = 0, maths = new Array(), hlCnt = 0, hlPending = 0, hls = new Array(), res, callback, ss, cache = render.cache, cacheOption = render.cacheOption, finished = false;
+ if (cacheOption.result) {
+ let x = cache.get('RES_' + s);
+ if (x !== undefined) return cb(x);
+ }
+
+ MoeMark.setOptions({
+ lineNumber: false,
+ math: true,
+ highlight: function(code, lang) {
+ if (cacheOption.highlight) {
+ let x = cache.get('H_' + lang + '_' + code);
+ if (x !== undefined) return x;
+ }
+ let id = hlCnt;
+ hlCnt++, hlPending++;
+ config.highlight(code, lang, res => {
+ hls[id] = res;
+ if (cacheOption.highlight) cache.set('H_' + lang + '_' + code, res);
+ if (!--hlPending) finish();
+ });
+ return '';
+ },
+ mathRenderer: function(str, display) {
+ if (cacheOption.math) {
+ let x = cache.get('M_' + display + '_' + str);
+ if (x !== undefined) return x;
+ }
+ try {
+ let res = katex.renderToString(str, { displayMode: display });
+ if (cacheOption.math) cache.set('M_' + display + '_' + str, res);
+ return res;
+ } catch (e) {
+ const id = mathCnt;
+ mathCnt++, mathPending++;
+ mj.typeset({
+ math: str,
+ format: display ? 'TeX' : 'inline-TeX',
+ html: true, css: true,
+ width: 0
+ }, function (data) {
+ if (data.errors) maths[id] = '
' + data.errors.toString() + '
';
+ else if (display) maths[id] = '
' + data.html + '
';
+ else maths[id] = data.html;
+ if (cacheOption.math) cache.set('M_' + display + '_' + str, maths[id]);
+ if (!--mathPending) finish();
+ });
+
+ return '';
+ }
+ }
+ });
+
+ function finish() {
+ if (finished || !res || mathPending || hlPending) return;
+ finished = true;
+ if (maths.length || hls.length) {
+ let x = new (require('jsdom').JSDOM)().window.document.createElement('div');
+ x.innerHTML = res;
+ for (let i = 0; i < maths.length; i++) {
+ x.querySelector('#math-' + i).outerHTML = maths[i];
+ }
+ for (let i = 0; i < hls.length; i++) {
+ x.querySelector('#hl-' + i).outerHTML = hls[i];
+ }
+ res = x.innerHTML;
+ }
+ if (cacheOption.result) cache.set('RES_' + s, res);
+ cb(res);
+ }
+
+ try {
+ res = MoeMark(s);
+ if (mathPending == 0 && hlPending == 0) {
+ finish();
+ }
+ } catch(e) {
+ cb(e);
+ }
+};
+
+render.moemark = MoeMark;
+render.cache = defaultCache;
+render.cacheOption = {
+ highlight: true,
+ math: true,
+ result: false
+};
+render.config = config;
+
+module.exports = render;
diff --git a/libs/timeago/index.js b/libs/timeago/index.js
new file mode 100644
index 0000000..ccb08e6
--- /dev/null
+++ b/libs/timeago/index.js
@@ -0,0 +1,7 @@
+module.exports =
+{
+ locale: 'zh',
+ long: require('./long.json'),
+ short: require('./short.json'),
+ narrow: require('./narrow.json')
+}
\ No newline at end of file
diff --git a/libs/timeago/long.json b/libs/timeago/long.json
new file mode 100644
index 0000000..685227c
--- /dev/null
+++ b/libs/timeago/long.json
@@ -0,0 +1,53 @@
+{
+ "year": {
+ "previous": "去年",
+ "current": "今年",
+ "next": "明年",
+ "past": "{0} 年前",
+ "future": "{0} 年后"
+ },
+ "quarter": {
+ "previous": "上季度",
+ "current": "本季度",
+ "next": "下季度",
+ "past": "{0} 个季度前",
+ "future": "{0} 个季度后"
+ },
+ "month": {
+ "previous": "上个月",
+ "current": "本月",
+ "next": "下个月",
+ "past": "{0} 个月前",
+ "future": "{0} 个月后"
+ },
+ "week": {
+ "previous": "上周",
+ "current": "本周",
+ "next": "下周",
+ "past": "{0} 周前",
+ "future": "{0} 周后"
+ },
+ "day": {
+ "previous": "昨天",
+ "current": "今天",
+ "next": "明天",
+ "past": "{0} 天前",
+ "future": "{0} 天后"
+ },
+ "hour": {
+ "current": "这一时间 / 此时",
+ "past": "{0} 小时前",
+ "future": "{0} 小时后"
+ },
+ "minute": {
+ "current": "此刻",
+ "past": "{0} 分钟前",
+ "future": "{0} 分钟后"
+ },
+ "second": {
+ "current": "现在",
+ "past": "{0} 秒钟前",
+ "future": "{0} 秒钟后"
+ },
+ "now": "现在"
+}
diff --git a/libs/timeago/narrow.json b/libs/timeago/narrow.json
new file mode 100644
index 0000000..c0e45e6
--- /dev/null
+++ b/libs/timeago/narrow.json
@@ -0,0 +1,53 @@
+{
+ "year": {
+ "previous": "去年",
+ "current": "今年",
+ "next": "明年",
+ "past": "{0} 年前",
+ "future": "{0} 年后"
+ },
+ "quarter": {
+ "previous": "上季度",
+ "current": "本季度",
+ "next": "下季度",
+ "past": "{0} 个季度前",
+ "future": "{0} 个季度后"
+ },
+ "month": {
+ "previous": "上个月",
+ "current": "本月",
+ "next": "下个月",
+ "past": "{0} 个月前",
+ "future": "{0} 个月后"
+ },
+ "week": {
+ "previous": "上周",
+ "current": "本周",
+ "next": "下周",
+ "past": "{0} 周前",
+ "future": "{0} 周后"
+ },
+ "day": {
+ "previous": "昨天",
+ "current": "今天",
+ "next": "明天",
+ "past": "{0} 天前",
+ "future": "{0} 天后"
+ },
+ "hour": {
+ "current": "这一时间 / 此时",
+ "past": "{0} 小时前",
+ "future": "{0} 小时后"
+ },
+ "minute": {
+ "current": "此刻",
+ "past": "{0} 分钟前",
+ "future": "{0} 分钟后"
+ },
+ "second": {
+ "current": "现在",
+ "past": "{0} 秒前",
+ "future": "{0} 秒后"
+ },
+ "now": "现在"
+}
diff --git a/libs/timeago/short.json b/libs/timeago/short.json
new file mode 100644
index 0000000..c0e45e6
--- /dev/null
+++ b/libs/timeago/short.json
@@ -0,0 +1,53 @@
+{
+ "year": {
+ "previous": "去年",
+ "current": "今年",
+ "next": "明年",
+ "past": "{0} 年前",
+ "future": "{0} 年后"
+ },
+ "quarter": {
+ "previous": "上季度",
+ "current": "本季度",
+ "next": "下季度",
+ "past": "{0} 个季度前",
+ "future": "{0} 个季度后"
+ },
+ "month": {
+ "previous": "上个月",
+ "current": "本月",
+ "next": "下个月",
+ "past": "{0} 个月前",
+ "future": "{0} 个月后"
+ },
+ "week": {
+ "previous": "上周",
+ "current": "本周",
+ "next": "下周",
+ "past": "{0} 周前",
+ "future": "{0} 周后"
+ },
+ "day": {
+ "previous": "昨天",
+ "current": "今天",
+ "next": "明天",
+ "past": "{0} 天前",
+ "future": "{0} 天后"
+ },
+ "hour": {
+ "current": "这一时间 / 此时",
+ "past": "{0} 小时前",
+ "future": "{0} 小时后"
+ },
+ "minute": {
+ "current": "此刻",
+ "past": "{0} 分钟前",
+ "future": "{0} 分钟后"
+ },
+ "second": {
+ "current": "现在",
+ "past": "{0} 秒前",
+ "future": "{0} 秒后"
+ },
+ "now": "现在"
+}
diff --git a/models/article-comment.js b/models/article-comment.js
index 3a57fd8..b1b9028 100644
--- a/models/article-comment.js
+++ b/models/article-comment.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/article.js b/models/article.js
index 977a6ed..d5e6b05 100644
--- a/models/article.js
+++ b/models/article.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/common.js b/models/common.js
index 43e78a1..952e1a1 100644
--- a/models/common.js
+++ b/models/common.js
@@ -1,23 +1,4 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
+let Sequelize = require('sequelize');
class Model {
constructor(record) {
@@ -29,9 +10,9 @@ class Model {
let model = this.getModel();
let obj = JSON.parse(JSON.stringify(this.record.get({ plain: true })));
for (let key in obj) {
- if (model.tableAttributes[key].json) {
+ if (model.tableAttributes[key].type instanceof Sequelize.JSON && typeof obj[key] === 'string') {
try {
- this[key] = eval(`(${obj[key]})`);
+ this[key] = JSON.parse(obj[key]);
} catch (e) {
this[key] = {};
}
@@ -43,8 +24,7 @@ class Model {
let model = this.getModel();
let obj = JSON.parse(JSON.stringify(this.record.get({ plain: true })));
for (let key in obj) {
- if (model.tableAttributes[key].json) obj[key] = JSON.stringify(this[key]);
- else obj[key] = this[key];
+ obj[key] = this[key];
}
return obj;
}
@@ -76,7 +56,7 @@ class Model {
}
static async fromID(id) {
- return this.fromRecord(this.model.findById(id))
+ return this.fromRecord(this.model.findByPk(id));
}
static async findOne(options) {
@@ -98,7 +78,7 @@ class Model {
return this.model.count({ where: where });
}
- static async query(paginate, where, order) {
+ static async query(paginate, where, order, largeData) {
let records = [];
if (typeof paginate === 'string') {
@@ -120,11 +100,34 @@ class Model {
options.limit = parseInt(paginate.perPage);
}
- records = await this.model.findAll(options);
+ if (!largeData) records = await this.model.findAll(options);
+ else {
+ let sql = await getSqlFromFindAll(this.model, options);
+ let i = sql.indexOf('FROM');
+ sql = 'SELECT id ' + sql.substr(i, sql.length - i);
+ sql = `SELECT a.* FROM (${sql}) AS b JOIN ${this.model.name} AS a ON a.id = b.id ORDER BY id DESC`;
+ records = await syzoj.db.query(sql, { model: this.model });
+ }
}
return records.mapAsync(record => (this.fromRecord(record)));
}
}
+function getSqlFromFindAll(Model, options) {
+ let id = require('uuid')();
+
+ return new Promise((resolve, reject) => {
+ Model.addHook('beforeFindAfterOptions', id, options => {
+ Model.removeHook('beforeFindAfterOptions', id);
+
+ resolve(Model.sequelize.dialect.QueryGenerator.selectQuery(Model.getTableName(), options, Model).slice(0, -1));
+
+ return new Promise(() => {});
+ });
+
+ return Model.findAll(options).catch(reject);
+ });
+}
+
module.exports = Model;
diff --git a/models/contest.js b/models/contest.js
index b90ad72..e5066e2 100644
--- a/models/contest.js
+++ b/models/contest.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/contest_player.js b/models/contest_player.js
index b559dec..28a105d 100644
--- a/models/contest_player.js
+++ b/models/contest_player.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
@@ -31,7 +10,7 @@ let model = db.define('contest_player', {
user_id: { type: Sequelize.INTEGER },
score: { type: Sequelize.INTEGER },
- score_details: { type: Sequelize.TEXT, json: true },
+ score_details: { type: Sequelize.JSON },
time_spent: { type: Sequelize.INTEGER }
}, {
timestamps: false,
@@ -53,7 +32,7 @@ class ContestPlayer extends Model {
contest_id: 0,
user_id: 0,
score: 0,
- score_details: '{}',
+ score_details: {},
time_spent: 0
}, val)));
}
diff --git a/models/contest_ranklist.js b/models/contest_ranklist.js
index 09970dd..7532e0d 100644
--- a/models/contest_ranklist.js
+++ b/models/contest_ranklist.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
@@ -28,8 +7,8 @@ let ContestPlayer = syzoj.model('contest_player');
let model = db.define('contest_ranklist', {
id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
- ranking_params: { type: Sequelize.TEXT, json: true },
- ranklist: { type: Sequelize.TEXT, json: true }
+ ranking_params: { type: Sequelize.JSON },
+ ranklist: { type: Sequelize.JSON }
}, {
timestamps: false,
tableName: 'contest_ranklist'
@@ -39,8 +18,8 @@ let Model = require('./common');
class ContestRanklist extends Model {
static async create(val) {
return ContestRanklist.fromRecord(ContestRanklist.model.build(Object.assign({
- ranking_params: '{}',
- ranklist: '{}'
+ ranking_params: {},
+ ranklist: {}
}, val)));
}
diff --git a/models/custom_test.js b/models/custom_test.js
index 5b1b5bf..609541b 100644
--- a/models/custom_test.js
+++ b/models/custom_test.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
@@ -38,7 +17,7 @@ let model = db.define('custom_test', {
pending: { type: Sequelize.BOOLEAN },
memory: { type: Sequelize.INTEGER },
- result: { type: Sequelize.TEXT('medium'), json: true },
+ result: { type: Sequelize.JSON },
user_id: { type: Sequelize.INTEGER },
@@ -76,6 +55,7 @@ class CustomTest extends Model {
time: 0,
memory: 0,
+ result: {},
status: 'Waiting',
}, val)));
}
diff --git a/models/file.js b/models/file.js
index a503178..1308f52 100644
--- a/models/file.js
+++ b/models/file.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/judge_state.js b/models/judge_state.js
index 5fb5edc..025cb5d 100644
--- a/models/judge_state.js
+++ b/models/judge_state.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
const randomstring = require('randomstring');
let db = syzoj.db;
@@ -45,9 +24,9 @@ let model = db.define('judge_state', {
max_memory: { type: Sequelize.INTEGER },
// For NOI contest
- compilation: { type: Sequelize.TEXT('medium'), json: true },
+ compilation: { type: Sequelize.JSON },
- result: { type: Sequelize.TEXT('medium'), json: true },
+ result: { type: Sequelize.JSON },
user_id: { type: Sequelize.INTEGER },
@@ -107,7 +86,8 @@ class JudgeState extends Model {
total_time: null,
max_memory: null,
status: 'Unknown',
- result: null,
+ compilation: {},
+ result: {},
task_id: randomstring.generate(10),
is_public: false
}, val)));
diff --git a/models/problem.js b/models/problem.js
index 1e6a32f..6c5ecf0 100644
--- a/models/problem.js
+++ b/models/problem.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let statisticsStatements = {
fastest:
'\
@@ -244,6 +223,8 @@ let model = db.define('problem', {
file_io_input_name: { type: Sequelize.TEXT },
file_io_output_name: { type: Sequelize.TEXT },
+ publicize_time: { type: Sequelize.DATE },
+
type: {
type: Sequelize.ENUM,
values: ['traditional', 'submit-answer', 'interaction']
@@ -257,7 +238,10 @@ let model = db.define('problem', {
},
{
fields: ['user_id'],
- }
+ },
+ {
+ fields: ['publicize_time'],
+ },
]
});
@@ -340,7 +324,8 @@ class Problem extends Model {
await fs.remove(dir);
await fs.ensureDir(dir);
- await p7zip.extract(path, dir);
+ let execFileAsync = Promise.promisify(require('child_process').execFile);
+ await execFileAsync(__dirname + '/../bin/unzip', ['-j', '-o', '-d', dir, path]);
await fs.move(path, this.getTestdataArchivePath(), { overwrite: true });
});
}
@@ -363,6 +348,10 @@ class Problem extends Model {
if (!noLimit && oldCount + !replace > syzoj.config.limit.testdata_filecount) throw new ErrorMessage('数据包中的文件太多。');
await fs.move(filepath, path.join(dir, filename), { overwrite: true });
+
+ let execFileAsync = Promise.promisify(require('child_process').execFile);
+ try { await execFileAsync('dos2unix', [path.join(dir, filename)]); } catch (e) {}
+
await fs.remove(this.getTestdataArchivePath());
});
}
diff --git a/models/problem_tag.js b/models/problem_tag.js
index 09f7077..a354ecb 100644
--- a/models/problem_tag.js
+++ b/models/problem_tag.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/problem_tag_map.js b/models/problem_tag_map.js
index a49415f..3fcee39 100644
--- a/models/problem_tag_map.js
+++ b/models/problem_tag_map.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/rating_calculation.js b/models/rating_calculation.js
index 8584328..44f7756 100644
--- a/models/rating_calculation.js
+++ b/models/rating_calculation.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2017 t123yh
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
const User = syzoj.model('user');
diff --git a/models/rating_history.js b/models/rating_history.js
index 7980f46..fa06270 100644
--- a/models/rating_history.js
+++ b/models/rating_history.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2017 t123yh
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
const User = syzoj.model('user');
let db = syzoj.db;
diff --git a/models/user.js b/models/user.js
index 4d12f26..0fd9b21 100644
--- a/models/user.js
+++ b/models/user.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/user_privilege.js b/models/user_privilege.js
index 5bb13a3..eb889a8 100644
--- a/models/user_privilege.js
+++ b/models/user_privilege.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/models/waiting_judge.js b/models/waiting_judge.js
index 48bb874..312074b 100644
--- a/models/waiting_judge.js
+++ b/models/waiting_judge.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Sequelize = require('sequelize');
let db = syzoj.db;
diff --git a/modules/admin.js b/modules/admin.js
index 1845eb3..6cc45a2 100644
--- a/modules/admin.js
+++ b/modules/admin.js
@@ -1,22 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
let Problem = syzoj.model('problem');
let JudgeState = syzoj.model('judge_state');
let Article = syzoj.model('article');
diff --git a/modules/api.js b/modules/api.js
index 60ef4fc..7fe2da4 100644
--- a/modules/api.js
+++ b/modules/api.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let User = syzoj.model('user');
let Problem = syzoj.model('problem');
let File = syzoj.model('file');
diff --git a/modules/api_v2.js b/modules/api_v2.js
index 3819433..eb5522f 100644
--- a/modules/api_v2.js
+++ b/modules/api_v2.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
app.get('/api/v2/search/users/:keyword*?', async (req, res) => {
try {
let User = syzoj.model('user');
@@ -30,7 +9,7 @@ app.get('/api/v2/search/users/:keyword*?', async (req, res) => {
conditions.push({ id: uid });
}
if (keyword != null && String(keyword).length >= 2) {
- conditions.push({ username: { like: `%${req.params.keyword}%` } });
+ conditions.push({ username: { $like: `%${req.params.keyword}%` } });
}
if (conditions.length === 0) {
res.send({ success: true, results: [] });
@@ -56,7 +35,7 @@ app.get('/api/v2/search/problems/:keyword*?', async (req, res) => {
let keyword = req.params.keyword || '';
let problems = await Problem.query(null, {
- title: { like: `%${req.params.keyword}%` }
+ title: { $like: `%${req.params.keyword}%` }
}, [['id', 'asc']]);
let result = [];
@@ -89,7 +68,7 @@ app.get('/api/v2/search/tags/:keyword*?', async (req, res) => {
let keyword = req.params.keyword || '';
let tags = await ProblemTag.query(null, {
- name: { like: `%${req.params.keyword}%` }
+ name: { $like: `%${req.params.keyword}%` }
}, [['name', 'asc']]);
let result = tags.slice(0, syzoj.config.page.edit_problem_tag_list);
diff --git a/modules/contest.js b/modules/contest.js
index a905211..9a9165d 100644
--- a/modules/contest.js
+++ b/modules/contest.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Contest = syzoj.model('contest');
let ContestRanklist = syzoj.model('contest_ranklist');
let ContestPlayer = syzoj.model('contest_player');
diff --git a/modules/discussion.js b/modules/discussion.js
index c700de3..a0984e5 100644
--- a/modules/discussion.js
+++ b/modules/discussion.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Problem = syzoj.model('problem');
let Article = syzoj.model('article');
let ArticleComment = syzoj.model('article-comment');
@@ -190,7 +169,7 @@ app.post('/article/:id/edit', async (req, res) => {
article.title = req.body.title;
article.content = req.body.content;
article.update_time = time;
- article.is_notice = res.locals.user && res.locals.user.is_admin && req.body.is_notice === 'on';
+ article.is_notice = (res.locals.user && res.locals.user.is_admin ? req.body.is_notice === 'on' : article.is_notice);
await article.save();
diff --git a/modules/index.js b/modules/index.js
index 7d1fb37..8782c38 100644
--- a/modules/index.js
+++ b/modules/index.js
@@ -1,32 +1,16 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let User = syzoj.model('user');
let Article = syzoj.model('article');
let Contest = syzoj.model('contest');
+let Problem = syzoj.model('problem');
let Divine = require('syzoj-divine');
+let TimeAgo = require('javascript-time-ago');
+let zh = require('../libs/timeago');
+TimeAgo.locale(zh);
+const timeAgo = new TimeAgo('zh-CN');
app.get('/', async (req, res) => {
try {
- let ranklist = await User.query([1, 10], { is_show: true }, [[syzoj.config.sorting.ranklist.field, syzoj.config.sorting.ranklist.order]]);
+ let ranklist = await User.query([1, syzoj.config.page.ranklist_index], { is_show: true }, [[syzoj.config.sorting.ranklist.field, syzoj.config.sorting.ranklist.order]]);
await ranklist.forEachAsync(async x => x.renderInformation());
let notices = (await Article.query(null, { is_notice: true }, [['public_time', 'desc']])).map(article => ({
@@ -40,16 +24,20 @@ app.get('/', async (req, res) => {
fortune = Divine(res.locals.user.username, res.locals.user.sex);
}
- let where;
- if (res.locals.user && await res.locals.user.is_admin) where = {}
- else where = { is_public: true };
- let contests = await Contest.query([1, 5], where, [['start_time', 'desc']]);
+ let contests = await Contest.query([1, 5], { is_public: true }, [['start_time', 'desc']]);
+
+ let problems = (await Problem.query([1, 5], { is_public: true }, [['publicize_time', 'desc']])).map(problem => ({
+ id: problem.id,
+ title: problem.title,
+ time: timeAgo.format(new Date(problem.publicize_time)),
+ }));
res.render('index', {
ranklist: ranklist,
notices: notices,
fortune: fortune,
contests: contests,
+ problems: problems,
links: syzoj.config.links
});
} catch (e) {
diff --git a/modules/legacy.js b/modules/legacy.js
index 89922b0..2bfa8d1 100644
--- a/modules/legacy.js
+++ b/modules/legacy.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
app.get('/problem', async (req, res) => {
res.redirect('/problems');
});
diff --git a/modules/problem.js b/modules/problem.js
index f30da2d..fe42845 100644
--- a/modules/problem.js
+++ b/modules/problem.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let Problem = syzoj.model('problem');
let JudgeState = syzoj.model('judge_state');
let CustomTest = syzoj.model('custom_test');
@@ -35,7 +14,7 @@ app.get('/problems', async (req, res) => {
try {
const sort = req.query.sort || syzoj.config.sorting.problem.field;
const order = req.query.order || syzoj.config.sorting.problem.order;
- if (!['id', 'title', 'rating', 'ac_num', 'submit_num', 'ac_rate'].includes(sort) || !['asc', 'desc'].includes(order)) {
+ if (!['id', 'title', 'rating', 'ac_num', 'submit_num', 'ac_rate', 'publicize_time'].includes(sort) || !['asc', 'desc'].includes(order)) {
throw new ErrorMessage('错误的排序参数。');
}
@@ -94,7 +73,7 @@ app.get('/problems/search', async (req, res) => {
let where = {
$or: {
- title: { like: `%${req.query.keyword}%` },
+ title: { $like: `%${req.query.keyword}%` },
id: id
}
};
@@ -581,6 +560,7 @@ async function setPublic(req, res, is_public) {
problem.is_public = is_public;
problem.publicizer_id = res.locals.user.id;
+ problem.publicize_time = new Date();
await problem.save();
JudgeState.model.update(
diff --git a/modules/problem_tag.js b/modules/problem_tag.js
index 15ea58e..f6b0f54 100644
--- a/modules/problem_tag.js
+++ b/modules/problem_tag.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let ProblemTag = syzoj.model('problem_tag');
app.get('/problems/tag/:id/edit', async (req, res) => {
diff --git a/modules/socketio.js b/modules/socketio.js
index aae0d91..cc0fc7e 100644
--- a/modules/socketio.js
+++ b/modules/socketio.js
@@ -1,4 +1,3 @@
-"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const socketio = require("socket.io");
const diff = require("jsondiffpatch");
diff --git a/modules/submission.js b/modules/submission.js
index 4502511..9fb21f5 100644
--- a/modules/submission.js
+++ b/modules/submission.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let JudgeState = syzoj.model('judge_state');
let User = syzoj.model('user');
let Contest = syzoj.model('contest');
@@ -113,7 +92,7 @@ app.get('/submissions', async (req, res) => {
}
let paginate = syzoj.utils.paginate(await JudgeState.count(where), req.query.page, syzoj.config.page.judge_state);
- let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']]);
+ let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']], true);
await judge_state.forEachAsync(async obj => obj.loadRelationships());
diff --git a/modules/user.js b/modules/user.js
index 30725a8..65985c9 100644
--- a/modules/user.js
+++ b/modules/user.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
let User = syzoj.model('user');
const RatingCalculation = syzoj.model('rating_calculation');
const RatingHistory = syzoj.model('rating_history');
diff --git a/package.json b/package.json
index e255ac2..ff8eed6 100644
--- a/package.json
+++ b/package.json
@@ -17,51 +17,54 @@
"express"
],
"author": "Menci",
- "license": "GPL-3.0",
+ "license": "AGPL-3.0",
"bugs": {
"url": "https://github.com/syzoj/syzoj/issues"
},
"homepage": "https://github.com/syzoj/syzoj#readme",
"dependencies": {
"amqplib": "^0.5.2",
- "ansi-to-html": "^0.4.2",
- "async-lock": "^0.3.9",
+ "ansi-to-html": "^0.6.8",
+ "async-lock": "^1.1.3",
"body-parser": "^1.15.2",
"cheerio": "^1.0.0-rc.1",
- "command-line-args": "^4.0.7",
+ "command-line-args": "^5.0.2",
"cookie-parser": "^1.4.3",
"cssfilter": "0.0.10",
- "download": "^5.0.3",
+ "download": "^7.1.0",
"ejs": "^2.5.2",
"express": "^4.14.0",
"express-session": "^1.14.1",
"file-size": "^1.0.0",
- "fs-extra": "^4.0.1",
+ "fs-extra": "^7.0.0",
"gravatar": "^1.5.2",
+ "javascript-time-ago": "^1.0.30",
"js-yaml": "^3.9.0",
- "jsondiffpatch": "0.2.4",
- "jsonwebtoken": "^7.4.3",
- "katex": "^0.10.0-rc.1",
- "moemark-renderer": "^1.2.6",
+ "jsdom": "^13.0.0",
+ "jsondiffpatch": "0.3.11",
+ "jsonwebtoken": "^8.3.0",
+ "katex": "^0.10.0",
+ "mathjax-node": "^2.1.1",
+ "moemark": "^0.3.10",
"moment": "^2.15.0",
"msgpack-lite": "^0.1.26",
"multer": "^1.2.0",
- "mysql": "^2.11.1",
+ "mysql2": "^1.6.2",
"node-7z": "^0.4.0",
"nodemailer": "^4.1.0",
+ "object-assign-deep": "^0.4.0",
"pygmentize-bundled-cached": "^1.1.0",
"randomstring": "^1.1.5",
"request": "^2.74.0",
"request-promise": "^4.1.1",
"sendmail": "^1.1.1",
- "sequelize": "^3.24.3",
+ "sequelize": "^4.41.0",
"session-file-store": "^1.0.0",
"socket.io": "^2.0.3",
- "sqlite3": "^3.1.4",
"syzoj-divine": "^1.0.2",
"tmp-promise": "^1.0.3",
"waliyun": "^3.1.1",
- "winston": "^2.3.1",
- "xss": "^0.3.3"
+ "winston": "^3.1.0",
+ "xss": "^1.0.3"
}
}
diff --git a/static/mathjax.css b/static/mathjax.css
index c19242f..b87be21 100644
--- a/static/mathjax.css
+++ b/static/mathjax.css
@@ -1,7 +1,6 @@
-.MJX_Assistive_MathML {position: absolute!important; top: 0; left: 0; clip: rect(1px, 1px, 1px, 1px); padding: 1px 0 0 0!important; border: 0!important; height: 1px!important; width: 1px!important; overflow: hidden!important; display: block!important; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none}
-.MJX_Assistive_MathML.MJX_Assistive_MathML_Block {width: 100%!important}
-.mjx-chtml {display: inline-block; line-height: 0; text-indent: 0; text-align: left; text-transform: none; font-style: normal; font-weight: normal; font-size: 1.19em; font-size-adjust: none; letter-spacing: normal; word-wrap: normal; word-spacing: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; margin: 0; padding: 1px 0}
-.MJXc-display {display: block; text-align: center; margin: 1em 0; padding: 0; font-size: 1em !important; }
+.mjx-chtml {display: inline-block; line-height: 0; text-indent: 0; text-align: left; text-transform: none; font-style: normal; font-weight: normal; font-size: 1.19em !important; font-size-adjust:
+none; letter-spacing: normal; word-wrap: normal; word-spacing: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; margin: 0; padding: 1px 0}
+.MJXc-display {display: block; text-align: center; margin: 1em 0; padding: 0}
.mjx-chtml[tabindex]:focus, body :focus .mjx-chtml[tabindex] {display: inline-table}
.mjx-full-width {text-align: center; display: table-cell!important; width: 10000em}
.mjx-math {display: inline-block; border-collapse: separate; border-spacing: 0}
@@ -45,20 +44,17 @@
.MJXc-space1 {margin-left: .167em}
.MJXc-space2 {margin-left: .222em}
.MJXc-space3 {margin-left: .278em}
-.mjx-chartest {display: block; visibility: hidden; position: absolute; top: 0; line-height: normal; font-size: 500%}
-.mjx-chartest .mjx-char {display: inline}
-.mjx-chartest .mjx-box {padding-top: 1000px}
-.MJXc-processed {display: none}
-.mjx-test {display: block; font-style: normal; font-weight: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-transform: none; letter-spacing: normal; word-spacing: normal; overflow: hidden; height: 1px}
-.mjx-ex-box-test {position: absolute; width: 1px; height: 60ex}
-.mjx-line-box-test {display: table!important}
-.mjx-line-box-test span {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}
-#MathJax_CHTML_Tooltip {background-color: InfoBackground; color: InfoText; border: 1px solid black; box-shadow: 2px 2px 5px #AAAAAA; -webkit-box-shadow: 2px 2px 5px #AAAAAA; -moz-box-shadow: 2px 2px 5px #AAAAAA; -khtml-box-shadow: 2px 2px 5px #AAAAAA; padding: 3px 4px; z-index: 401; position: absolute; left: 0; top: 0; width: auto; height: auto; display: none}
-.mjx-chtml .mjx-noError {line-height: 1.2; vertical-align: ; font-size: 90%; text-align: left; color: black; padding: 1px 3px; border: 1px solid}
-.MJXc-TeX-unknown-R {font-family: STIXGeneral,'Cambria Math','Arial Unicode MS',serif; font-style: normal; font-weight: normal}
-.MJXc-TeX-unknown-I {font-family: STIXGeneral,'Cambria Math','Arial Unicode MS',serif; font-style: italic; font-weight: normal}
-.MJXc-TeX-unknown-B {font-family: STIXGeneral,'Cambria Math','Arial Unicode MS',serif; font-style: normal; font-weight: bold}
-.MJXc-TeX-unknown-BI {font-family: STIXGeneral,'Cambria Math','Arial Unicode MS',serif; font-style: italic; font-weight: bold}
+.mjx-test.mjx-test-display {display: table!important}
+.mjx-test.mjx-test-inline {display: inline!important; margin-right: -1px}
+.mjx-test.mjx-test-default {display: block!important; clear: both}
+.mjx-ex-box {display: inline-block!important; position: absolute; overflow: hidden; min-height: 0; max-height: none; padding: 0; border: 0; margin: 0; width: 1px; height: 60ex}
+.mjx-test-inline .mjx-left-box {display: inline-block; width: 0; float: left}
+.mjx-test-inline .mjx-right-box {display: inline-block; width: 0; float: right}
+.mjx-test-display .mjx-right-box {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}
+.MJXc-TeX-unknown-R {font-family: monospace; font-style: normal; font-weight: normal}
+.MJXc-TeX-unknown-I {font-family: monospace; font-style: italic; font-weight: normal}
+.MJXc-TeX-unknown-B {font-family: monospace; font-style: normal; font-weight: bold}
+.MJXc-TeX-unknown-BI {font-family: monospace; font-style: italic; font-weight: bold}
.MJXc-TeX-ams-R {font-family: MJXc-TeX-ams-R,MJXc-TeX-ams-Rw}
.MJXc-TeX-cal-B {font-family: MJXc-TeX-cal-B,MJXc-TeX-cal-Bx,MJXc-TeX-cal-Bw}
.MJXc-TeX-frak-R {font-family: MJXc-TeX-frak-R,MJXc-TeX-frak-Rw}
@@ -78,49 +74,184 @@
.MJXc-TeX-size2-R {font-family: MJXc-TeX-size2-R,MJXc-TeX-size2-Rw}
.MJXc-TeX-size3-R {font-family: MJXc-TeX-size3-R,MJXc-TeX-size3-Rw}
.MJXc-TeX-size4-R {font-family: MJXc-TeX-size4-R,MJXc-TeX-size4-Rw}
+.MJXc-TeX-vec-R {font-family: MJXc-TeX-vec-R,MJXc-TeX-vec-Rw}
+.MJXc-TeX-vec-B {font-family: MJXc-TeX-vec-B,MJXc-TeX-vec-Bx,MJXc-TeX-vec-Bw}
@font-face {font-family: MJXc-TeX-ams-R; src: local('MathJax_AMS'), local('MathJax_AMS-Regular')}
-@font-face {font-family: MJXc-TeX-ams-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-ams-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-cal-B; src: local('MathJax_Caligraphic Bold'), local('MathJax_Caligraphic-Bold')}
@font-face {font-family: MJXc-TeX-cal-Bx; src: local('MathJax_Caligraphic'); font-weight: bold}
-@font-face {font-family: MJXc-TeX-cal-Bw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-cal-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-frak-R; src: local('MathJax_Fraktur'), local('MathJax_Fraktur-Regular')}
-@font-face {font-family: MJXc-TeX-frak-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-frak-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-frak-B; src: local('MathJax_Fraktur Bold'), local('MathJax_Fraktur-Bold')}
@font-face {font-family: MJXc-TeX-frak-Bx; src: local('MathJax_Fraktur'); font-weight: bold}
-@font-face {font-family: MJXc-TeX-frak-Bw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-frak-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-math-BI; src: local('MathJax_Math BoldItalic'), local('MathJax_Math-BoldItalic')}
@font-face {font-family: MJXc-TeX-math-BIx; src: local('MathJax_Math'); font-weight: bold; font-style: italic}
-@font-face {font-family: MJXc-TeX-math-BIw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-math-BIw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-sans-R; src: local('MathJax_SansSerif'), local('MathJax_SansSerif-Regular')}
-@font-face {font-family: MJXc-TeX-sans-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-sans-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-sans-B; src: local('MathJax_SansSerif Bold'), local('MathJax_SansSerif-Bold')}
@font-face {font-family: MJXc-TeX-sans-Bx; src: local('MathJax_SansSerif'); font-weight: bold}
-@font-face {font-family: MJXc-TeX-sans-Bw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-sans-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-sans-I; src: local('MathJax_SansSerif Italic'), local('MathJax_SansSerif-Italic')}
@font-face {font-family: MJXc-TeX-sans-Ix; src: local('MathJax_SansSerif'); font-style: italic}
-@font-face {font-family: MJXc-TeX-sans-Iw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-sans-Iw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-script-R; src: local('MathJax_Script'), local('MathJax_Script-Regular')}
-@font-face {font-family: MJXc-TeX-script-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-script-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-type-R; src: local('MathJax_Typewriter'), local('MathJax_Typewriter-Regular')}
-@font-face {font-family: MJXc-TeX-type-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-type-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-cal-R; src: local('MathJax_Caligraphic'), local('MathJax_Caligraphic-Regular')}
-@font-face {font-family: MJXc-TeX-cal-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-cal-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-main-B; src: local('MathJax_Main Bold'), local('MathJax_Main-Bold')}
@font-face {font-family: MJXc-TeX-main-Bx; src: local('MathJax_Main'); font-weight: bold}
-@font-face {font-family: MJXc-TeX-main-Bw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-main-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-main-I; src: local('MathJax_Main Italic'), local('MathJax_Main-Italic')}
@font-face {font-family: MJXc-TeX-main-Ix; src: local('MathJax_Main'); font-style: italic}
-@font-face {font-family: MJXc-TeX-main-Iw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-main-Iw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-main-R; src: local('MathJax_Main'), local('MathJax_Main-Regular')}
-@font-face {font-family: MJXc-TeX-main-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-main-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-math-I; src: local('MathJax_Math Italic'), local('MathJax_Math-Italic')}
@font-face {font-family: MJXc-TeX-math-Ix; src: local('MathJax_Math'); font-style: italic}
-@font-face {font-family: MJXc-TeX-math-Iw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-math-Iw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-size1-R; src: local('MathJax_Size1'), local('MathJax_Size1-Regular')}
-@font-face {font-family: MJXc-TeX-size1-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size1-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-size2-R; src: local('MathJax_Size2'), local('MathJax_Size2-Regular')}
-@font-face {font-family: MJXc-TeX-size2-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size2-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-size3-R; src: local('MathJax_Size3'), local('MathJax_Size3-Regular')}
-@font-face {font-family: MJXc-TeX-size3-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size3-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf') format('opentype')}
@font-face {font-family: MJXc-TeX-size4-R; src: local('MathJax_Size4'), local('MathJax_Size4-Regular')}
-@font-face {font-family: MJXc-TeX-size4-Rw; src /*1*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot'); src /*2*/: url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff') format('woff'), url('https://cdn.loli.net/ajax/libs/mathjax/2.7.0/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size4-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-vec-R; src: local('MathJax_Vector'), local('MathJax_Vector-Regular')}
+@font-face {font-family: MJXc-TeX-vec-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-vec-B; src: local('MathJax_Vector Bold'), local('MathJax_Vector-Bold')}
+@font-face {font-family: MJXc-TeX-vec-Bx; src: local('MathJax_Vector'); font-weight: bold}
+@font-face {font-family: MJXc-TeX-vec-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Bold.otf') format('opentype')}.mjx-chtml {display: inline-block; line-height: 0; text-indent: 0; text-align: left; text-transform: none; font-style: normal; font-weight: normal; font-size: 100%; font-size-adjust:
+none; letter-spacing: normal; word-wrap: normal; word-spacing: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; margin: 0; padding: 1px 0}
+.MJXc-display {display: block; text-align: center; margin: 1em 0; padding: 0}
+.mjx-chtml[tabindex]:focus, body :focus .mjx-chtml[tabindex] {display: inline-table}
+.mjx-full-width {text-align: center; display: table-cell!important; width: 10000em}
+.mjx-math {display: inline-block; border-collapse: separate; border-spacing: 0}
+.mjx-math * {display: inline-block; -webkit-box-sizing: content-box!important; -moz-box-sizing: content-box!important; box-sizing: content-box!important; text-align: left}
+.mjx-numerator {display: block; text-align: center}
+.mjx-denominator {display: block; text-align: center}
+.MJXc-stacked {height: 0; position: relative}
+.MJXc-stacked > * {position: absolute}
+.MJXc-bevelled > * {display: inline-block}
+.mjx-stack {display: inline-block}
+.mjx-op {display: block}
+.mjx-under {display: table-cell}
+.mjx-over {display: block}
+.mjx-over > * {padding-left: 0px!important; padding-right: 0px!important}
+.mjx-under > * {padding-left: 0px!important; padding-right: 0px!important}
+.mjx-stack > .mjx-sup {display: block}
+.mjx-stack > .mjx-sub {display: block}
+.mjx-prestack > .mjx-presup {display: block}
+.mjx-prestack > .mjx-presub {display: block}
+.mjx-delim-h > .mjx-char {display: inline-block}
+.mjx-surd {vertical-align: top}
+.mjx-mphantom * {visibility: hidden}
+.mjx-merror {background-color: #FFFF88; color: #CC0000; border: 1px solid #CC0000; padding: 2px 3px; font-style: normal; font-size: 90%}
+.mjx-annotation-xml {line-height: normal}
+.mjx-menclose > svg {fill: none; stroke: currentColor}
+.mjx-mtr {display: table-row}
+.mjx-mlabeledtr {display: table-row}
+.mjx-mtd {display: table-cell; text-align: center}
+.mjx-label {display: table-row}
+.mjx-box {display: inline-block}
+.mjx-block {display: block}
+.mjx-span {display: inline}
+.mjx-char {display: block; white-space: pre}
+.mjx-itable {display: inline-table; width: auto}
+.mjx-row {display: table-row}
+.mjx-cell {display: table-cell}
+.mjx-table {display: table; width: 100%}
+.mjx-line {display: block; height: 0}
+.mjx-strut {width: 0; padding-top: 1em}
+.mjx-vsize {width: 0}
+.MJXc-space1 {margin-left: .167em}
+.MJXc-space2 {margin-left: .222em}
+.MJXc-space3 {margin-left: .278em}
+.mjx-test.mjx-test-display {display: table!important}
+.mjx-test.mjx-test-inline {display: inline!important; margin-right: -1px}
+.mjx-test.mjx-test-default {display: block!important; clear: both}
+.mjx-ex-box {display: inline-block!important; position: absolute; overflow: hidden; min-height: 0; max-height: none; padding: 0; border: 0; margin: 0; width: 1px; height: 60ex}
+.mjx-test-inline .mjx-left-box {display: inline-block; width: 0; float: left}
+.mjx-test-inline .mjx-right-box {display: inline-block; width: 0; float: right}
+.mjx-test-display .mjx-right-box {display: table-cell!important; width: 10000em!important; min-width: 0; max-width: none; padding: 0; border: 0; margin: 0}
+.MJXc-TeX-unknown-R {font-family: monospace; font-style: normal; font-weight: normal}
+.MJXc-TeX-unknown-I {font-family: monospace; font-style: italic; font-weight: normal}
+.MJXc-TeX-unknown-B {font-family: monospace; font-style: normal; font-weight: bold}
+.MJXc-TeX-unknown-BI {font-family: monospace; font-style: italic; font-weight: bold}
+.MJXc-TeX-ams-R {font-family: MJXc-TeX-ams-R,MJXc-TeX-ams-Rw}
+.MJXc-TeX-cal-B {font-family: MJXc-TeX-cal-B,MJXc-TeX-cal-Bx,MJXc-TeX-cal-Bw}
+.MJXc-TeX-frak-R {font-family: MJXc-TeX-frak-R,MJXc-TeX-frak-Rw}
+.MJXc-TeX-frak-B {font-family: MJXc-TeX-frak-B,MJXc-TeX-frak-Bx,MJXc-TeX-frak-Bw}
+.MJXc-TeX-math-BI {font-family: MJXc-TeX-math-BI,MJXc-TeX-math-BIx,MJXc-TeX-math-BIw}
+.MJXc-TeX-sans-R {font-family: MJXc-TeX-sans-R,MJXc-TeX-sans-Rw}
+.MJXc-TeX-sans-B {font-family: MJXc-TeX-sans-B,MJXc-TeX-sans-Bx,MJXc-TeX-sans-Bw}
+.MJXc-TeX-sans-I {font-family: MJXc-TeX-sans-I,MJXc-TeX-sans-Ix,MJXc-TeX-sans-Iw}
+.MJXc-TeX-script-R {font-family: MJXc-TeX-script-R,MJXc-TeX-script-Rw}
+.MJXc-TeX-type-R {font-family: MJXc-TeX-type-R,MJXc-TeX-type-Rw}
+.MJXc-TeX-cal-R {font-family: MJXc-TeX-cal-R,MJXc-TeX-cal-Rw}
+.MJXc-TeX-main-B {font-family: MJXc-TeX-main-B,MJXc-TeX-main-Bx,MJXc-TeX-main-Bw}
+.MJXc-TeX-main-I {font-family: MJXc-TeX-main-I,MJXc-TeX-main-Ix,MJXc-TeX-main-Iw}
+.MJXc-TeX-main-R {font-family: MJXc-TeX-main-R,MJXc-TeX-main-Rw}
+.MJXc-TeX-math-I {font-family: MJXc-TeX-math-I,MJXc-TeX-math-Ix,MJXc-TeX-math-Iw}
+.MJXc-TeX-size1-R {font-family: MJXc-TeX-size1-R,MJXc-TeX-size1-Rw}
+.MJXc-TeX-size2-R {font-family: MJXc-TeX-size2-R,MJXc-TeX-size2-Rw}
+.MJXc-TeX-size3-R {font-family: MJXc-TeX-size3-R,MJXc-TeX-size3-Rw}
+.MJXc-TeX-size4-R {font-family: MJXc-TeX-size4-R,MJXc-TeX-size4-Rw}
+.MJXc-TeX-vec-R {font-family: MJXc-TeX-vec-R,MJXc-TeX-vec-Rw}
+.MJXc-TeX-vec-B {font-family: MJXc-TeX-vec-B,MJXc-TeX-vec-Bx,MJXc-TeX-vec-Bw}
+@font-face {font-family: MJXc-TeX-ams-R; src: local('MathJax_AMS'), local('MathJax_AMS-Regular')}
+@font-face {font-family: MJXc-TeX-ams-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-cal-B; src: local('MathJax_Caligraphic Bold'), local('MathJax_Caligraphic-Bold')}
+@font-face {font-family: MJXc-TeX-cal-Bx; src: local('MathJax_Caligraphic'); font-weight: bold}
+@font-face {font-family: MJXc-TeX-cal-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-frak-R; src: local('MathJax_Fraktur'), local('MathJax_Fraktur-Regular')}
+@font-face {font-family: MJXc-TeX-frak-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-frak-B; src: local('MathJax_Fraktur Bold'), local('MathJax_Fraktur-Bold')}
+@font-face {font-family: MJXc-TeX-frak-Bx; src: local('MathJax_Fraktur'); font-weight: bold}
+@font-face {font-family: MJXc-TeX-frak-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-math-BI; src: local('MathJax_Math BoldItalic'), local('MathJax_Math-BoldItalic')}
+@font-face {font-family: MJXc-TeX-math-BIx; src: local('MathJax_Math'); font-weight: bold; font-style: italic}
+@font-face {font-family: MJXc-TeX-math-BIw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-sans-R; src: local('MathJax_SansSerif'), local('MathJax_SansSerif-Regular')}
+@font-face {font-family: MJXc-TeX-sans-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-sans-B; src: local('MathJax_SansSerif Bold'), local('MathJax_SansSerif-Bold')}
+@font-face {font-family: MJXc-TeX-sans-Bx; src: local('MathJax_SansSerif'); font-weight: bold}
+@font-face {font-family: MJXc-TeX-sans-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-sans-I; src: local('MathJax_SansSerif Italic'), local('MathJax_SansSerif-Italic')}
+@font-face {font-family: MJXc-TeX-sans-Ix; src: local('MathJax_SansSerif'); font-style: italic}
+@font-face {font-family: MJXc-TeX-sans-Iw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-script-R; src: local('MathJax_Script'), local('MathJax_Script-Regular')}
+@font-face {font-family: MJXc-TeX-script-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-type-R; src: local('MathJax_Typewriter'), local('MathJax_Typewriter-Regular')}
+@font-face {font-family: MJXc-TeX-type-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-cal-R; src: local('MathJax_Caligraphic'), local('MathJax_Caligraphic-Regular')}
+@font-face {font-family: MJXc-TeX-cal-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-main-B; src: local('MathJax_Main Bold'), local('MathJax_Main-Bold')}
+@font-face {font-family: MJXc-TeX-main-Bx; src: local('MathJax_Main'); font-weight: bold}
+@font-face {font-family: MJXc-TeX-main-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-main-I; src: local('MathJax_Main Italic'), local('MathJax_Main-Italic')}
+@font-face {font-family: MJXc-TeX-main-Ix; src: local('MathJax_Main'); font-style: italic}
+@font-face {font-family: MJXc-TeX-main-Iw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-main-R; src: local('MathJax_Main'), local('MathJax_Main-Regular')}
+@font-face {font-family: MJXc-TeX-main-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-math-I; src: local('MathJax_Math Italic'), local('MathJax_Math-Italic')}
+@font-face {font-family: MJXc-TeX-math-Ix; src: local('MathJax_Math'); font-style: italic}
+@font-face {font-family: MJXc-TeX-math-Iw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size1-R; src: local('MathJax_Size1'), local('MathJax_Size1-Regular')}
+@font-face {font-family: MJXc-TeX-size1-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size2-R; src: local('MathJax_Size2'), local('MathJax_Size2-Regular')}
+@font-face {font-family: MJXc-TeX-size2-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size3-R; src: local('MathJax_Size3'), local('MathJax_Size3-Regular')}
+@font-face {font-family: MJXc-TeX-size3-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-size4-R; src: local('MathJax_Size4'), local('MathJax_Size4-Regular')}
+@font-face {font-family: MJXc-TeX-size4-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-vec-R; src: local('MathJax_Vector'), local('MathJax_Vector-Regular')}
+@font-face {font-family: MJXc-TeX-vec-Rw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Regular.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Regular.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Regular.otf') format('opentype')}
+@font-face {font-family: MJXc-TeX-vec-B; src: local('MathJax_Vector Bold'), local('MathJax_Vector-Bold')}
+@font-face {font-family: MJXc-TeX-vec-Bx; src: local('MathJax_Vector'); font-weight: bold}
+@font-face {font-family: MJXc-TeX-vec-Bw; src /*1*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Bold.eot'); src /*2*/: url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Bold.woff') format('woff'), url('https://cdnjs.loli.net/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Bold.otf') format('opentype')
diff --git a/static/style.css b/static/style.css
index 8ddf9ba..5f076c6 100644
--- a/static/style.css
+++ b/static/style.css
@@ -35,6 +35,14 @@ body
sans-serif;
}
+a.black-link {
+ color: #000;
+}
+
+a.black-link:hover {
+ color: #4183c4;
+}
+
.font-content {
font-family: 'Open Sans', 'Source Han Sans SC', 'Noto Sans CJK SC', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
}
@@ -43,10 +51,6 @@ body
font-family: 'Fira Mono', 'Noto Sans CJK SC', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', monospace;
}
-.main.container {
- margin-top: 5.5em;
-}
-
.padding {
padding-left: 1em;
padding-right: 1em;
@@ -92,14 +96,6 @@ body > .ui.page.dimmer {
position: fixed !important;
}
-/* status color */
-
-/*
-.accordion .status_detail {
- transition: color .1s ease;
-}
-*/
-
:not(.status_detail).status.success,
.title:hover .status_detail.status.success,
.title.active .status_detail.status.success,
@@ -272,3 +268,35 @@ code {
animation: spinner-icon-rotate 3s linear infinite;
display: block;
}
+
+::-webkit-scrollbar {
+ -webkit-appearance: none;
+ width: 10px;
+ height: 10px;
+}
+
+::-webkit-scrollbar-track {
+ background: rgba(0, 0, 0, 0.1);
+ border-radius: 0px;
+}
+
+::-webkit-scrollbar-thumb {
+ cursor: pointer;
+ border-radius: 5px;
+ background: rgba(0, 0, 0, 0.25);
+ -webkit-transition: color 0.2s ease;
+ transition: color 0.2s ease;
+}
+
+::-webkit-scrollbar-thumb:window-inactive {
+ background: rgba(0, 0, 0, 0.15);
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: rgba(128, 135, 139, 0.8);
+}
+
+.ui.top.attached.block.header i.icon {
+ font-size: 1em;
+ vertical-align: initial;
+}
diff --git a/utility.js b/utility.js
index a01c2d8..6304b22 100644
--- a/utility.js
+++ b/utility.js
@@ -1,24 +1,3 @@
-/*
- * This file is part of SYZOJ.
- *
- * Copyright (c) 2016 Menci
- *
- * SYZOJ is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * SYZOJ is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with SYZOJ. If not, see .
- */
-
-'use strict';
-
Array.prototype.forEachAsync = Array.prototype.mapAsync = async function (fn) {
return Promise.all(this.map(fn));
};
@@ -40,41 +19,14 @@ let Promise = require('bluebird');
let path = require('path');
let fs = Promise.promisifyAll(require('fs-extra'));
let util = require('util');
-let renderer = require('moemark-renderer');
+let markdownRenderer = require('./libs/markdown');
let moment = require('moment');
let url = require('url');
let querystring = require('querystring');
-let pygmentize = require('pygmentize-bundled-cached');
let gravatar = require('gravatar');
let filesize = require('file-size');
let AsyncLock = require('async-lock');
-function escapeHTML(s) {
- // Code from http://stackoverflow.com/questions/5251520/how-do-i-escape-some-html-in-javascript/5251551
- return s.replace(/[^0-9A-Za-z ]/g, (c) => {
- return "" + c.charCodeAt(0) + ";";
- });
-}
-
-function highlightPygmentize(code, lang, cb) {
- pygmentize({
- lang: lang,
- format: 'html',
- options: {
- nowrap: true,
- classprefix: 'pl-'
- }
- }, code, (err, res) => {
- if (err || res.toString() === 'undefined') {
- cb(escapeHTML(code));
- } else {
- cb(res);
- }
- });
-}
-
-renderer.config.highlight = highlightPygmentize;
-
module.exports = {
resolvePath(s) {
let a = Array.from(arguments);
@@ -137,13 +89,13 @@ module.exports = {
return new Promise((resolve, reject) => {
if (!keys) {
if (!obj || !obj.trim()) resolve("");
- else renderer(obj, { mathjaxUseHtml: true }, s => {
+ else markdownRenderer(obj, s => {
resolve(replaceUI(replaceXSS(s)));
});
} else {
let res = obj, cnt = keys.length;
for (let key of keys) {
- renderer(res[key], { mathjaxUseHtml: true }, (s) => {
+ markdownRenderer(res[key], (s) => {
res[key] = replaceUI(replaceXSS(s));
if (!--cnt) resolve(res);
});
@@ -206,10 +158,9 @@ module.exports = {
if (encoded) res += '?' + encoded;
return res;
},
- escapeHTML: escapeHTML,
highlight(code, lang) {
return new Promise((resolve, reject) => {
- highlightPygmentize(code, lang, res => {
+ require('./libs/highlight')(code, lang, res => {
resolve(res);
});
});
diff --git a/views/admin_config.ejs b/views/admin_config.ejs
index 826538c..2c30f6b 100644
--- a/views/admin_config.ejs
+++ b/views/admin_config.ejs
@@ -48,7 +48,7 @@ for (let item in items) {
}
%>