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) { } %>
- +
<% include admin_footer %> diff --git a/views/admin_header.ejs b/views/admin_header.ejs index b78fae7..cbfe523 100644 --- a/views/admin_header.ejs +++ b/views/admin_header.ejs @@ -5,7 +5,7 @@ let items = { privilege: '权限管理', rejudge: '一键重测', links: '友链管理', - rating: 'Rating 管理', + rating: '积分管理', raw: '配置文件', other: '其他操作' }; diff --git a/views/admin_info.ejs b/views/admin_info.ejs index 3dc90d5..9e0204c 100644 --- a/views/admin_info.ejs +++ b/views/admin_info.ejs @@ -17,6 +17,8 @@ } .statistic .label { + padding-top: 15px; + font-size: 1.4em !important; font-weight: normal !important; } diff --git a/views/admin_links.ejs b/views/admin_links.ejs index 55f4bae..4fb8e51 100644 --- a/views/admin_links.ejs +++ b/views/admin_links.ejs @@ -54,7 +54,7 @@ this.adminPage = 'links'; -
添加
+
添加
diff --git a/views/admin_other.ejs b/views/admin_other.ejs index e422dd0..6ee8705 100644 --- a/views/admin_other.ejs +++ b/views/admin_other.ejs @@ -1,8 +1,8 @@ <% this.adminPage = 'other'; %> <% include admin_header %> -

-

-

+

+

+

<% include admin_footer %> diff --git a/views/admin_privilege.ejs b/views/admin_privilege.ejs index e67f27c..6f47910 100644 --- a/views/admin_privilege.ejs +++ b/views/admin_privilege.ejs @@ -37,7 +37,7 @@ let privileges = {
- +
diff --git a/views/admin_rating.ejs b/views/admin_rating.ejs index 3d82646..06273f9 100644 --- a/views/admin_rating.ejs +++ b/views/admin_rating.ejs @@ -14,10 +14,10 @@
- + -注意:如果删除一个比赛的 Rating,则该比赛之上的所有比赛也将被删除,Rating 将还原至该比赛之前的状态! +注意:如果删除一个比赛的积分,则该比赛之上的所有比赛也将被删除,积分将还原至该比赛之前的状态!
<% for (const calc of calcs) { %> diff --git a/views/admin_raw.ejs b/views/admin_raw.ejs index 4ae461a..24b92e3 100644 --- a/views/admin_raw.ejs +++ b/views/admin_raw.ejs @@ -28,7 +28,7 @@ editor.getSession().on("change", function () {
- +
<% include admin_footer %> diff --git a/views/admin_rejudge.ejs b/views/admin_rejudge.ejs index 10acd21..f300906 100644 --- a/views/admin_rejudge.ejs +++ b/views/admin_rejudge.ejs @@ -71,15 +71,15 @@
- + <% if (form.type === 'rejudge') { %> - + <% } else if (count !== null) { %> - <% if (count === 0) { %>没有符合条件的记录<% } else { %>重测 <%= count %> 条记录<% } %> + <% if (count === 0) { %>没有符合条件的记录<% } else { %>重测 <%= count %> 条记录<% } %> - +
+
+ diff --git a/views/header.ejs b/views/header.ejs index de22f27..5b609dd 100644 --- a/views/header.ejs +++ b/views/header.ejs @@ -1,21 +1,21 @@ <% include util %> - + <%= title %> - <%= syzoj.config.title %> - + - - + + - + - + <% if (syzoj.config.google_analytics && syzoj.config.google_analytics !== 'UA-XXXXXXXX-X') { %> <% } %> - - +
diff --git a/views/index.ejs b/views/index.ejs index 6c96ad3..e31aa09 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -3,7 +3,7 @@
-

公告

+

公告

@@ -22,7 +22,7 @@
-

排名

+

排名

@@ -51,7 +51,7 @@ ++i; %> - + - + diff --git a/views/user_edit.ejs b/views/user_edit.ejs index a90ead3..0bb59e1 100644 --- a/views/user_edit.ejs +++ b/views/user_edit.ejs @@ -70,9 +70,9 @@ -
- - 返回个人资料 +
+ + 返回
@@ -119,7 +119,7 @@ function check() { <% include footer %>
<%= i %><%= i %> <%= user.username %><% if (user.nameplate) { %><%- user.nameplate %><% } %> <% include footer %> diff --git a/views/problem_tag_edit.ejs b/views/problem_tag_edit.ejs index 2b3ae19..326f760 100644 --- a/views/problem_tag_edit.ejs +++ b/views/problem_tag_edit.ejs @@ -60,7 +60,11 @@ - +
+ +
+<% if (active === 'submission') { %> + +<% } %> diff --git a/views/user.ejs b/views/user.ejs index 7036e36..f7c9d73 100644 --- a/views/user.ejs +++ b/views/user.ejs @@ -32,7 +32,7 @@ @@ -135,7 +135,7 @@
比赛 名次Rating积分