From c68953c59ff8862373ce1203ebaa0e4b42275488 Mon Sep 17 00:00:00 2001 From: masnn Date: Thu, 9 Apr 2020 17:06:01 +0800 Subject: [PATCH] record_detail autoupdate --- hydro/handler/base.js | 2 +- hydro/handler/judge.js | 15 +- hydro/handler/record.js | 56 +++++- hydro/handler/ui.js | 19 +- hydro/model/user.js | 3 + hydro/service/bus.js | 15 ++ hydro/service/server.js | 57 +++++- package.json | 2 +- templates/components/record.html | 2 +- templates/layout/html5.html | 2 +- templates/record_detail.html | 8 +- templates/record_detail_status.html | 8 +- templates/record_main.html | 2 +- templates/record_main_tr.html | 11 +- ui/build/config/webpack.js | 2 +- ui/pages/record_detail.page.js | 4 +- yarn.lock | 279 +++++----------------------- 17 files changed, 209 insertions(+), 278 deletions(-) create mode 100644 hydro/service/bus.js diff --git a/hydro/handler/base.js b/hydro/handler/base.js index 4d4734d5..78037b90 100644 --- a/hydro/handler/base.js +++ b/hydro/handler/base.js @@ -69,4 +69,4 @@ MIDDLEWARE(async (ctx, next) => { console.error(e.stack); ctx.body = { error: { message: e.message, params: e.params, stack: e.stack } }; } -}); \ No newline at end of file +}, true); \ No newline at end of file diff --git a/hydro/handler/judge.js b/hydro/handler/judge.js index 1356ebb7..d8e7af38 100644 --- a/hydro/handler/judge.js +++ b/hydro/handler/judge.js @@ -1,9 +1,10 @@ const - { GET, POST } = require('../service/server'), - queue = require('../service/queue'), - record = require('../model/record'), { requirePerm } = require('./tools'), - { PERM_JUDGE } = require('../permission'); + { PERM_JUDGE } = require('../permission'), + record = require('../model/record'), + bus = require('../service/bus'), + queue = require('../service/queue'), + { GET, POST } = require('../service/server'); queue.assert('judge'); @@ -46,7 +47,8 @@ POST('/judge/next', requirePerm(PERM_JUDGE), async ctx => { 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); + rdoc = await record.update(body.rid, $set); + bus.publish('record_change', rdoc); ctx.body = {}; }); POST('/judge/end', requirePerm(PERM_JUDGE), async ctx => { @@ -71,6 +73,7 @@ POST('/judge/end', requirePerm(PERM_JUDGE), async ctx => { 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); + rdoc = await record.update(body.rid, $set); + bus.publish('record_change', rdoc); ctx.body = {}; }); diff --git a/hydro/handler/record.js b/hydro/handler/record.js index 84cff658..89cb5d58 100644 --- a/hydro/handler/record.js +++ b/hydro/handler/record.js @@ -1,26 +1,49 @@ const bson = require('bson'), { constants } = require('../options'), - { GET, POST } = require('../service/server'), + { PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD, + PERM_REJUDGE, PERM_VIEW_PROBLEM_HIDDEN } = require('../permission'), { requirePerm } = require('../handler/tools'), - queue = require('../service/queue'), + problem = require('../model/problem'), record = require('../model/record'), user = require('../model/user'), - problem = require('../model/problem'), - { PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD, PERM_REJUDGE } = require('../permission'); + bus = require('../service/bus'), + queue = require('../service/queue'), + { GET, POST, SOCKET } = require('../service/server'); 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); - let pdict, udict; - for (let rdoc in rdocs) { + let pdict = {}, udict = {}; + for (let rdoc of rdocs) { udict[rdoc.uid] = await user.getById(rdoc.uid); pdict[rdoc.pid] = await problem.get({ pid: rdoc.pid, uid: ctx.state.user._id }); } ctx.body = { page, rdocs, pdict, udict }; }); +SOCKET('/record-conn', class RecordConnHandler { + constructor(conn) { + this.tid = null; + this.h = async data => { + let rdoc = data.value; + if (rdoc.tid && rdoc.tid != this.tid.toString()) return; + let [udoc, pdoc] = await Promise.all([user.getById(rdoc.uid), problem.get({ pid: rdoc.pid })]); + if (pdoc.hidden && !conn.state.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) pdoc = null; + conn.send({ html: await conn.renderHTML('record_main_tr.html', { rdoc, udoc, pdoc }) }); + }; + } + onOpen() { + bus.subscribe(['record_change'], this.h); + } + onMessage(data) { + if (data.tid) this.tid = data.tid; + } + onClose() { + bus.unsubscribe(['record_change'], this.h); + } +}); GET('/r/:rid', async ctx => { ctx.templateName = 'record_detail.html'; let uid = ctx.state.user._id, rid = new bson.ObjectID(ctx.params.rid); @@ -29,6 +52,27 @@ GET('/r/:rid', async ctx => { if (rdoc.uid != uid && !ctx.state.user.hasPerm(PERM_READ_RECORD_CODE)) rdoc.code = null; ctx.body = { rdoc, show_status: true }; }); +SOCKET('/record-detail-conn', class RecordDetailConnHandler { + constructor(conn) { + this.rid = conn.params.rid; + this.h = async data => { + let rdoc = data.value; + if (rdoc.rid.toString() != this.rid) return; + let [udoc, pdoc] = await Promise.all([user.getById(rdoc.uid), problem.get({ pid: rdoc.pid })]); + if (pdoc.hidden && !conn.state.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) pdoc = null; + conn.send({ html: await conn.renderHTML('record_main_tr.html', { rdoc, udoc, pdoc }) }); + }; + } + async onOpen() { + bus.subscribe(['record_change'], this.h); + } + onMessage(data) { + if (data.rid) this.rid = data.rid; + } + onClose() { + bus.unsubscribe(['record_change'], this.h); + } +}); POST('/r/:rid/rejudge', requirePerm(PERM_REJUDGE), async ctx => { ctx.templateName = 'record_detail.html'; let uid = ctx.state.user._id, rid = new bson.ObjectID(ctx.params.rid); diff --git a/hydro/handler/ui.js b/hydro/handler/ui.js index d100959d..bf614d7a 100644 --- a/hydro/handler/ui.js +++ b/hydro/handler/ui.js @@ -30,10 +30,11 @@ class Markdown extends MarkdownIt { } const md = new Markdown(); function datetime_span(dt, { relative = true } = {}) { - dt = new Date(dt); + if (dt.generationTime) dt = new Date(dt.generationTime * 1000); + else if (typeof dt == 'number' || typeof dt == 'string') dt = new Date(dt); return '{2}'.format( relative ? ' relative' : '', - dt.getTime(), + dt.getTime() / 1000, dt.toLocaleString() ); } @@ -93,14 +94,14 @@ MIDDLEWARE(async (ctx, next) => { url_prefix: '/' }; ctx.preferJson = (ctx.request.headers['accept'] || '').includes('application/json'); - ctx.render = async (name, context) => { + ctx.renderHTML = (name, context) => { ctx.user = ctx.state.user; ctx.translate = str => { if (!str) return ''; return str.toString().translate(ctx.state.user.language); }; ctx.has_perm = perm => ctx.state.user.hasPerm(perm); - ctx.body = await new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { env.render(name, Object.assign(ctx.state, context, { handler: ctx, _: ctx.translate, @@ -110,6 +111,9 @@ MIDDLEWARE(async (ctx, next) => { else resolve(res); }); }); + }; + ctx.render = async (name, context) => { + ctx.body = await ctx.renderHTML(name, context); ctx.response.type = 'text/html'; }; try { @@ -125,8 +129,11 @@ MIDDLEWARE(async (ctx, next) => { ctx.response.type = 'application/octet-stream'; ctx.redirect(ctx.setRedirect); } - } else throw new NotFoundError(); + } else { + throw new NotFoundError(); + } } catch (error) { + if (error instanceof NotFoundError) ctx.status = 404; if (error.toString().startsWith('NotFoundError')) console.log(error); if (error.toString().startsWith('Template render error')) throw error; if (ctx.preferJson) ctx.body = { error }; @@ -136,4 +143,4 @@ MIDDLEWARE(async (ctx, next) => { if (ctx.preferJson) ctx.body = { error }; else await ctx.render('bsod.html', { error }); } -}); \ No newline at end of file +}, true); \ No newline at end of file diff --git a/hydro/model/user.js b/hydro/model/user.js index d58299fc..d08902b5 100644 --- a/hydro/model/user.js +++ b/hydro/model/user.js @@ -14,6 +14,9 @@ class USER { this.salt = user.salt; this.hash = user.hash; this.perm = user.perm; + this.lang = user.language || 'zh_CN'; + this.codeLang = user.codeLang || 'c'; + this.codeTemplate = user.codeTemplate || ''; } hasPerm(perm) { return this.perm == '-' || (this.perm || '').includes(perm); diff --git a/hydro/service/bus.js b/hydro/service/bus.js new file mode 100644 index 00000000..d675fc90 --- /dev/null +++ b/hydro/service/bus.js @@ -0,0 +1,15 @@ +const EventEmitter = require('events').EventEmitter; +const bus = new EventEmitter(); +module.exports = { + subscribe(events, handler) { + for (let event of events) + bus.on(event, handler); + }, + unsubscribe(events, handler) { + for (let event of events) + bus.off(event, handler); + }, + publish(event, data) { + bus.emit(event, { value: data, event }); + } +}; \ No newline at end of file diff --git a/hydro/service/server.js b/hydro/service/server.js index d2d17b14..6ad78429 100644 --- a/hydro/service/server.js +++ b/hydro/service/server.js @@ -3,14 +3,13 @@ const morgan = require('koa-morgan'), Body = require('koa-body'), Router = require('koa-router'), - SocketIO = require('socket.io'); + sockjs = require('sockjs'); const options = require('../options'); let http = options.listen.https ? require('https') : require('http'); let app = new Koa(); let server = http.createServer(app.callback()); -let io = SocketIO(server); app.keys = options.session.keys; app.use(Body({ multipart: true, @@ -19,12 +18,14 @@ app.use(Body({ } })); let router = new Router(); - +let m = []; /** * @param {import('koa').Middleware} middleware + * @param {boolean} installForSocket */ -function MIDDLEWARE(middleware) { +function MIDDLEWARE(middleware, installForSocket = false) { app.use(middleware); + if (installForSocket) m.push(middleware); } /** * @param {string} route @@ -44,13 +45,57 @@ function POST(route, ...handler) { * @callback SocketIOHandler * @param {import('socket.io').Socket} socket */ +/** + * @callback SockJSHandler + * @param {import('sockjs').Connection} conn + */ /** * @param {string} prefix * @param {SocketIOHandler} handler */ function SOCKET(prefix, handler) { - io.of(prefix).on('connection', handler); + const sock = sockjs.createServer({ prefix }); + sock.on('connection', async conn => { + conn.cookies = { + get(name) { + return conn.cookies[name]; + }, + set() { } + }; + conn.state = {}; + conn.params = {}; + conn.request = { + headers: conn.headers + }; + let p = conn.url.split('?')[1].split('&'); + for (let i in p) p[i] = p[i].split('='); + for (let i in p) conn.params[p[i][0]] = decodeURIComponent(p[i][1]); + await new Promise((resolve, reject) => { + conn.once('data', msg => { + for (let i of msg.split(';')) { + i = i.trim().split('='); + conn.cookies[i[0]] = i[1]; + } + resolve(); + }); + setTimeout(reject, 5000); + }); + for (let i of m) { + await new Promise((resolve, reject) => { + i(conn, resolve).catch(reject); + }); + } + conn.send = data => { + conn.write(JSON.stringify(data)); + }; + let h = new handler(conn); + if (h.onOpen) conn.on('open', h.onOpen); + if (h.onClose) conn.on('close', h.onClose); + if (h.onMessage) conn.on('data', h.onMessage); + }); + sock.installHandlers(server); } + exports.MIDDLEWARE = MIDDLEWARE; exports.GET = GET; exports.POST = POST; @@ -58,6 +103,6 @@ exports.SOCKET = SOCKET; exports.start = function start() { app.use(morgan(':method :url :status :res[content-length] - :response-time ms')); app.use(router.routes()).use(router.allowedMethods()); - app.listen(options.listen.port); + server.listen(options.listen.port); console.log('Server listening at: %s', options.listen.port); }; diff --git a/package.json b/package.json index b76d37e6..e90a34e8 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "mongodb": "^3.5.5", "nodemailer": "^6.3.1", "nunjucks": "^3.2.1", - "socket.io": "^2.3.0" + "sockjs": "^0.3.20" }, "devDependencies": { "eslint": "^6.6.0" diff --git a/templates/components/record.html b/templates/components/record.html index 5bbec242..fb9843bb 100644 --- a/templates/components/record.html +++ b/templates/components/record.html @@ -3,7 +3,7 @@
- {{ status.STATUS_TEXTS[rdoc['status']] }} + {{ builtin.STATUS_TEXTS[rdoc['status']] }}
{% if rdoc['status'] == status.STATUS_JUDGING %} diff --git a/templates/layout/html5.html b/templates/layout/html5.html index 910b3cea..b1d866da 100644 --- a/templates/layout/html5.html +++ b/templates/layout/html5.html @@ -40,7 +40,7 @@ - + diff --git a/templates/record_detail.html b/templates/record_detail.html index 47e55170..bd3c2999 100644 --- a/templates/record_detail.html +++ b/templates/record_detail.html @@ -4,7 +4,7 @@ {% block content %}
@@ -57,8 +57,6 @@
{{ _('Submit By') }}
{{ user.render_inline(udoc, dudoc, modbadge=false) }}
-
{{ _('Type') }}
-
{{ _(vj4.constant.record.TYPE_TEXTS[rdoc['type']]) }}
{% if pdoc %}
{{ _('Problem') }}
@@ -84,13 +82,13 @@ {% endif %}
{{ _('Language') }}
- {{ vj4.constant.language.LANG_TEXTS[rdoc['lang']] }} + {{ builtin.LANG_TEXTS[rdoc['lang']] }}
{{ _('Submit At') }}
- {{ datetime_span(rdoc['_id'].generationTime)|safe }} + {{ datetime_span(rdoc._id)|safe }}
{% if rdoc.judgeAt %}
{{ _('Judged At') }}
diff --git a/templates/record_detail_status.html b/templates/record_detail_status.html index 2f0d1d14..eda358ed 100644 --- a/templates/record_detail_status.html +++ b/templates/record_detail_status.html @@ -7,17 +7,17 @@
-{% if rdoc.compilerTexts %} +{% if rdoc.compilerTexts.length %}
{{ rdoc.compilerTexts|join('\n') }}
{% endif %} -{% if rdoc.judgeTexts %} +{% if rdoc.judgeTexts.length %}
{{ rdoc.judgeTexts|join('\n') }}
{% endif %} -{% if rdoc['cases'] %} +{% if rdoc.cases.length %}
@@ -35,7 +35,7 @@ - {% for rcdoc in rdoc['cases'] %} + {% for rcdoc in rdoc.cases %} {{ record.render_status_td(rdoc) }} - - + + diff --git a/ui/build/config/webpack.js b/ui/build/config/webpack.js index 8b757f61..4540c6ab 100644 --- a/ui/build/config/webpack.js +++ b/ui/build/config/webpack.js @@ -203,7 +203,7 @@ export default function (env = {}) { name: 'vendors', minChunks: (module, count) => ( module.resource - && module.resource.indexOf(root()) === -1 + && module.resource.indexOf(root('node_modules')) && module.resource.match(/\.jsx?$/) ), }), diff --git a/ui/pages/record_detail.page.js b/ui/pages/record_detail.page.js index 5dfa38f8..9d326012 100644 --- a/ui/pages/record_detail.page.js +++ b/ui/pages/record_detail.page.js @@ -6,7 +6,9 @@ const page = new NamedPage('record_detail', async () => { const sock = new SockJs(Context.socketUrl); const dd = new DiffDOM(); - + sock.onopen = () => { + sock.send(document.cookie); + }; sock.onmessage = (message) => { const msg = JSON.parse(message.data); const newStatus = $(msg.status_html); diff --git a/yarn.lock b/yarn.lock index 53f50911..6bfd1d08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41,7 +41,7 @@ a-sync-waterfall@^1.0.0: resolved "https://registry.yarnpkg.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz#75b6b6aa72598b497a125e7a2770f14f4c8a1fa7" integrity sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA== -accepts@^1.3.5, accepts@~1.3.4: +accepts@^1.3.5: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== @@ -59,11 +59,6 @@ acorn@^7.1.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== -after@0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" - integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= - ajv@^6.10.0, ajv@^6.10.2: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" @@ -118,11 +113,6 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -arraybuffer.slice@~0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" - integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== - asap@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -133,11 +123,6 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - axios@^0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" @@ -146,31 +131,16 @@ axios@^0.19.0: follow-redirects "1.5.10" is-buffer "^2.0.2" -backo2@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" - integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-arraybuffer@0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" - integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= - base64-js@^1.0.2: version "1.3.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== -base64id@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" - integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== - basic-auth@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" @@ -178,13 +148,6 @@ basic-auth@~2.0.0: dependencies: safe-buffer "5.1.2" -better-assert@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" - integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= - dependencies: - callsite "1.0.0" - binary-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" @@ -198,11 +161,6 @@ bl@^2.2.0: readable-stream "^2.3.5" safe-buffer "^5.1.1" -blob@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" - integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -252,11 +210,6 @@ cache-content-type@^1.0.0: mime-types "^2.1.18" ylru "^1.2.0" -callsite@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" - integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -335,21 +288,6 @@ commander@^3.0.2: resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== -component-bind@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" - integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= - -component-emitter@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= - -component-inherit@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" - integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -367,11 +305,6 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= - cookies@~0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" @@ -417,7 +350,7 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@~4.1.0: +debug@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -486,46 +419,6 @@ encodeurl@^1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -engine.io-client@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700" - integrity sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA== - dependencies: - component-emitter "1.2.1" - component-inherit "0.0.3" - debug "~4.1.0" - engine.io-parser "~2.2.0" - has-cors "1.1.0" - indexof "0.0.1" - parseqs "0.0.5" - parseuri "0.0.5" - ws "~6.1.0" - xmlhttprequest-ssl "~1.5.4" - yeast "0.1.2" - -engine.io-parser@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed" - integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w== - dependencies: - after "0.8.2" - arraybuffer.slice "~0.0.7" - base64-arraybuffer "0.1.5" - blob "0.0.5" - has-binary2 "~1.0.2" - -engine.io@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3" - integrity sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w== - dependencies: - accepts "~1.3.4" - base64id "2.0.0" - cookie "0.3.1" - debug "~4.1.0" - engine.io-parser "~2.2.0" - ws "^7.1.2" - entities@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" @@ -671,6 +564,13 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + figures@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.1.0.tgz#4b198dd07d8d71530642864af2d45dd9e459c4ec" @@ -769,18 +669,6 @@ globals@^11.7.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -has-binary2@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" - integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== - dependencies: - isarray "2.0.1" - -has-cors@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" - integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -820,6 +708,11 @@ http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" +"http-parser-js@>=0.4.0 <0.4.11": + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -850,11 +743,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= - inflation@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" @@ -951,11 +839,6 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= -isarray@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" - integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= - isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1284,11 +1167,6 @@ object-assign@^4.0.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-component@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" - integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= - on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -1344,20 +1222,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parseqs@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" - integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= - dependencies: - better-assert "~1.0.0" - -parseuri@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" - integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= - dependencies: - better-assert "~1.0.0" - parseurl@^1.3.2: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -1505,7 +1369,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.1.1, 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== @@ -1568,60 +1432,14 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -socket.io-adapter@~1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" - integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== - -socket.io-client@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4" - integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA== - dependencies: - backo2 "1.0.2" - base64-arraybuffer "0.1.5" - component-bind "1.0.0" - component-emitter "1.2.1" - debug "~4.1.0" - engine.io-client "~3.4.0" - has-binary2 "~1.0.2" - has-cors "1.1.0" - indexof "0.0.1" - object-component "0.0.3" - parseqs "0.0.5" - parseuri "0.0.5" - socket.io-parser "~3.3.0" - to-array "0.1.4" - -socket.io-parser@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" - integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== +sockjs@^0.3.20: + version "0.3.20" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.20.tgz#b26a283ec562ef8b2687b44033a4eeceac75d855" + integrity sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA== dependencies: - component-emitter "1.2.1" - debug "~3.1.0" - isarray "2.0.1" - -socket.io-parser@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a" - integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ== - dependencies: - component-emitter "1.2.1" - debug "~4.1.0" - isarray "2.0.1" - -socket.io@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb" - integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg== - dependencies: - debug "~4.1.0" - engine.io "~3.4.0" - has-binary2 "~1.0.2" - socket.io-adapter "~1.1.0" - socket.io-client "2.3.0" - socket.io-parser "~3.4.0" + faye-websocket "^0.10.0" + uuid "^3.4.0" + websocket-driver "0.6.5" sparse-bitfield@^3.0.3: version "3.0.3" @@ -1732,11 +1550,6 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -to-array@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" - integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -1806,6 +1619,11 @@ util-deprecate@~1.0.1: 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" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + v8-compile-cache@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" @@ -1816,6 +1634,27 @@ vary@^1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +websocket-driver@0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + integrity sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY= + dependencies: + websocket-extensions ">=0.1.1" + +websocket-driver@>=0.5.1: + version "0.7.3" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" + integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== + dependencies: + http-parser-js ">=0.4.0 <0.4.11" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -1840,28 +1679,6 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^7.1.2: - version "7.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" - integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== - -ws@~6.1.0: - version "6.1.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" - integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== - dependencies: - async-limiter "~1.0.0" - -xmlhttprequest-ssl@~1.5.4: - version "1.5.5" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" - integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= - -yeast@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" - integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= - ylru@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f"
#{{ loop.index }} diff --git a/templates/record_main.html b/templates/record_main.html index 22a04264..cd50d3ac 100644 --- a/templates/record_main.html +++ b/templates/record_main.html @@ -3,7 +3,7 @@ {% block content %}
diff --git a/templates/record_main_tr.html b/templates/record_main_tr.html index 47d155f4..438c6264 100644 --- a/templates/record_main_tr.html +++ b/templates/record_main_tr.html @@ -3,7 +3,7 @@
- {% if = handler.has_perm(perm.PERM_REJUDGE) %} + {% if handler.has_perm(perm.PERM_REJUDGE) %}
|
{% endif %} - {% if rdoc['type'] == vj4.constant.record.TYPE_PRETEST %} - ({{ _('Pretest') }}) - {% endif %} - {% if pdoc and (not pdoc['hidden'] or handler.has_perm(perm.PERM_VIEW_PROBLEM_HIDDEN)) %} + {% if pdoc and (not pdoc.hidden or handler.has_perm(perm.PERM_VIEW_PROBLEM_HIDDEN)) %} {{ problem.render_problem_title(pdoc, show_tags=false) }} {% else %} * @@ -28,6 +25,6 @@
{% if rdoc['status'] == status.STATUS_TIME_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_MEMORY_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_OUTPUT_LIMIT_EXCEEDED %}≥{% endif %}{{ rdoc.time }}ms {% if rdoc['status'] == status.STATUS_TIME_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_MEMORY_LIMIT_EXCEEDED or rdoc['status'] == status.STATUS_OUTPUT_LIMIT_EXCEEDED %}≥{% endif %}{{ rdoc.memory|format_size(1024) }}{{ vj4.constant.language.LANG_TEXTS[rdoc['lang']] }}{{ datetime_span(rdoc['_id'].generationTime) }}{{ builtin.LANG_TEXTS[rdoc['lang']] }}{{ datetime_span(rdoc['_id'].generationTime)|safe }}