This commit is contained in:
masnn committed 2020-06-11 22:46:10 +08:00
1 parent 8c20c34d8b
commit ca11d80776
45 files changed
+418 -444

No files matched your search

+2 -11
View File
@@ -3,19 +3,10 @@
Hydro是一个高效的信息学在线测评系统。 Hydro是一个高效的信息学在线测评系统。
特点: 易于部署,轻量,功能强大。 特点: 易于部署,轻量,功能强大。
[中文文档](wiki/deploy.md)
Hydro 的界面基于 Vijos 二次开发。 Hydro 的界面基于 Vijos 二次开发。
## 使用方式
#### 使用 `docker-compose`(推荐)
// TODO(WIP)
#### 直接部署:
安装mongodb (省略)
下载Github Actions自动编译的 app.js 直接运行即可。
## 鸣谢 ## 鸣谢
排名不分先后,按照链接字典序 排名不分先后,按照链接字典序
+3
View File
@@ -6,6 +6,7 @@ const yaml = require('js-yaml');
const { root, ignoreFailure, rmdir } = require('./utils'); const { root, ignoreFailure, rmdir } = require('./utils');
const template = require('./template'); const template = require('./template');
const hack = require('./hack'); const hack = require('./hack');
const wikiBuild = require('./wiki');
const fsp = fs.promises; const fsp = fs.promises;
@@ -42,6 +43,8 @@ async function build(type) {
template: template('templates'), template: template('templates'),
public: {}, public: {},
}; };
const wiki = wikiBuild();
builtin.lib = `Object.assign(global.Hydro.wiki,${JSON.stringify(wiki)})`;
const files = getFiles('.uibuild'); const files = getFiles('.uibuild');
for (const f of files) { for (const f of files) {
if (fs.statSync(root(`.uibuild/${f}`)).isDirectory()) { if (fs.statSync(root(`.uibuild/${f}`)).isDirectory()) {
+27
View File
@@ -0,0 +1,27 @@
const fs = require('fs');
const { root } = require('./utils');
module.exports = () => {
const pages = fs.readdirSync(root('wiki'));
const res = {};
for (const page of pages) {
const c = fs.readFileSync(root(`wiki/${page}`)).toString().split('\n');
const pagename = page.split('.')[0];
res[pagename] = [];
let content = null;
for (let i = 0; i < c.length; i++) {
const line = c[i];
if (line.startsWith('# ')) {
if (content) res[pagename].push(content);
content = {};
const t = line.split('# ')[1].split('|');
[content.title, content.id] = t.map((q) => q.trim());
content.content = '';
} else {
content.content = `${content.content}${line}\n`;
}
res[pagename].push(content);
}
}
return res;
};
@@ -1,12 +1,10 @@
const { Route, Handler } = global.Hydro.service.server; const { Route, Handler } = require('../service/server');
const { NotFoundError } = global.Hydro.error; const { NotFoundError } = require('../error');
// eslint-disable-next-line import/no-unresolved
const pages = require('./__build.json');
class WikiHandler extends Handler { class WikiHandler extends Handler {
async get({ name }) { async get({ name }) {
if (!pages[name]) throw new NotFoundError(name); if (!global.Hydro.wiki[name]) throw new NotFoundError(name);
const contents = pages[name]; const contents = global.Hydro.wiki[name];
const path = [ const path = [
['Hydro', '/'], ['Hydro', '/'],
['wiki', '/wiki'], ['wiki', '/wiki'],
+8 -7
View File
@@ -166,7 +166,7 @@ const builtinModel = [
const builtinHandler = [ const builtinHandler = [
'home', 'problem', 'record', 'judge', 'user', 'home', 'problem', 'record', 'judge', 'user',
'contest', 'training', 'discussion', 'manage', 'import', 'contest', 'training', 'discussion', 'manage', 'import',
'misc', 'homework', 'domain', 'misc', 'homework', 'domain', 'wiki',
]; ];
const builtinScript = [ const builtinScript = [
@@ -297,23 +297,25 @@ async function terminate() {
} }
async function load() { async function load() {
global.nodeModules = {
bson: require('bson'),
'js-yaml': require('js-yaml'),
mongodb: require('mongodb'),
};
global.Hydro = { global.Hydro = {
handler: {}, handler: {},
service: {}, service: {},
model: {}, model: {},
script: {}, script: {},
lib: {}, lib: {},
nodeModules: { wiki: {},
bson: require('bson'),
'js-yaml': require('js-yaml'),
mongodb: require('mongodb'),
},
template: {}, template: {},
ui: {}, ui: {},
}; };
global.onDestory = []; global.onDestory = [];
Error.stackTraceLimit = 50; Error.stackTraceLimit = 50;
process.on('unhandledRejection', (e) => console.error(e)); process.on('unhandledRejection', (e) => console.error(e));
process.on('SIGINT', terminate);
if (cluster.isMaster) { if (cluster.isMaster) {
console.log(`Master ${process.pid} Starting`); console.log(`Master ${process.pid} Starting`);
process.stdin.setEncoding('utf8'); process.stdin.setEncoding('utf8');
@@ -326,7 +328,6 @@ async function load() {
console.warn(e); console.warn(e);
} }
}); });
process.on('SIGINT', terminate);
await loadAsMaster(); await loadAsMaster();
cluster.on('exit', (worker, code, signal) => { cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} exit: ${code} ${signal}`); console.log(`Worker ${worker.process.pid} exit: ${code} ${signal}`);
+1 -1
View File
@@ -1,5 +1,5 @@
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const { mongodb } = global.Hydro.nodeModules; const { mongodb } = global.nodeModules;
const dst = global.Hydro.service.db; const dst = global.Hydro.service.db;
const { file, problem, discussion } = global.Hydro.model; const { file, problem, discussion } = global.Hydro.model;
+1 -2
View File
@@ -1,7 +1,6 @@
const assert = require('assert'); const assert = require('assert');
const { download } = global.Hydro.lib; const { download, axios } = global.Hydro.lib;
const { axios } = global.Hydro.lib;
const { ValidationError, RemoteOnlineJudgeError } = global.Hydro.error; const { ValidationError, RemoteOnlineJudgeError } = global.Hydro.error;
async function syzoj(url, handler) { async function syzoj(url, handler) {
-24
View File
@@ -1,24 +0,0 @@
const fs = require('fs');
const path = require('path');
const root = (name) => path.resolve(__dirname, name);
exports.prebuild = async () => {
const pages = fs.readdirSync(root('raw'));
const res = {};
for (const page of pages) {
// eslint-disable-next-line import/no-dynamic-require
const contents = require(root(`raw/${page}/contents.json`));
res[page] = [];
for (const id of contents) {
const content = {};
const c = fs.readFileSync(root(`raw/${page}/${id}.md`)).toString().split('\n');
// eslint-disable-next-line prefer-destructuring
content.title = c[0].split('# ')[1];
content.id = id;
content.content = c.splice(1, c.length - 1).join('\n');
res[page].push(content);
}
}
fs.writeFileSync(root('__build.json'), JSON.stringify(res));
};
-5
View File
@@ -1,5 +0,0 @@
{
"id": "wiki",
"version": "1.0.0",
"description": "Basic wiki module."
}
-3
View File
@@ -1,3 +0,0 @@
wiki_about: About
wiki_help: Help
wiki_development: Development
-7
View File
@@ -1,7 +0,0 @@
wiki_about: 关于
wiki_help: 帮助
wiki_development: 开发文档
Basic: 基础
Module: 模块
Introduction: 介绍
Deployment: 部署
-5
View File
@@ -1,5 +0,0 @@
[
"privacy",
"tos",
"discuss"
]
-23
View File
@@ -1,23 +0,0 @@
# Discussion: Terms Of Service
为了更好地发挥讨论、题解的积极作用,使广大用户学到知识、获得利益,进一步规范讨论和题解功能的使用,我们制定了《讨论和题解版规》(简称《版规》)。您在发布(或回复)讨论和题解时,即代表您已充分阅读、理解、接受并保证遵守此版规。
您在发布(或回复)讨论和题解或使用相关功能时须遵守以下规定:
- 第一次使用编辑器前,要先阅读编辑器快速入门和 Markdown 详细帮助。
- 不得将讨论、题解混淆。例如,不得将题解发布到讨论中,题解应发布在相应题目的题解区中。
- 发布(或回复)的所有内容不得包含会干扰 Hydro 用户界面呈现的相关内容。
- 发布(或回复)的所有内容不得包含恶意代码和指向恶意网站或 Hydro 明确禁止的网站的链接。
- 特别地,发布(或回复)含有代码的内容时,应当将代码高亮。一个简单的方法是选中代码块然后按下 Tab 键。
- 发布的题解禁止只包含无详细注释的代码。题解中难以理解的代码应当有尽可能详细的注释。
- 打分、投票和评价应当客观。例如,对于题解的打分、投票和评价应当关注于题解本身的质量。
- 我们欢迎原创作品,并会对其作者给予数量不等的 RP 奖励。
您在发布、回复讨论和题解时还须遵守法律法规,不得发布违法违规内容,包括但不限于:
- 危害国家安全统一、破坏社会稳定、违反公序良俗、侮辱、诽谤、淫秽、暴力以及任何违反国家法律法规的内容;
- 侵害他人知识产权、商业秘密等合法权利的内容;
- 恶意虚构事实、隐瞒真相以误导、欺骗他人的内容;
- 广告信息及垃圾信息;
- 其他法律法规禁止的内容。
对于违反《版规》的,我们将进行警告并删除相关内容、临时冻结用户、永久冻结用户等操作。
-23
View File
@@ -1,23 +0,0 @@
# Privacy
#### 1. 收集的信息
我们收集信息是为了向所有用户提供更好的服务。我们有两种信息收集方式:
s
- 您向我们提供信息。在您注册 Hydro 帐户时,我们会要求您提供个人信息,例如您的电子邮件地址、QQ号码等。
- 我们在您使用服务的过程中获取信息。我们会收集关于您使用的服务以及使用方式的信息,例如您在何时使用了我们服务。
#### 2. 如何使用收集到的信息
我们利用从所有服务中收集的信息来提供、维护、保护和改进这些服务,同时开发新的服务并保护 Hydro 以及用户的隐私。
当我们要将信息用于本隐私权政策未载明的其它用途时,则会事先征求您的同意。
#### 3. 访问和更新您的个人信息
无论您在何时使用我们的服务,我们都力求让您能够访问自己的个人信息。如果这些信息有误,我们会努力通过各种方式让您快速更新信息或删除信息。在更新您的个人信息时,我们可能会要求您先验证自己的身份,然后再处理您的请求。
我们力求对服务进行完善的维护,以保护信息免遭意外或恶意的破坏。因此,当您从我们的服务中删除信息后,我们可能不会立即从在用的服务器中删除这些信息的残留副本,也可能不会从备份系统中删除相应的信息。
#### 4. 信息安全
我们为您提供SSL加密访问服务,您可以通过SSL(https)使用我们的服务,这可以很大程度上保障在传输过程中您信息的安全。
对于敏感数据(如您的密码),我们承诺在存储时进行高强度不可逆加密。Hydro 的管理员、维护人员等均不能够访问到敏感数据的明文,所有操作均无人工介入。
-12
View File
@@ -1,12 +0,0 @@
# Basic
Hydro 后端使用 NodeJS 编写,前端使用 JQuery + React。
代码风格遵循 airbnb 标准(详见 .eslintrc.js)。
由于模块中不能使用 require() 引入 Hydro 的文件,因此需要从 global.Hydro 中取出需要的模块。
例:
```js
const { db } = global.Hydro.service;
const { problem } = global.Hydro.model;
```
-11
View File
@@ -1,11 +0,0 @@
[
"basic",
"module",
"hydro",
"handler",
"service",
"lib",
"file",
"locale",
"template"
]
-3
View File
@@ -1,3 +0,0 @@
# File
file 文件夹下的所有文件将被自动解压到 `$TMPDIR/hydro/模块ID/路径` 的位置(权限755,通常用于启动子进程)。
-96
View File
@@ -1,96 +0,0 @@
# Handler
通常用于提供页面路由。
例:注册新路由:
```js
const { Handler, Route } = global.Hydro.service.server;
const { user } = global.Hydro.model;
const { PERM_LOGGEDIN } = global.Hydro.permission;
class CustomHandler extends Handler {
async prepare() {
this.checkPassword(PERM_LOGGEDIN);
}
async get({ username, password }) {
const udoc = await user.getByUname(username);
udoc.checkPassword(password);
this.response.body = { udoc };
}
async post() {
// 当提交表单时会执行该函数
}
async postConfirm() {
// 当提交表单并存在 operation 值为 confirm 时执行。
}
}
async function apply() {
Route('/route/:username', module.exports.CustomHandler);
}
global.Hydro.handler.custom = module.exports = { CustomHandler, apply };
```
在路由中定义所有的函数应均为异步函数,支持的函数如下:
_prepare, prepare, get, post, post[Operation], cleanup, _cleanup
具体流程如下:
先执行 _prepare(args) (如果存在)
args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参数,并对以下字段进行了校验:
| 名称 | 类型 |
| :------: | :-----------: |
| content | string |
| title | string |
| uid | number(int) |
| password | string |
| mail | string(mail) |
| uname | string |
| page | number(int) |
| duration | number(float) |
| role | string |
| roles | string[] |
| pids | string |
| tid | bson.ObjectID |
| rid | bson.ObjectID |
| did | bson.ObjectID |
| drid | bson.ObjectID |
| drrid | bson.ObjectID |
| psid | bson.ObjectID |
| psrid | bson.ObjectID |
| docId | bson.ObjectID |
| mongoId | bson.ObjectID |
再执行 prepare(args) (如果存在)
检查请求类型:
```
为 GET ?
-> 执行 get(args)
为 POST ?
-> 执行 post(args)
-> 含有 operation 字段?
-> 执行 post[Operation]
```
执行 cleanup()
执行 _cleanup()
如果在 this.response.template 指定模板则渲染,否则直接返回 this.response.body 中的内容。
* 在表单提交时的 operation 字段使用下划线,函数名使用驼峰命名。
如 `<input type="hidden" name="operation" value="confirm_delete">` 对应 `postConfirmDelete` 函数。
应当提供 `apply` 函数,并与定义的 Handler 一同挂载到 `global.Hydro.handler[模块名]` 位置。
`apply` 函数将在初始化阶段被调用。
<blockquote class="note">请在 apply 函数中从 module.exports 引用,因为它们可能需要被其他模块修改。</blockquote>
-11
View File
@@ -1,11 +0,0 @@
# Hydro.json
Hydro.json 是模块的声明文件,格式如下。
```json
{
"id": "模块ID",
"version": "模块版本",
"description": "模块描述"
}
```
-3
View File
@@ -1,3 +0,0 @@
# Lib
库文件。通常用于提供一些功能(废话)。
-3
View File
@@ -1,3 +0,0 @@
# Locale
用于提供多国翻译。格式与 Hydro 的 locale 文件夹格式相同。
-23
View File
@@ -1,23 +0,0 @@
# Module
## 文件架构
Hydro 的模块由以下几个部分组成:
service: 服务
script: 脚本
handler: 访问路由
lib: 库
model: 数据库模型
file: 额外文件
locale: 多国化
template: UI 模板
README.md: 介绍
hydro.json: 声明文件(必须)
## 模块编译
使用 `hydro-build` 进行编译。
安装:`yarn add hydro-build -D`
编译:`hydro-build`
如果命运的齿轮没有出差错,您应该可以找到生成的.hydro文件了。
-3
View File
@@ -1,3 +0,0 @@
# README.md
项目的说明文件。
-3
View File
@@ -1,3 +0,0 @@
# Service
通常用于提供与其他程序对接的接口。(如内置的 MongoDB 等)
-31
View File
@@ -1,31 +0,0 @@
# Template
页面模板,使用 nunjucks 语法。
传入了 _ 翻译函数与 model 等。
```html
{% set page_name = "page_name" %}
{% extends "layout/basic.html" %}
{% block content %}
<div class="error__container clearfix">
<div class="error__icon-container">
<div class="error__twd2"></div>
</div>
<div class="error__text-container">
<h1>{{ _('Oops!') }}</h1>
<p>{{ _(error.message).format(error.params) }}</p>
<p>{{ _('Technical Information') }}:</p>
<p>{{ _('Type') }}: {{ error.code }}</p>
<p>{{ _('Arguments') }}:
<ol>
{% for param in error.params %}
<li>{{ param }}</li>
{% endfor %}
</ol>
</p>
</div>
</div>
{% endblock %}
```
<blockquote class="note">请不要覆盖已有模板。</blockquote>
@@ -1,4 +0,0 @@
[
"introduction",
"deploy"
]
-13
View File
@@ -1,13 +0,0 @@
# Deployment
Hydro 依赖于 MongoDB 与 NodeJS,您应该先安装它们。
之后您可以下载最新版的 Hydro 程序,放置于一个空文件夹,使用如下命令启动 Hydro:
```sh
node hydro.js
```
Hydro 会自行初始化并监听 8888 端口。请用浏览器访问并进行相应配置。
数据库配置完成后,会自动创建 Root 用户。(账号 `root` ,密码 `rootroot`),请及时修改。
之后的进阶配置可在 管理 面板进行。
@@ -1,11 +0,0 @@
# Introduction
为什么使用 Hydro ?
- 安全:使用 cgroup 进行隔离,杜绝卡评测;
- 高效:Hydro 使用了沙箱复用技术,拥有极高的评测效率;
- 扩展:Hydro 支持安装额外模块进行扩展;
- 强大:配合 Judger 模块(或 HydroJudger 独立评测机),可支持 spj,交互题,提交答案题,文件IO等多种特性;
- 简便:提供了多种迁移脚本,可从 Vijos 等快速升级至 Hydro;
- 自定:所有权限节点均可自由设置;
- 社区:Hydro 正在持续维护中;
-3
View File
@@ -1,3 +0,0 @@
# Accepted Ratio
通过率的影响极其恶劣,Hydro 不提供也不承认通过率。
-19
View File
@@ -1,19 +0,0 @@
# Compile Error
可能有以下情况:
- 递交时选错了编程语言
- Java 的主类名没有使用 "Main"
- 对于 C/C++:见下
- 一般性的编译错误
<blockquote class="warn">
对 C/C++ 选手的特别提醒:
<ul>
<li>1. __int64 在 GNU C++ 中应写成 long long 类型</li>
<li>2. main() 返回值必须定义为 int ,而不是 void</li>
<li>3. for 语句中的指标变量 i 将会在如"for (int i = 0...) {...}"语句之后变为无效</li>
<li>4. itoa 不是一个通用 ANSI 函数(标准 C/C++ 中无此函数)</li>
<li>5. printf 中使用 %lf 格式是不正确的</li>
</ul>
</blockquote>
-14
View File
@@ -1,14 +0,0 @@
# Compilers' Version and Parameters
Hydro使用 [HydroJudger](https://github.com/hydro-dev/HydroJudger) 进行评测,以docker镜像的形式安装至评测机。
所使用的编译器均为创建镜像时 [debian testing](https://wiki.debian.org/DebianTesting) 分支的最新版。编译参数如下:
- Free Pascal `fpc -O2 -o/out/foo /in/foo.pas`
- C `gcc -O2 -Wall -std=c99 -o /out/foo /in/foo.c -lm`
- C++ `g++ -O2 -Wall -std=c++11 -o /out/foo /in/foo.cc -lm`
- Java `javac Main.java`
- Python `python foo.py`
- Python 3 `python3 foo.py`
- PHP `php foo.php`
- Rust `rustc -O -o /out/foo /in/foo.rs`
- Haskell `ghc -O -outputdir /tmp -o /out/foo /in/foo.hs`
-13
View File
@@ -1,13 +0,0 @@
[
"compiler",
"limits",
"io",
"status",
"ce",
"training",
"contest",
"acratio",
"rp",
"dataformat",
"lostpass"
]
-8
View File
@@ -1,8 +0,0 @@
# Contest
按照赛制不同,有不同的递交、排名规则。
OI 赛制所有题目均以最后一次递交为准,特别地,请避免编译错误。
OI 赛制排名规则为:总分高的排在前面,总分相等则排名相同。
ACM/ICPC 赛制所有题目递交后立即评测,以是否通过为准。
ACM/ICPC 赛制排名规则为:通过题目数多的排在前面,通过题目数相同的做题耗时(含罚时)少的排在前。
时间与空间限制以题目说明为准,默认限制参见[Limitations](#Limits)。
-3
View File
@@ -1,3 +0,0 @@
# Dataset Format
TODO
-3
View File
@@ -1,3 +0,0 @@
# IO
若无特殊说明,Hydro 使用标准输入输出(控制台输入输出,屏幕输入输出,STD I/O)。
-4
View File
@@ -1,4 +0,0 @@
# Limitations
Hydro 评测机使用进程的CPU时间计算时间消耗,时间的限定为题目中评测点所指定的时间。
Hydro 评测机使用进程虚拟内存与物理内存总和计算内存空间消耗。内存空间默认限定为256MiB,题目中特别指明的,限定为题目中评测点所指定的内存空间。
-4
View File
@@ -1,4 +0,0 @@
# Forgot Password and/or Username
如果您无法登录,请仔细想想,是不是用户名记错了。比如,自己原本想要注册的用户名已经被注册,所以使用了一个带有前和/或后缀的用户名。
如果您确信您的账号被盗或者忘记了账号和/或密码,请及时[{{ _('Reset Password or Find Username') }}](/lostpass)。
-6
View File
@@ -1,6 +0,0 @@
# RP
Hydro RP 分为固定 RP 与浮动 RP ,固定 RP 可由活动、比赛等的奖励获得,浮动 RP 由一般性通过题目获得。
浮动 RP 是一个动态的数值,每个用户在每道题上获得的 RP 都不一样,并且未来也不固定(即浮动之意)。
<blockquote class="note">每道题的浮动 RP 由该题通过总人数与该用户通过此题的名次计算得来。</blockquote>
-17
View File
@@ -1,17 +0,0 @@
# Judge Status
- <span class="record-status--text pending">Waiting</span> 评测:评测请求正在等待被评测机抓取
- <span class="record-status--text progress">Fetched</span> 评测:评测请求已被评测机抓取,正在准备开始评测
- <span class="record-status--text progress">Compiling</span> 评测:正在编译中
- <span class="record-status--text progress">Judging</span> 评测:编译成功,正在评测中
- <span class="record-status--text pass">Accepted</span> 通过:程序输出完全正确
- <span class="record-status--text fail">Wrong Answer</span> 不通过:程序输出与标准答案不一致(不包括行末空格以及文件末空行)
- <span class="record-status--text fail">Time Exceeded</span> 不通过:程序运行时间超过了题目限制
- <span class="record-status--text fail">Memory Exceeded</span> 不通过:程序运行内存空间超过了题目限制
- <span class="record-status--text fail">Runtime Error</span> 不通过:程序运行时错误(如数组越界、被零除、运算溢出、栈溢出、无效指针等)
- <span class="record-status--text fail">Compile Error</span> 不通过:编译失败
- <span class="record-status--text fail">System Error</span> 错误:系统错误(如果您遇到此问题,请及时在讨论区进行反馈)
- <span class="record-status--text ignored">Canceled</span> 其他:评测被取消
- <span class="record-status--text fail">Unknown Error</span> 其他:未知错误
<blockquote class="note">有“成绩取消”字样则说明管理员手动标记此记录为取消,可能违反了服务条款,比如代码被发现与其他用户的代码十分相似。</blockquote>
-3
View File
@@ -1,3 +0,0 @@
# Training
我们精心挑选了一些题目组成了训练计划。单击导航栏的“训练”即可进入!
@@ -19,7 +19,7 @@
<ol class="menu"> <ol class="menu">
{{ sidemenu.render_item('info', 'wiki_about', '/wiki/about') }} {{ sidemenu.render_item('info', 'wiki_about', '/wiki/about') }}
{{ sidemenu.render_item('help', 'wiki_help', '/wiki/help') }} {{ sidemenu.render_item('help', 'wiki_help', '/wiki/help') }}
{{ sidemenu.render_item('help', 'wiki_gettingstarted', '/wiki/gettingstarted') }} {{ sidemenu.render_item('help', 'wiki_deploy', '/wiki/deploy') }}
{{ sidemenu.render_item('help', 'wiki_development', '/wiki/development') }} {{ sidemenu.render_item('help', 'wiki_development', '/wiki/development') }}
</ol> </ol>
</div> </div>
+50 -2
View File
@@ -1,4 +1,28 @@
# Terms of Service # Privacy | privacy
#### 1. 收集的信息
我们收集信息是为了向所有用户提供更好的服务。我们有两种信息收集方式:
s
- 您向我们提供信息。在您注册 Hydro 帐户时,我们会要求您提供个人信息,例如您的电子邮件地址、QQ号码等。
- 我们在您使用服务的过程中获取信息。我们会收集关于您使用的服务以及使用方式的信息,例如您在何时使用了我们服务。
#### 2. 如何使用收集到的信息
我们利用从所有服务中收集的信息来提供、维护、保护和改进这些服务,同时开发新的服务并保护 Hydro 以及用户的隐私。
当我们要将信息用于本隐私权政策未载明的其它用途时,则会事先征求您的同意。
#### 3. 访问和更新您的个人信息
无论您在何时使用我们的服务,我们都力求让您能够访问自己的个人信息。如果这些信息有误,我们会努力通过各种方式让您快速更新信息或删除信息。在更新您的个人信息时,我们可能会要求您先验证自己的身份,然后再处理您的请求。
我们力求对服务进行完善的维护,以保护信息免遭意外或恶意的破坏。因此,当您从我们的服务中删除信息后,我们可能不会立即从在用的服务器中删除这些信息的残留副本,也可能不会从备份系统中删除相应的信息。
#### 4. 信息安全
我们为您提供SSL加密访问服务,您可以通过SSL(https)使用我们的服务,这可以很大程度上保障在传输过程中您信息的安全。
对于敏感数据(如您的密码),我们承诺在存储时进行高强度不可逆加密。Hydro 的管理员、维护人员等均不能够访问到敏感数据的明文,所有操作均无人工介入。
# Terms of Service | tos
#### 0. 欢迎使用 Hydro #### 0. 欢迎使用 Hydro
@@ -57,4 +81,28 @@
#### 9. 其他 #### 9. 其他
如果您对这个协议或我们的服务有意见或建议,可与我们联系,我们会给予您必要的帮助。 如果您对这个协议或我们的服务有意见或建议,可与我们联系,我们会给予您必要的帮助。
# Discussion: Terms Of Service | discussion
为了更好地发挥讨论、题解的积极作用,使广大用户学到知识、获得利益,进一步规范讨论和题解功能的使用,我们制定了《讨论和题解版规》(简称《版规》)。您在发布(或回复)讨论和题解时,即代表您已充分阅读、理解、接受并保证遵守此版规。
您在发布(或回复)讨论和题解或使用相关功能时须遵守以下规定:
- 第一次使用编辑器前,要先阅读编辑器快速入门和 Markdown 详细帮助。
- 不得将讨论、题解混淆。例如,不得将题解发布到讨论中,题解应发布在相应题目的题解区中。
- 发布(或回复)的所有内容不得包含会干扰 Hydro 用户界面呈现的相关内容。
- 发布(或回复)的所有内容不得包含恶意代码和指向恶意网站或 Hydro 明确禁止的网站的链接。
- 特别地,发布(或回复)含有代码的内容时,应当将代码高亮。一个简单的方法是选中代码块然后按下 Tab 键。
- 发布的题解禁止只包含无详细注释的代码。题解中难以理解的代码应当有尽可能详细的注释。
- 打分、投票和评价应当客观。例如,对于题解的打分、投票和评价应当关注于题解本身的质量。
- 我们欢迎原创作品,并会对其作者给予数量不等的 RP 奖励。
您在发布、回复讨论和题解时还须遵守法律法规,不得发布违法违规内容,包括但不限于:
- 危害国家安全统一、破坏社会稳定、违反公序良俗、侮辱、诽谤、淫秽、暴力以及任何违反国家法律法规的内容;
- 侵害他人知识产权、商业秘密等合法权利的内容;
- 恶意虚构事实、隐瞒真相以误导、欺骗他人的内容;
- 广告信息及垃圾信息;
- 其他法律法规禁止的内容。
对于违反《版规》的,我们将进行警告并删除相关内容、临时冻结用户、永久冻结用户等操作。
+33
View File
@@ -0,0 +1,33 @@
# Introduction | introduction
为什么使用 Hydro ?
- 安全:使用 cgroup 进行隔离,杜绝卡评测;
- 高效:Hydro 使用了沙箱复用技术,拥有极高的评测效率;
- 扩展:Hydro 支持安装额外模块进行扩展;
- 强大:配合 Judger 模块(或 HydroJudger 独立评测机),可支持 spj,交互题,提交答案题,文件IO等多种特性;
- 简便:提供了多种迁移脚本,可从 Vijos 等快速升级至 Hydro;
- 自定:所有权限节点均可自由设置;
- 社区:Hydro 正在持续维护中;
# Deployment | deployment
Hydro 依赖于 MongoDB 与 NodeJS,您应该先安装它们。
提示:推荐使用 [nvm](https://nvm.sh/) 安装 NodeJS。
clone 本项目到一个空文件夹,并进行编译:
```sh
git clone https://github.com/hydro-dev/Hydro.git
cd Hydro
yarn build:all
node hydro/loader.js
```
注意:单个Hydro实例需要约100MB的运行内存,但在载入时可能需要较多内存(取决于安装的模块数量与大小)
Hydro 会自行初始化并监听 8888 端口。请用浏览器访问并进行相应配置。
数据库配置完成后,会自动创建 Root 用户。(账号 `root` ,密码 `rootroot`),请及时修改。
之后的进阶配置可在 管理 面板进行。
+194
View File
@@ -0,0 +1,194 @@
# Basic | basic
Hydro 后端使用 NodeJS 编写,前端使用 JQuery + React。
代码风格遵循 airbnb 标准(详见 .eslintrc.js)。
由于模块中不能使用 require() 引入 Hydro 的文件,因此需要从 global.Hydro 中取出需要的模块。
例:
```js
const { db } = global.Hydro.service;
const { problem } = global.Hydro.model;
```
# Module | module
## 文件架构
Hydro 的模块由以下几个部分组成:
service: 服务
script: 脚本
handler: 访问路由
lib: 库
model: 数据库模型
file: 额外文件
locale: 多国化
template: UI 模板
README.md: 介绍
hydro.json: 声明文件(必须)
## 模块编译
使用 `hydro-build` 进行编译。
安装:`yarn add hydro-build -D`
编译:`hydro-build`
如果命运的齿轮没有出差错,您应该可以找到生成的.hydro文件了。
# Hydro.json | hydro
Hydro.json 是模块的声明文件,格式如下。
```json
{
"id": "模块ID",
"version": "模块版本",
"description": "模块描述"
}
```
# Handler | handler
通常用于提供页面路由。
例:注册新路由:
```js
const { Handler, Route } = global.Hydro.service.server;
const { user } = global.Hydro.model;
const { PERM_LOGGEDIN } = global.Hydro.permission;
class CustomHandler extends Handler {
async prepare() {
this.checkPassword(PERM_LOGGEDIN);
}
async get({ username, password }) {
const udoc = await user.getByUname(username);
udoc.checkPassword(password);
this.response.body = { udoc };
}
async post() {
// 当提交表单时会执行该函数
}
async postConfirm() {
// 当提交表单并存在 operation 值为 confirm 时执行。
}
}
async function apply() {
Route('/route/:username', CustomHandler);
}
global.Hydro.handler.handlerName = module.exports = apply;
```
在路由中定义所有的函数应均为异步函数,支持的函数如下:
_prepare, prepare, get, post, post[Operation], cleanup, _cleanup
具体流程如下:
先执行 _prepare(args) (如果存在)
args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参数,并对以下字段进行了校验:
| 名称 | 类型 |
| :------: | :-----------: |
| content | string |
| title | string |
| uid | number(int) |
| password | string |
| mail | string(mail) |
| uname | string |
| page | number(int) |
| duration | number(float) |
| role | string |
| roles | string[] |
| pids | string |
| tid | bson.ObjectID |
| rid | bson.ObjectID |
| did | bson.ObjectID |
| drid | bson.ObjectID |
| drrid | bson.ObjectID |
| psid | bson.ObjectID |
| psrid | bson.ObjectID |
| docId | bson.ObjectID |
| mongoId | bson.ObjectID |
再执行 prepare(args) (如果存在)
检查请求类型:
```
为 GET ?
-> 执行 get(args)
为 POST ?
-> 执行 post(args)
-> 含有 operation 字段?
-> 执行 post[Operation]
```
执行 cleanup()
执行 _cleanup()
如果在 this.response.template 指定模板则渲染,否则直接返回 this.response.body 中的内容。
* 在表单提交时的 operation 字段使用下划线,函数名使用驼峰命名。
如 `<input type="hidden" name="operation" value="confirm_delete">` 对应 `postConfirmDelete` 函数。
应当提供 `apply` 函数,并与定义的 Handler 一同挂载到 `global.Hydro.handler[模块名]` 位置。
`apply` 函数将在初始化阶段被调用。
# Service | service
通常用于提供与其他程序对接的接口或启动其他外部程序。(如内置的 MongoDB / 外置的沙箱模块等)
# Lib | lib
库文件。通常用于提供一些功能(废话)。
# File | file
file 文件夹下的所有文件将被自动解压到 `$TMPDIR/hydro/模块ID/路径` 的位置(权限755,通常用于启动子进程)。
# Locale | locale
用于提供多国翻译。格式与 Hydro 的 locale 文件夹格式相同。
# Template | template
页面模板,使用 [nunjucks](https://mozilla.github.io/nunjucks/cn/templating.html) 语法。
传入了 _ 翻译函数与 model 等。
```html
{% set page_name = "page_name" %}
{% extends "layout/basic.html" %}
{% block content %}
<div class="error__container clearfix">
<div class="error__icon-container">
<div class="error__twd2"></div>
</div>
<div class="error__text-container">
<h1>{{ _('Oops!') }}</h1>
<p>{{ _(error.message).format(error.params) }}</p>
<p>{{ _('Technical Information') }}:</p>
<p>{{ _('Type') }}: {{ error.code }}</p>
<p>{{ _('Arguments') }}:
<ol>
{% for param in error.params %}
<li>{{ param }}</li>
{% endfor %}
</ol>
</p>
</div>
</div>
{% endblock %}
```
<blockquote class="note">请不要覆盖已有模板。</blockquote>
# README.md | readme
项目的说明文件。
+94
View File
@@ -0,0 +1,94 @@
# Compilers' Version and Parameters
Hydro使用 [HydroJudger](https://github.com/hydro-dev/HydroJudger) 进行评测,以docker镜像的形式安装至评测机。
所使用的编译器均为创建镜像时 [debian testing](https://wiki.debian.org/DebianTesting) 分支的最新版。编译参数如下:
- Free Pascal `fpc -O2 -o/out/foo /in/foo.pas`
- C `gcc -O2 -Wall -std=c99 -o /out/foo /in/foo.c -lm`
- C++ `g++ -O2 -Wall -std=c++11 -o /out/foo /in/foo.cc -lm`
- Java `javac Main.java`
- Python `python foo.py`
- Python 3 `python3 foo.py`
- PHP `php foo.php`
- Rust `rustc -O -o /out/foo /in/foo.rs`
- Haskell `ghc -O -outputdir /tmp -o /out/foo /in/foo.hs`
# Limitations
Hydro 评测机使用进程的CPU时间计算时间消耗,时间的限定为题目中评测点所指定的时间。
Hydro 评测机使用进程虚拟内存与物理内存总和计算内存空间消耗。内存空间默认限定为256MiB,题目中特别指明的,限定为题目中评测点所指定的内存空间。
# IO
若无特殊说明,Hydro 使用标准输入输出(控制台输入输出,屏幕输入输出,STD I/O)。
# Judge Status
- <span class="record-status--text pending">Waiting</span> 评测:评测请求正在等待被评测机抓取
- <span class="record-status--text progress">Fetched</span> 评测:评测请求已被评测机抓取,正在准备开始评测
- <span class="record-status--text progress">Compiling</span> 评测:正在编译中
- <span class="record-status--text progress">Judging</span> 评测:编译成功,正在评测中
- <span class="record-status--text pass">Accepted</span> 通过:程序输出完全正确
- <span class="record-status--text fail">Wrong Answer</span> 不通过:程序输出与标准答案不一致(不包括行末空格以及文件末空行)
- <span class="record-status--text fail">Time Exceeded</span> 不通过:程序运行时间超过了题目限制
- <span class="record-status--text fail">Memory Exceeded</span> 不通过:程序运行内存空间超过了题目限制
- <span class="record-status--text fail">Runtime Error</span> 不通过:程序运行时错误(如数组越界、被零除、运算溢出、栈溢出、无效指针等)
- <span class="record-status--text fail">Compile Error</span> 不通过:编译失败
- <span class="record-status--text fail">System Error</span> 错误:系统错误(如果您遇到此问题,请及时在讨论区进行反馈)
- <span class="record-status--text ignored">Canceled</span> 其他:评测被取消
- <span class="record-status--text fail">Unknown Error</span> 其他:未知错误
<blockquote class="note">有“成绩取消”字样则说明管理员手动标记此记录为取消,可能违反了服务条款,比如代码被发现与其他用户的代码十分相似。</blockquote>
# Compile Error
可能有以下情况:
- 递交时选错了编程语言
- Java 的主类名没有使用 "Main"
- 对于 C/C++:见下
- 一般性的编译错误
<blockquote class="warn">
对 C/C++ 选手的特别提醒:
<ul>
<li>1. __int64 在 GNU C++ 中应写成 long long 类型</li>
<li>2. main() 返回值必须定义为 int ,而不是 void</li>
<li>3. for 语句中的指标变量 i 将会在如"for (int i = 0...) {...}"语句之后变为无效</li>
<li>4. itoa 不是一个通用 ANSI 函数(标准 C/C++ 中无此函数)</li>
<li>5. printf 中使用 %lf 格式是不正确的</li>
</ul>
</blockquote>
# Training
我们精心挑选了一些题目组成了训练计划。单击导航栏的“训练”即可进入!
# Contest
按照赛制不同,有不同的递交、排名规则。
OI 赛制所有题目均以最后一次递交为准,特别地,请避免编译错误。
OI 赛制排名规则为:总分高的排在前面,总分相等则排名相同。
ACM/ICPC 赛制所有题目递交后立即评测,以是否通过为准。
ACM/ICPC 赛制排名规则为:通过题目数多的排在前面,通过题目数相同的做题耗时(含罚时)少的排在前。
时间与空间限制以题目说明为准,默认限制参见[Limitations](#Limits)。
# Accepted Ratio
通过率的影响极其恶劣,Hydro 不提供也不承认通过率。
# RP
Hydro RP 分为固定 RP 与浮动 RP ,固定 RP 可由活动、比赛等的奖励获得,浮动 RP 由一般性通过题目获得。
浮动 RP 是一个动态的数值,每个用户在每道题上获得的 RP 都不一样,并且未来也不固定(即浮动之意)。
<blockquote class="note">每道题的浮动 RP 由该题通过总人数与该用户通过此题的名次计算得来。</blockquote>
# Dataset Format
TODO
# Forgot Password and/or Username
如果您无法登录,请仔细想想,是不是用户名记错了。比如,自己原本想要注册的用户名已经被注册,所以使用了一个带有前和/或后缀的用户名。
如果您确信您的账号被盗或者忘记了账号和/或密码,请及时[{{ _('Reset Password or Find Username') }}](/lostpass)。