mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
1 parent
d5c5b3fd47
commit
1c89596cb3
20 files changed
+84
-59
No files matched your search
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hydrooj/hydrojudge",
|
||||
"bin": "bin/hydrojudge.js",
|
||||
"version": "2.4.19",
|
||||
"version": "2.5.0",
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
|
||||
@@ -88,8 +88,8 @@ async function read0(folder: string, files: string[], checkFile, cfg) {
|
||||
const config = {
|
||||
count: 0,
|
||||
subtasks: [{
|
||||
time_limit_ms: parseTimeMS(cfg.time || '1s'),
|
||||
memory_limit_mb: parseMemoryMB(cfg.memory || '256m'),
|
||||
time: parseTimeMS(cfg.time || '1s'),
|
||||
memory: parseMemoryMB(cfg.memory || '256m'),
|
||||
type: 'sum',
|
||||
cases: [],
|
||||
score: Math.floor(100 / cases.length),
|
||||
@@ -105,8 +105,8 @@ async function read0(folder: string, files: string[], checkFile, cfg) {
|
||||
}
|
||||
if (extra < cases.length) {
|
||||
config.subtasks.push({
|
||||
time_limit_ms: parseTimeMS(cfg.time || '1s'),
|
||||
memory_limit_mb: parseMemoryMB(cfg.memory || '256m'),
|
||||
time: parseTimeMS(cfg.time || '1s'),
|
||||
memory: parseMemoryMB(cfg.memory || '256m'),
|
||||
type: 'sum',
|
||||
cases: [],
|
||||
score: Math.floor(100 / cases.length) + 1,
|
||||
@@ -134,8 +134,8 @@ async function read1(folder: string, files: string[], checkFile, cfg) {
|
||||
if (fs.existsSync(path.resolve(folder, c.output))) {
|
||||
if (!subtask[REG.subtask(data)]) {
|
||||
subtask[REG.subtask(data)] = [{
|
||||
time_limit_ms: parseTimeMS(cfg.time || '1s'),
|
||||
memory_limit_mb: parseMemoryMB(cfg.memory || '256m'),
|
||||
time: parseTimeMS(cfg.time || '1s'),
|
||||
memory: parseMemoryMB(cfg.memory || '256m'),
|
||||
type: 'min',
|
||||
cases: [c],
|
||||
}];
|
||||
@@ -199,7 +199,7 @@ function isValidConfig(config) {
|
||||
if (config.count > (getConfig('testcases_max') || 100)) {
|
||||
throw new FormatError('Too many testcases. Cancelled.');
|
||||
}
|
||||
const total_time = sum(config.subtasks.map((subtask) => subtask.time_limit_ms * subtask.cases.length));
|
||||
const total_time = sum(config.subtasks.map((subtask) => subtask.time * subtask.cases.length));
|
||||
if (total_time > (getConfig('total_time_limit') || 60) * 1000) {
|
||||
throw new FormatError('Total time limit longer than {0}s. Cancelled.', [+getConfig('total_time_limit') || 60]);
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ function judgeCase(c, sid) {
|
||||
stderr,
|
||||
copyIn,
|
||||
copyOut,
|
||||
time_limit_ms: ctxSubtask.subtask.time_limit_ms * ctx.execute.time,
|
||||
memory_limit_mb: ctxSubtask.subtask.memory_limit_mb,
|
||||
time: ctxSubtask.subtask.time * ctx.execute.time,
|
||||
memory: ctxSubtask.subtask.memory,
|
||||
},
|
||||
);
|
||||
const { code, time_usage_ms, memory_usage_kb } = res;
|
||||
@@ -62,9 +62,9 @@ function judgeCase(c, sid) {
|
||||
let message: any = '';
|
||||
let score = 0;
|
||||
if (status === STATUS.STATUS_ACCEPTED) {
|
||||
if (time_usage_ms > ctxSubtask.subtask.time_limit_ms * ctx.execute.time) {
|
||||
if (time_usage_ms > ctxSubtask.subtask.time * ctx.execute.time) {
|
||||
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
|
||||
} else if (memory_usage_kb > ctxSubtask.subtask.memory_limit_mb * 1024) {
|
||||
} else if (memory_usage_kb > ctxSubtask.subtask.memory * 1024) {
|
||||
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
|
||||
} else {
|
||||
[status, score, message] = await check({
|
||||
|
||||
@@ -77,8 +77,8 @@ export const judge = async (ctx) => {
|
||||
stderr,
|
||||
copyIn: execute.copyIn,
|
||||
copyOut,
|
||||
time_limit_ms: 1000,
|
||||
memory_limit_mb: 512,
|
||||
time: 1000,
|
||||
memory: 512,
|
||||
},
|
||||
);
|
||||
const { code, time_usage_ms, memory_usage_kb } = res;
|
||||
|
||||
@@ -24,21 +24,21 @@ function judgeCase(c) {
|
||||
{
|
||||
execute: ctx.executeUser.execute.replace(/\$\{name\}/g, 'code'),
|
||||
copyIn: ctx.executeUser.copyIn,
|
||||
time_limit_ms: ctxSubtask.subtask.time_limit_ms,
|
||||
memory_limit_mb: ctxSubtask.subtask.memory_limit_mb,
|
||||
time: ctxSubtask.subtask.time,
|
||||
memory: ctxSubtask.subtask.memory,
|
||||
}, {
|
||||
execute: `${ctx.executeInteractor.execute.replace(/\$\{name\}/g, 'interactor')} /w/in /w/tout`,
|
||||
copyIn: ctx.executeInteractor.copyIn,
|
||||
time_limit_ms: ctxSubtask.subtask.time_limit_ms * 2,
|
||||
memory_limit_mb: ctxSubtask.subtask.memory_limit_mb * 2,
|
||||
time: ctxSubtask.subtask.time * 2,
|
||||
memory: ctxSubtask.subtask.memory * 2,
|
||||
},
|
||||
]);
|
||||
let status;
|
||||
let score = 0;
|
||||
let message: any = '';
|
||||
if (time_usage_ms > ctxSubtask.subtask.time_limit_ms) {
|
||||
if (time_usage_ms > ctxSubtask.subtask.time) {
|
||||
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
|
||||
} else if (memory_usage_kb > ctxSubtask.subtask.memory_limit_mb * 1024) {
|
||||
} else if (memory_usage_kb > ctxSubtask.subtask.memory * 1024) {
|
||||
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
|
||||
} else if (code) {
|
||||
status = STATUS.STATUS_RUNTIME_ERROR;
|
||||
|
||||
@@ -69,8 +69,8 @@ export const judge = async (ctx) => {
|
||||
stderr,
|
||||
copyIn,
|
||||
copyOut,
|
||||
time_limit_ms: parseTimeMS(ctx.config.time || '1s'),
|
||||
memory_limit_mb: parseMemoryMB(ctx.config.memory || '128m'),
|
||||
time: parseTimeMS(ctx.config.time || '1s'),
|
||||
memory: parseMemoryMB(ctx.config.memory || '128m'),
|
||||
},
|
||||
);
|
||||
const { code, time_usage_ms, memory_usage_kb } = res;
|
||||
|
||||
@@ -25,8 +25,8 @@ const statusMap = {
|
||||
|
||||
function proc({
|
||||
execute = '',
|
||||
time_limit_ms = 16000,
|
||||
memory_limit_mb = 1024,
|
||||
time = 16000,
|
||||
memory = 1024,
|
||||
process_limit = 32,
|
||||
stdin = '', copyIn = {}, copyOut = [], copyOutCached = [],
|
||||
} = {}) {
|
||||
@@ -39,9 +39,9 @@ function proc({
|
||||
{ name: 'stdout', max: 1024 * 1024 * size },
|
||||
{ name: 'stderr', max: 1024 * 1024 * size },
|
||||
],
|
||||
cpuLimit: time_limit_ms * 1000 * 1000,
|
||||
realCpuLimit: time_limit_ms * 3000 * 1000,
|
||||
memoryLimit: memory_limit_mb * 1024 * 1024,
|
||||
cpuLimit: time * 1000 * 1000,
|
||||
realCpuLimit: time * 3000 * 1000,
|
||||
memoryLimit: memory * 1024 * 1024,
|
||||
procLimit: process_limit,
|
||||
copyIn,
|
||||
copyOut,
|
||||
@@ -58,7 +58,7 @@ async function adaptResult(result, params) {
|
||||
files: result.files,
|
||||
code: result.exitStatus,
|
||||
};
|
||||
if (ret.time_usage_ms >= (params.time_limit_ms || 16000)) {
|
||||
if (ret.time_usage_ms >= (params.time || 16000)) {
|
||||
ret.status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
|
||||
}
|
||||
ret.files = result.files || {};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "2.21.19",
|
||||
"version": "2.22.0",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "dist/loader.js",
|
||||
"typings": "dist/loader.d.ts",
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import paginate from '../lib/paginate';
|
||||
import { isPid } from '../lib/validator';
|
||||
import difficultyAlgorithm from '../lib/difficulty';
|
||||
import { parseConfig } from '../lib/testdataConfig';
|
||||
import * as system from '../model/system';
|
||||
import problem from '../model/problem';
|
||||
import record from '../model/record';
|
||||
@@ -189,6 +190,12 @@ export class ProblemDetailHandler extends ProblemHandler {
|
||||
// e.g.  will navigate to 
|
||||
this.response.body.pdoc.content = this.response.body.pdoc.content
|
||||
.replace(/\(file:\/\//g, `(./${this.pdoc.docId}/file/`);
|
||||
// Get time and memory limit
|
||||
try {
|
||||
this.response.body.pdoc.config = await parseConfig(this.pdoc.config);
|
||||
} catch (e) {
|
||||
this.response.body.pdoc.config = `Cannot parse: ${e.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
@param('pid', Types.UnsignedInt)
|
||||
|
||||
@@ -189,7 +189,6 @@ declare module './model/problem' {
|
||||
data: FileInfo[],
|
||||
additional_file: FileInfo[],
|
||||
hidden: boolean,
|
||||
acMsg?: string,
|
||||
html?: boolean,
|
||||
difficulty?: number,
|
||||
/** @deprecated */
|
||||
|
||||
@@ -21,24 +21,26 @@ export async function parseConfig(config: string | ProblemConfig) {
|
||||
let cfg: ProblemConfig = {};
|
||||
if (typeof config === 'string') {
|
||||
// TODO should validate here?
|
||||
cfg = readYamlCases(load(config) as Record<string, any>) as ProblemConfig;
|
||||
cfg = await readYamlCases(load(config) as Record<string, any>) as ProblemConfig;
|
||||
} else cfg = config;
|
||||
if (cfg.cases) {
|
||||
for (const c of cfg.cases) {
|
||||
result.memoryMax = Math.max(result.memoryMax, c.memory);
|
||||
result.memoryMin = Math.min(result.memoryMin, c.memory);
|
||||
result.timeMax = Math.max(result.timeMax, c.time);
|
||||
result.timeMin = Math.min(result.timeMin, c.time);
|
||||
result.count++;
|
||||
}
|
||||
} else if (cfg.subtasks) {
|
||||
if (cfg.subtasks.length) {
|
||||
for (const subtask of cfg.subtasks) {
|
||||
result.memoryMax = Math.max(result.memoryMax, subtask.memory);
|
||||
result.memoryMin = Math.min(result.memoryMin, subtask.memory);
|
||||
result.timeMax = Math.max(result.timeMax, subtask.time);
|
||||
result.timeMin = Math.min(result.timeMin, subtask.time);
|
||||
}
|
||||
} else if (cfg.time || cfg.memory) {
|
||||
if (cfg.time) result.timeMax = result.timeMin = cfg.time as unknown as number;
|
||||
if (cfg.memory) result.memoryMax = result.memoryMin = cfg.memory as unknown as number;
|
||||
}
|
||||
if (result.memoryMax < result.memoryMin) {
|
||||
result.memoryMax = result.memoryMin = 256;
|
||||
}
|
||||
if (result.timeMax < result.timeMin) {
|
||||
result.timeMax = result.timeMin = 1000;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
global.Hydro.lib.testdataConfig = { parseConfig };
|
||||
@@ -28,8 +28,7 @@ export class ProblemModel {
|
||||
|
||||
static PROJECTION_PUBLIC: Field[] = [
|
||||
...ProblemModel.PROJECTION_LIST,
|
||||
'content', 'html', 'data', 'config', 'acMsg',
|
||||
'additional_file',
|
||||
'content', 'html', 'data', 'config', 'additional_file',
|
||||
];
|
||||
|
||||
static extend(getter: Getter) {
|
||||
@@ -258,7 +257,6 @@ ProblemModel.extend((docId, pid) => ({
|
||||
additional_file: [],
|
||||
hidden: true,
|
||||
config: '',
|
||||
acMsg: '',
|
||||
difficulty: 0,
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/migrate-vijos",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"main": "package.json",
|
||||
"repository": "git@github.com:hydro-dev/Hydro.git",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
|
||||
@@ -74,7 +74,6 @@ const tasks = {
|
||||
return res;
|
||||
},
|
||||
},
|
||||
ac_msg: 'acMsg',
|
||||
parent_doc_id: {
|
||||
field: 'parentId',
|
||||
processer: (parentId, doc) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/ui-default",
|
||||
"version": "4.5.14",
|
||||
"version": "4.5.15",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "hydro.js",
|
||||
|
||||
@@ -126,10 +126,6 @@
|
||||
{% else %}
|
||||
{{ _('(None)') }}
|
||||
{% endif %}
|
||||
{% if pdoc['acMsg'] and pdoc['psdoc']['status'] == STATUS.STATUS_ACCEPTED %}
|
||||
<dt>{{ _('AC Message') }}</dt>
|
||||
<dd>{{ pdoc['acMsg'] }}</dd>
|
||||
{% endif %}
|
||||
</dd>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -25,7 +25,27 @@
|
||||
<div class="section">
|
||||
<div class="problem-content-container"><div class="problem-content" data-marker-enabled>
|
||||
<div class="section__header non-scratchpad--hide">
|
||||
<h1>{{ pdoc.title }}</h1>
|
||||
<h1 class="section__title">
|
||||
{%- if rdoc -%}
|
||||
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc['status']] }}"></span>
|
||||
<span class="record-status--text {{ model.builtin.STATUS_CODES[rdoc['status']] }}">
|
||||
{{ rdoc.score }}
|
||||
</span>
|
||||
{%- endif %}
|
||||
{{ pdoc.title }}
|
||||
</h1>
|
||||
</div>
|
||||
<div class="section__header scratchpad--hide">
|
||||
{% if rdoc %}
|
||||
<h1 class="section__title">
|
||||
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc['status']] }}"></span>
|
||||
<span class="record-status--text {{ model.builtin.STATUS_CODES[rdoc['status']] }}">
|
||||
{{ rdoc.score }}
|
||||
</span>
|
||||
</h1>
|
||||
{% endif %}
|
||||
<span class="record-status--text">{{ _('Time Limit') }}: {{ pdoc.config.timeMax if pdoc.config.timeMax == pdoc.config.timeMin else pdoc.config.timeMin+'~'+pdoc.config.timeMax }}ms</span>
|
||||
<span class="record-status--text">{{ _('Memory Limit') }}: {{ pdoc.config.memoryMax if pdoc.config.memoryMax == pdoc.config.memoryMin else pdoc.config.memoryMin+'~'+pdoc.config.memoryMax }}MiB</span>
|
||||
</div>
|
||||
<div class="section__body typo">
|
||||
{% if tdoc %}
|
||||
|
||||
@@ -35,8 +35,8 @@ export default async function readYamlCases(cfg: Record<string, any> = {}, check
|
||||
} else if (cfg.cases) {
|
||||
config.subtasks = [{
|
||||
score: parseInt(cfg.score, 10) || Math.floor(100 / cfg.cases.length),
|
||||
time_limit_ms: parseTimeMS(cfg.time || '1s'),
|
||||
memory_limit_mb: parseMemoryMB(cfg.memory || '512m'),
|
||||
time: parseTimeMS(cfg.time || '1s'),
|
||||
memory: parseMemoryMB(cfg.memory || '256m'),
|
||||
cases: [],
|
||||
type: 'sum',
|
||||
}];
|
||||
@@ -63,11 +63,13 @@ export default async function readYamlCases(cfg: Record<string, any> = {}, check
|
||||
score: parseInt(subtask.score, 10),
|
||||
if: subtask.if || [],
|
||||
cases,
|
||||
time_limit_ms: parseTimeMS(subtask.time || cfg.time || '1s'),
|
||||
memory_limit_mb: parseMemoryMB(subtask.memory || cfg.memory || '512m'),
|
||||
time: parseTimeMS(subtask.time || cfg.time || '1s'),
|
||||
memory: parseMemoryMB(subtask.memory || cfg.memory || '256m'),
|
||||
});
|
||||
}
|
||||
}
|
||||
if (cfg.time) config.time = parseTimeMS(cfg.time);
|
||||
if (cfg.memory) config.memory = parseMemoryMB(cfg.memory);
|
||||
if (config.type === 'submit_answer' && !cfg.outputs) throw new Error('outputs config not found');
|
||||
return Object.assign(cfg, config);
|
||||
}
|
||||
@@ -83,7 +85,7 @@ export function convertIniConfig(ini: string) {
|
||||
cases: [{ input: `input/${input.toLowerCase()}`, output: `output/${output.toLowerCase()}` }],
|
||||
score: parseInt(score, 10),
|
||||
time: `${time}s`,
|
||||
memory: '512m',
|
||||
memory: '256m',
|
||||
};
|
||||
if (!Number.isNaN(parseInt(memory, 10))) cur.memory = `${Math.floor(parseInt(memory, 10) / 1024)}m`;
|
||||
res.subtasks.push(cur);
|
||||
|
||||
@@ -161,13 +161,15 @@ const TIME_UNITS = { '': 1000, m: 1, u: 0.001 };
|
||||
const MEMORY_RE = /^([0-9]+(?:\.[0-9]*)?)([kmg])b?$/i;
|
||||
const MEMORY_UNITS = { k: 1 / 1024, m: 1, g: 1024 };
|
||||
|
||||
export function parseTimeMS(str: string) {
|
||||
export function parseTimeMS(str: string | number) {
|
||||
if (typeof str === 'number') return str;
|
||||
const match = TIME_RE.exec(str);
|
||||
if (!match) throw new Error(`${str} error parsing time`);
|
||||
return Math.floor(parseFloat(match[1]) * TIME_UNITS[match[2]]);
|
||||
}
|
||||
|
||||
export function parseMemoryMB(str: string) {
|
||||
export function parseMemoryMB(str: string | number) {
|
||||
if (typeof str === 'number') return str;
|
||||
const match = MEMORY_RE.exec(str);
|
||||
if (!match) throw new Error(`${str} error parsing memory`);
|
||||
return Math.ceil(parseFloat(match[1]) * MEMORY_UNITS[match[2]]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/utils",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"description": "hydrooj utils",
|
||||
"main": "package.json",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
|
||||
Reference in new issue
Block a user