diff --git a/remote_judger/src/providers/loj.ts b/remote_judger/src/providers/loj.ts
index c93a1ff..2c007fa 100644
--- a/remote_judger/src/providers/loj.ts
+++ b/remote_judger/src/providers/loj.ts
@@ -5,6 +5,7 @@ import sleep from '../utils/sleep';
import { IBasicProvider, RemoteAccount, USER_AGENT } from '../interface';
import Logger from '../utils/logger';
import { normalize, VERDICT } from '../verdict';
+import { crlf, LF } from 'crlf-normalize';
proxy(superagent);
const logger = new Logger('remote/loj');
@@ -303,12 +304,149 @@ export default class LibreojProvider implements IBasicProvider {
});
}
+ const parse = (str: string) => crlf(str, LF);
+
+ const getSubtaskStatusDisplayText = (testcases: any): string => {
+ let result: string = null;
+
+ for (const testcase of testcases) {
+ if (!testcase.testcaseHash) {
+ result = 'Skipped';
+
+ break;
+ } else if (
+ body.progress.testcaseResult[testcase.testcaseHash].status !==
+ 'Accepted'
+ ) {
+ result = body.progress.testcaseResult[testcase.testcaseHash].status;
+
+ break;
+ }
+ }
+
+ result ||= 'Accepted';
+ result =
+ VERDICT[
+ Object.keys(VERDICT).find(k => normalize(result).includes(k))
+ ];
+
+ return result;
+ };
+
+ const getTestcaseBlock = (id: string, index: number): string => {
+ const testcase = body.progress.testcaseResult[id];
+
+ if (!testcase) return '';
+
+ const status =
+ VERDICT[
+ Object.keys(VERDICT).find(k =>
+ normalize(testcase.status).includes(k)
+ )
+ ];
+ let test_info = '';
+
+ test_info += ``;
+
+ if (testcase.input) {
+ if (typeof testcase.input === 'string') {
+ test_info += `${parse(testcase.input)}\n`;
+ } else {
+ test_info += `${parse(testcase.input.data)}\n\n(${
+ testcase.input.omittedLength
+ } bytes omitted)\n`;
+ }
+ }
+
+ if (testcase.userOutput) {
+ if (typeof testcase.userOutput === 'string') {
+ test_info += `${parse(testcase.userOutput)}\n`;
+ } else {
+ test_info += `${parse(testcase.userOutput.data)}\n\n(${
+ testcase.userOutput.omittedLength
+ } bytes omitted)\n`;
+ }
+ }
+
+ if (testcase.output) {
+ if (typeof testcase.output === 'string') {
+ test_info += `${parse(testcase.output)}\n`;
+ } else {
+ test_info += `${parse(testcase.output.data)}\n\n(${
+ testcase.output.omittedLength
+ } bytes omitted)\n`;
+ }
+ }
+
+ if (testcase.checkerMessage) {
+ if (typeof testcase.checkerMessage === 'string') {
+ test_info += `${parse(testcase.checkerMessage)}\n`;
+ } else {
+ test_info += `${parse(testcase.checkerMessage.data)}\n\n(${
+ testcase.checkerMessage.omittedLength
+ } bytes omitted)\n`;
+ }
+ }
+
+ test_info += '';
+
+ return test_info;
+ };
+
+ let details = '';
+
+ details += `REMOTE_SUBMISSION_ID = ${id}\nVERDICT = ${status}`;
+
+ // Samples
+ if (body.progress.samples) {
+ details += `${body.progress.samples
+ .map((item, index) =>
+ item.testcaseHash
+ ? getTestcaseBlock(item.testcaseHash, index)
+ : ``
+ )
+ .join('\n')}`;
+ }
+
+ // Tests
+ if (body.progress.subtasks.length === 1) {
+ details += `${body.progress.subtasks[0].testcases
+ .map((item, index) =>
+ item.testcaseHash
+ ? getTestcaseBlock(item.testcaseHash, index)
+ : ``
+ )
+ .join('\n')}`;
+ } else {
+ details += `${body.progress.subtasks
+ .map(
+ (subtask, index) =>
+ `${subtask.testcases
+ .map((item, index) =>
+ item.testcaseHash
+ ? getTestcaseBlock(item.testcaseHash, index)
+ : ``
+ )
+ .join('\n')}`
+ )
+ .join('\n')}`;
+ }
+
return await end({
id,
status: body.meta.status,
score: body.meta.score,
time: body.meta.timeUsed,
memory: body.meta.memoryUsed,
+ details: `
${details}
`,
});
}
}
diff --git a/web/app/libs/uoj-html-lib.php b/web/app/libs/uoj-html-lib.php
index 15bb957..a8224fa 100644
--- a/web/app/libs/uoj-html-lib.php
+++ b/web/app/libs/uoj-html-lib.php
@@ -465,6 +465,7 @@ class JudgmentDetailsPrinter {
echo '';
} elseif ($node->nodeName == 'subtask') {
$subtask_info = $node->getAttribute('info');
+ $subtask_title = $node->getAttribute('title');
$subtask_num = $node->getAttribute('num');
$subtask_score = $node->getAttribute('score');
$subtask_time = $this->_get_attr($node, 'time', -1);
@@ -482,7 +483,11 @@ class JudgmentDetailsPrinter {
echo '';
echo '
';
- echo '
', 'Subtask #', $subtask_num, ': ', '
';
+ if ($subtask_title !== '') {
+ echo '', $subtask_title, ': ', '
';
+ } else {
+ echo '', 'Subtask #', $subtask_num, ': ', '
';
+ }
echo '';
if ($this->styler->show_score && $subtask_score !== '') {
@@ -494,7 +499,7 @@ class JudgmentDetailsPrinter {
echo htmlspecialchars($subtask_info);
echo '
';
} else {
- echo '';
+ echo '
';
echo $this->styler->getTestInfoIcon($subtask_info);
echo htmlspecialchars($subtask_info);
echo '
';
@@ -541,6 +546,9 @@ class JudgmentDetailsPrinter {
$accordion_parent .= "_collapse_subtask_{$this->subtask_num}_accordion";
}
$accordion_collapse = "{$accordion_parent}_collapse_test_{$test_num}";
+ if ($this->subtask_num != null) {
+ $accordion_collapse .= "_in_subtask_{$this->subtask_num}";
+ }
if (!$this->styler->shouldFadeDetails($test_info)) {
echo '