judge, problem_settings, problem_upload

This commit is contained in:
masnn committed 2020-04-05 09:02:35 +08:00
1 parent 5b4f5b6520
commit b3024bebb0
45 files changed
+598 -250

No files matched your search

+1 -1
View File
@@ -31,8 +31,8 @@ async function run() {
resolve();
});
});
require('./service/gridfs');
let server = require('./service/server');
require('./handler/ui');
require('./handler/base');
require('./handler/home');
+8 -13
View File
@@ -104,10 +104,17 @@ class ContestNotFoundError extends NotFoundError {
this.params = [cid];
}
}
class ProblemDataNotFoundError extends NotFoundError {
constructor(pid) {
super('Data of problem {0} not found.');
this.params = [pid];
}
}
module.exports = {
BadRequestError, ForbiddenError, NotFoundError,
LoginError, UserAlreadyExistError, InvalidTokenError,
UserNotFoundError, VerifyPasswordError,
UserNotFoundError, VerifyPasswordError, ProblemDataNotFoundError,
OpcountExceededError, PermissionError, NoProblemError,
ValidationError, ProblemNotFoundError, TrainingNotFoundError,
ContestNotFoundError, RecordNotFoundError
@@ -179,18 +186,6 @@ class DocumentNotFoundError(NotFoundError):
return 'Document {2} not found.'
class ProblemDataNotFoundError(NotFoundError):
@property
def message(self):
return 'Data of problem {1} not found.'
class RecordDataNotFoundError(NotFoundError):
@property
def message(self):
return 'Data of record {0} not found.'
class CsrfTokenError(ForbiddenError):
pass
-1
View File
@@ -59,7 +59,6 @@ MIDDLEWARE(async (ctx, next) => {
update_ip: ctx.request.ip,
update_ua: ctx.request.headers['user-agent'] || ''
}, ctx.session));
console.log(ctx.session.sid, ctx.session.uid);
let cookie = { secure: options.session.secure, httponly: true };
if (save) {
cookie.expires = ctx.session.expireAt, cookie.maxAge = expireSeconds;
+47 -2
View File
@@ -14,7 +14,7 @@ GET('/judge/fetch', requirePerm(PERM_JUDGE), async ctx => {
let rid = await queue.get('judge', false);
if (rid) {
let rdoc = await record.get(rid);
let data = {
let task = {
event: 'judge',
rid, type: 0,
pid: rdoc.pid,
@@ -22,12 +22,57 @@ GET('/judge/fetch', requirePerm(PERM_JUDGE), async ctx => {
lang: rdoc.lang,
code: rdoc.code
};
ctx.body = data;
ctx.body = { task };
}
else ctx.body = {};
});
POST('/judge/next', requirePerm(PERM_JUDGE), async ctx => {
console.log(ctx.request.body);
let body = ctx.request.body;
let rdoc = await record.get(body.rid);
let $set = {};
if (body.case) {
rdoc.testCases.push(body.case);
$set.testCases = rdoc.testCases;
}
if (body.judge_text) {
rdoc.judgeTexts.push(body.judge_text);
$set.judgeTexts = rdoc.judgeTexts;
}
if (body.compiler_text) {
rdoc.compilerTexts.push(body.compilerTexts);
$set.compilerTexts = rdoc.compilerTexts;
}
if (body.status) $set.status = body.status;
if (body.score) $set.score = body.score;
if (body.time_ms) $set.time = body.time_ms;
if (body.memory_kb) $set.memory = body.memory_kb;
await record.update(body.rid, $set);
ctx.body = {};
});
POST('/judge/end', requirePerm(PERM_JUDGE), async ctx => {
console.log(ctx.request.body);
let body = ctx.request.body;
let rdoc = await record.get(body.rid);
let $set = {};
if (body.case) {
rdoc.testCases.push(body.case);
$set.testCases = rdoc.testCases;
}
if (body.judge_text) {
rdoc.judgeTexts.push(body.judge_text);
$set.judgeTexts = rdoc.judgeTexts;
}
if (body.compiler_text) {
rdoc.compilerTexts.push(body.compilerTexts);
$set.compilerTexts = rdoc.compilerTexts;
}
if (body.status) $set.status = body.status;
if (body.score) $set.score = body.score;
if (body.time_ms) $set.time = body.time_ms;
if (body.memory_kb) $set.memory = body.memory_kb;
$set.judgeAt = new Date();
$set.judger = ctx.state.user._id;
await record.update(body.rid, $set);
ctx.body = {};
});
+73 -7
View File
@@ -1,29 +1,37 @@
const
fs = require('fs'),
bson = require('bson'),
validator = require('../lib/validator'),
problem = require('../model/problem'),
record = require('../model/record'),
user = require('../model/user'),
system = require('../model/system'),
{ GET, POST } = require('../service/server'),
gridfs = require('../service/gridfs'),
queue = require('../service/queue'),
{ requirePerm } = require('./tools'),
{ NoProblemError } = require('../error'),
{ NoProblemError, ProblemDataNotFoundError, BadRequestError } = require('../error'),
{ constants } = require('../options'),
{
PERM_VIEW_PROBLEM,
PERM_VIEW_PROBLEM_HIDDEN,
PERM_SUBMIT_PROBLEM,
PERM_CREATE_PROBLEM
PERM_CREATE_PROBLEM,
PERM_READ_PROBLEM_DATA,
PERM_EDIT_PROBLEM,
PERM_JUDGE
} = require('../permission');
queue.assert('judge');
GET('/p', requirePerm(PERM_VIEW_PROBLEM), async ctx => {
ctx.templateName = 'problem_main.html';
let q = {},
page = ctx.query.page || 1;
if (ctx.query.category) q.category = ctx.query.category;
if (!ctx.state.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
let pdocs = await problem.getMany(q, { pid: 1 }, page, constants.PROBLEM_PER_PAGE);
ctx.templateName = 'problem_main.html';
ctx.body = { page_name: 'problem_list', page, pdocs, category: '' };
ctx.body = { page, pdocs, category: '' };
});
GET('/problem/random', requirePerm(PERM_VIEW_PROBLEM), async ctx => {
let q = {};
@@ -33,33 +41,89 @@ GET('/problem/random', requirePerm(PERM_VIEW_PROBLEM), async ctx => {
ctx.body = { pid };
});
GET('/p/:pid', requirePerm(PERM_VIEW_PROBLEM), async ctx => {
ctx.templateName = 'problem_detail.html';
let uid = ctx.state.user._id,
pid = ctx.params.pid;
let pdoc = await problem.get({ pid, uid });
if (pdoc.hidden) ctx.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
let udoc = await user.getById(pdoc.owner);
ctx.templateName = 'problem_detail.html';
ctx.body = { pdoc, udoc, title: pdoc.title };
});
GET('/p/:pid/submit', requirePerm(PERM_SUBMIT_PROBLEM), async ctx => {
ctx.templateName = 'problem_submit.html';
let uid = ctx.state.user._id,
pid = ctx.params.pid;
let pdoc = await problem.get({ pid, uid });
if (pdoc.hidden) ctx.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
let udoc = await user.getById(pdoc.owner);
ctx.templateName = 'problem_submit.html';
ctx.body = { pdoc, udoc, title: pdoc.title };
});
POST('/p/:pid/submit', requirePerm(PERM_SUBMIT_PROBLEM), async ctx => {
let rid = await record.add({
uid: ctx.state.user._id,
lang: ctx.request.body.language,
lang: ctx.request.body.lang,
code: ctx.request.body.code,
pid: ctx.params.pid
});
await queue.push('judge', rid);
ctx.state.user.nSubmit++;
ctx.body = { rid };
ctx.setRedirect = `/r/${rid}`;
});
GET('/p/:pid/settings', async ctx => {
ctx.templateName = 'problem_settings.html';
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
if (pdoc.hidden) ctx.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
ctx.body = { pdoc };
});
POST('/p/:pid/settings', async ctx => {
ctx.templateName = 'problem_settings.html';
// TODO(masnn)
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
ctx.body = { pdoc };
});
GET('/p/:pid/upload', async ctx => {
ctx.templateName = 'problem_upload.html';
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
if (pdoc.owner != ctx.state.user._id) ctx.checkPerm(PERM_EDIT_PROBLEM);
let md5;
if (typeof pdoc.data == 'object') {
let files = await gridfs.find({ _id: pdoc.data }).toArray();
md5 = files[0].md5;
}
ctx.body = { pdoc, md5 };
});
POST('/p/:pid/upload', async ctx => {
ctx.templateName = 'problem_upload.html';
if (!ctx.request.files.file) throw new BadRequestError();
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
if (pdoc.owner != ctx.state.user._id) ctx.checkPerm(PERM_EDIT_PROBLEM);
const r = fs.createReadStream(ctx.request.files.file.path);
let f = gridfs.openUploadStream('data.zip');
await new Promise((resolve, reject) => {
r.pipe(f);
f.once('finish', resolve);
f.once('error', reject);
});
let md5;
if (typeof pdoc.data == 'object') {
let files = await gridfs.find({ _id: pdoc.data }).toArray();
md5 = files[0].md5;
}
pdoc = await problem.edit(ctx.params.pid, { data: f.id });
ctx.body = { pdoc, md5 };
});
GET('/p/:pid/data', async ctx => {
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
if (!ctx.state.user._id == pdoc.owner) ctx.checkPerm([PERM_READ_PROBLEM_DATA, PERM_JUDGE]);
if (!pdoc.data) throw new ProblemDataNotFoundError(ctx.params.pid);
else if (typeof pdoc.data == 'string') ctx.setRedirect = pdoc.data.split('from:')[1];
ctx.attachment(`${pdoc.title}.zip`);
ctx.body = gridfs.openDownloadStream(pdoc.data);
});
GET('/problem/create', requirePerm(PERM_CREATE_PROBLEM), async ctx => {
ctx.templateName = 'problem_edit.html';
ctx.body = { page_name: 'problem_create' };
});
POST('/problem/create', requirePerm(PERM_CREATE_PROBLEM), async ctx => {
let { title, pid, content, hidden } = ctx.request.body;
@@ -67,8 +131,10 @@ POST('/problem/create', requirePerm(PERM_CREATE_PROBLEM), async ctx => {
pid = pid || await system.incPidCounter();
await problem.add({ title, content, owner: ctx.state.user._id, pid, hidden });
ctx.body = { pid };
ctx.setRedirect = `/p/${pid}/settings`;
});
/*
@app.route('/p/category/{category:[^/]*}/random', 'problem_category_random')
+15 -4
View File
@@ -1,13 +1,16 @@
const
bson = require('bson'),
{ constants } = require('../options'),
{ GET } = require('../service/server'),
{ GET, POST } = require('../service/server'),
{ requirePerm } = require('../handler/tools'),
queue = require('../service/queue'),
record = require('../model/record'),
user = require('../model/user'),
problem = require('../model/problem'),
{ PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD } = require('../permission');
{ PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD, PERM_REJUDGE } = require('../permission');
GET('/r', async ctx => {
ctx.templateName = 'record_main.html';
let q = {},
page = ctx.query.page || 1;
let rdocs = await record.getMany(q, { rid: 1 }, page, constants.RECORD_PER_PAGE);
@@ -16,16 +19,24 @@ GET('/r', async ctx => {
udict[rdoc.uid] = await user.getById(rdoc.uid);
pdict[rdoc.pid] = await problem.get({ pid: rdoc.pid, uid: ctx.state.user._id });
}
ctx.templateName = 'record_main.html';
ctx.body = { page, rdocs, pdict, udict };
});
GET('/r/:rid', async ctx => {
ctx.templateName = 'record_detail.html';
let uid = ctx.state.user._id, rid = new bson.ObjectID(ctx.params.rid);
let rdoc = await record.get(rid);
if (rdoc.hidden) ctx.checkPerm(PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
if (rdoc.uid != uid && !ctx.state.user.hasPerm(PERM_READ_RECORD_CODE)) rdoc.code = null;
ctx.body = { rdoc, show_status: true };
});
POST('/r/:rid/rejudge', requirePerm(PERM_REJUDGE), async ctx => {
ctx.templateName = 'record_detail.html';
ctx.body = { rdoc };
let uid = ctx.state.user._id, rid = new bson.ObjectID(ctx.params.rid);
let rdoc = await record.get(rid);
if (rdoc.hidden) ctx.checkPerm(PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
if (rdoc.uid != uid && !ctx.state.user.hasPerm(PERM_READ_RECORD_CODE)) rdoc.code = null;
if (rdoc) await queue.push('judge', rid);
ctx.body = { rdoc, show_status: true };
});
/*
+34 -13
View File
@@ -1,6 +1,5 @@
const
path = require('path'),
md5 = require('blueimp-md5'),
static = require('koa-static'),
nunjucks = require('nunjucks'),
hljs = require('hljs'),
@@ -9,14 +8,9 @@ const
options = require('../options'),
perm = require('../permission'),
builtin = require('../model/builtin'),
md5 = require('../lib/md5'),
{ MIDDLEWARE } = require('../service/server'),
{ NotFoundError } = require('../error'),
MD5_REGEX = /^[0-9a-f]{32}$/;
function getHash(email) {
email = (typeof email === 'string') ? email.trim().toLowerCase() : 'unspecified';
return email.match(MD5_REGEX) ? email : md5(email);
}
{ NotFoundError } = require('../error');
class Markdown extends MarkdownIt {
constructor() {
@@ -35,6 +29,14 @@ class Markdown extends MarkdownIt {
}
}
const md = new Markdown();
function datetime_span(dt, { relative = true } = {}) {
dt = new Date(dt);
return '<span class="time{0}" data-timestamp="{1}">{2}</span>'.format(
relative ? ' relative' : '',
dt.getTime(),
dt.toLocaleString()
);
}
class Nunjucks extends nunjucks.Environment {
constructor() {
super(
@@ -51,12 +53,26 @@ class Nunjucks extends nunjucks.Environment {
return md.render(self);
});
this.addFilter('gravatar_url', function (email, size) {
return `//gravatar.loli.net/avatar/${getHash(email)}?d=mm&s=${size}`;
return `//gravatar.loli.net/avatar/${md5(email.toString().trim().toLowerCase())}?d=mm&s=${size}`;
});
this.addFilter('format_size', function (size, base = 1) {
size *= base;
let unit = 1024;
let unit_names = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
for (let unit_name of unit_names) {
if (size < unit) return '{0} {1}'.format(Math.round(size), unit_name);
size /= unit;
}
return '{0} {1}'.format(Math.round(size * unit), unit_names[unit_names.length - 1]);
});
this.addGlobal('typeof', o => typeof o);
this.addGlobal('console', console);
this.addGlobal('static_url', str => `/${str}`);
this.addGlobal('reverse_url', str => str);
this.addGlobal('datetime_span', datetime_span);
this.addGlobal('perm', perm);
this.addGlobal('builtin', builtin);
this.addGlobal('status', builtin.STATUS);
}
}
const env = new Nunjucks();
@@ -67,6 +83,7 @@ MIDDLEWARE(async (ctx, next) => {
cdn_prefix: '/',
url_prefix: '/'
};
ctx.preferJson = ctx.request.headers['accept'].includes('application/json');
ctx.render = async (name, context) => {
ctx.user = ctx.state.user;
ctx.translate = str => {
@@ -77,7 +94,8 @@ MIDDLEWARE(async (ctx, next) => {
ctx.body = await new Promise((resolve, reject) => {
env.render(name, Object.assign(ctx.state, context, {
handler: ctx,
_: ctx.translate
_: ctx.translate,
user: ctx.state.user
}), (error, res) => {
if (error) reject(error);
else resolve(res);
@@ -89,6 +107,7 @@ MIDDLEWARE(async (ctx, next) => {
try {
await next();
if (ctx.body || ctx.templateName) {
if (ctx.preferJson) return;
if (ctx.query.template || ctx.templateName) {
ctx.body = ctx.body || {};
Object.assign(ctx.body, JSON.parse(ctx.query.data || '{}'));
@@ -99,11 +118,13 @@ MIDDLEWARE(async (ctx, next) => {
}
} else throw new NotFoundError();
} catch (error) {
console.log(error);
if (error.toString().startsWith('NotFoundError')) console.log(error);
if (error.toString().startsWith('Template render error')) throw error;
await ctx.render('error.html', { error });
if (ctx.preferJson) ctx.body = { error };
else await ctx.render('error.html', { error });
}
} catch (error) {
await ctx.render('bsod.html', { error });
if (ctx.preferJson) ctx.body = { error };
else await ctx.render('bsod.html', { error });
}
});
+133
View File
@@ -0,0 +1,133 @@
'use strict';
function safeAdd(x, y) {
var lsw = (x & 0xffff) + (y & 0xffff);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xffff);
}
const bitRotateLeft = (num, cnt) => (num << cnt) | (num >>> (32 - cnt));
const md5cmn = (q, a, b, x, s, t) => safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
const md5ff = (a, b, c, d, x, s, t) => md5cmn((b & c) | (~b & d), a, b, x, s, t);
const md5gg = (a, b, c, d, x, s, t) => md5cmn((b & d) | (c & ~d), a, b, x, s, t);
const md5hh = (a, b, c, d, x, s, t) => md5cmn(b ^ c ^ d, a, b, x, s, t);
const md5ii = (a, b, c, d, x, s, t) => md5cmn(c ^ (b | ~d), a, b, x, s, t);
function binlMD5(x, len) {
x[len >> 5] |= 0x80 << len % 32;
x[(((len + 64) >>> 9) << 4) + 14] = len;
var i;
var olda;
var oldb;
var oldc;
var oldd;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for (i = 0; i < x.length; i += 16) {
olda = a;
oldb = b;
oldc = c;
oldd = d;
a = md5ff(a, b, c, d, x[i], 7, -680876936);
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5gg(b, c, d, a, x[i], 20, -373897302);
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5hh(d, a, b, c, x[i], 11, -358537222);
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5ii(a, b, c, d, x[i], 6, -198630844);
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safeAdd(a, olda);
b = safeAdd(b, oldb);
c = safeAdd(c, oldc);
d = safeAdd(d, oldd);
}
return [a, b, c, d];
}
function binl2rstr(input) {
var i;
var output = '';
var length32 = input.length * 32;
for (i = 0; i < length32; i += 8)
output += String.fromCharCode((input[i >> 5] >>> i % 32) & 0xff);
return output;
}
function rstr2binl(input) {
var i;
var output = [];
output[(input.length >> 2) - 1] = undefined;
for (i = 0; i < output.length; i += 1)
output[i] = 0;
var length8 = input.length * 8;
for (i = 0; i < length8; i += 8)
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32;
return output;
}
const rstrMD5 = s => binl2rstr(binlMD5(rstr2binl(s), s.length * 8));
function rstr2hex(input) {
var hexTab = '0123456789abcdef';
var output = '';
var x;
var i;
for (i = 0; i < input.length; i += 1) {
x = input.charCodeAt(i);
output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f);
}
return output;
}
module.exports = s => rstr2hex(rstrMD5(unescape(encodeURIComponent(s))));
+55 -4
View File
@@ -177,9 +177,9 @@ const FOOTER_EXTRA_HTMLS = [];
const VIEW_LANGS = [
{ code: 'zh-CN', name: 'zh-CN' }
];
const LANGS = [
{ id: 'cc', name: 'cpp' }
];
const LANGS = {
cc: 'cpp'
};
const LANG_TEXTS = {
c: 'C',
cc: 'C++',
@@ -210,7 +210,58 @@ const LANG_HIGHLIGHT_ID = {
go: 'go',
rb: 'ruby',
};
const STATUS = {
STATUS_WAITING: 0,
STATUS_ACCEPTED: 1,
STATUS_WRONG_ANSWER: 2,
STATUS_TIME_LIMIT_EXCEEDED: 3,
STATUS_MEMORY_LIMIT_EXCEEDED: 4,
STATUS_OUTPUT_LIMIT_EXCEEDED: 5,
STATUS_RUNTIME_ERROR: 6,
STATUS_COMPILE_ERROR: 7,
STATUS_SYSTEM_ERROR: 8,
STATUS_CANCELED: 9,
STATUS_ETC: 10,
STATUS_JUDGING: 20,
STATUS_COMPILING: 21,
STATUS_FETCHED: 22,
STATUS_IGNORED: 30
};
const STATUS_TEXTS = {
[STATUS.STATUS_WAITING]: 'Waiting',
[STATUS.STATUS_ACCEPTED]: 'Accepted',
[STATUS.STATUS_WRONG_ANSWER]: 'Wrong Answer',
[STATUS.STATUS_TIME_LIMIT_EXCEEDED]: 'Time Exceeded',
[STATUS.STATUS_MEMORY_LIMIT_EXCEEDED]: 'Memory Exceeded',
[STATUS.STATUS_OUTPUT_LIMIT_EXCEEDED]: 'Output Exceeded',
[STATUS.STATUS_RUNTIME_ERROR]: 'Runtime Error',
[STATUS.STATUS_COMPILE_ERROR]: 'Compile Error',
[STATUS.STATUS_SYSTEM_ERROR]: 'System Error',
[STATUS.STATUS_CANCELED]: 'Cancelled',
[STATUS.STATUS_ETC]: 'Unknown Error',
[STATUS.STATUS_JUDGING]: 'Running',
[STATUS.STATUS_COMPILING]: 'Compiling',
[STATUS.STATUS_FETCHED]: 'Fetched',
[STATUS.STATUS_IGNORED]: 'Ignored',
};
const STATUS_CODES = {
0: 'pending',
1: 'pass',
2: 'fail',
3: 'fail',
4: 'fail',
5: 'fail',
6: 'fail',
7: 'fail',
8: 'fail',
9: 'ignored',
10: 'fail',
20: 'progress',
21: 'progress',
22: 'progress',
30: 'ignored'
};
module.exports = {
BUILTIN_USERS, BUILTIN_ROLES, CATEGORIES, VIEW_LANGS, FOOTER_EXTRA_HTMLS, LANGS,
LANG_TEXTS, LANG_HIGHLIGHT_ID
LANG_TEXTS, LANG_HIGHLIGHT_ID, STATUS, STATUS_TEXTS, STATUS_CODES
};
+7 -4
View File
@@ -1,7 +1,8 @@
const
_ = require('lodash'),
{ ObjectID } = require('bson'),
{ RecordNotFoundError } = require('../error'),
{ STATUS_WAITING } = require('../status'),
{ STATUS_WAITING } = require('../model/builtin').STATUS,
db = require('../service/db.js'),
coll = db.collection('record');
@@ -29,7 +30,8 @@ async function add(data) {
* @returns {import('../interface').Record}
*/
async function get(rid) {
let rdoc = await coll.findOne({ _id: rid });
let _id = new ObjectID(rid);
let rdoc = await coll.findOne({ _id });
if (!rdoc) throw new RecordNotFoundError(rid);
return rdoc;
}
@@ -37,8 +39,9 @@ async function getMany(query, sort, page, limit) {
return await coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit).toArray();
}
async function update(rid, $set) {
await coll.findOneAndUpdate({ _id: rid }, { $set });
let rdoc = await coll.findOne({ _id: rid });
let _id = new ObjectID(rid);
await coll.findOneAndUpdate({ _id }, { $set });
let rdoc = await coll.findOne({ _id });
if (!rdoc) throw new RecordNotFoundError(rid);
return rdoc;
}
-1
View File
@@ -16,7 +16,6 @@ class USER {
this.perm = user.perm;
}
hasPerm(perm) {
console.log('PERM', perm, this.perm);
return this.perm == '-' || (this.perm || '').includes(perm);
}
checkPassword(password) {
+1 -1
View File
@@ -9,7 +9,7 @@ module.exports = {
naccept[j.pid]++;
}
function _time(jdoc) {
let real = jdoc.rid.generation_time - Math.floor(tdoc.begin_at / 1000);
let real = jdoc.rid.generationTime - Math.floor(tdoc.begin_at / 1000);
let penalty = 20 * 60 * naccept[jdoc.pid];
return real + penalty;
}
+1 -1
View File
@@ -12,7 +12,7 @@ module.exports = {
effective[j.pid] = j;
const _time = jdoc => jdoc.rid.generationTime - Math.floor(tdoc.begin_at / 1000);
function _penalty_score(jdoc) {
let exceed_seconds = jdoc.rid.generation_time - Math.floor(tdoc.penalty_since / 1000);
let exceed_seconds = jdoc.rid.generationTime - Math.floor(tdoc.penalty_since / 1000);
if (exceed_seconds < 0) return jdoc.score;
else return 0.5 * jdoc.score;
}
+1
View File
@@ -41,6 +41,7 @@ let permissions = {
PERM_VIEW_TRAINING: 'a',
PERM_CREATE_TRAINING: 'b',
PERM_EDIT_TRAINING: 'c',
PERM_JUDGE: 'd'
};
permissions.PERM_BASIC =
permissions.PERM_VIEW +
+1
View File
@@ -10,6 +10,7 @@ let db = null;
Mongo.MongoClient.connect(mongourl, { useNewUrlParser: true, useUnifiedTopology: true })
.then(Database => {
db = Database.db(options.db.name);
db.Db = Database;
global.bus.emit('connected');
});
+5
View File
@@ -0,0 +1,5 @@
const
{ GridFSBucket } = require('mongodb'),
db = require('./db');
if (!db.s) db.s = {};
module.exports = new GridFSBucket(db);
+6 -1
View File
@@ -12,7 +12,12 @@ let app = new Koa();
let server = http.createServer(app.callback());
app.keys = options.session.keys;
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
app.use(Body());
app.use(Body({
multipart: true,
formidable: {
maxFileSize: 256 * 1024 * 1024
}
}));
let router = new Router();
/**
-32
View File
@@ -1,32 +0,0 @@
exports.STATUS_WAITING = 0;
exports.STATUS_ACCEPTED = 1;
exports.STATUS_WRONG_ANSWER = 2;
exports.STATUS_TIME_LIMIT_EXCEEDED = 3;
exports.STATUS_MEMORY_LIMIT_EXCEEDED = 4;
exports.STATUS_OUTPUT_LIMIT_EXCEEDED = 5;
exports.STATUS_RUNTIME_ERROR = 6;
exports.STATUS_COMPILE_ERROR = 7;
exports.STATUS_SYSTEM_ERROR = 8;
exports.STATUS_CANCELED = 9;
exports.STATUS_ETC = 10;
exports.STATUS_JUDGING = 20;
exports.STATUS_COMPILING = 21;
exports.STATUS_FETCHED = 22;
exports.STATUS_IGNORED = 30;
exports.STATUS_TEXTS = {
[exports.STATUS_WAITING]: 'Waiting',
[exports.STATUS_ACCEPTED]: 'Accepted',
[exports.STATUS_WRONG_ANSWER]: 'Wrong Answer',
[exports.STATUS_TIME_LIMIT_EXCEEDED]: 'Time Exceeded',
[exports.STATUS_MEMORY_LIMIT_EXCEEDED]: 'Memory Exceeded',
[exports.STATUS_OUTPUT_LIMIT_EXCEEDED]: 'Output Exceeded',
[exports.STATUS_RUNTIME_ERROR]: 'Runtime Error',
[exports.STATUS_COMPILE_ERROR]: 'Compile Error',
[exports.STATUS_SYSTEM_ERROR]: 'System Error',
[exports.STATUS_CANCELED]: 'Cancelled',
[exports.STATUS_ETC]: 'Unknown Error',
[exports.STATUS_JUDGING]: 'Running',
[exports.STATUS_COMPILING]: 'Compiling',
[exports.STATUS_FETCHED]: 'Fetched',
[exports.STATUS_IGNORED]: 'Ignored',
};
+1 -2
View File
@@ -7,7 +7,6 @@
"license": "MIT",
"dependencies": {
"axios": "^0.19.0",
"blueimp-md5": "^2.13.0",
"bson": "^4.0.2",
"hljs": "^6.2.3",
"js-yaml": "^3.13.1",
@@ -19,7 +18,7 @@
"lodash": "^4.17.15",
"markdown-it": "^10.0.0",
"markdown-it-katex": "^2.0.3",
"mongodb": "^3.3.4",
"mongodb": "^3.5.5",
"nodemailer": "^6.3.1",
"nunjucks": "^3.2.1",
"sockjs": "^0.3.20"
@@ -10,7 +10,7 @@
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
{{ user.render_inline(udoc, dudict[udoc['_id']], avatar=false) }}
@ {{ datetime_span(rdoc['_id'].generation_time) }}
@ {{ datetime_span(rdoc['_id'].generationTime) }}
</div>
{{ comment_base.reply_operations(doc, rdoc) }}
</div>
@@ -37,7 +37,7 @@
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
{{ user.render_inline(udoc, dudict[udoc['_id']], avatar=false) }}
@ {{ datetime_span(doc['_id'].generation_time) }}
@ {{ datetime_span(doc['_id'].generationTime) }}
</div>
{{ comment_base.comment_operations(doc) }}
</div>
+2 -2
View File
@@ -7,7 +7,7 @@
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
{{ user.render_inline(udoc, badge=false) }}
@ {{ datetime_span(rdoc['_id'].generation_time) }}
@ {{ datetime_span(rdoc['_id'].generationTime) }}
</div>
{{ comment_base.reply_operations(doc, rdoc) }}
</div>
@@ -65,7 +65,7 @@
<div class="clearfix">
<div class="supplementary dczcomments__supplementary">
{{ user.render_inline(udoc, dudict[udoc['_id']]) }}
@ {{ datetime_span(doc['_id'].generation_time) }}
@ {{ datetime_span(doc['_id'].generationTime) }}
</div>
{{ comment_base.comment_operations(doc) }}
</div>
+37 -37
View File
@@ -71,19 +71,19 @@
name="{{ args.name }}"
{{ form_attr('select', args) }}
>
{% for item in args.options %}
<option value="{{ item.id }}"{% if value == item.id %} selected{% endif %}>
{{ _(item.name) }}
{% for k, v in args.options %}
<option value="{{ k }}"{% if value == k %} selected{% endif %}>
{{ _(v) }}
</option>
{% endfor %}
</select>
</div>
{% endmacro %}
{% macro form_select(columns=5, args) %}
{{ form_begin({columns:columns}|assign(args)) }}
{{ select({columns:columns}|assign(args)) }}
{{ form_end({columns:columns}|assign(args)) }}
{% macro form_select(args) %}
{{ form_begin({columns:5}|assign(args)) }}
{{ select(args) }}
{{ form_end(args) }}
{% endmacro %}
{% macro radio(args) %}
@@ -91,24 +91,24 @@
name="form_item_{{ args.name }}"
{{ container_attr('radiobox-container', args) }}
>
{% for item in options %}
{% for k, v in options %}
<label class="radiobox">
<input
value="{{ item.id }}"
value="{{ k }}"
type="radio"
name="{{ args.name }}"
name="{{ v }}"
{{ form_attr('radiobox__input', args) }}
{% if value == args.id %} checked{% endif %}
/> {{ _(item.name) }}
/> {{ _(v) }}
</label>
{% endfor %}
</div>
{% endmacro %}
{% macro form_radio(columns=5, args) %}
{{ form_begin({columns:columns, label_wrap:false}|assign(args)) }}
{{ radio({columns:columns}|assign(args)) }}
{{ form_end({columns:columns, label_warp:false}|assign(args)) }}
{% macro form_radio(args) %}
{{ form_begin({columns:5, label_wrap:false}|assign(args)) }}
{{ radio(args) }}
{{ form_end({label_warp:false}|assign(args)) }}
{% endmacro %}
{% macro image_radio(args) %}
@@ -116,27 +116,27 @@
name="form_item_{{ args.name }}"
{{ container_attr('radiobox-container with-image', args) }}
>
{% for item in options %}
{% for k, v in options %}
<label class="radiobox with-image">
<input
value="{{ item.id }}"
value="{{ k }}"
type="radio"
name="{{ name }}"
name="{{ args.name }}"
{{ form_attr('radiobox__input', args) }}
{% if value == item.id %} checked{% endif %}
{% if value == k %} checked{% endif %}
/>
<div class="radiobox__image-container" data-tooltip="{{ _(item.name) }}">
<div class="radiobox__image {{ image_class.format(item.id) }}"></div>
<div class="radiobox__image-container" data-tooltip="{{ _(v) }}">
<div class="radiobox__image {{ image_class.format(k) }}"></div>
</div>
</label>
{% endfor %}
</div>
{% endmacro %}
{% macro form_image_radio(columns=8, args) %}
{{ form_begin({columns:columns, label_warp:false}|assign(args)) }}
{{ image_radio({columns:columns}|assign(args)) }}
{{ form_end({columns:columns, label_warp:false}|assign(args)) }}
{% macro form_image_radio(args) %}
{{ form_begin({columns:8, label_warp:false}|assign(args)) }}
{{ image_radio(args) }}
{{ form_end({label_warp:false}|assign(args)) }}
{% endmacro %}
{% macro text(args) %}
@@ -154,10 +154,10 @@
</div>
{% endmacro %}
{% macro form_text(columns=5, args) %}
{{ form_begin({columns:columns}|assign(args)) }}
{{ text({columns:columns}|assign(args)) }}
{{ form_end({columns:columns}|assign(args)) }}
{% macro form_text(args) %}
{{ form_begin({columns:5}|assign(args)) }}
{{ text(args) }}
{{ form_end(args) }}
{% endmacro %}
{% macro textarea(args) %}
@@ -175,10 +175,10 @@
</div>
{% endmacro %}
{% macro form_textarea(columns=8) %}
{{ form_begin({columns:columns}|assign(args)) }}
{{ textarea({columns:columns}|assign(args)) }}
{{ form_end({columns:columns}|assign(args)) }}
{% macro form_textarea(args) %}
{{ form_begin({columns:8}|assign(args)) }}
{{ textarea(args) }}
{{ form_end(args) }}
{% endmacro %}
{% macro checkbox(args) %}
@@ -194,8 +194,8 @@
</div>
{% endmacro %}
{% macro form_checkbox(columns=5, args) %}
{{ form_begin({columns:columns, no_label:true}|assign(args)) }}
{{ checkbox({columns:columns}|assign(args)) }}
{{ form_end({columns:columns, no_label:true}|assign(args)) }}
{% macro form_checkbox(args) %}
{{ form_begin({columns:5, no_label:true}|assign(args)) }}
{{ checkbox(args) }}
{{ form_end({no_label:true}|assign(args)) }}
{% endmacro %}
+3 -3
View File
@@ -1,8 +1,8 @@
{% macro render_status_td(rdoc, rid_key='_id') %}
<td class="col--status record-status--border {{ status.STATUS_CODES[rdoc['status']] }}">
<td class="col--status record-status--border {{ builtin.STATUS_CODES[rdoc['status']] }}">
<div class="col--status__text">
<span class="icon record-status--icon {{ status.STATUS_CODES[rdoc['status']] }}"></span>
<a href="{{ reverse_url('record_detail', rid=rdoc[rid_key], domain_id=rdoc['domain_id']) }}" class="record-status--text {{ status.STATUS_CODES[rdoc['status']] }}">
<span class="icon record-status--icon {{ builtin.STATUS_CODES[rdoc['status']] }}"></span>
<a href="/r/{{ rdoc._id }}" class="record-status--text {{ builtin.STATUS_CODES[rdoc['status']] }}">
{{ status.STATUS_TEXTS[rdoc['status']] }}
</a>
</div>
+2 -2
View File
@@ -48,9 +48,9 @@
{% if handler.can_show_record(tdoc) %}
{{ record.render_status_td(rdoc) }}
{% else %}
<td class="col--status record-status--border"><a href="{{ reverse_url('record_detail', rid=rdoc['_id'], domain_id=handler.domain_id) }}">{{ _('Submitted') }}</a></td>
<td class="col--status record-status--border"><a href="/r/{{ rdoc._id }}">{{ _('Submitted') }}</a></td>
{% endif %}
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generation_time) }}</td>
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generationTime) }}</td>
{% endwith %}
{% else %}
<td class="col--status record-status--border">{{ _('No Submissions') }}</td>
+1 -1
View File
@@ -21,7 +21,7 @@
<li>
{{ user.render_inline(udict[ddoc['owner_uid']], dudict[ddoc['owner_uid']]) }}
@
{{ datetime_span(ddoc['_id'].generation_time) }}
{{ datetime_span(ddoc['_id'].generationTime) }}
</li>
</ul>
<div class="typo topic__content" data-emoji-enabled data-raw-url="{{ reverse_url('discussion_detail_raw', did=ddoc['_id']) }}">
+1 -1
View File
@@ -7,7 +7,7 @@
{% if handler.has_priv(vj4.model.builtin.PRIV_CREATE_DOMAIN) %}
<a class="primary rounded button" href="{{ reverse_url('home_domain_create') }}"><span class="icon icon-add"></span> {{ _('Create Domain') }}</a>
{% endif %}
<a class="tool-button" href="{{ reverse_url('wiki_help') }}#domain"><span class="icon icon-help"></span> {{ _('What\'s domain?') }}</a>
<a class="tool-button" href="/wiki/help#domain"><span class="icon icon-help"></span> {{ _('What\'s domain?') }}</a>
</div>
</div>
{% if pending_ddocs|length > 0 %}
+1 -1
View File
@@ -7,7 +7,7 @@
{% if handler.has_priv(vj4.model.builtin.PRIV_CREATE_FILE) %}
<a class="primary rounded button" href="{{ reverse_url('fs_upload') }}" target="_blank"><span class="icon icon-add"></span> {{ _('Upload File') }}</a>
{% endif %}
<a class="tool-button" href="{{ reverse_url('wiki_help') }}#file"><span class="icon icon-help"></span> {{ _('What\'s file?') }}</a>
<a class="tool-button" href="/wiki/help#file"><span class="icon icon-help"></span> {{ _('What\'s file?') }}</a>
</div>
</div>
<div class="section__body no-padding">
+2 -2
View File
@@ -47,9 +47,9 @@
{% if handler.can_show_record(tdoc) %}
{{ record.render_status_td(rdoc) }}
{% else %}
<td class="col--status record-status--border"><a href="{{ reverse_url('record_detail', rid=rdoc['_id'], domain_id=handler.domain_id) }}">{{ _('Submitted') }}</a></td>
<td class="col--status record-status--border"><a href="/r/{{ rdoc._id }}">{{ _('Submitted') }}</a></td>
{% endif %}
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generation_time) }}</td>
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generationTime) }}</td>
{% endwith %}
{% else %}
<td class="col--status record-status--border">{{ _('No Submissions') }}</td>
+1 -1
View File
@@ -81,7 +81,7 @@
<li class="menu__item"><a class="menu__link" href="/r?tid={{ tdoc['doc_id'] }}">
<span class="icon icon-flag"></span> {{ _('All Submissions') }}
</a></li>
<li class="menu__item"><a class="menu__link" href="{{ reverse_url('wiki_help') }}#contest">
<li class="menu__item"><a class="menu__link" href="/wiki/help#contest">
<span class="icon icon-help"></span> {{ _('Help') }}
</a></li>
<li class="menu__seperator"></li>
+1 -1
View File
@@ -32,7 +32,7 @@
<li>
{{ user.render_inline(udict[ddoc['owner_uid']], dudoc=dudoc if dudoc else dudict[ddoc['owner_uid']], badge=false) }}
@
{{ datetime_span(ddoc['update_at'] or ddoc['_id'].generation_time) }}
{{ datetime_span(ddoc['update_at'] or ddoc['_id'].generationTime) }}
</li>
</ul>
</div>
+1 -1
View File
@@ -67,7 +67,7 @@
<span class="icon icon-flag"></span> {{ _('My Recent Submissions') }}
</a></li>
{% endif %}
<li class="menu__item"><a class="menu__link" href="{{ reverse_url('wiki_help') }}#homework">
<li class="menu__item"><a class="menu__link" href="/wiki/help#homework">
<span class="icon icon-help"></span> {{ _('Help') }}
</a></li>
<li class="menu__seperator"></li>
+8 -6
View File
@@ -1,8 +1,10 @@
<div data-fragment-id="problem_lucky">
<p>
<a href="{% if not category %}{{ reverse_url('problem_random') }}{% else %}{{ reverse_url('problem_category_random', category=category) }}{% endif %}" class="expanded button" target="_blank"><span class="icon icon-feeling-lucky"></span> {{ _('Lucky') }}</a>
</p>
<div class="typo supplementary">
<p>{{ _('Pick a problem randomly based on current filter') }}</p>
</div>
<p>
<a href="/problem/random{% if category %}?category={{ category }}{% endif %}" class="expanded button" target="_blank">
<span class="icon icon-feeling-lucky"></span> {{ _('Lucky') }}
</a>
</p>
<div class="typo supplementary">
<p>{{ _('Pick a problem randomly based on current filter') }}</p>
</div>
</div>
@@ -70,7 +70,7 @@
<span class="icon icon-copy"></span> {{ _('Copy Problem') }}
</a></li>
{% endif %}
{% if handler.user._id == pdoc.owner or handler.has_perm(perm.PERM_EDIT_PROBLEM) %}
{% if user._id == pdoc.owner or handler.has_perm(perm.PERM_EDIT_PROBLEM) %}
<li class="menu__seperator"></li>
<li class="menu__item"><a class="menu__link{% if page_name == 'problem_edit' %} active{% endif %}" href="/p/{{ pdoc.pid }}/edit">
<span class="icon icon-edit"></span> {{ _('Edit') }}
@@ -98,8 +98,8 @@
<dt>{{ _('Submission') }}</dt>
<dd>
{% if pdoc['psdoc']['status'] %}
<span class="icon record-status--icon {{ status.STATUS_CODES[pdoc['psdoc']['status']] }}"></span>
<a href="/r/{{ pdoc['psdoc']['rid'] }}" class="record-status--text {{ status.STATUS_CODES[pdoc['psdoc']['status']] }}">
<span class="icon record-status--icon {{ builtin.STATUS_CODES[pdoc['psdoc']['status']] }}"></span>
<a href="/r/{{ pdoc['psdoc']['rid'] }}" class="record-status--text {{ builtin.STATUS_CODES[pdoc['psdoc']['status']] }}">
{{ status.STATUS_TEXTS[pdoc['psdoc']['status']] }}
</a>
{% else %}
+1 -1
View File
@@ -23,7 +23,7 @@
<blockquote class="warn">
<p>{{ _('No dataset at present.') }}</p>
</blockquote>
{% elif pdoc.data.startsWith('from:') %}
{% elif typeof(pdoc.data) == 'string' %}
<blockquote class="note">
<p>{{ _('Test data comes from') }} <a href="#" target="_blank">{{ pdoc.data.split(':')[1] }}</a></p>
</blockquote>
+5 -11
View File
@@ -6,19 +6,18 @@
<div class="section__body">
<form method="post">
<div class="row">
<div class="medium-8 columns">
<div class="medium-7 columns">
<label>
{{ _('Title') }}
<input name="title" placeholder="{{ _('title') }}" value="{{ pdoc['title']|default('') }}" class="textbox" autofocus>
</label>
</div>
{% if page_name == 'problem_create' %}
<div class="medium-2 columns">
<div class="medium-3 columns">
<label>
{{ _('Settings') }}
{{ _('pid') }}
<br>
<label class="checkbox">
<input type="checkbox" name="numeric_pid" value="on" checked>{{ _('Numeric PID') }}
<label>
<input name="pid" placeholder="{{ _('Leave blank to use numeric pid.') }}" value="{{ pdoc['pid']|default('') }}" class="textbox">
</label>
</label>
</div>
@@ -30,7 +29,6 @@
</label>
</label>
</div>
{% endif %}
</div>
<div class="row"><div class="columns">
<label>
@@ -49,9 +47,6 @@
{{ _('Create') }}
</button>
{% endif %}
<button type="button" class="rounded button" onclick="window.history.go(-1)">
{{ _('Cancel') }}
</button>
</div></div>
</form>
</div>
@@ -61,7 +56,6 @@
{% if page_name == 'problem_edit' %}
{% set owner_udoc=udoc %}{% set owner_dudoc=dudoc %}
{% include "partials/problem_sidebar.html" %}
{% endwith %}
{% else %}
{% include 'components/md_hint.html' %}
{% endif %}
+16 -17
View File
@@ -1,3 +1,4 @@
{% set page_name = "problem_main" %}
{% import "components/record.html" as record with context %}
{% import "components/problem.html" as problem with context %}
{% extends "layout/basic.html" %}
@@ -24,23 +25,21 @@
</div>
<div class="section__body">
<ul class="group-list" data-widget-cf-container>
{% for category in builtin.CATEGORIES %}
{% for sub_categories in category %}
<li class="group-list__item">
<h2 class="section__title">
<a href="/p?category={{ category|urlencode }}">{{ category }}</a>
</h2>
{% if sub_categories | length > 0 %}
<ol class="chip-list">
{% for sub_category in sub_categories %}
<li class="chip-list__item">
<a class="typo-a" href="/p?category={{ category|urlencode + ',' + sub_category|urlencode }}">{{ sub_category }}</a>
</li>
{% endfor %}
</ol>
{% endif %}
</li>
{% endfor %}
{% for category, sub_categories in builtin.CATEGORIES %}
<li class="group-list__item">
<h2 class="section__title">
<a href="/p?category={{ category|urlencode }}">{{ category }}</a>
</h2>
{% if sub_categories | length > 0 %}
<ol class="chip-list">
{% for sub_category in sub_categories %}
<li class="chip-list__item">
<a class="typo-a" href="/p?category={{ category|urlencode + ',' + sub_category|urlencode }}">{{ sub_category }}</a>
</li>
{% endfor %}
</ol>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
+25 -22
View File
@@ -1,3 +1,4 @@
{% set page_name = "problem_settings" %}
{% extends "layout/basic.html" %}
{% block content %}
<div class="row">
@@ -7,9 +8,9 @@
<h1 class="section__title">{{ _('Dataset') }}</h1>
</div>
<div class="section__body">
<iframe src="{{ reverse_url('problem_upload', pid=pdoc['_id']) }}" frameborder="0" style="width: 100%; height: 100px;"></iframe>
<p class="help-text">{{ _('Hint') }}: <a href="{{ reverse_url('wiki_help') }}#upload">{{ _('Dataset Format') }}</a>, {{ _('An example of dataset') }}: <a href="https://github.com/vijos/jd4/blob/master/jd4/testdata/aplusb-legacy.zip?raw=true">{{ _('Download') }}</a></p>
{% if pdoc and (handler.own(pdoc, perm.PERM_READ_PROBLEM_DATA_SELF) or handler.has_perm(perm.PERM_READ_PROBLEM_DATA) or handler.has_priv(vj4.model.builtin.PRIV_READ_PROBLEM_DATA)) %}
<iframe src="/p/{{ pdoc.pid }}/upload" frameborder="0" style="width: 100%; height: 100px;"></iframe>
<p class="help-text">{{ _('Hint') }}: <a href="/wiki/help#upload">{{ _('Dataset Format') }}</a>, {{ _('An example of dataset') }}: <a href="https://github.com/vijos/jd4/blob/master/jd4/testdata/aplusb-legacy.zip?raw=true">{{ _('Download') }}</a></p>
{% if pdoc and (pdoc.owner == user._id or handler.has_perm(perm.PERM_READ_PROBLEM_DATA)) %}
<p><a href="/p/{{ pdoc.pid }}/data" class="expanded button">{{ _('Download Dataset') }}</a></p>
{% endif %}
</div>
@@ -20,27 +21,31 @@
</div>
<div class="section__body">
<form method="post">
{{ form.form_checkbox(label='Hidden', help_text='Note: Problem title may not be hidden.', name='hidden', value=pdoc['hidden']) }}
{{ form.form_text(columns=12, label='Category', help_text='Format: category 1, sub category 1.1, sub category 1.2, ..., sub category 1.x, ..., category n, sub category n.1, sub category n.2, ..., sub category n.m, ...', name='category', value=pdoc['category']|join(', ')) }}
{{ form.form_text(columns=12, label='Tags', help_text='Splitted by \', \'.', name='tag', value=pdoc['tag']|join(', ')) }}
{{ form.form_text(columns=12, label='AC Message', help_text='This message will be presented to those whose submissions are accepted.', name='ac_msg', value=(pdoc['ac_msg'] or '' )) }}
<div class="row">
{{ form.form_select(columns=4, label='Difficulty', name='difficulty_setting', options=vj4.model.adaptor.problem.SETTING_DIFFICULTY_RANGE.items(), value=pdoc['difficulty_setting']|default(0), row=false) }}
{{ form.form_text(columns=4, label='Evaluated difficulty', help_text='Effects only when Difficulty is not \'Use algorithm calculated\'.', name='difficulty_admin', placeholder='9', value=pdoc['difficulty_admin'] or '', row=False) }}
<div class="medium-4 columns">
<p class="help-text">{{ _('Difficulty displayed') }}: {{ pdoc['difficulty'] or _('(None)') }}</p>
<p class="help-text">{{ _('Difficulty by algorithm') }}: {{ pdoc['difficulty_algo'] or _('(None)') }}</p>
<p class="help-text">{{ _('Difficulty by admin') }}: {{ pdoc['difficulty_admin'] or _('(None)') }}</p>
</div>
</div>
{{ form.form_checkbox({
label:'Hidden',
help_text:'Note: Problem title may not be hidden.',
name:'hidden',
value:pdoc['hidden']
}) }}
{{ form.form_text({
columns:12,
label:'Category',
help_text:'Format: category 1, sub category 1.1, sub category 1.2, ..., sub category 1.x, ..., category n, sub category n.1, sub category n.2, ..., sub category n.m, ...',
name:'category',
value:pdoc['category']|join(', ')
}) }}
{{ form.form_text({
columns:12,
label:'Tags',
help_text:'Splitted by \', \'.',
name:'tag',
value:pdoc['tag']|join(', ')
}) }}
<div class="row"><div class="columns">
<input type="hidden" name="csrf_token" value="{{ handler.csrf_token }}">
<button type="submit" class="rounded primary button">
{{ _('Update') }}
</button>
<button type="button" class="rounded button" onclick="window.history.go(-1)">
{{ _('Cancel') }}
</button>
</div></div>
</form>
</div>
@@ -50,8 +55,7 @@
<h1 class="section__title">{{ _('Categories') }} ({{ _('click to add') }})</h1>
</div>
<div class="section__body">
<!-- TODO: chip -->
{% for category, sub_categories in categories.items() %}
{% for category, sub_categories in builtin.CATEGORIES %}
<div>
<h2 class="section__title"><a class="category-a" href="javascript:;" data-category="{{ category }}">{{ category }}</a></h2>
<ol>
@@ -67,7 +71,6 @@
<div class="medium-3 columns">
{% set owner_udoc=udoc %}{% set owner_dudoc=dudoc %}
{% include "partials/problem_sidebar.html" %}
{% endwith %}
</div>
</div>
{% endblock %}
+3 -4
View File
@@ -6,7 +6,7 @@
{% if not tdoc or rdocs %}
<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Recent {0} Records').format(10) }}</h1>
<h1 class="section__title">{{ _('Recent 10 Records') }}</h1>
</div>
<div class="section__body no-padding">
{% if not rdocs %}
@@ -23,7 +23,6 @@
<thead>
<tr>
<th class="col--status record-status--border">{{ _('Status') }}</th>
<th class="col--pretest">{{ _('Pretest?') }}</th>
<th class="col--memory">{{ _('Peak Memory') }}</th>
<th class="col--time">{{ _('Total Time') }}</th>
<th class="col--submit-at">{{ _('Submit At') }}</th>
@@ -45,8 +44,8 @@
</div>
<div class="section__body">
<form method="post">
{{ form.form_select(label='Code language', options=builtin.LANGS, name='lang', value=handler.user.codeLang) }}
{{ form.form_textarea(label='Code', columns=12, name='code', extra_class='monospace', autofocus=true) }}
{{ form.form_select({label:'Code language', options:builtin.LANG_TEXTS, name:'lang', value:handler.user.codeLang}) }}
{{ form.form_textarea({label:'Code', columns:12, name:'code', extra_class:'monospace', autofocus:true}) }}
<div class="row"><div class="columns">
<input type="hidden" name="csrf_token" value="{{ handler.csrf_token }}">
<input type="submit" class="rounded primary button" value="{{ _('Submit') }}">
+1 -1
View File
@@ -14,5 +14,5 @@
<td class="col--time">
{{ (rdoc.time / 1000)|round(1) }}s
</td>
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generation_time) }}</td>
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generationTime) }}</td>
</tr>
+11 -12
View File
@@ -1,17 +1,16 @@
{% extends 'layout/simple.html' %}
{% block body %}
<form method="post" enctype="multipart/form-data">
{% if pdoc['data'].startsWith('from:') %}
<p><b>{{ _('Current dataset comes from') }} <a href="{{ pdoc.data.split('from:')[1] }}" target="_blank">{{ pdoc.data.split('from:')[1] }}</a></b></p>
{% else %}
<p>{{ _('Current dataset: {0}').format(pdoc['data']|default(_('(None)'))) }}</p>
<p>{{ _('MD5: {0}').format(md5|default(_('(None)'))) }}</p>
{% endif %}
<p>
{{ _('New dataset') }}:
<input type="hidden" name="csrf_token" value="{{ handler.csrf_token }}">
<input type="file" name="file">
<input type="submit" value="{{ _('Upload') }}" class="rounded primary button">
</p>
{% if (typeof(pdoc.data) == 'string') %}
<p><b>{{ _('Current dataset comes from') }} <a href="{{ pdoc.data.split('from:')[1] }}" target="_blank">{{ pdoc.data.split('from:')[1] }}</a></b></p>
{% else %}
<p>{{ _('Current dataset: {0}').format(pdoc['data'].toString()|default(_('(None)'))) }}</p>
<p>{{ _('MD5: {0}').format(md5|default(_('(None)'))) }}</p>
{% endif %}
<p>{{ _('New dataset') }}:
<input type="hidden" name="csrf_token" value="{{ handler.csrf_token }}">
<input type="file" name="file">
<input type="submit" value="{{ _('Upload') }}" class="rounded primary button">
</p>
</form>
{% endblock %}
+6 -8
View File
@@ -1,5 +1,6 @@
{% extends "layout/basic.html" %}
{% set page_name = "record_detail" %}
{% import "components/problem.html" as problem with context %}
{% extends "layout/basic.html" %}
{% block content %}
<script>
var Context = {
@@ -77,10 +78,7 @@
</dd>
{% endif %}{# tdoc['doc_type'] == vj4.model.document.TYPE_CONTEST #}
{% endif %}{# tdoc #}
{% if rdoc['type'] == vj4.constant.record.TYPE_PRETEST and (handler.own(rdoc, priv=vj4.model.builtin.PRIV_READ_PRETEST_DATA_SELF, field='uid') or handler.has_priv(vj4.model.builtin.PRIV_READ_PRETEST_DATA)) %}
<dt>{{ _('Pretest Data') }}</dt>
<dd><a href="{{ reverse_url('record_pretest_data', rid=rdoc['_id']) }}"><span class="icon icon-download"></span> {{ _('Download') }}</a></dd>
{% elif rdoc['type'] == vj4.constant.record.TYPE_SUBMISSION and pdoc and (handler.own(pdoc, perm.PERM_READ_PROBLEM_DATA_SELF) or handler.has_perm(perm.PERM_READ_PROBLEM_DATA) or handler.has_priv(vj4.model.builtin.PRIV_READ_PROBLEM_DATA)) %}
{% if pdoc and (user._id == pdoc.owner or handler.has_perm(perm.PERM_READ_PROBLEM_DATA)) %}
<dt>{{ _('Problem Data') }}</dt>
<dd><a href="/p/{{ pdoc.pid }}/data"><span class="icon icon-download"></span> {{ _('Download') }}</a></dd>
{% endif %}
@@ -92,11 +90,11 @@
{{ _('Submit At') }}
</dt>
<dd>
{{ datetime_span(rdoc['_id'].generation_time) }}
{{ datetime_span(rdoc['_id'].generationTime)|safe }}
</dd>
{% if rdoc['judge_at'] %}
{% if rdoc.judgeAt %}
<dt>{{ _('Judged At') }}</dt>
<dd>{{ datetime_span(rdoc['judge_at']) }}</dd>
<dd>{{ datetime_span(rdoc.judgeAt)|safe }}</dd>
{% endif %}
{% if judge_udoc %}
<dt>{{ _('Judged By') }}</dt>
+10 -8
View File
@@ -1,15 +1,17 @@
<div class="section visible" id="status">
<div class="section__header">
<h1 class="section__title">
<span class="icon record-status--icon {{ status.STATUS_CODES[rdoc['status']] }}"></span>
<span class="record-status--text {{ status.STATUS_CODES[rdoc['status']] }}">
{{ status.STATUS_TEXTS[rdoc['status']] }}
<span class="icon record-status--icon {{ builtin.STATUS_CODES[rdoc['status']] }}"></span>
<span class="record-status--text {{ builtin.STATUS_CODES[rdoc['status']] }}">
{{ builtin.STATUS_TEXTS[rdoc['status']] }}
</span>
</h1>
</div>
{% if rdoc.compilerTexts %}
<div class="section__body">
<pre class="compiler-text">{{ rdoc.compilerTexts|join('\n') }}</pre>
</div>
{% endif %}
{% if rdoc.judgeTexts %}
<div class="section__body">
<pre class="judge-text">{{ rdoc.judgeTexts|join('\n') }}</pre>
@@ -35,16 +37,16 @@
<tbody>
{% for rcdoc in rdoc['cases'] %}
<tr>
<td class="col--case record-status--border {{ status.STATUS_CODES[rcdoc['status']] }}">
<td class="col--case record-status--border {{ builtin.STATUS_CODES[rcdoc['status']] }}">
#{{ loop.index }}
</td>
<td class="col--status">
<span class="icon record-status--icon {{ status.STATUS_CODES[rcdoc['status']] }}"></span>
<span class="record-status--text {{ status.STATUS_CODES[rcdoc['status']] }}">
<span class="icon record-status--icon {{ builtin.STATUS_CODES[rcdoc['status']] }}"></span>
<span class="record-status--text {{ builtin.STATUS_CODES[rcdoc['status']] }}">
{{ status.STATUS_TEXTS[rcdoc['status']] }}
</span>
<span>{{ rcdoc['judge_text'] }}</span>
<a class="tool-button" href="{{ reverse_url('wiki_help') }}#status"><span class="icon icon-help"></span></a>
<span>{{ rcdoc['judgeText'] }}</span>
<a class="tool-button" href="/wiki/help#status"><span class="icon icon-help"></span></a>
</td>
<td class="col--time">{% if rcdoc['status'] == status.STATUS_TIME_LIMIT_EXCEEDED or rcdoc['status'] == status.STATUS_MEMORY_LIMIT_EXCEEDED or rcdoc['status'] == status.STATUS_OUTPUT_LIMIT_EXCEEDED %}&ge;{% endif %}{{ rcdoc['time_ms'] }}ms</td>
<td class="col--memory">{% if rcdoc['status'] == status.STATUS_TIME_LIMIT_EXCEEDED or rcdoc['status'] == status.STATUS_MEMORY_LIMIT_EXCEEDED or rcdoc['status'] == status.STATUS_OUTPUT_LIMIT_EXCEEDED %}&ge;{% endif %}{{ rcdoc['memory_kb']|format_size(1024) }}</td>
+1 -1
View File
@@ -29,5 +29,5 @@
<td class="col--time">{% if rdoc['status'] == status.STATUS_TIME_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_MEMORY_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_OUTPUT_LIMIT_EXCEEDED %}&ge;{% endif %}{{ rdoc.time }}ms</td>
<td class="col--memory">{% if rdoc['status'] == status.STATUS_TIME_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_MEMORY_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_OUTPUT_LIMIT_EXCEEDED %}&ge;{% endif %}{{ rdoc.memory|format_size(1024) }}</td>
<td class="col--lang">{{ vj4.constant.language.LANG_TEXTS[rdoc['lang']] }}</td>
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generation_time) }}</td>
<td class="col--submit-at">{{ datetime_span(rdoc['_id'].generationTime) }}</td>
</tr>
+1 -1
View File
@@ -180,7 +180,7 @@
<span class="icon icon-edit"></span> {{ _('Edit') }}
</a></li>
{% endif %}
<li class="menu__item"><a class="menu__link" href="{{ reverse_url('wiki_help') }}#training">
<li class="menu__item"><a class="menu__link" href="/wiki/help#training">
<span class="icon icon-help"></span> {{ _('Help') }}
</a></li>
<li class="menu__seperator"></li>
+64 -14
View File
@@ -153,10 +153,13 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
blueimp-md5@^2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.13.0.tgz#07314b0c64dda0bf1733f96ce40d5af94eb28965"
integrity sha512-lmp0m647R5e77ORduxLW5mISIDcvgJZa52vMBv5uVI3UmSWTQjkJsZVBfaFqQPw/QFogJwvY6e3Gl9nP+Loe+Q==
bl@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
dependencies:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
brace-expansion@^1.1.7:
version "1.1.11"
@@ -174,9 +177,9 @@ braces@~3.0.2:
fill-range "^7.0.1"
bson@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.3.tgz#aa82cb91f9a453aaa060d6209d0675114a8154d3"
integrity sha512-TdiJxMVnodVS7r0BdL42y/pqC9cL2iKynVwA0Ho3qbsQYr428veL3l7BQyuqiw+Q5SqqoT0m4srSY/BlZ9AxXg==
version "1.1.4"
resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.4.tgz#f76870d799f15b854dffb7ee32f0a874797f7e89"
integrity sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q==
bson@^4.0.2:
version "4.0.2"
@@ -310,6 +313,11 @@ cookies@~0.8.0:
depd "~2.0.0"
keygrip "~1.1.0"
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@@ -364,6 +372,11 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
denque@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
depd@^1.1.2, depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@@ -743,7 +756,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4:
inherits@2, inherits@2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -826,6 +839,11 @@ isarray@0.0.1:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -1068,12 +1086,14 @@ mkdirp@^0.5.1:
dependencies:
minimist "0.0.8"
mongodb@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.3.4.tgz#f52eec4a04005101e63715d4d1f67bf784fa0aef"
integrity sha512-6fmHu3FJTpeZxacJcfjUGIP3BSteG0l2cxLkSrf1nnnS1OrlnVGiP9P/wAC4aB6dM6H4vQ2io8YDjkuPkje7AA==
mongodb@^3.5.5:
version "3.5.5"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.5.5.tgz#1334c3e5a384469ac7ef0dea69d59acc829a496a"
integrity sha512-GCjDxR3UOltDq00Zcpzql6dQo1sVry60OXJY3TDmFc2SWFY6c8Gn1Ardidc5jDirvJrx2GC3knGOImKphbSL3A==
dependencies:
bl "^2.2.0"
bson "^1.1.1"
denque "^1.4.1"
require_optional "^1.0.1"
safe-buffer "^5.1.2"
optionalDependencies:
@@ -1242,6 +1262,11 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
progress@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
@@ -1267,6 +1292,19 @@ raw-body@^2.2.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
readable-stream@^2.3.5:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readdirp@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
@@ -1334,12 +1372,12 @@ rxjs@^6.4.0:
dependencies:
tslib "^1.9.0"
safe-buffer@5.1.2:
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@>=5.1.0, safe-buffer@^5.1.2:
safe-buffer@>=5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
@@ -1446,6 +1484,13 @@ string-width@^4.1.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
strip-ansi@^5.1.0, strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
@@ -1577,6 +1622,11 @@ urijs@^1.19.0:
resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.2.tgz#f9be09f00c4c5134b7cb3cf475c1dd394526265a"
integrity sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
uuid@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"