icoa-cli 2.19.34 → 2.19.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/ai4ctf.js +96 -66
- package/dist/commands/ctf4ai-demo.js +6 -4
- package/dist/commands/exam.js +3 -3
- package/dist/lib/i18n.d.ts +50 -2
- package/dist/lib/i18n.js +99 -156
- package/package.json +1 -1
package/dist/commands/ai4ctf.js
CHANGED
|
@@ -17,6 +17,10 @@ function getChallengeContext() {
|
|
|
17
17
|
let chatActive = false;
|
|
18
18
|
let chatSession = null;
|
|
19
19
|
let chatTokensUsed = 0;
|
|
20
|
+
// Set true when the user burns through DEMO_TOKEN_CAP without solving. The
|
|
21
|
+
// chat session stays alive so `!<shell>` and `submit <flag>` still work, but
|
|
22
|
+
// further AI messages are blocked. See the reveal path in handleChatMessage.
|
|
23
|
+
let tokensLocked = false;
|
|
20
24
|
const DEMO_TOKEN_CAP = 5000;
|
|
21
25
|
export function isChatActive() {
|
|
22
26
|
return chatActive;
|
|
@@ -39,36 +43,45 @@ const DEMO_FLAG = 'icoa{w3lc0me_2_ai4ctf}';
|
|
|
39
43
|
// already enough. Instead c explains the hint principle and reminds the
|
|
40
44
|
// user how to run a shell command inside ai4ctf (the `!` prefix).
|
|
41
45
|
// This mirrors real competition behavior where trivial challenges cap at hint b.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
46
|
+
// Multi-line hint bodies live in i18n.ts (ai4ctfHintABody/BBody/CBody).
|
|
47
|
+
// Shown when the user hits the 5000-token demo cap without solving. Keeps
|
|
48
|
+
// the session alive (no chatActive=false) so they can still paste the shell
|
|
49
|
+
// command below and then `submit <flag>`.
|
|
50
|
+
function showTokenCapReveal() {
|
|
51
|
+
console.log();
|
|
52
|
+
console.log(chalk.yellow(' ─────────────────────────────────────────────'));
|
|
53
|
+
console.log(chalk.bold.yellow(` ${t('ai4ctfRevealTitle')}`));
|
|
54
|
+
console.log(chalk.yellow(' ─────────────────────────────────────────────'));
|
|
55
|
+
console.log();
|
|
56
|
+
for (const line of t('ai4ctfRevealBody').split('\n')) {
|
|
57
|
+
if (line === '')
|
|
58
|
+
console.log();
|
|
59
|
+
else
|
|
60
|
+
console.log(chalk.white(' ' + line));
|
|
61
|
+
}
|
|
62
|
+
console.log();
|
|
63
|
+
console.log(chalk.cyan(' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
64
|
+
console.log();
|
|
65
|
+
console.log(chalk.white(` ${t('ai4ctfRevealSeeFlag')}`));
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(chalk.green(' icoa{w3lc0me_2_ai4ctf}'));
|
|
68
|
+
console.log();
|
|
69
|
+
console.log(chalk.white(` ${t('ai4ctfRevealThenSubmit')}`));
|
|
70
|
+
console.log();
|
|
71
|
+
console.log(chalk.cyan(' submit icoa{w3lc0me_2_ai4ctf}'));
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(chalk.gray(` ${t('ai4ctfRevealLockNote')}`));
|
|
74
|
+
console.log();
|
|
75
|
+
}
|
|
64
76
|
function showDemoHint(tier) {
|
|
65
77
|
const title = tier === 'a' ? t('ai4ctfHintA') : tier === 'b' ? t('ai4ctfHintB') : t('ai4ctfHintC');
|
|
78
|
+
const body = tier === 'a' ? t('ai4ctfHintABody') : tier === 'b' ? t('ai4ctfHintBBody') : t('ai4ctfHintCBody');
|
|
66
79
|
const tierLabel = `Hint ${tier.toUpperCase()}`;
|
|
67
80
|
const color = tier === 'a' ? chalk.green : tier === 'b' ? chalk.yellow : chalk.red;
|
|
68
81
|
console.log();
|
|
69
82
|
console.log(color.bold(` ▸ ${tierLabel} `) + chalk.gray(title));
|
|
70
83
|
console.log();
|
|
71
|
-
for (const line of
|
|
84
|
+
for (const line of body.split('\n')) {
|
|
72
85
|
if (line === '')
|
|
73
86
|
console.log();
|
|
74
87
|
else
|
|
@@ -76,11 +89,11 @@ function showDemoHint(tier) {
|
|
|
76
89
|
}
|
|
77
90
|
console.log();
|
|
78
91
|
if (tier === 'a') {
|
|
79
|
-
console.log(chalk.gray(
|
|
92
|
+
console.log(chalk.gray(` ${t('ai4ctfHintNextA')} `) + chalk.cyan('hint b'));
|
|
80
93
|
console.log();
|
|
81
94
|
}
|
|
82
95
|
else if (tier === 'b') {
|
|
83
|
-
console.log(chalk.gray(
|
|
96
|
+
console.log(chalk.gray(` ${t('ai4ctfHintNextB')} `) + chalk.cyan('hint c'));
|
|
84
97
|
console.log();
|
|
85
98
|
}
|
|
86
99
|
// No trailing CTA after hint c — the content itself explains everything.
|
|
@@ -125,41 +138,53 @@ export async function handleChatMessage(input) {
|
|
|
125
138
|
await sleep(1500);
|
|
126
139
|
console.log();
|
|
127
140
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
128
|
-
console.log(chalk.bold.white(
|
|
141
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWrapTitle')}`));
|
|
129
142
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
130
143
|
console.log();
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
console.log(chalk.
|
|
134
|
-
|
|
144
|
+
const wrap1Head = t('ai4ctfWrapLine1Head');
|
|
145
|
+
const wrap1Body = t('ai4ctfWrapLine1Body');
|
|
146
|
+
console.log(chalk.white(` 1. ${wrap1Head} `) + chalk.gray(wrap1Body.split('\n')[0] || ''));
|
|
147
|
+
for (const line of wrap1Body.split('\n').slice(1)) {
|
|
148
|
+
if (line.trim())
|
|
149
|
+
console.log(chalk.gray(' ' + line.replace(/\{thinking\}/g, 'thinking')));
|
|
150
|
+
}
|
|
135
151
|
console.log();
|
|
136
|
-
console.log(chalk.white(
|
|
152
|
+
console.log(chalk.white(` 2. ${t('ai4ctfWrapLine2Head')} `) + chalk.gray(t('ai4ctfWrapLine2Body')));
|
|
137
153
|
console.log();
|
|
138
154
|
console.log(chalk.cyan(' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
139
155
|
console.log();
|
|
140
156
|
await sleep(2000);
|
|
141
157
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
142
|
-
console.log(chalk.bold.white(
|
|
158
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWrapQuotasTitle')}`));
|
|
143
159
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
144
160
|
console.log();
|
|
145
|
-
console.log(chalk.yellow(' hint a ') + chalk.white('
|
|
146
|
-
console.log(chalk.yellow(' hint b ') + chalk.white('
|
|
147
|
-
console.log(chalk.yellow(' hint c ') + chalk.white('
|
|
161
|
+
console.log(chalk.yellow(' hint a ') + chalk.white(t('ai4ctfWrapQuotaA').padEnd(26)) + chalk.gray(t('ai4ctfWrapQuotaAHint')));
|
|
162
|
+
console.log(chalk.yellow(' hint b ') + chalk.white(t('ai4ctfWrapQuotaB').padEnd(26)) + chalk.gray(t('ai4ctfWrapQuotaBHint')));
|
|
163
|
+
console.log(chalk.yellow(' hint c ') + chalk.white(t('ai4ctfWrapQuotaC').padEnd(26)) + chalk.gray(t('ai4ctfWrapQuotaCHint')));
|
|
148
164
|
console.log();
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
165
|
+
for (const line of t('ai4ctfWrapQuotaFooter').split('\n')) {
|
|
166
|
+
console.log(chalk.gray(' ' + line));
|
|
167
|
+
}
|
|
152
168
|
console.log();
|
|
153
169
|
await sleep(2000);
|
|
154
170
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
155
|
-
console.log(chalk.bold.white(
|
|
171
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWrapNextTitle')} `) + chalk.red.bold('ctf4ai') + chalk.white(` — ${t('ai4ctfWrapNextSub')}`));
|
|
156
172
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
157
173
|
console.log();
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
174
|
+
const nextBody = t('ai4ctfWrapNextBody');
|
|
175
|
+
const noProg = t('ai4ctfWrapNoProg');
|
|
176
|
+
const lines = nextBody.split('\n');
|
|
177
|
+
// First line contains the {noProg} placeholder to bold-emphasize.
|
|
178
|
+
if (lines[0]) {
|
|
179
|
+
const [before, after] = lines[0].split('{noProg}');
|
|
180
|
+
console.log(chalk.white(' ' + (before || '')) + chalk.bold.white(noProg) + chalk.white(after || ''));
|
|
181
|
+
}
|
|
182
|
+
for (const line of lines.slice(1)) {
|
|
183
|
+
if (line.trim())
|
|
184
|
+
console.log(chalk.white(' ' + line));
|
|
185
|
+
}
|
|
161
186
|
console.log();
|
|
162
|
-
console.log(chalk.gray(
|
|
187
|
+
console.log(chalk.gray(` ${t('ai4ctfWrapTypeCtf4ai')} `) + chalk.bold.red('ctf4ai'));
|
|
163
188
|
console.log();
|
|
164
189
|
return 'exit';
|
|
165
190
|
}
|
|
@@ -214,12 +239,14 @@ export async function handleChatMessage(input) {
|
|
|
214
239
|
console.log();
|
|
215
240
|
return 'exit';
|
|
216
241
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
//
|
|
242
|
+
// Token cap: first hit → reveal the answer, lock AI, but keep the session
|
|
243
|
+
// alive so the user can still paste the shell command and then submit.
|
|
244
|
+
// `tokensLocked` prevents any further sendMessage calls.
|
|
245
|
+
if (!tokensLocked && chatTokensUsed >= DEMO_TOKEN_CAP) {
|
|
246
|
+
tokensLocked = true;
|
|
247
|
+
// Report the token-cap session once (solved:false). If the user then
|
|
248
|
+
// submits the revealed flag, the submit-success path fires another POST
|
|
249
|
+
// with solved:true which is the canonical record.
|
|
223
250
|
fetch('https://practice.icoa2026.au/api/icoa/demo-stats', {
|
|
224
251
|
method: 'POST',
|
|
225
252
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -229,16 +256,18 @@ export async function handleChatMessage(input) {
|
|
|
229
256
|
console.log();
|
|
230
257
|
console.log(chalk.yellow(` ${t('tokenLimit')}`));
|
|
231
258
|
drawTokenBar();
|
|
259
|
+
showTokenCapReveal();
|
|
260
|
+
return 'continue';
|
|
261
|
+
}
|
|
262
|
+
// If AI is locked (post-reveal), bounce any non-shell, non-submit input
|
|
263
|
+
// back to the user with a reminder of what actually works now.
|
|
264
|
+
if (tokensLocked) {
|
|
232
265
|
console.log();
|
|
233
|
-
console.log(chalk.
|
|
234
|
-
console.log(chalk.
|
|
235
|
-
console.log(chalk.gray(` ${t('
|
|
236
|
-
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (gemma-4-31b-it)`));
|
|
237
|
-
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
238
|
-
console.log();
|
|
239
|
-
console.log(chalk.white(` ${t('ai4ctfNext')}`));
|
|
266
|
+
console.log(chalk.yellow(` ${t('ai4ctfLockedTitle')}`));
|
|
267
|
+
console.log(chalk.gray(` ${t('ai4ctfLockedUse')} `) + chalk.cyan('!echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
268
|
+
console.log(chalk.gray(` ${t('ai4ctfLockedThen')} `) + chalk.cyan('submit icoa{w3lc0me_2_ai4ctf}'));
|
|
240
269
|
console.log();
|
|
241
|
-
return '
|
|
270
|
+
return 'continue';
|
|
242
271
|
}
|
|
243
272
|
console.log(chalk.gray(` ${t('ai4ctfThinking')}`));
|
|
244
273
|
try {
|
|
@@ -280,6 +309,7 @@ export function registerAi4ctfCommand(program) {
|
|
|
280
309
|
}
|
|
281
310
|
chatActive = true;
|
|
282
311
|
chatTokensUsed = 0;
|
|
312
|
+
tokensLocked = false;
|
|
283
313
|
// Guided welcome
|
|
284
314
|
console.log();
|
|
285
315
|
console.log(chalk.green.bold(` ═══ ${t('ai4ctfTitle')} ═══`));
|
|
@@ -308,19 +338,19 @@ export function registerAi4ctfCommand(program) {
|
|
|
308
338
|
console.log(chalk.gray(` ${t('ai4ctfHintCUses')}`));
|
|
309
339
|
console.log();
|
|
310
340
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
311
|
-
console.log(chalk.bold.white(
|
|
312
|
-
console.log(' ' + chalk.cyan('hint a') + chalk.gray(
|
|
313
|
-
console.log(' ' + chalk.cyan('hint b') + chalk.gray(
|
|
314
|
-
console.log(' ' + chalk.cyan('hint c') + chalk.gray(
|
|
315
|
-
console.log(chalk.gray(
|
|
341
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWelcomeCta')}`));
|
|
342
|
+
console.log(' ' + chalk.cyan('hint a') + chalk.gray(` → ${t('ai4ctfHintNudge')}`));
|
|
343
|
+
console.log(' ' + chalk.cyan('hint b') + chalk.gray(` → ${t('ai4ctfHintTechnique')}`));
|
|
344
|
+
console.log(' ' + chalk.cyan('hint c') + chalk.gray(` → ${t('ai4ctfHintPrinciple')}`));
|
|
345
|
+
console.log(chalk.gray(` ${t('ai4ctfWelcomeNoReveal')}`));
|
|
316
346
|
console.log();
|
|
317
|
-
console.log(chalk.white(
|
|
318
|
-
console.log(chalk.gray(
|
|
347
|
+
console.log(chalk.white(` ${t('ai4ctfOrChat')}`));
|
|
348
|
+
console.log(chalk.gray(` ${t('ai4ctfOrChatExample')} `) + chalk.white('"what encoding is this?"'));
|
|
319
349
|
console.log();
|
|
320
350
|
console.log(chalk.yellow(` ${t('ai4ctfCommands')}`));
|
|
321
|
-
console.log(chalk.white(' hint a / b / c ') + chalk.gray(
|
|
351
|
+
console.log(chalk.white(' hint a / b / c ') + chalk.gray(t('ai4ctfCmdHintLine')));
|
|
322
352
|
console.log(chalk.white(' submit <flag> ') + chalk.gray(t('ai4ctfSubmitCmd')));
|
|
323
|
-
console.log(chalk.white(' !<shell cmd> ') + chalk.gray('
|
|
353
|
+
console.log(chalk.white(' !<shell cmd> ') + chalk.gray(t('ai4ctfCmdShellLine')));
|
|
324
354
|
console.log(chalk.gray(' e.g. ') + chalk.white('!echo aWNv... | base64 -d'));
|
|
325
355
|
console.log(chalk.gray(` exit ${t('ai4ctfEndSession')}`));
|
|
326
356
|
console.log();
|
|
@@ -50,18 +50,20 @@ function printDemoReport(ctf4aiSolved, ctf4aiTokens) {
|
|
|
50
50
|
console.log(chalk.white(` ${t('theoryDone2')}`));
|
|
51
51
|
console.log();
|
|
52
52
|
if (hasWrongAnswers) {
|
|
53
|
-
console.log(chalk.white(
|
|
53
|
+
console.log(chalk.white(` 💪 ${t('reportRetryCta')} `) + chalk.bold.cyan('retry'));
|
|
54
54
|
console.log();
|
|
55
55
|
}
|
|
56
56
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
57
57
|
console.log(chalk.white(` ${t('reportReady')}`));
|
|
58
58
|
if (hasWrongAnswers) {
|
|
59
|
-
|
|
59
|
+
const n = retryQueue.length;
|
|
60
|
+
const tmpl = n === 1 ? t('reportRetryWrongN') : t('reportRetryWrongNPlural');
|
|
61
|
+
console.log(chalk.cyan(' retry') + chalk.gray(` ${tmpl.replace('{n}', String(n))}`));
|
|
60
62
|
}
|
|
61
|
-
console.log(chalk.white(' back') + chalk.gray(`
|
|
63
|
+
console.log(chalk.white(' back') + chalk.gray(` ${t('reportBackHint')}`));
|
|
62
64
|
console.log(chalk.white(' demo') + chalk.gray(` ${t('reportDemo')}`));
|
|
63
65
|
console.log(chalk.white(' nations') + chalk.gray(` ${t('reportNations')}`));
|
|
64
|
-
console.log(chalk.white(' about') + chalk.gray(` ${t('
|
|
66
|
+
console.log(chalk.white(' about') + chalk.gray(` ${t('reportAboutHint')}`));
|
|
65
67
|
console.log();
|
|
66
68
|
console.log(chalk.yellow(' ICOA 2026 · Sydney, Australia · Jun 27 - Jul 2'));
|
|
67
69
|
console.log(chalk.cyan.underline(' https://icoa2026.au'));
|
package/dist/commands/exam.js
CHANGED
|
@@ -260,8 +260,8 @@ function printQuestion(q, answer) {
|
|
|
260
260
|
console.log(chalk.yellow(' A/B/C/D') + chalk.gray(` ${t('answerThis')}`));
|
|
261
261
|
console.log(chalk.yellow(' help') + ' ' + helpLabel);
|
|
262
262
|
console.log(chalk.yellow(' next') + chalk.gray(' / ') + chalk.yellow('prev') + chalk.gray(` ${t('htpNav')}`));
|
|
263
|
-
console.log(chalk.yellow(` exam q 1..${total}`) + chalk.gray(
|
|
264
|
-
console.log(chalk.yellow(' exam review') + chalk.gray(
|
|
263
|
+
console.log(chalk.yellow(` exam q 1..${total}`) + chalk.gray(` ${t('htpJump')}`));
|
|
264
|
+
console.log(chalk.yellow(' exam review') + chalk.gray(` ${t('htpReview')}`));
|
|
265
265
|
console.log(chalk.yellow(' back') + chalk.gray(` ${t('htpBack')}`));
|
|
266
266
|
console.log(chalk.yellow(' lang') + chalk.gray(` ${t('htpLang')}`));
|
|
267
267
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
@@ -929,7 +929,7 @@ export function registerExamCommand(program) {
|
|
|
929
929
|
await sleep(2000);
|
|
930
930
|
console.log();
|
|
931
931
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
932
|
-
console.log(chalk.white(
|
|
932
|
+
console.log(chalk.white(` ${t('nextLabel')} `) + chalk.bold.green('ai4ctf') + chalk.gray(` — ${t('ai4ctfDesc')}`));
|
|
933
933
|
console.log(chalk.gray(` ${t('ai4ctfSub')}`));
|
|
934
934
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
935
935
|
console.log();
|
package/dist/lib/i18n.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
type Strings = typeof EN
|
|
2
|
-
declare const EN: {
|
|
1
|
+
type Strings = Partial<typeof EN>;
|
|
2
|
+
export declare const EN: {
|
|
3
3
|
howToPlay: string;
|
|
4
4
|
htpAnswer: string;
|
|
5
5
|
htpHelp: string;
|
|
@@ -139,6 +139,54 @@ declare const EN: {
|
|
|
139
139
|
forNational: string;
|
|
140
140
|
viewRegions: string;
|
|
141
141
|
enterExam: string;
|
|
142
|
+
htpJump: string;
|
|
143
|
+
htpReview: string;
|
|
144
|
+
nextLabel: string;
|
|
145
|
+
reportRetryCta: string;
|
|
146
|
+
reportRetryWrongN: string;
|
|
147
|
+
reportRetryWrongNPlural: string;
|
|
148
|
+
reportBackHint: string;
|
|
149
|
+
reportAboutHint: string;
|
|
150
|
+
ai4ctfWelcomeCta: string;
|
|
151
|
+
ai4ctfHintNudge: string;
|
|
152
|
+
ai4ctfHintTechnique: string;
|
|
153
|
+
ai4ctfHintPrinciple: string;
|
|
154
|
+
ai4ctfWelcomeNoReveal: string;
|
|
155
|
+
ai4ctfOrChat: string;
|
|
156
|
+
ai4ctfOrChatExample: string;
|
|
157
|
+
ai4ctfCmdHintLine: string;
|
|
158
|
+
ai4ctfCmdShellLine: string;
|
|
159
|
+
ai4ctfHintABody: string;
|
|
160
|
+
ai4ctfHintBBody: string;
|
|
161
|
+
ai4ctfHintCBody: string;
|
|
162
|
+
ai4ctfHintNextA: string;
|
|
163
|
+
ai4ctfHintNextB: string;
|
|
164
|
+
ai4ctfWrapTitle: string;
|
|
165
|
+
ai4ctfWrapLine1Head: string;
|
|
166
|
+
ai4ctfWrapLine1Body: string;
|
|
167
|
+
ai4ctfWrapLine2Head: string;
|
|
168
|
+
ai4ctfWrapLine2Body: string;
|
|
169
|
+
ai4ctfWrapQuotasTitle: string;
|
|
170
|
+
ai4ctfWrapQuotaA: string;
|
|
171
|
+
ai4ctfWrapQuotaAHint: string;
|
|
172
|
+
ai4ctfWrapQuotaB: string;
|
|
173
|
+
ai4ctfWrapQuotaBHint: string;
|
|
174
|
+
ai4ctfWrapQuotaC: string;
|
|
175
|
+
ai4ctfWrapQuotaCHint: string;
|
|
176
|
+
ai4ctfWrapQuotaFooter: string;
|
|
177
|
+
ai4ctfWrapNextTitle: string;
|
|
178
|
+
ai4ctfWrapNextSub: string;
|
|
179
|
+
ai4ctfWrapNextBody: string;
|
|
180
|
+
ai4ctfWrapNoProg: string;
|
|
181
|
+
ai4ctfWrapTypeCtf4ai: string;
|
|
182
|
+
ai4ctfRevealTitle: string;
|
|
183
|
+
ai4ctfRevealBody: string;
|
|
184
|
+
ai4ctfRevealSeeFlag: string;
|
|
185
|
+
ai4ctfRevealThenSubmit: string;
|
|
186
|
+
ai4ctfRevealLockNote: string;
|
|
187
|
+
ai4ctfLockedTitle: string;
|
|
188
|
+
ai4ctfLockedUse: string;
|
|
189
|
+
ai4ctfLockedThen: string;
|
|
142
190
|
};
|
|
143
191
|
export declare function t(key: keyof Strings): string;
|
|
144
192
|
export declare function hasFullTranslation(lang: string): boolean;
|