>(
+ {
+ RUNTIME_ERROR: 'Runtime Error',
+ WRONG_ANSWER: 'Wrong Answer',
+ OK: 'Accepted',
+ COMPILING: 'Compiling',
+ TIME_LIMIT_EXCEEDED: 'Time Limit Exceeded',
+ MEMORY_LIMIT_EXCEEDED: 'Memory Limit Exceeded',
+ IDLENESS_LIMIT_EXCEEDED: 'Idleness Limit Exceeded',
+ ACCEPTED: 'Accepted',
+ PRESENTATION_ERROR: 'Wrong Answer',
+ OUTPUT_LIMIT_EXCEEDED: 'Output Limit Exceeded',
+ EXTRA_TEST_PASSED: 'Accepted',
+ COMPILE_ERROR: 'Compile Error',
+ 'RUNNING_&_JUDGING': 'Judging',
+
+ // Codeforces
+ 'HAPPY_NEW_YEAR!': 'Accepted',
+ },
+ {
+ get(self, key) {
+ if (typeof key === 'symbol') return null;
+ key = normalize(key);
+ if (self[key]) return self[key];
+ return null;
+ },
+ }
+);
diff --git a/remote_judger/src/vjudge.ts b/remote_judger/src/vjudge.ts
new file mode 100644
index 0000000..fb9e900
--- /dev/null
+++ b/remote_judger/src/vjudge.ts
@@ -0,0 +1,155 @@
+import type { BasicProvider, IBasicProvider, RemoteAccount } from './interface';
+import * as Time from './utils/time';
+import Logger from './utils/logger';
+import htmlspecialchars from './utils/htmlspecialchars';
+
+const logger = new Logger('vjudge');
+
+class AccountService {
+ api: IBasicProvider;
+
+ constructor(
+ public Provider: BasicProvider,
+ public account: RemoteAccount,
+ private request: any
+ ) {
+ this.api = new Provider(account);
+ this.main().catch(e =>
+ logger.error(`Error occured in ${account.type}/${account.handle}`, e)
+ );
+ }
+
+ async judge(
+ id: number,
+ problem_id: string,
+ language: string,
+ code: string,
+ judge_time: string
+ ) {
+ const next = async payload => {
+ return await this.request('/submit', {
+ 'update-status': true,
+ fetch_new: false,
+ id,
+ status: `Judging Test #${payload.test_id}`,
+ });
+ };
+
+ const end = async payload => {
+ if (payload.error) {
+ return await this.request('/submit', {
+ submit: true,
+ fetch_new: false,
+ id,
+ result: JSON.stringify({
+ status: 'Judged',
+ score: 0,
+ error: payload.status,
+ details:
+ '' +
+ `ID = ${payload.id || 'None'}` +
+ `${htmlspecialchars(payload.message)}` +
+ '
',
+ }),
+ judge_time,
+ });
+ }
+
+ return await this.request('/submit', {
+ submit: true,
+ fetch_new: false,
+ id,
+ result: JSON.stringify({
+ status: 'Judged',
+ score: payload.score,
+ time: payload.time,
+ memory: payload.memory,
+ details:
+ '' +
+ `ID = ${payload.id || 'None'}` +
+ `VERDICT = ${payload.status}` +
+ '
',
+ }),
+ judge_time,
+ });
+ };
+
+ try {
+ const rid = await this.api.submitProblem(
+ problem_id,
+ language,
+ code,
+ id,
+ next,
+ end
+ );
+
+ if (!rid) return;
+
+ await this.api.waitForSubmission(rid, next, end);
+ } catch (e) {
+ logger.error(e);
+ await end({ error: true, message: e.message });
+ }
+ }
+
+ async login() {
+ const login = await this.api.ensureLogin();
+ if (login === true) {
+ logger.info(`${this.account.type}/${this.account.handle}: logged in`);
+ return true;
+ }
+ logger.warn(
+ `${this.account.type}/${this.account.handle}: login fail`,
+ login || ''
+ );
+ return false;
+ }
+
+ async main() {
+ const res = await this.login();
+ if (!res) return;
+ setInterval(() => this.login(), Time.hour);
+ }
+}
+
+class VJudge {
+ private providers: Record = {};
+
+ constructor(private request: any) {}
+
+ async addProvider(type: string) {
+ if (this.providers[type]) throw new Error(`duplicate provider ${type}`);
+ const provider = await import(`./providers/${type}`);
+ const account = provider.getAccountInfoFromEnv();
+
+ if (!account) throw new Error(`no account info for ${type}`);
+
+ this.providers[type] = new AccountService(
+ provider.default,
+ account,
+ this.request
+ );
+ }
+
+ async judge(
+ id: number,
+ type: string,
+ problem_id: string,
+ language: string,
+ code: string,
+ judge_time: string
+ ) {
+ if (!this.providers[type]) throw new Error(`no provider ${type}`);
+
+ this.providers[type].judge(id, problem_id, language, code, judge_time);
+ }
+}
+
+export async function apply(request: any) {
+ const vjudge = new VJudge(request);
+
+ await vjudge.addProvider('codeforces');
+
+ return vjudge;
+}
diff --git a/remote_judger/tsconfig.json b/remote_judger/tsconfig.json
index 6eaa6c6..48b6c8c 100644
--- a/remote_judger/tsconfig.json
+++ b/remote_judger/tsconfig.json
@@ -13,9 +13,6 @@
"isolatedModules": true,
"incremental": true,
"baseUrl": ".",
- "paths": {
- "@/*": ["src/*"]
- },
"outDir": "./dist"
},
"include": ["**/*.ts"],
diff --git a/web/app/libs/uoj-html-lib.php b/web/app/libs/uoj-html-lib.php
index 02242c0..3de8d1e 100644
--- a/web/app/libs/uoj-html-lib.php
+++ b/web/app/libs/uoj-html-lib.php
@@ -687,7 +687,7 @@ class JudgmentDetailsPrinter {
}
echo '', $node->getAttribute("title"), ":
";
}
- echo '', "\n";
+ echo '', "\n";
$this->_print_c($node);
echo "\n
";
echo '';