@xcpcio/core 0.52.0 → 0.53.0

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/index.cjs CHANGED
@@ -1,55 +1,312 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
3
+ const _ = require('lodash');
4
+ const chroma = require('chroma-js');
5
+ const colorDiff = require('color-diff');
5
6
  const types = require('@xcpcio/types');
7
+ const jsBase64 = require('js-base64');
6
8
  const dayjs = require('dayjs');
7
- const duration = require('dayjs/plugin/duration');
8
- const utc = require('dayjs/plugin/utc');
9
- const timezone = require('dayjs/plugin/timezone');
10
9
  const advancedFormat = require('dayjs/plugin/advancedFormat');
11
- const isSameOrBefore = require('dayjs/plugin/isSameOrBefore');
10
+ const duration = require('dayjs/plugin/duration');
12
11
  const isSameOrAfter = require('dayjs/plugin/isSameOrAfter');
12
+ const isSameOrBefore = require('dayjs/plugin/isSameOrBefore');
13
13
  const minMax = require('dayjs/plugin/minMax');
14
14
  const relativeTime = require('dayjs/plugin/relativeTime');
15
- const _ = require('lodash');
16
- const XLSX = require('xlsx-js-style');
15
+ const timezone = require('dayjs/plugin/timezone');
16
+ const utc = require('dayjs/plugin/utc');
17
17
  const stringWidth = require('string-width');
18
- const Papa = require('papaparse');
18
+ const XLSX = require('xlsx-js-style');
19
19
  const ordinal = require('ordinal');
20
- const chroma = require('chroma-js');
21
- const colorDiff = require('color-diff');
22
- const jsBase64 = require('js-base64');
20
+ const Papa = require('papaparse');
23
21
 
24
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
22
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
25
23
 
26
- function _interopNamespace(e) {
27
- if (e && e.__esModule) return e;
24
+ function _interopNamespaceCompat(e) {
25
+ if (e && typeof e === 'object' && 'default' in e) return e;
28
26
  const n = Object.create(null);
29
27
  if (e) {
30
28
  for (const k in e) {
31
29
  n[k] = e[k];
32
30
  }
33
31
  }
34
- n["default"] = e;
32
+ n.default = e;
35
33
  return n;
36
34
  }
37
35
 
38
- const dayjs__default = /*#__PURE__*/_interopDefaultLegacy(dayjs);
39
- const duration__default = /*#__PURE__*/_interopDefaultLegacy(duration);
40
- const utc__default = /*#__PURE__*/_interopDefaultLegacy(utc);
41
- const timezone__default = /*#__PURE__*/_interopDefaultLegacy(timezone);
42
- const advancedFormat__default = /*#__PURE__*/_interopDefaultLegacy(advancedFormat);
43
- const isSameOrBefore__default = /*#__PURE__*/_interopDefaultLegacy(isSameOrBefore);
44
- const isSameOrAfter__default = /*#__PURE__*/_interopDefaultLegacy(isSameOrAfter);
45
- const minMax__default = /*#__PURE__*/_interopDefaultLegacy(minMax);
46
- const relativeTime__default = /*#__PURE__*/_interopDefaultLegacy(relativeTime);
47
- const ___default = /*#__PURE__*/_interopDefaultLegacy(_);
48
- const XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
49
- const stringWidth__default = /*#__PURE__*/_interopDefaultLegacy(stringWidth);
50
- const Papa__default = /*#__PURE__*/_interopDefaultLegacy(Papa);
51
- const ordinal__default = /*#__PURE__*/_interopDefaultLegacy(ordinal);
52
- const chroma__default = /*#__PURE__*/_interopDefaultLegacy(chroma);
36
+ const ___default = /*#__PURE__*/_interopDefaultCompat(_);
37
+ const chroma__default = /*#__PURE__*/_interopDefaultCompat(chroma);
38
+ const dayjs__default = /*#__PURE__*/_interopDefaultCompat(dayjs);
39
+ const advancedFormat__default = /*#__PURE__*/_interopDefaultCompat(advancedFormat);
40
+ const duration__default = /*#__PURE__*/_interopDefaultCompat(duration);
41
+ const isSameOrAfter__default = /*#__PURE__*/_interopDefaultCompat(isSameOrAfter);
42
+ const isSameOrBefore__default = /*#__PURE__*/_interopDefaultCompat(isSameOrBefore);
43
+ const minMax__default = /*#__PURE__*/_interopDefaultCompat(minMax);
44
+ const relativeTime__default = /*#__PURE__*/_interopDefaultCompat(relativeTime);
45
+ const timezone__default = /*#__PURE__*/_interopDefaultCompat(timezone);
46
+ const utc__default = /*#__PURE__*/_interopDefaultCompat(utc);
47
+ const stringWidth__default = /*#__PURE__*/_interopDefaultCompat(stringWidth);
48
+ const XLSX__namespace = /*#__PURE__*/_interopNamespaceCompat(XLSX);
49
+ const ordinal__default = /*#__PURE__*/_interopDefaultCompat(ordinal);
50
+ const Papa__default = /*#__PURE__*/_interopDefaultCompat(Papa);
51
+
52
+ var __defProp$j = Object.defineProperty;
53
+ var __defNormalProp$j = (obj, key, value) => key in obj ? __defProp$j(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
54
+ var __publicField$j = (obj, key, value) => {
55
+ __defNormalProp$j(obj, typeof key !== "symbol" ? key + "" : key, value);
56
+ return value;
57
+ };
58
+ var MedalType = /* @__PURE__ */ ((MedalType2) => {
59
+ MedalType2["UNKNOWN"] = "Unknown";
60
+ MedalType2["GOLD"] = "Gold";
61
+ MedalType2["SILVER"] = "Silver";
62
+ MedalType2["BRONZE"] = "Bronze";
63
+ MedalType2["HONORABLE"] = "Honorable";
64
+ return MedalType2;
65
+ })(MedalType || {});
66
+ class Award {
67
+ constructor() {
68
+ __publicField$j(this, "medalType");
69
+ __publicField$j(this, "minRank");
70
+ __publicField$j(this, "maxRank");
71
+ this.medalType = "Unknown" /* UNKNOWN */;
72
+ this.minRank = 0;
73
+ this.maxRank = 0;
74
+ }
75
+ }
76
+ function isValidMedalType(medal) {
77
+ const validMedalType = [
78
+ "Gold" /* GOLD */,
79
+ "Silver" /* SILVER */,
80
+ "Bronze" /* BRONZE */,
81
+ "Honorable" /* HONORABLE */
82
+ ];
83
+ return validMedalType.includes(medal);
84
+ }
85
+
86
+ function calcDirt(attemptedNum, solvedNum) {
87
+ if (solvedNum === 0) {
88
+ return 0;
89
+ }
90
+ return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
91
+ }
92
+
93
+ function getWhiteOrBlackColorV1(background) {
94
+ const [R, G, B] = chroma__default(background).rgb();
95
+ const color = { R, G, B };
96
+ const palette = [
97
+ { R: 0, G: 0, B: 0 },
98
+ { R: 255, G: 255, B: 255 }
99
+ ];
100
+ const f = colorDiff.furthest(color, palette);
101
+ if (f.R === 0 && f.G === 0 && f.B === 0) {
102
+ return "#000";
103
+ } else {
104
+ return "#fff";
105
+ }
106
+ }
107
+ function getWhiteOrBlackColor(background) {
108
+ const [R, G, B] = chroma__default(background).rgb();
109
+ const brightness = (R * 299 + G * 587 + B * 114) / 1e3;
110
+ const threshold = 148;
111
+ return brightness <= threshold ? "#fff" : "#000";
112
+ }
113
+
114
+ dayjs__default.extend(duration__default);
115
+ dayjs__default.extend(utc__default);
116
+ dayjs__default.extend(timezone__default);
117
+ dayjs__default.extend(advancedFormat__default);
118
+ dayjs__default.extend(isSameOrBefore__default);
119
+ dayjs__default.extend(isSameOrAfter__default);
120
+ dayjs__default.extend(minMax__default);
121
+ dayjs__default.extend(relativeTime__default);
122
+ function createDayJS(time = void 0) {
123
+ if (time === void 0) {
124
+ return dayjs__default();
125
+ }
126
+ if (typeof time == "number" && String(time).length === 10) {
127
+ return dayjs__default.unix(time);
128
+ }
129
+ return dayjs__default(time);
130
+ }
131
+ function getTimestamp(time) {
132
+ if (typeof time === "number") {
133
+ return time;
134
+ }
135
+ return time.unix();
136
+ }
137
+ function getTimeDiff(seconds) {
138
+ const two = (a) => {
139
+ if (a < 10) {
140
+ return `0${a}`;
141
+ }
142
+ return String(a);
143
+ };
144
+ const h = Math.floor(seconds / 3600);
145
+ const m = Math.floor(seconds % 3600 / 60);
146
+ const s = seconds % 60;
147
+ return [two(h), two(m), two(s)].join(":");
148
+ }
149
+
150
+ var __defProp$i = Object.defineProperty;
151
+ var __defNormalProp$i = (obj, key, value) => key in obj ? __defProp$i(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
152
+ var __publicField$i = (obj, key, value) => {
153
+ __defNormalProp$i(obj, typeof key !== "symbol" ? key + "" : key, value);
154
+ return value;
155
+ };
156
+ class ProblemStatistics {
157
+ constructor() {
158
+ __publicField$i(this, "acceptedNum");
159
+ __publicField$i(this, "rejectedNum");
160
+ __publicField$i(this, "pendingNum");
161
+ __publicField$i(this, "submittedNum");
162
+ __publicField$i(this, "attemptedNum");
163
+ __publicField$i(this, "ignoreNum");
164
+ __publicField$i(this, "firstSolveSubmissions");
165
+ __publicField$i(this, "lastSolveSubmissions");
166
+ __publicField$i(this, "se");
167
+ this.acceptedNum = 0;
168
+ this.rejectedNum = 0;
169
+ this.pendingNum = 0;
170
+ this.submittedNum = 0;
171
+ this.attemptedNum = 0;
172
+ this.ignoreNum = 0;
173
+ this.se = 0;
174
+ this.firstSolveSubmissions = [];
175
+ this.lastSolveSubmissions = [];
176
+ }
177
+ reset() {
178
+ this.acceptedNum = 0;
179
+ this.rejectedNum = 0;
180
+ this.pendingNum = 0;
181
+ this.submittedNum = 0;
182
+ this.attemptedNum = 0;
183
+ this.ignoreNum = 0;
184
+ this.se = 0;
185
+ this.firstSolveSubmissions = [];
186
+ this.lastSolveSubmissions = [];
187
+ }
188
+ get dirt() {
189
+ if (this.acceptedNum === 0) {
190
+ return 0;
191
+ }
192
+ return calcDirt(this.attemptedNum, this.acceptedNum);
193
+ }
194
+ calcSE(totalTeams) {
195
+ const res = (totalTeams - this.acceptedNum) / totalTeams;
196
+ this.se = Math.round(res * 100) / 100;
197
+ return this.se;
198
+ }
199
+ }
200
+ class Problem {
201
+ constructor() {
202
+ __publicField$i(this, "id");
203
+ __publicField$i(this, "label");
204
+ __publicField$i(this, "name");
205
+ __publicField$i(this, "timeLimit");
206
+ __publicField$i(this, "memoryLimit");
207
+ __publicField$i(this, "balloonColor");
208
+ __publicField$i(this, "statistics");
209
+ this.id = "";
210
+ this.label = "";
211
+ this.name = "";
212
+ this.statistics = new ProblemStatistics();
213
+ this.balloonColor = {
214
+ background_color: "#a0f0a0",
215
+ color: "#000"
216
+ };
217
+ }
218
+ }
219
+ function createProblem(problemJSON) {
220
+ const p = new Problem();
221
+ p.id = String(problemJSON.id);
222
+ p.label = problemJSON.label;
223
+ p.name = problemJSON.name ?? "";
224
+ p.timeLimit = problemJSON.time_limit;
225
+ p.memoryLimit = problemJSON.memory_limit;
226
+ if (problemJSON.balloon_color) {
227
+ p.balloonColor = ___default.cloneDeep(problemJSON.balloon_color);
228
+ }
229
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
230
+ return p;
231
+ }
232
+ function createProblems(problemsJSON) {
233
+ return problemsJSON.map((pJSON) => createProblem(pJSON));
234
+ }
235
+ function createProblemsByProblemIds(problemIds, balloonColors) {
236
+ const problems = problemIds.map((label, index) => {
237
+ const p = new Problem();
238
+ p.id = String(index);
239
+ p.label = label;
240
+ return p;
241
+ });
242
+ if (balloonColors !== void 0 && balloonColors !== null) {
243
+ for (const index in balloonColors) {
244
+ problems[index].balloonColor = ___default.cloneDeep(balloonColors[index]);
245
+ }
246
+ }
247
+ problems.forEach((p) => {
248
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
249
+ });
250
+ return problems;
251
+ }
252
+ class TeamProblemStatistics {
253
+ constructor(options) {
254
+ __publicField$i(this, "isFirstSolved");
255
+ __publicField$i(this, "isSolved");
256
+ __publicField$i(this, "solvedTimestamp");
257
+ __publicField$i(this, "isSubmitted");
258
+ __publicField$i(this, "lastSubmitTimestamp");
259
+ __publicField$i(this, "failedCount");
260
+ __publicField$i(this, "pendingCount");
261
+ __publicField$i(this, "ignoreCount");
262
+ __publicField$i(this, "totalCount");
263
+ __publicField$i(this, "submissions");
264
+ __publicField$i(this, "problem");
265
+ __publicField$i(this, "contestPenalty");
266
+ this.isFirstSolved = options?.teamProblemStatistics?.isFirstSolved ?? false;
267
+ this.isSolved = options?.teamProblemStatistics?.isSolved ?? false;
268
+ this.solvedTimestamp = options?.teamProblemStatistics?.solvedTimestamp ?? 0;
269
+ this.isSubmitted = options?.teamProblemStatistics?.isSubmitted ?? false;
270
+ this.lastSubmitTimestamp = options?.teamProblemStatistics?.lastSubmitTimestamp ?? 0;
271
+ this.failedCount = options?.teamProblemStatistics?.failedCount ?? 0;
272
+ this.pendingCount = options?.teamProblemStatistics?.pendingCount ?? 0;
273
+ this.ignoreCount = options?.teamProblemStatistics?.ignoreCount ?? 0;
274
+ this.totalCount = options?.teamProblemStatistics?.totalCount ?? 0;
275
+ this.submissions = options?.teamProblemStatistics?.submissions ?? [];
276
+ this.problem = options?.teamProblemStatistics?.problem ?? new Problem();
277
+ this.contestPenalty = options?.teamProblemStatistics?.contestPenalty ?? 20 * 60;
278
+ }
279
+ get isAccepted() {
280
+ return this.isSolved;
281
+ }
282
+ get isWrongAnswer() {
283
+ return !this.isSolved && this.pendingCount === 0 && this.failedCount > 0;
284
+ }
285
+ get isPending() {
286
+ return !this.isSolved && this.pendingCount > 0;
287
+ }
288
+ get isUnSubmitted() {
289
+ return this.totalCount === 0;
290
+ }
291
+ get solvedTimestampToMinute() {
292
+ return Math.floor(this.solvedTimestamp / 60);
293
+ }
294
+ get penalty() {
295
+ if (this.isSolved === false) {
296
+ return 0;
297
+ }
298
+ return this.solvedTimestampToMinute * 60 + this.failedCount * this.contestPenalty;
299
+ }
300
+ get penaltyToMinute() {
301
+ return Math.floor(this.penalty / 60);
302
+ }
303
+ get penaltyInSecond() {
304
+ if (this.isSolved === false) {
305
+ return 0;
306
+ }
307
+ return this.solvedTimestamp + this.failedCount * this.contestPenalty;
308
+ }
309
+ }
53
310
 
54
311
  function stringToSubmissionStatus(status) {
55
312
  status = status.toUpperCase().replace(" ", "_");
@@ -173,1675 +430,1233 @@ function isNotCalculatedPenaltyStatus(status) {
173
430
  return isNotCalculatedPenaltyArray.includes(status);
174
431
  }
175
432
 
176
- dayjs__default.extend(duration__default);
177
- dayjs__default.extend(utc__default);
178
- dayjs__default.extend(timezone__default);
179
- dayjs__default.extend(advancedFormat__default);
180
- dayjs__default.extend(isSameOrBefore__default);
181
- dayjs__default.extend(isSameOrAfter__default);
182
- dayjs__default.extend(minMax__default);
183
- dayjs__default.extend(relativeTime__default);
184
- function createDayJS(time = void 0) {
185
- if (time === void 0) {
186
- return dayjs__default();
187
- }
188
- if (typeof time == "number" && String(time).length === 10) {
189
- return dayjs__default.unix(time);
190
- }
191
- return dayjs__default(time);
192
- }
193
- function getTimestamp(time) {
194
- if (typeof time === "number") {
195
- return time;
196
- }
197
- return time.unix();
198
- }
199
- function getTimeDiff(seconds) {
200
- const two = (a) => {
201
- if (a < 10) {
202
- return `0${a}`;
203
- }
204
- return String(a);
205
- };
206
- const h = Math.floor(seconds / 3600);
207
- const m = Math.floor(seconds % 3600 / 60);
208
- const s = seconds % 60;
209
- return [two(h), two(m), two(s)].join(":");
210
- }
211
-
212
- class CodeforcesGymGhostDATConverter {
433
+ var __defProp$h = Object.defineProperty;
434
+ var __defNormalProp$h = (obj, key, value) => key in obj ? __defProp$h(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
435
+ var __publicField$h = (obj, key, value) => {
436
+ __defNormalProp$h(obj, typeof key !== "symbol" ? key + "" : key, value);
437
+ return value;
438
+ };
439
+ class Submission {
213
440
  constructor() {
441
+ __publicField$h(this, "id");
442
+ __publicField$h(this, "teamId");
443
+ __publicField$h(this, "problemId");
444
+ __publicField$h(this, "timestamp");
445
+ __publicField$h(this, "timestampUnit");
446
+ __publicField$h(this, "time");
447
+ __publicField$h(this, "language");
448
+ __publicField$h(this, "reaction");
449
+ __publicField$h(this, "status", types.SubmissionStatus.UNKNOWN);
450
+ __publicField$h(this, "isIgnore", false);
451
+ __publicField$h(this, "isSolved", false);
452
+ __publicField$h(this, "isFirstSolved", false);
453
+ this.id = "";
454
+ this.teamId = "";
455
+ this.problemId = "";
456
+ this.timestamp = 0;
457
+ this.timestampUnit = "second";
214
458
  }
215
- convert(rank) {
216
- let res = "";
217
- res += `@contest "${rank.contest.name}"
218
- @contlen ${Math.floor(dayjs__default.duration(rank.contest.endTime.diff(rank.contest.startTime)).asMinutes())}
219
- @problems ${rank.contest.problems.length}
220
- @teams ${rank.teams.length + 100}
221
- @submissions ${rank.submissions.length}
222
- `;
223
- rank.contest.problems.forEach((p) => {
224
- res += `@p ${p.label},${p.label},20,0
225
- `;
226
- });
227
- let teamIndex = 1;
228
- const teamIdMap = /* @__PURE__ */ new Map();
229
- const submissionsIdMap = /* @__PURE__ */ new Map();
230
- rank.teams.forEach((team) => {
231
- let name = team.name;
232
- if (team.organization) {
233
- name = `${team.organization} - ${name}`;
234
- }
235
- if (team.members) {
236
- name = `${name} - ${team.membersToString}`;
237
- }
238
- res += `@t ${teamIndex},0,1,"${name}"
239
- `;
240
- teamIdMap.set(team.id, teamIndex);
241
- teamIndex++;
242
- {
243
- const mp = /* @__PURE__ */ new Map();
244
- rank.contest.problems.forEach((p) => {
245
- mp.set(p.id, 0);
246
- });
247
- submissionsIdMap.set(team.id, mp);
248
- }
249
- });
250
- for (let i = 0; i < 100; i++) {
251
- res += `@t ${teamIndex},0,1,"\u041F\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043A\u043E\u043C\u0430\u043D\u0434\u0443"
252
- `;
253
- teamIndex++;
254
- }
255
- rank.getSubmissions().forEach((submission) => {
256
- const teamId = submission.teamId;
257
- const problemId = submission.problemId;
258
- const problem = rank.contest.problemsMap.get(problemId);
259
- const teamIndex2 = teamIdMap.get(teamId);
260
- if (!problem) {
261
- return;
262
- }
263
- if (!teamIndex2) {
264
- return;
265
- }
266
- const status = this.submissionStatusToCodeforcesGymDatStatus(submission.status);
267
- submissionsIdMap.get(teamId).set(problemId, submissionsIdMap.get(teamId).get(problemId) + 1);
268
- res += `@s ${teamIndex2},${problem.label},${submissionsIdMap.get(teamId)?.get(problemId)},${submission.timestampToSecond},${status}
269
- `;
270
- });
271
- return res;
459
+ isAccepted() {
460
+ return isAccepted(this.status);
272
461
  }
273
- submissionStatusToCodeforcesGymDatStatus(status) {
274
- if (isAccepted(status)) {
275
- return "OK";
462
+ isRejected() {
463
+ return isRejected(this.status);
464
+ }
465
+ isPending() {
466
+ return isPending(this.status);
467
+ }
468
+ isNotCalculatedPenaltyStatus() {
469
+ return isNotCalculatedPenaltyStatus(this.status);
470
+ }
471
+ get timestampToMinute() {
472
+ if (this.timestampUnit === "nanosecond") {
473
+ return Math.floor(this.timestamp / 60 / 1e3 / 1e3 / 1e3);
276
474
  }
277
- if (status === types.SubmissionStatus.WRONG_ANSWER) {
278
- return "WA";
475
+ if (this.timestampUnit === "microsecond") {
476
+ return Math.floor(this.timestamp / 60 / 1e3 / 1e3);
279
477
  }
280
- if (status === types.SubmissionStatus.TIME_LIMIT_EXCEEDED) {
281
- return "TL";
478
+ if (this.timestampUnit === "millisecond") {
479
+ return Math.floor(this.timestamp / 60 / 1e3);
282
480
  }
283
- if (status === types.SubmissionStatus.MEMORY_LIMIT_EXCEEDED) {
284
- return "ML";
481
+ return Math.floor(this.timestamp / 60);
482
+ }
483
+ get timestampToSecond() {
484
+ if (this.timestampUnit === "nanosecond") {
485
+ return Math.floor(this.timestamp / 1e3 / 1e3 / 1e3);
285
486
  }
286
- if (status === types.SubmissionStatus.OUTPUT_LIMIT_EXCEEDED) {
287
- return "IL";
487
+ if (this.timestampUnit === "microsecond") {
488
+ return Math.floor(this.timestamp / 1e3 / 1e3);
288
489
  }
289
- if (status === types.SubmissionStatus.PRESENTATION_ERROR) {
290
- return "PE";
490
+ if (this.timestampUnit === "millisecond") {
491
+ return Math.floor(this.timestamp / 1e3);
291
492
  }
292
- if (status === types.SubmissionStatus.RUNTIME_ERROR) {
293
- return "RT";
493
+ return this.timestamp;
494
+ }
495
+ get timestampDisplayFormatWithSecond() {
496
+ const second = this.timestampToSecond;
497
+ const h = Math.floor(second / 3600);
498
+ const m = Math.floor(second % 3600 / 60);
499
+ const s = second % 60;
500
+ const f = (x) => x.toString().padStart(2, "0");
501
+ const res = `${f(h)}:${f(m)}:${f(s)}`;
502
+ return res;
503
+ }
504
+ get timestampDisplayFormatWithMilliSecond() {
505
+ let res = this.timestampDisplayFormatWithSecond;
506
+ if (this.timestampUnit === "millisecond") {
507
+ const fl = (this.timestamp % 1e3).toString().padStart(3, "0");
508
+ res += `.${fl}`;
294
509
  }
295
- if (status === types.SubmissionStatus.COMPILATION_ERROR || isNotCalculatedPenaltyStatus(status)) {
296
- return "CE";
510
+ return res;
511
+ }
512
+ static compare(lhs, rhs) {
513
+ if (lhs.timestamp !== rhs.timestamp) {
514
+ return lhs.timestamp - rhs.timestamp;
297
515
  }
298
- if (isPending(status)) {
299
- return "PD";
516
+ if (lhs.teamId === rhs.teamId) {
517
+ if (lhs.isAccepted() && !rhs.isAccepted()) {
518
+ return -1;
519
+ }
520
+ if (!lhs.isAccepted() && rhs.isAccepted()) {
521
+ return 1;
522
+ }
523
+ }
524
+ if (lhs.id < rhs.id) {
525
+ return -1;
526
+ } else if (lhs.id === rhs.id) {
527
+ return 0;
528
+ } else {
529
+ return 1;
300
530
  }
301
- return "RJ";
302
531
  }
303
532
  }
304
-
305
- var MedalType = /* @__PURE__ */ ((MedalType2) => {
306
- MedalType2["UNKNOWN"] = "Unknown";
307
- MedalType2["GOLD"] = "Gold";
308
- MedalType2["SILVER"] = "Silver";
309
- MedalType2["BRONZE"] = "Bronze";
310
- MedalType2["HONORABLE"] = "Honorable";
311
- return MedalType2;
312
- })(MedalType || {});
313
- class Award {
314
- constructor() {
315
- this.medalType = "Unknown" /* UNKNOWN */;
316
- this.minRank = 0;
317
- this.maxRank = 0;
533
+ function createSubmission(submissionJSON) {
534
+ const s = new Submission();
535
+ s.id = String(submissionJSON.id ?? submissionJSON.submission_id ?? "");
536
+ s.teamId = String(submissionJSON.team_id);
537
+ s.problemId = String(submissionJSON.problem_id);
538
+ s.timestamp = submissionJSON.timestamp;
539
+ s.status = stringToSubmissionStatus(submissionJSON.status);
540
+ s.isIgnore = submissionJSON.is_ignore ?? false;
541
+ if (submissionJSON.time) {
542
+ s.time = submissionJSON.time;
543
+ }
544
+ if (submissionJSON.language) {
545
+ s.language = submissionJSON.language;
546
+ }
547
+ if (submissionJSON.reaction) {
548
+ s.reaction = submissionJSON.reaction;
318
549
  }
550
+ return s;
319
551
  }
320
- function isValidMedalType(medal) {
321
- const validMedalType = [
322
- "Gold" /* GOLD */,
323
- "Silver" /* SILVER */,
324
- "Bronze" /* BRONZE */,
325
- "Honorable" /* HONORABLE */
326
- ];
327
- return validMedalType.includes(medal);
552
+ function createSubmissions(submissionsJSON) {
553
+ if (Array.isArray(submissionsJSON)) {
554
+ return submissionsJSON.map((s, index) => createSubmission({ ...s, id: s.submission_id ?? String(index) }));
555
+ } else {
556
+ const submissions = Object.entries(submissionsJSON).map(
557
+ ([submissionId, s]) => createSubmission({ ...s, id: s.submission_id ?? submissionId })
558
+ );
559
+ return submissions;
560
+ }
328
561
  }
329
562
 
330
- class GeneralExcelConverter {
563
+ var __defProp$g = Object.defineProperty;
564
+ var __defNormalProp$g = (obj, key, value) => key in obj ? __defProp$g(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
565
+ var __publicField$g = (obj, key, value) => {
566
+ __defNormalProp$g(obj, typeof key !== "symbol" ? key + "" : key, value);
567
+ return value;
568
+ };
569
+ class PlaceChartPointData {
331
570
  constructor() {
571
+ __publicField$g(this, "timePoint");
572
+ __publicField$g(this, "rank");
573
+ __publicField$g(this, "lastSolvedProblem");
574
+ this.timePoint = 0;
575
+ this.rank = 0;
576
+ this.lastSolvedProblem = null;
332
577
  }
333
- convert(oriRank) {
334
- const rank = ___default.cloneDeep(oriRank);
335
- rank.options.disableFilterTeamsByGroup();
336
- rank.options.disableFilterSubmissionByTimestamp();
337
- const workbook = XLSX__namespace.utils.book_new();
338
- for (const [k, v] of rank.contest.group) {
339
- rank.options.setGroup(k);
340
- rank.buildRank();
341
- const sheet = this.convertToSheet(rank);
342
- XLSX__namespace.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang));
343
- }
344
- return workbook;
578
+ }
579
+ class Team {
580
+ constructor() {
581
+ __publicField$g(this, "id");
582
+ __publicField$g(this, "name");
583
+ __publicField$g(this, "organization");
584
+ __publicField$g(this, "badge");
585
+ __publicField$g(this, "group");
586
+ __publicField$g(this, "tag");
587
+ __publicField$g(this, "coach");
588
+ __publicField$g(this, "members");
589
+ __publicField$g(this, "rank");
590
+ __publicField$g(this, "originalRank");
591
+ __publicField$g(this, "organizationRank");
592
+ __publicField$g(this, "solvedProblemNum");
593
+ __publicField$g(this, "attemptedProblemNum");
594
+ __publicField$g(this, "lastSolvedProblem");
595
+ __publicField$g(this, "lastSolvedProblemStatistics");
596
+ __publicField$g(this, "penalty");
597
+ __publicField$g(this, "problemStatistics");
598
+ __publicField$g(this, "problemStatisticsMap");
599
+ __publicField$g(this, "submissions");
600
+ __publicField$g(this, "placeChartPoints");
601
+ __publicField$g(this, "awards");
602
+ __publicField$g(this, "location");
603
+ __publicField$g(this, "icpcID");
604
+ __publicField$g(this, "se");
605
+ this.id = "";
606
+ this.name = "";
607
+ this.organization = "";
608
+ this.group = [];
609
+ this.tag = [];
610
+ this.rank = 0;
611
+ this.originalRank = 0;
612
+ this.organizationRank = -1;
613
+ this.solvedProblemNum = 0;
614
+ this.attemptedProblemNum = 0;
615
+ this.lastSolvedProblem = null;
616
+ this.lastSolvedProblemStatistics = null;
617
+ this.penalty = 0;
618
+ this.problemStatistics = [];
619
+ this.problemStatisticsMap = /* @__PURE__ */ new Map();
620
+ this.submissions = [];
621
+ this.placeChartPoints = [];
622
+ this.awards = [];
623
+ this.se = 0;
345
624
  }
346
- convertAndWrite(rank, filename) {
347
- return XLSX__namespace.writeFile(
348
- this.convert(rank),
349
- filename,
350
- {
351
- compression: true
352
- }
353
- );
625
+ reset() {
626
+ this.rank = 0;
627
+ this.originalRank = 0;
628
+ this.organizationRank = -1;
629
+ this.solvedProblemNum = 0;
630
+ this.attemptedProblemNum = 0;
631
+ this.lastSolvedProblem = null;
632
+ this.lastSolvedProblemStatistics = null;
633
+ this.penalty = 0;
634
+ this.problemStatistics = [];
635
+ this.problemStatisticsMap = /* @__PURE__ */ new Map();
636
+ this.submissions = [];
637
+ this.placeChartPoints = [];
638
+ this.awards = [];
639
+ this.se = 0;
354
640
  }
355
- convertToSheet(rank) {
356
- const aoa = this.convertToAoa(rank);
357
- const sheet = XLSX__namespace.utils.aoa_to_sheet(aoa);
358
- const cols = [];
359
- const head = aoa[1];
360
- for (let j = 0; j < head.length; j++) {
361
- let wch = 10;
362
- for (let i = 1; i < aoa.length; i++) {
363
- wch = Math.max(wch, stringWidth__default(aoa[i][j]) + 2);
364
- }
365
- cols.push({
366
- wch
367
- });
368
- }
369
- sheet["!cols"] = cols;
370
- {
371
- const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
372
- const merges = [{ s: mergeRange.s, e: mergeRange.e }];
373
- sheet["!merges"] = merges;
641
+ get penaltyToMinute() {
642
+ return Math.floor(this.penalty / 60);
643
+ }
644
+ get isUnofficial() {
645
+ return this.group.includes("unofficial");
646
+ }
647
+ get isGirl() {
648
+ return this.group.includes("girl");
649
+ }
650
+ get membersToArray() {
651
+ if (Array.isArray(this.members)) {
652
+ return this.members;
374
653
  }
375
- const font = {
376
- name: "Arial Unicode MS",
377
- bold: false,
378
- italic: false,
379
- sz: 12
380
- };
381
- const borderStyle = {
382
- style: "thin"
383
- };
384
- const cellStyle = {
385
- alignment: {
386
- vertical: "center",
387
- horizontal: "center"
388
- },
389
- border: {
390
- top: borderStyle,
391
- bottom: borderStyle,
392
- left: borderStyle,
393
- right: borderStyle
394
- },
395
- font
396
- };
397
- for (let i = 1; i < aoa.length; i++) {
398
- for (let j = 0; j < aoa[i].length; j++) {
399
- const cellAddress = XLSX__namespace.utils.encode_cell({ r: i, c: j });
400
- const cell = sheet[cellAddress];
401
- cell.s = cellStyle;
654
+ if (typeof this.members === "string") {
655
+ if (this.members.includes(", ")) {
656
+ return this.members.split(", ");
657
+ }
658
+ if (this.members.includes("\u3001")) {
659
+ return this.members.split("\u3001");
402
660
  }
403
661
  }
404
- {
405
- const cellAddress = XLSX__namespace.utils.encode_cell({ r: 0, c: 0 });
406
- const cell = sheet[cellAddress];
407
- const titleStyle = ___default.cloneDeep(cellStyle);
408
- titleStyle.font.sz = 28;
409
- titleStyle.font.bold = true;
410
- cell.s = titleStyle;
411
- }
412
- return sheet;
662
+ return [];
413
663
  }
414
- convertToAoa(rank) {
415
- const aoa = [];
416
- const enableAwards = rank.contest.isEnableAwards(rank.options.group);
417
- const enableMembers = (Array.isArray(rank.teams) && rank.teams[0]?.members) ?? false;
418
- const enableCoach = rank.teams[0]?.coach ?? false;
419
- {
420
- aoa.push([rank.contest.name]);
664
+ get membersToString() {
665
+ if (typeof this.members === "string") {
666
+ return this.members;
421
667
  }
422
- {
423
- const head = [];
424
- head.push("Rank");
425
- if (rank.contest.organization) {
426
- head.push(`${rank.contest.organization} Rank`);
427
- head.push(rank.contest.organization);
428
- }
429
- head.push("Team", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dirt");
430
- if (enableAwards) {
431
- head.push("Medal");
432
- }
433
- if (enableMembers) {
434
- head.push("Member1", "Member2", "Member3");
435
- }
436
- if (enableCoach) {
437
- head.push("Coach");
668
+ return this.members?.join(", ");
669
+ }
670
+ get isEffectiveTeam() {
671
+ return this.solvedProblemNum > 0;
672
+ }
673
+ get dirt() {
674
+ const attemptedNum = this.attemptedProblemNum;
675
+ const solvedNum = this.solvedProblemNum;
676
+ return calcDirt(attemptedNum, solvedNum);
677
+ }
678
+ calcSE(totalTeams) {
679
+ let acceptedProblemNums = 0;
680
+ let total = 0;
681
+ this.problemStatistics.forEach((p) => {
682
+ if (p.isSolved) {
683
+ acceptedProblemNums += 1;
684
+ total += p.problem.statistics.acceptedNum;
438
685
  }
439
- head.push("Unofficial");
440
- head.push("Girl");
441
- aoa.push(head);
686
+ });
687
+ if (totalTeams === 0 || acceptedProblemNums === 0) {
688
+ return 0;
442
689
  }
443
- for (const team of rank.teams) {
444
- const arr = [];
445
- arr.push(team.rank.toString());
446
- if (team.organization) {
447
- if (team.organizationRank !== -1) {
448
- arr.push(team.organizationRank.toString());
449
- } else {
450
- arr.push("");
451
- }
452
- arr.push(team.organization);
453
- }
454
- arr.push(team.name, team.solvedProblemNum.toString(), team.penaltyToMinute.toString());
455
- for (const p of team.problemStatistics) {
456
- if (p.isUnSubmitted) {
457
- arr.push("-");
458
- }
459
- if (p.isSolved) {
460
- arr.push(`+${p.totalCount}(${p.solvedTimestampToMinute})`);
461
- }
462
- if (p.isWrongAnswer) {
463
- arr.push(`-${p.failedCount}`);
464
- }
465
- if (p.isPending) {
466
- arr.push(`? ${p.failedCount} + ${p.pendingCount}`);
467
- }
468
- }
469
- arr.push(`${team.dirt}%`);
470
- if (enableAwards) {
471
- const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
472
- arr.push(medals.join(", "));
473
- }
474
- if (enableMembers) {
475
- const members = team.members;
476
- if (Array.isArray(members)) {
477
- arr.push(members[0] ?? "");
478
- arr.push(members[1] ?? "");
479
- arr.push(members[2] ?? "");
480
- } else {
481
- arr.push("", "", "");
482
- }
483
- }
484
- if (enableCoach) {
485
- if (typeof team.coach === "string") {
486
- arr.push(team.coach ?? "");
690
+ const res = (acceptedProblemNums * totalTeams - total) / totalTeams / acceptedProblemNums;
691
+ this.se = Math.round(res * 100) / 100;
692
+ return this.se;
693
+ }
694
+ calcSolvedData(options) {
695
+ this.solvedProblemNum = 0;
696
+ this.attemptedProblemNum = 0;
697
+ this.penalty = 0;
698
+ for (const p of this.problemStatistics) {
699
+ if (p.isAccepted) {
700
+ this.solvedProblemNum++;
701
+ this.attemptedProblemNum += p.failedCount + 1;
702
+ if (options?.calculationOfPenalty === "in_seconds" || options?.calculationOfPenalty === "accumulate_in_seconds_and_finally_to_the_minute") {
703
+ this.penalty += p.penaltyInSecond;
487
704
  } else {
488
- arr.push("");
705
+ this.penalty += p.penalty;
489
706
  }
490
707
  }
491
- arr.push(team.isUnofficial ? "Y" : "N");
492
- arr.push(team.isGirl ? "Y" : "N");
493
- aoa.push(arr);
494
708
  }
495
- return aoa;
496
- }
497
- }
498
-
499
- class ICPCStandingsCsvConverter {
500
- constructor() {
501
- }
502
- convert(oriRank) {
503
- const rank = ___default.cloneDeep(oriRank);
504
- rank.options.disableFilterTeamsByGroup();
505
- rank.options.disableFilterSubmissionByTimestamp();
506
- rank.options.setGroup("official");
507
- rank.buildRank();
508
- const resList = [];
509
- for (const team of rank.teams) {
510
- const res = {
511
- teamId: team.icpcID ?? "",
512
- rank: team.rank,
513
- medalCitation: this.getMedalCitation(team),
514
- problemsSolved: team.solvedProblemNum,
515
- totalTime: team.penaltyToMinute,
516
- lastProblemTime: team.lastSolvedProblemStatistics?.solvedTimestampToMinute ?? 0,
517
- siteCitation: rank.contest.name,
518
- citation: ordinal__default(team.rank),
519
- teamName: team.name,
520
- institution: team.organization
521
- };
522
- resList.push(res);
709
+ if (options?.calculationOfPenalty === "accumulate_in_seconds_and_finally_to_the_minute") {
710
+ this.penalty = Math.floor(this.penalty / 60) * 60;
523
711
  }
524
- const csv = Papa__default.unparse(resList);
525
- return csv;
526
712
  }
527
- getMedalCitation(team) {
528
- if (team.solvedProblemNum === 0) {
529
- return "";
713
+ calcAwards(awards) {
714
+ if (!awards) {
715
+ return;
530
716
  }
531
- const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
532
- if (medals.length === 1) {
533
- const medal = medals[0];
534
- if (medal === "Gold") {
535
- return "Gold Medal";
536
- }
537
- if (medal === "Silver") {
538
- return "Silver Medal";
539
- }
540
- if (medal === "Bronze") {
541
- return "Bronze Medal";
542
- }
543
- if (medal === "Honorable") {
544
- return "Honorable Mention";
717
+ for (const award of awards) {
718
+ if (this.rank >= award.minRank && this.rank <= award.maxRank) {
719
+ this.awards.push(award.medalType);
545
720
  }
546
721
  }
547
- return "";
548
722
  }
549
- }
550
-
551
- class Person {
552
- constructor(name = "") {
553
- this.name = name;
723
+ isEqualRank(otherTeam) {
724
+ return this.solvedProblemNum === otherTeam.solvedProblemNum && this.penalty === otherTeam.penalty;
554
725
  }
555
- toJSON() {
556
- return {
557
- name: this.name
558
- };
726
+ postProcessPlaceChartPoints() {
727
+ if (this.placeChartPoints.length === 0) {
728
+ return;
729
+ }
730
+ const res = [];
731
+ res.push(this.placeChartPoints[0]);
732
+ for (let i = 1; i < this.placeChartPoints.length - 1; i++) {
733
+ const p = this.placeChartPoints[i];
734
+ const preP = res[res.length - 1];
735
+ if (p.rank !== preP.rank || p.lastSolvedProblem !== preP.lastSolvedProblem) {
736
+ res.push(p);
737
+ }
738
+ }
739
+ if (this.placeChartPoints.length > 1) {
740
+ res.push(this.placeChartPoints[this.placeChartPoints.length - 1]);
741
+ }
742
+ this.placeChartPoints = res;
559
743
  }
560
- static fromJSON(iPerson) {
561
- if (typeof iPerson === "string") {
562
- iPerson = JSON.parse(iPerson);
744
+ static compare(lhs, rhs) {
745
+ if (lhs.solvedProblemNum !== rhs.solvedProblemNum) {
746
+ return rhs.solvedProblemNum - lhs.solvedProblemNum;
563
747
  }
564
- const person = new Person();
565
- person.name = iPerson.name;
566
- return person;
748
+ if (lhs.penalty !== rhs.penalty) {
749
+ return lhs.penalty - rhs.penalty;
750
+ }
751
+ if (lhs.lastSolvedProblemStatistics && rhs.lastSolvedProblemStatistics) {
752
+ return lhs.lastSolvedProblemStatistics.solvedTimestampToMinute - rhs.lastSolvedProblemStatistics.solvedTimestampToMinute;
753
+ }
754
+ if (lhs.name < rhs.name) {
755
+ return -1;
756
+ } else if (lhs.name > rhs.name) {
757
+ return 1;
758
+ }
759
+ return 0;
567
760
  }
568
761
  }
569
- function createPersons(iPersons) {
570
- if (typeof iPersons === "string") {
571
- for (const c of " ,\u3001|") {
572
- if (iPersons.includes(c)) {
573
- return iPersons.split(c).map((name) => new Person(name));
762
+ function createTeam(teamJSON) {
763
+ const t = new Team();
764
+ t.id = teamJSON.id ?? teamJSON.team_id ?? "";
765
+ t.name = teamJSON.name ?? teamJSON.team_name ?? "";
766
+ t.organization = teamJSON.organization ?? "";
767
+ t.badge = teamJSON.badge;
768
+ t.group = ___default.cloneDeep(teamJSON.group ?? []);
769
+ t.tag = ___default.cloneDeep(teamJSON.tag ?? []);
770
+ t.coach = teamJSON.coach;
771
+ t.members = teamJSON.members;
772
+ if (Boolean(teamJSON.official) === true) {
773
+ t.group.push("official");
774
+ }
775
+ if (Boolean(teamJSON.unofficial) === true) {
776
+ t.group.push("unofficial");
777
+ }
778
+ if (Boolean(teamJSON.girl) === true) {
779
+ t.group.push("girl");
780
+ }
781
+ {
782
+ const tt = teamJSON;
783
+ for (const key of Object.keys(tt)) {
784
+ if (tt[key] === 1 || tt[key] === true) {
785
+ t.group.push(key);
574
786
  }
575
787
  }
576
- return [new Person(iPersons)];
577
788
  }
578
- return iPersons.map((name) => new Person(name));
579
- }
580
-
581
- function calcDirt(attemptedNum, solvedNum) {
582
- if (solvedNum === 0) {
583
- return 0;
789
+ t.group = [...new Set(t.group)];
790
+ t.group.sort();
791
+ if (teamJSON.location) {
792
+ t.location = teamJSON.location;
584
793
  }
585
- return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
794
+ if (teamJSON.icpc_id) {
795
+ t.icpcID = teamJSON.icpc_id;
796
+ }
797
+ return t;
586
798
  }
587
-
588
- function getWhiteOrBlackColorV1(background) {
589
- const [R, G, B] = chroma__default(background).rgb();
590
- const color = { R, G, B };
591
- const palette = [
592
- { R: 0, G: 0, B: 0 },
593
- { R: 255, G: 255, B: 255 }
594
- ];
595
- const f = colorDiff.furthest(color, palette);
596
- if (f.R === 0 && f.G === 0 && f.B === 0) {
597
- return "#000";
799
+ function createTeams(teamsJSON) {
800
+ if (Array.isArray(teamsJSON)) {
801
+ return teamsJSON.map((t) => createTeam(t));
598
802
  } else {
599
- return "#fff";
803
+ const teams = Object.entries(teamsJSON).map(
804
+ ([teamId, team]) => createTeam({ ...team, team_id: team.team_id ?? teamId })
805
+ );
806
+ return teams;
600
807
  }
601
808
  }
602
- function getWhiteOrBlackColor(background) {
603
- const [R, G, B] = chroma__default(background).rgb();
604
- const brightness = (R * 299 + G * 587 + B * 114) / 1e3;
605
- const threshold = 148;
606
- return brightness <= threshold ? "#fff" : "#000";
607
- }
608
809
 
609
- class RatingHistory {
810
+ var __defProp$f = Object.defineProperty;
811
+ var __defNormalProp$f = (obj, key, value) => key in obj ? __defProp$f(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
812
+ var __publicField$f = (obj, key, value) => {
813
+ __defNormalProp$f(obj, typeof key !== "symbol" ? key + "" : key, value);
814
+ return value;
815
+ };
816
+ class Balloon {
610
817
  constructor() {
611
- this.rank = 0;
612
- this.rating = 0;
613
- this.teamName = "";
614
- this.organization = "";
615
- this.members = [];
616
- this.coaches = [];
617
- this.contestID = "";
618
- this.contestName = "";
619
- this.contestLink = "";
620
- this.contestTime = createDayJS();
818
+ __publicField$f(this, "problem");
819
+ __publicField$f(this, "team");
820
+ __publicField$f(this, "submission");
821
+ this.problem = new Problem();
822
+ this.team = new Team();
823
+ this.submission = new Submission();
621
824
  }
622
- toJSON() {
623
- return {
624
- rank: this.rank,
625
- rating: this.rating,
626
- teamName: this.teamName,
627
- organization: this.organization,
628
- members: this.members.map((member) => member.toJSON()),
629
- coaches: this.coaches.map((coach) => coach.toJSON()),
630
- contestID: this.contestID,
631
- contestName: this.contestName,
632
- contestLink: this.contestLink,
633
- contestTime: this.contestTime.toDate()
634
- };
825
+ get key() {
826
+ return `balloon-${this.team.id}-${this.problem.id}`;
635
827
  }
636
- static fromJSON(iRatingHistory) {
637
- if (typeof iRatingHistory === "string") {
638
- iRatingHistory = JSON.parse(iRatingHistory);
639
- }
640
- const ratingHistory = new RatingHistory();
641
- ratingHistory.rank = iRatingHistory.rank;
642
- ratingHistory.rating = iRatingHistory.rating;
643
- ratingHistory.teamName = iRatingHistory.teamName;
644
- ratingHistory.organization = iRatingHistory.organization;
645
- ratingHistory.members = iRatingHistory.members.map((iMember) => Person.fromJSON(iMember));
646
- ratingHistory.coaches = iRatingHistory.coaches.map((iCoach) => Person.fromJSON(iCoach));
647
- ratingHistory.contestID = iRatingHistory.contestID;
648
- ratingHistory.contestName = iRatingHistory.contestName;
649
- ratingHistory.contestLink = iRatingHistory.contestLink;
650
- ratingHistory.contestTime = createDayJS(iRatingHistory.contestTime);
651
- return ratingHistory;
828
+ static compare(lhs, rhs) {
829
+ return Submission.compare(lhs.submission, rhs.submission);
652
830
  }
653
831
  }
654
832
 
655
- class RatingUser {
656
- constructor() {
657
- this.id = "";
658
- this.name = "";
659
- this.organization = "";
660
- this.members = [];
661
- this.coaches = [];
662
- this.rating = 0;
663
- this.minRating = 1061109567;
664
- this.maxRating = -1061109567;
665
- this.rank = 0;
666
- this.oldRating = 0;
667
- this.seed = 1;
668
- this.delta = 0;
669
- this.ratingHistories = [];
833
+ var __defProp$e = Object.defineProperty;
834
+ var __defNormalProp$e = (obj, key, value) => key in obj ? __defProp$e(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
835
+ var __publicField$e = (obj, key, value) => {
836
+ __defNormalProp$e(obj, typeof key !== "symbol" ? key + "" : key, value);
837
+ return value;
838
+ };
839
+ var GiantsType = /* @__PURE__ */ ((GiantsType2) => {
840
+ GiantsType2[GiantsType2["BLUE"] = 0] = "BLUE";
841
+ GiantsType2[GiantsType2["RED"] = 1] = "RED";
842
+ return GiantsType2;
843
+ })(GiantsType || {});
844
+ class Giants {
845
+ constructor(type = 0 /* BLUE */) {
846
+ __publicField$e(this, "type");
847
+ __publicField$e(this, "name");
848
+ __publicField$e(this, "filterOrganizations");
849
+ __publicField$e(this, "filterOrganizationMap");
850
+ __publicField$e(this, "filterTeams");
851
+ __publicField$e(this, "filterTeamMap");
852
+ __publicField$e(this, "teams");
853
+ this.type = type;
854
+ this.name = `${type === 0 /* BLUE */ ? "Blue" : "Red"} Team`;
855
+ this.teams = [];
856
+ this.filterOrganizations = [];
857
+ this.filterOrganizationMap = /* @__PURE__ */ new Map();
858
+ this.filterTeams = [];
859
+ this.filterTeamMap = /* @__PURE__ */ new Map();
670
860
  }
671
- UpdateRating(rating) {
672
- this.rating = rating;
673
- this.minRating = Math.min(this.minRating, rating);
674
- this.maxRating = Math.max(this.maxRating, rating);
861
+ setFilterOrganizations(filterOrganizations) {
862
+ const m = /* @__PURE__ */ new Map();
863
+ filterOrganizations.forEach((item) => {
864
+ m.set(item.value, item);
865
+ });
866
+ this.filterOrganizations = filterOrganizations;
867
+ this.filterOrganizationMap = m;
675
868
  }
676
- toJSON() {
677
- return {
678
- id: this.id,
679
- name: this.name,
680
- organization: this.organization,
681
- members: this.members.map((member) => member.toJSON()),
682
- coaches: this.coaches.map((coach) => coach.toJSON()),
683
- rating: this.rating,
684
- minRating: this.minRating,
685
- maxRating: this.maxRating,
686
- ratingHistories: this.ratingHistories.map((ratingHistory) => ratingHistory.toJSON())
687
- };
869
+ setFilterTeams(filterTeams) {
870
+ const m = /* @__PURE__ */ new Map();
871
+ filterTeams.forEach((item) => {
872
+ m.set(item.value, item);
873
+ });
874
+ this.filterTeams = filterTeams;
875
+ this.filterTeamMap = m;
688
876
  }
689
- static fromJSON(iRatingUser) {
690
- if (typeof iRatingUser === "string") {
691
- iRatingUser = JSON.parse(iRatingUser);
692
- }
693
- const ratingUser = new RatingUser();
694
- ratingUser.id = iRatingUser.id;
695
- ratingUser.name = iRatingUser.name;
696
- ratingUser.organization = iRatingUser.organization;
697
- ratingUser.members = iRatingUser.members.map((member) => Person.fromJSON(member));
698
- ratingUser.coaches = iRatingUser.coaches.map((coach) => Person.fromJSON(coach));
699
- ratingUser.rating = iRatingUser.rating;
700
- ratingUser.minRating = iRatingUser.minRating;
701
- ratingUser.maxRating = iRatingUser.maxRating;
702
- for (const iRatingHistory of iRatingUser.ratingHistories) {
703
- ratingUser.ratingHistories.push(RatingHistory.fromJSON(iRatingHistory));
877
+ refreshName() {
878
+ if (this.filterOrganizations.length > 0) {
879
+ this.name = this.filterOrganizations[0].text;
880
+ } else {
881
+ this.name = `${this.type === 0 /* BLUE */ ? "Blue" : "Red"} Team`;
704
882
  }
705
- return ratingUser;
706
- }
707
- }
708
-
709
- class RatingCalculator {
710
- constructor() {
711
- this.users = [];
712
- }
713
- calculate() {
714
- this.calculateInternal();
883
+ return this.name;
715
884
  }
716
- calcP(userA, userB) {
717
- return 1 / (1 + 10 ** ((userB.oldRating - userA.oldRating) / 400));
885
+ get totalSolvedProblemNum() {
886
+ let total = 0;
887
+ this.teams.forEach((team) => {
888
+ total += team.solvedProblemNum;
889
+ });
890
+ return total;
718
891
  }
719
- getExSeed(users, rating, ownUser) {
720
- const exUser = new RatingUser();
721
- exUser.oldRating = rating;
722
- let res = 0;
723
- users.forEach((user) => {
724
- if (user.id !== ownUser.id) {
725
- res += this.calcP(user, exUser);
726
- }
892
+ get totalPenalty() {
893
+ let total = 0;
894
+ this.teams.forEach((team) => {
895
+ total += team.penaltyToMinute;
727
896
  });
728
- return res;
897
+ return total;
729
898
  }
730
- calcRating(users, rank, user) {
731
- let left = 1;
732
- let right = 8e3;
733
- while (right - left > 1) {
734
- const mid = Math.floor((left + right) / 2);
735
- if (this.getExSeed(users, mid, user) < rank) {
736
- right = mid;
737
- } else {
738
- left = mid;
899
+ get totalPenaltyToString() {
900
+ const penalty = this.totalPenalty;
901
+ const two = (a) => {
902
+ if (a < 10) {
903
+ return `0${a}`;
739
904
  }
740
- }
741
- return left;
905
+ return String(a);
906
+ };
907
+ const h = Math.floor(penalty / 60);
908
+ const m = Math.floor(penalty % 60);
909
+ return [two(h), two(m)].join(":");
742
910
  }
743
- calculateInternal() {
744
- for (let i = 0; i < this.users.length; i++) {
745
- const u = this.users[i];
746
- u.seed = 1;
747
- for (let j = 0; j < this.users.length; j++) {
748
- if (i !== j) {
749
- const otherUser = this.users[j];
750
- u.seed += this.calcP(otherUser, u);
751
- }
752
- }
753
- }
754
- let sumDelta = 0;
755
- for (let i = 0; i < this.users.length; i++) {
756
- const u = this.users[i];
757
- u.delta = Math.floor(
758
- (this.calcRating(this.users, Math.sqrt(u.rank * u.seed), u) - u.oldRating) / 2
759
- );
760
- sumDelta += u.delta;
761
- }
762
- let inc = Math.floor(-sumDelta / this.users.length) - 1;
763
- for (let i = 0; i < this.users.length; i++) {
764
- const u = this.users[i];
765
- u.delta += inc;
911
+ toJSON() {
912
+ return {
913
+ type: this.type,
914
+ name: this.name,
915
+ filterOrganizations: this.filterOrganizations,
916
+ filterTeams: this.filterTeams
917
+ };
918
+ }
919
+ }
920
+ class BattleOfGiants {
921
+ constructor() {
922
+ __publicField$e(this, "enable");
923
+ __publicField$e(this, "topX");
924
+ __publicField$e(this, "equalTeams");
925
+ __publicField$e(this, "persist");
926
+ __publicField$e(this, "blueTeam");
927
+ __publicField$e(this, "redTeam");
928
+ this.enable = false;
929
+ this.topX = 5;
930
+ this.equalTeams = true;
931
+ this.persist = false;
932
+ this.blueTeam = new Giants(0 /* BLUE */);
933
+ this.redTeam = new Giants(1 /* RED */);
934
+ }
935
+ ToBase64() {
936
+ return jsBase64.Base64.encode(JSON.stringify(this));
937
+ }
938
+ FromBase64(base64) {
939
+ if (base64.length === 0) {
940
+ return;
766
941
  }
767
- this.users = this.users.sort((a, b) => b.oldRating - a.oldRating);
768
- const s = Math.min(this.users.length, Math.floor(4 * Math.round(Math.sqrt(this.users.length))));
769
- let sumS = 0;
770
- for (let i = 0; i < s; i++) {
771
- sumS += this.users[i].delta;
942
+ if (jsBase64.Base64.isValid(base64) === false) {
943
+ return;
772
944
  }
773
- inc = Math.min(Math.max(Math.floor(-sumS / s), -10), 0);
774
- this.users.forEach((u) => {
775
- u.delta += inc;
776
- u.UpdateRating(u.oldRating + u.delta);
777
- });
778
- this.users = this.users.sort((a, b) => a.rank - b.rank);
945
+ const j = JSON.parse(jsBase64.Base64.decode(base64));
946
+ this.enable = j.enable;
947
+ this.topX = j.topX;
948
+ this.equalTeams = j.equalTeams;
949
+ this.persist = j.persist;
950
+ this.blueTeam = new Giants(0 /* BLUE */);
951
+ this.blueTeam.name = j.blueTeam.name;
952
+ this.blueTeam.setFilterOrganizations(j.blueTeam.filterOrganizations);
953
+ this.blueTeam.setFilterTeams(j.blueTeam.filterTeams);
954
+ this.redTeam = new Giants(1 /* RED */);
955
+ this.redTeam.name = j.redTeam.name;
956
+ this.redTeam.setFilterOrganizations(j.redTeam.filterOrganizations);
957
+ this.redTeam.setFilterTeams(j.redTeam.filterTeams);
779
958
  }
780
959
  }
781
960
 
782
- var RatingLevel = /* @__PURE__ */ ((RatingLevel2) => {
783
- RatingLevel2["NEWBIE"] = "NEWBIE";
784
- RatingLevel2["PUPIL"] = "PUPIL";
785
- RatingLevel2["SPECIALIST"] = "SPECIALIST";
786
- RatingLevel2["EXPERT"] = "EXPERT";
787
- RatingLevel2["CANDIDATE_MASTER"] = "CANDIDATE_MASTER";
788
- RatingLevel2["MASTER"] = "MASTER";
789
- RatingLevel2["INTERNATIONAL_MASTER"] = "INTERNATIONAL_MASTER";
790
- RatingLevel2["GRANDMASTER"] = "GRANDMASTER";
791
- RatingLevel2["INTERNATIONAL_GRANDMASTER"] = "INTERNATIONAL_GRANDMASTER";
792
- RatingLevel2["LEGENDARY_GRANDMASTER"] = "LEGENDARY_GRANDMASTER";
793
- return RatingLevel2;
794
- })(RatingLevel || {});
795
- const RatingLevelToString = {
796
- ["NEWBIE" /* NEWBIE */]: "Newbie",
797
- ["PUPIL" /* PUPIL */]: "Pupil",
798
- ["SPECIALIST" /* SPECIALIST */]: "Specialist",
799
- ["EXPERT" /* EXPERT */]: "Expert",
800
- ["CANDIDATE_MASTER" /* CANDIDATE_MASTER */]: "Candidate Master",
801
- ["MASTER" /* MASTER */]: "Master",
802
- ["INTERNATIONAL_MASTER" /* INTERNATIONAL_MASTER */]: "International Master",
803
- ["GRANDMASTER" /* GRANDMASTER */]: "Grandmaster",
804
- ["INTERNATIONAL_GRANDMASTER" /* INTERNATIONAL_GRANDMASTER */]: "International Grandmaster",
805
- ["LEGENDARY_GRANDMASTER" /* LEGENDARY_GRANDMASTER */]: "Legendary Grandmaster"
961
+ var __defProp$d = Object.defineProperty;
962
+ var __defNormalProp$d = (obj, key, value) => key in obj ? __defProp$d(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
963
+ var __publicField$d = (obj, key, value) => {
964
+ __defNormalProp$d(obj, typeof key !== "symbol" ? key + "" : key, value);
965
+ return value;
806
966
  };
807
- class RatingUtility {
808
- static getRatingLevel(rating) {
809
- if (rating >= 3e3) {
810
- return "LEGENDARY_GRANDMASTER" /* LEGENDARY_GRANDMASTER */;
811
- } else if (rating >= 2600) {
812
- return "INTERNATIONAL_GRANDMASTER" /* INTERNATIONAL_GRANDMASTER */;
813
- } else if (rating >= 2400) {
814
- return "GRANDMASTER" /* GRANDMASTER */;
815
- } else if (rating >= 2300) {
816
- return "INTERNATIONAL_MASTER" /* INTERNATIONAL_MASTER */;
817
- } else if (rating >= 2100) {
818
- return "MASTER" /* MASTER */;
819
- } else if (rating >= 1900) {
820
- return "CANDIDATE_MASTER" /* CANDIDATE_MASTER */;
821
- } else if (rating >= 1600) {
822
- return "EXPERT" /* EXPERT */;
823
- } else if (rating >= 1400) {
824
- return "SPECIALIST" /* SPECIALIST */;
825
- } else if (rating >= 1200) {
826
- return "PUPIL" /* PUPIL */;
827
- }
828
- return "NEWBIE" /* NEWBIE */;
967
+ class ContestOptions {
968
+ constructor() {
969
+ __publicField$d(this, "calculationOfPenalty");
970
+ __publicField$d(this, "submissionTimestampUnit");
971
+ __publicField$d(this, "submissionHasTimeField");
972
+ __publicField$d(this, "submissionHasLanguageField");
973
+ __publicField$d(this, "submissionEnableActionField");
974
+ this.calculationOfPenalty = "in_minutes";
975
+ this.submissionTimestampUnit = "second";
976
+ this.submissionHasTimeField = false;
977
+ this.submissionHasLanguageField = false;
978
+ this.submissionEnableActionField = false;
829
979
  }
830
- static getRatingLevelClass(ratingLevel) {
831
- if (typeof ratingLevel === "number") {
832
- return this.getRatingLevelClass(this.getRatingLevel(ratingLevel));
833
- }
834
- switch (ratingLevel) {
835
- case "NEWBIE" /* NEWBIE */:
836
- return "user-gray";
837
- case "PUPIL" /* PUPIL */:
838
- return "user-green";
839
- case "SPECIALIST" /* SPECIALIST */:
840
- return "user-cyan";
841
- case "EXPERT" /* EXPERT */:
842
- return "user-blue";
843
- case "CANDIDATE_MASTER" /* CANDIDATE_MASTER */:
844
- return "user-violet";
845
- case "MASTER" /* MASTER */:
846
- return "user-orange";
847
- case "INTERNATIONAL_MASTER" /* INTERNATIONAL_MASTER */:
848
- return "user-orange";
849
- case "GRANDMASTER" /* GRANDMASTER */:
850
- return "user-red";
851
- case "INTERNATIONAL_GRANDMASTER" /* INTERNATIONAL_GRANDMASTER */:
852
- return "user-red";
853
- case "LEGENDARY_GRANDMASTER" /* LEGENDARY_GRANDMASTER */:
854
- return "user-legendary";
855
- }
980
+ }
981
+ function createContestOptions(contestOptionsJSON = {}) {
982
+ const j = contestOptionsJSON;
983
+ const o = new ContestOptions();
984
+ if (j.calculation_of_penalty) {
985
+ o.calculationOfPenalty = j.calculation_of_penalty;
986
+ }
987
+ if (j.submission_timestamp_unit) {
988
+ o.submissionTimestampUnit = j.submission_timestamp_unit;
989
+ }
990
+ if (j.submission_has_reaction) {
991
+ o.submissionEnableActionField = j.submission_has_reaction;
856
992
  }
993
+ return o;
857
994
  }
858
995
 
859
- class Rating {
996
+ var __defProp$c = Object.defineProperty;
997
+ var __defNormalProp$c = (obj, key, value) => key in obj ? __defProp$c(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
998
+ var __publicField$c = (obj, key, value) => {
999
+ __defNormalProp$c(obj, typeof key !== "symbol" ? key + "" : key, value);
1000
+ return value;
1001
+ };
1002
+ class Group {
860
1003
  constructor() {
861
- this.id = "";
862
- this.name = "";
863
- this.baseRating = 1500;
864
- this.contestIDs = [];
865
- this.users = [];
866
- this.ranks = [];
867
- this.userMap = /* @__PURE__ */ new Map();
868
- }
869
- buildRating() {
870
- for (const rank of this.ranks) {
871
- rank.buildRank();
872
- const ratingCalculator = new RatingCalculator();
873
- for (const t of rank.teams) {
874
- const id = this.generateTeamId(t);
875
- let u = null;
876
- if (!this.userMap.has(id)) {
877
- u = new RatingUser();
878
- u.id = id;
879
- u.name = t.name;
880
- u.organization = t.organization;
881
- u.members = createPersons(t.members ?? []);
882
- u.coaches = createPersons(t.coach ?? []);
883
- u.rank = t.rank;
884
- u.oldRating = this.baseRating;
885
- u.UpdateRating(this.baseRating);
886
- this.userMap.set(id, u);
887
- this.users.push(u);
888
- ratingCalculator.users.push(u);
889
- } else {
890
- u = this.userMap.get(id);
891
- u.rank = t.rank;
892
- u.oldRating = u.rating;
893
- ratingCalculator.users.push(u);
894
- }
895
- {
896
- const h = new RatingHistory();
897
- h.rank = t.rank;
898
- h.rating = u.rating;
899
- h.teamName = t.name;
900
- h.organization = t.organization;
901
- h.members = createPersons(t.members ?? []);
902
- h.coaches = createPersons(t.coach ?? []);
903
- h.contestID = rank.contest.id;
904
- h.contestLink = h.contestID;
905
- h.contestName = rank.contest.name;
906
- h.contestTime = rank.contest.startTime;
907
- u.ratingHistories.push(h);
908
- }
909
- }
910
- ratingCalculator.calculate();
911
- for (const u of ratingCalculator.users) {
912
- u.ratingHistories.at(-1).rating = u.rating;
913
- }
914
- }
915
- }
916
- generateTeamId(t) {
917
- const persons = createPersons(t.members ?? []);
918
- if (persons.length > 0) {
919
- return persons.map((person) => person.name.trim()).sort().join("|");
920
- }
921
- return `${t.organization}-${t.name}`;
922
- }
923
- toJSON() {
924
- return {
925
- id: this.id,
926
- name: this.name,
927
- baseRating: this.baseRating,
928
- contestIDs: this.contestIDs,
929
- users: this.users.map((ratingUser) => ratingUser.toJSON())
930
- };
931
- }
932
- static fromJSON(iRating) {
933
- if (typeof iRating === "string") {
934
- iRating = JSON.parse(iRating);
935
- }
936
- const rating = new Rating();
937
- rating.id = iRating.id;
938
- rating.name = iRating.name;
939
- rating.baseRating = iRating.baseRating;
940
- rating.contestIDs = iRating.contestIDs;
941
- for (const iUser of iRating.users) {
942
- rating.users.push(RatingUser.fromJSON(iUser));
943
- }
944
- return rating;
1004
+ __publicField$c(this, "names");
1005
+ __publicField$c(this, "defaultLang");
1006
+ __publicField$c(this, "isDefault");
1007
+ this.names = /* @__PURE__ */ new Map();
1008
+ this.defaultLang = "zh-CN";
1009
+ this.isDefault = false;
945
1010
  }
946
1011
  }
947
1012
 
948
- class ProblemStatistics {
949
- constructor() {
950
- this.acceptedNum = 0;
951
- this.rejectedNum = 0;
952
- this.pendingNum = 0;
953
- this.submittedNum = 0;
954
- this.attemptedNum = 0;
955
- this.ignoreNum = 0;
956
- this.se = 0;
957
- this.firstSolveSubmissions = [];
958
- this.lastSolveSubmissions = [];
959
- }
960
- reset() {
961
- this.acceptedNum = 0;
962
- this.rejectedNum = 0;
963
- this.pendingNum = 0;
964
- this.submittedNum = 0;
965
- this.attemptedNum = 0;
966
- this.ignoreNum = 0;
967
- this.se = 0;
968
- this.firstSolveSubmissions = [];
969
- this.lastSolveSubmissions = [];
970
- }
971
- get dirt() {
972
- if (this.acceptedNum === 0) {
973
- return 0;
974
- }
975
- return calcDirt(this.attemptedNum, this.acceptedNum);
976
- }
977
- calcSE(totalTeams) {
978
- const res = (totalTeams - this.acceptedNum) / totalTeams;
979
- this.se = Math.round(res * 100) / 100;
980
- return this.se;
981
- }
982
- }
983
- class Problem {
1013
+ var __defProp$b = Object.defineProperty;
1014
+ var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1015
+ var __publicField$b = (obj, key, value) => {
1016
+ __defNormalProp$b(obj, typeof key !== "symbol" ? key + "" : key, value);
1017
+ return value;
1018
+ };
1019
+ class Contest {
984
1020
  constructor() {
985
- this.id = "";
986
- this.label = "";
987
- this.name = "";
988
- this.statistics = new ProblemStatistics();
989
- this.balloonColor = {
990
- background_color: "#a0f0a0",
991
- color: "#000"
1021
+ __publicField$b(this, "id", "");
1022
+ __publicField$b(this, "name", "");
1023
+ __publicField$b(this, "startTime");
1024
+ __publicField$b(this, "endTime");
1025
+ __publicField$b(this, "freezeTime");
1026
+ __publicField$b(this, "replayStartTime");
1027
+ __publicField$b(this, "replayEndTime");
1028
+ __publicField$b(this, "replayFreezeTime");
1029
+ __publicField$b(this, "replayNowTime");
1030
+ __publicField$b(this, "replayContestStartTimestamp");
1031
+ __publicField$b(this, "totalDurationTimestamp");
1032
+ __publicField$b(this, "freezeDurationTimestamp");
1033
+ __publicField$b(this, "unFreezeDurationTimestamp");
1034
+ __publicField$b(this, "penalty");
1035
+ __publicField$b(this, "problems");
1036
+ __publicField$b(this, "problemsMap");
1037
+ __publicField$b(this, "statusTimeDisplay");
1038
+ __publicField$b(this, "badge");
1039
+ __publicField$b(this, "medal");
1040
+ __publicField$b(this, "awards");
1041
+ __publicField$b(this, "organization");
1042
+ __publicField$b(this, "group");
1043
+ __publicField$b(this, "tag");
1044
+ __publicField$b(this, "logo");
1045
+ __publicField$b(this, "banner");
1046
+ __publicField$b(this, "bannerMode");
1047
+ __publicField$b(this, "boardLink");
1048
+ __publicField$b(this, "options");
1049
+ this.startTime = createDayJS();
1050
+ this.endTime = createDayJS();
1051
+ this.freezeTime = createDayJS();
1052
+ this.totalDurationTimestamp = 0;
1053
+ this.freezeDurationTimestamp = 0;
1054
+ this.unFreezeDurationTimestamp = 0;
1055
+ this.penalty = 20 * 60;
1056
+ this.problems = [];
1057
+ this.problemsMap = /* @__PURE__ */ new Map();
1058
+ this.statusTimeDisplay = {
1059
+ correct: true,
1060
+ incorrect: true,
1061
+ pending: true
992
1062
  };
1063
+ this.group = /* @__PURE__ */ new Map();
1064
+ this.tag = /* @__PURE__ */ new Map();
1065
+ this.options = new ContestOptions();
993
1066
  }
994
- }
995
- function createProblem(problemJSON) {
996
- const p = new Problem();
997
- p.id = String(problemJSON.id);
998
- p.label = problemJSON.label;
999
- p.name = problemJSON.name ?? "";
1000
- p.timeLimit = problemJSON.time_limit;
1001
- p.memoryLimit = problemJSON.memory_limit;
1002
- if (problemJSON.balloon_color) {
1003
- p.balloonColor = ___default.cloneDeep(problemJSON.balloon_color);
1067
+ getStartTime() {
1068
+ return this.replayStartTime ?? this.startTime;
1004
1069
  }
1005
- p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
1006
- return p;
1007
- }
1008
- function createProblems(problemsJSON) {
1009
- return problemsJSON.map((pJSON) => createProblem(pJSON));
1010
- }
1011
- function createProblemsByProblemIds(problemIds, balloonColors) {
1012
- const problems = problemIds.map((label, index) => {
1013
- const p = new Problem();
1014
- p.id = String(index);
1015
- p.label = label;
1016
- return p;
1017
- });
1018
- if (balloonColors !== void 0 && balloonColors !== null) {
1019
- for (const index in balloonColors) {
1020
- problems[index].balloonColor = ___default.cloneDeep(balloonColors[index]);
1021
- }
1070
+ getEndTime() {
1071
+ return this.replayEndTime ?? this.endTime;
1022
1072
  }
1023
- problems.forEach((p) => {
1024
- p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
1025
- });
1026
- return problems;
1027
- }
1028
- class TeamProblemStatistics {
1029
- constructor(options) {
1030
- this.isFirstSolved = options?.teamProblemStatistics?.isFirstSolved ?? false;
1031
- this.isSolved = options?.teamProblemStatistics?.isSolved ?? false;
1032
- this.solvedTimestamp = options?.teamProblemStatistics?.solvedTimestamp ?? 0;
1033
- this.isSubmitted = options?.teamProblemStatistics?.isSubmitted ?? false;
1034
- this.lastSubmitTimestamp = options?.teamProblemStatistics?.lastSubmitTimestamp ?? 0;
1035
- this.failedCount = options?.teamProblemStatistics?.failedCount ?? 0;
1036
- this.pendingCount = options?.teamProblemStatistics?.pendingCount ?? 0;
1037
- this.ignoreCount = options?.teamProblemStatistics?.ignoreCount ?? 0;
1038
- this.totalCount = options?.teamProblemStatistics?.totalCount ?? 0;
1039
- this.submissions = options?.teamProblemStatistics?.submissions ?? [];
1040
- this.problem = options?.teamProblemStatistics?.problem ?? new Problem();
1041
- this.contestPenalty = options?.teamProblemStatistics?.contestPenalty ?? 20 * 60;
1073
+ getFreezeTime() {
1074
+ return this.replayFreezeTime ?? this.freezeTime;
1042
1075
  }
1043
- get isAccepted() {
1044
- return this.isSolved;
1076
+ getContestDuration(timeFormat = "HH:mm:ss") {
1077
+ return dayjs__default.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
1045
1078
  }
1046
- get isWrongAnswer() {
1047
- return !this.isSolved && this.pendingCount === 0 && this.failedCount > 0;
1079
+ getContestState(nowTime) {
1080
+ const now = createDayJS(nowTime);
1081
+ if (now.isBefore(this.getStartTime())) {
1082
+ return types.ContestState.PENDING;
1083
+ }
1084
+ if (now.isSameOrAfter(this.getEndTime())) {
1085
+ return types.ContestState.FINISHED;
1086
+ }
1087
+ if (now.isSameOrAfter(this.getFreezeTime())) {
1088
+ return types.ContestState.FROZEN;
1089
+ }
1090
+ return types.ContestState.RUNNING;
1048
1091
  }
1049
- get isPending() {
1050
- return !this.isSolved && this.pendingCount > 0;
1092
+ getContestPendingTime(nowTime) {
1093
+ let baseTime = createDayJS(nowTime);
1094
+ if (baseTime.isAfter(this.getStartTime())) {
1095
+ baseTime = this.getStartTime();
1096
+ }
1097
+ return getTimeDiff(Math.floor(dayjs__default.duration(this.getStartTime().diff(baseTime)).asSeconds()));
1051
1098
  }
1052
- get isUnSubmitted() {
1053
- return this.totalCount === 0;
1099
+ getContestElapsedTime(nowTime) {
1100
+ let baseTime = createDayJS(nowTime);
1101
+ if (baseTime.isAfter(this.getEndTime())) {
1102
+ baseTime = this.getEndTime();
1103
+ }
1104
+ if (baseTime.isBefore(this.getStartTime())) {
1105
+ baseTime = this.getStartTime();
1106
+ }
1107
+ return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.getStartTime())).asSeconds()));
1054
1108
  }
1055
- get solvedTimestampToMinute() {
1056
- return Math.floor(this.solvedTimestamp / 60);
1109
+ getContestRemainingTime(nowTime) {
1110
+ let baseTime = createDayJS(nowTime);
1111
+ if (baseTime.isAfter(this.getEndTime())) {
1112
+ baseTime = this.getEndTime();
1113
+ }
1114
+ if (baseTime.isBefore(this.getStartTime())) {
1115
+ baseTime = this.getStartTime();
1116
+ }
1117
+ return getTimeDiff(Math.floor(dayjs__default.duration(this.getEndTime().diff(baseTime)).asSeconds()));
1057
1118
  }
1058
- get penalty() {
1059
- if (this.isSolved === false) {
1119
+ getContestProgressRatio(nowTime) {
1120
+ const baseTime = createDayJS(nowTime);
1121
+ if (this.getStartTime().isSameOrAfter(baseTime)) {
1060
1122
  return 0;
1061
1123
  }
1062
- return this.solvedTimestampToMinute * 60 + this.failedCount * this.contestPenalty;
1063
- }
1064
- get penaltyToMinute() {
1065
- return Math.floor(this.penalty / 60);
1124
+ if (this.getEndTime().isSameOrBefore(baseTime)) {
1125
+ return 100;
1126
+ }
1127
+ const total = this.getEndTime().diff(this.getStartTime(), "s");
1128
+ const pass = baseTime.diff(this.getStartTime(), "s");
1129
+ return Math.round(pass * 100 / total);
1066
1130
  }
1067
- get penaltyInSecond() {
1068
- if (this.isSolved === false) {
1069
- return 0;
1131
+ isEnableAwards(group) {
1132
+ if (!this.awards) {
1133
+ return false;
1070
1134
  }
1071
- return this.solvedTimestamp + this.failedCount * this.contestPenalty;
1135
+ if (!this.awards.has(group)) {
1136
+ return false;
1137
+ }
1138
+ return true;
1072
1139
  }
1073
- }
1074
-
1075
- class PlaceChartPointData {
1076
- constructor() {
1077
- this.timePoint = 0;
1078
- this.rank = 0;
1079
- this.lastSolvedProblem = null;
1140
+ resetReplayTime() {
1141
+ this.replayStartTime = void 0;
1142
+ this.replayEndTime = void 0;
1143
+ this.replayFreezeTime = void 0;
1144
+ this.replayNowTime = void 0;
1145
+ this.replayContestStartTimestamp = void 0;
1080
1146
  }
1081
- }
1082
- class Team {
1083
- constructor() {
1084
- this.id = "";
1085
- this.name = "";
1086
- this.organization = "";
1087
- this.group = [];
1088
- this.tag = [];
1089
- this.rank = 0;
1090
- this.originalRank = 0;
1091
- this.organizationRank = -1;
1092
- this.solvedProblemNum = 0;
1093
- this.attemptedProblemNum = 0;
1094
- this.lastSolvedProblem = null;
1095
- this.lastSolvedProblemStatistics = null;
1096
- this.penalty = 0;
1097
- this.problemStatistics = [];
1098
- this.problemStatisticsMap = /* @__PURE__ */ new Map();
1099
- this.submissions = [];
1100
- this.placeChartPoints = [];
1101
- this.awards = [];
1102
- this.se = 0;
1103
- }
1104
- reset() {
1105
- this.rank = 0;
1106
- this.originalRank = 0;
1107
- this.organizationRank = -1;
1108
- this.solvedProblemNum = 0;
1109
- this.attemptedProblemNum = 0;
1110
- this.lastSolvedProblem = null;
1111
- this.lastSolvedProblemStatistics = null;
1112
- this.penalty = 0;
1113
- this.problemStatistics = [];
1114
- this.problemStatisticsMap = /* @__PURE__ */ new Map();
1115
- this.submissions = [];
1116
- this.placeChartPoints = [];
1117
- this.awards = [];
1118
- this.se = 0;
1119
- }
1120
- get penaltyToMinute() {
1121
- return Math.floor(this.penalty / 60);
1122
- }
1123
- get isUnofficial() {
1124
- return this.group.includes("unofficial");
1125
- }
1126
- get isGirl() {
1127
- return this.group.includes("girl");
1128
- }
1129
- get membersToArray() {
1130
- if (Array.isArray(this.members)) {
1131
- return this.members;
1132
- }
1133
- if (typeof this.members === "string") {
1134
- if (this.members.includes(", ")) {
1135
- return this.members.split(", ");
1136
- }
1137
- if (this.members.includes("\u3001")) {
1138
- return this.members.split("\u3001");
1139
- }
1140
- }
1141
- return [];
1142
- }
1143
- get membersToString() {
1144
- if (typeof this.members === "string") {
1145
- return this.members;
1146
- }
1147
- return this.members?.join(", ");
1148
- }
1149
- get isEffectiveTeam() {
1150
- return this.solvedProblemNum > 0;
1151
- }
1152
- get dirt() {
1153
- const attemptedNum = this.attemptedProblemNum;
1154
- const solvedNum = this.solvedProblemNum;
1155
- return calcDirt(attemptedNum, solvedNum);
1156
- }
1157
- calcSE(totalTeams) {
1158
- let acceptedProblemNums = 0;
1159
- let total = 0;
1160
- this.problemStatistics.forEach((p) => {
1161
- if (p.isSolved) {
1162
- acceptedProblemNums += 1;
1163
- total += p.problem.statistics.acceptedNum;
1164
- }
1165
- });
1166
- if (totalTeams === 0 || acceptedProblemNums === 0) {
1167
- return 0;
1147
+ setReplayTime(replayStartTimestamp) {
1148
+ if (replayStartTimestamp === 0) {
1149
+ this.resetReplayTime();
1150
+ return;
1168
1151
  }
1169
- const res = (acceptedProblemNums * totalTeams - total) / totalTeams / acceptedProblemNums;
1170
- this.se = Math.round(res * 100) / 100;
1171
- return this.se;
1152
+ const replayStartTime = createDayJS(replayStartTimestamp);
1153
+ const diff = replayStartTime.diff(this.startTime, "s");
1154
+ this.replayStartTime = this.startTime.add(diff, "s");
1155
+ this.replayEndTime = this.endTime.add(diff, "s");
1156
+ this.replayFreezeTime = this.freezeTime.add(diff, "s");
1157
+ this.replayNowTime = createDayJS();
1158
+ this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
1172
1159
  }
1173
- calcSolvedData(options) {
1174
- this.solvedProblemNum = 0;
1175
- this.attemptedProblemNum = 0;
1176
- this.penalty = 0;
1177
- for (const p of this.problemStatistics) {
1178
- if (p.isAccepted) {
1179
- this.solvedProblemNum++;
1180
- this.attemptedProblemNum += p.failedCount + 1;
1181
- if (options?.calculationOfPenalty === "in_seconds" || options?.calculationOfPenalty === "accumulate_in_seconds_and_finally_to_the_minute") {
1182
- this.penalty += p.penaltyInSecond;
1183
- } else {
1184
- this.penalty += p.penalty;
1185
- }
1186
- }
1160
+ }
1161
+ function createContest(contestJSON) {
1162
+ const c = new Contest();
1163
+ c.name = contestJSON.contest_name;
1164
+ c.startTime = createDayJS(contestJSON.start_time);
1165
+ c.endTime = createDayJS(contestJSON.end_time);
1166
+ c.totalDurationTimestamp = c.endTime.unix() - c.startTime.unix();
1167
+ {
1168
+ c.freezeTime = c.endTime;
1169
+ c.freezeDurationTimestamp = 0;
1170
+ if (contestJSON.frozen_time !== void 0 && contestJSON.frozen_time != null) {
1171
+ const frozenTime = Number(contestJSON.frozen_time);
1172
+ c.freezeTime = createDayJS(c.endTime.unix() - frozenTime);
1173
+ c.freezeDurationTimestamp = frozenTime;
1187
1174
  }
1188
- if (options?.calculationOfPenalty === "accumulate_in_seconds_and_finally_to_the_minute") {
1189
- this.penalty = Math.floor(this.penalty / 60) * 60;
1175
+ if (contestJSON.freeze_time !== void 0 && contestJSON.freeze_time !== null) {
1176
+ c.freezeTime = createDayJS(contestJSON.freeze_time);
1177
+ c.freezeDurationTimestamp = c.endTime.unix() - c.freezeTime.unix();
1190
1178
  }
1179
+ c.unFreezeDurationTimestamp = c.totalDurationTimestamp - c.freezeDurationTimestamp;
1191
1180
  }
1192
- calcAwards(awards) {
1193
- if (!awards) {
1194
- return;
1181
+ c.penalty = contestJSON.penalty;
1182
+ {
1183
+ if (contestJSON.problem_id !== void 0 && contestJSON.problem_id !== null) {
1184
+ c.problems = createProblemsByProblemIds(contestJSON.problem_id, contestJSON.balloon_color);
1195
1185
  }
1196
- for (const award of awards) {
1197
- if (this.rank >= award.minRank && this.rank <= award.maxRank) {
1198
- this.awards.push(award.medalType);
1199
- }
1186
+ if (contestJSON.problems !== void 0 && contestJSON.problems !== null) {
1187
+ c.problems = createProblems(contestJSON.problems);
1200
1188
  }
1189
+ c.problemsMap = new Map(c.problems.map((p) => [p.id, p]));
1201
1190
  }
1202
- isEqualRank(otherTeam) {
1203
- return this.solvedProblemNum === otherTeam.solvedProblemNum && this.penalty === otherTeam.penalty;
1191
+ if (contestJSON.status_time_display !== void 0 && contestJSON.status_time_display !== null) {
1192
+ c.statusTimeDisplay = {
1193
+ correct: Boolean(contestJSON.status_time_display.correct ?? false),
1194
+ incorrect: Boolean(contestJSON.status_time_display.incorrect ?? false),
1195
+ pending: Boolean(contestJSON.status_time_display.pending ?? false)
1196
+ };
1204
1197
  }
1205
- postProcessPlaceChartPoints() {
1206
- if (this.placeChartPoints.length === 0) {
1198
+ c.badge = contestJSON.badge;
1199
+ c.medal = contestJSON.medal;
1200
+ (() => {
1201
+ if (contestJSON.medal === void 0 || contestJSON.medal === null) {
1207
1202
  return;
1208
1203
  }
1209
- const res = [];
1210
- res.push(this.placeChartPoints[0]);
1211
- for (let i = 1; i < this.placeChartPoints.length - 1; i++) {
1212
- const p = this.placeChartPoints[i];
1213
- const preP = res[res.length - 1];
1214
- if (p.rank !== preP.rank || p.lastSolvedProblem !== preP.lastSolvedProblem) {
1215
- res.push(p);
1204
+ c.awards = /* @__PURE__ */ new Map();
1205
+ if (typeof contestJSON.medal === "string") ; else {
1206
+ for (const k in contestJSON.medal) {
1207
+ const v = contestJSON.medal[k];
1208
+ {
1209
+ const award = [];
1210
+ let rank = 1;
1211
+ const work = (key, medalType) => {
1212
+ if (Object.keys(v).includes(key)) {
1213
+ const a = new Award();
1214
+ a.medalType = medalType;
1215
+ a.minRank = rank;
1216
+ rank += Number(v[key]);
1217
+ a.maxRank = rank - 1;
1218
+ award.push(a);
1219
+ }
1220
+ };
1221
+ work("gold", MedalType.GOLD);
1222
+ work("silver", MedalType.SILVER);
1223
+ work("bronze", MedalType.BRONZE);
1224
+ {
1225
+ const a = new Award();
1226
+ a.medalType = MedalType.HONORABLE;
1227
+ a.minRank = rank;
1228
+ a.maxRank = 1061109567;
1229
+ award.push(a);
1230
+ }
1231
+ c.awards.set(k, award);
1232
+ }
1216
1233
  }
1217
1234
  }
1218
- if (this.placeChartPoints.length > 1) {
1219
- res.push(this.placeChartPoints[this.placeChartPoints.length - 1]);
1220
- }
1221
- this.placeChartPoints = res;
1235
+ })();
1236
+ c.organization = contestJSON.organization;
1237
+ {
1238
+ const g = new Group();
1239
+ g.names.set("en", "All");
1240
+ g.names.set("zh-CN", "\u6240\u6709\u961F\u4F0D");
1241
+ g.isDefault = true;
1242
+ c.group.set("all", g);
1222
1243
  }
1223
- static compare(lhs, rhs) {
1224
- if (lhs.solvedProblemNum !== rhs.solvedProblemNum) {
1225
- return rhs.solvedProblemNum - lhs.solvedProblemNum;
1226
- }
1227
- if (lhs.penalty !== rhs.penalty) {
1228
- return lhs.penalty - rhs.penalty;
1244
+ for (const [k, v] of Object.entries(contestJSON?.group ?? {})) {
1245
+ let key = k;
1246
+ const g = new Group();
1247
+ g.names.set("zh-CN", v);
1248
+ if (k === "official") {
1249
+ g.names.set("en", "Official");
1229
1250
  }
1230
- if (lhs.lastSolvedProblemStatistics && rhs.lastSolvedProblemStatistics) {
1231
- return lhs.lastSolvedProblemStatistics.solvedTimestampToMinute - rhs.lastSolvedProblemStatistics.solvedTimestampToMinute;
1251
+ if (k === "unofficial") {
1252
+ g.names.set("en", "Unofficial");
1232
1253
  }
1233
- if (lhs.name < rhs.name) {
1234
- return -1;
1235
- } else if (lhs.name > rhs.name) {
1236
- return 1;
1254
+ if (k === "girl" || k === "girls") {
1255
+ g.names.set("en", "Girls");
1256
+ key = "girl";
1237
1257
  }
1238
- return 0;
1258
+ c.group.set(key, g);
1239
1259
  }
1240
- }
1241
- function createTeam(teamJSON) {
1242
- const t = new Team();
1243
- t.id = teamJSON.id ?? teamJSON.team_id ?? "";
1244
- t.name = teamJSON.name ?? teamJSON.team_name ?? "";
1245
- t.organization = teamJSON.organization ?? "";
1246
- t.badge = teamJSON.badge;
1247
- t.group = ___default.cloneDeep(teamJSON.group ?? []);
1248
- t.tag = ___default.cloneDeep(teamJSON.tag ?? []);
1249
- t.coach = teamJSON.coach;
1250
- t.members = teamJSON.members;
1251
- if (Boolean(teamJSON.official) === true) {
1252
- t.group.push("official");
1260
+ c.banner = contestJSON.banner;
1261
+ if (c.banner) {
1262
+ c.bannerMode = contestJSON.banner_mode ?? "ALL";
1253
1263
  }
1254
- if (Boolean(teamJSON.unofficial) === true) {
1255
- t.group.push("unofficial");
1256
- }
1257
- if (Boolean(teamJSON.girl) === true) {
1258
- t.group.push("girl");
1259
- }
1260
- {
1261
- const tt = teamJSON;
1262
- for (const key of Object.keys(tt)) {
1263
- if (tt[key] === 1 || tt[key] === true) {
1264
- t.group.push(key);
1265
- }
1266
- }
1267
- }
1268
- t.group = [...new Set(t.group)];
1269
- t.group.sort();
1270
- if (teamJSON.location) {
1271
- t.location = teamJSON.location;
1272
- }
1273
- if (teamJSON.icpc_id) {
1274
- t.icpcID = teamJSON.icpc_id;
1275
- }
1276
- return t;
1277
- }
1278
- function createTeams(teamsJSON) {
1279
- if (Array.isArray(teamsJSON)) {
1280
- return teamsJSON.map((t) => createTeam(t));
1281
- } else {
1282
- const teams = Object.entries(teamsJSON).map(
1283
- ([teamId, team]) => createTeam({ ...team, team_id: team.team_id ?? teamId })
1284
- );
1285
- return teams;
1264
+ c.logo = contestJSON.logo;
1265
+ c.boardLink = contestJSON.board_link;
1266
+ if (contestJSON.options) {
1267
+ c.options = createContestOptions(contestJSON.options);
1286
1268
  }
1269
+ return c;
1287
1270
  }
1288
1271
 
1289
- class Submission {
1272
+ var __defProp$a = Object.defineProperty;
1273
+ var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1274
+ var __publicField$a = (obj, key, value) => {
1275
+ __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
1276
+ return value;
1277
+ };
1278
+ class ContestIndexConfig {
1290
1279
  constructor() {
1291
- this.status = types.SubmissionStatus.UNKNOWN;
1292
- this.isIgnore = false;
1293
- this.isSolved = false;
1294
- this.isFirstSolved = false;
1295
- this.id = "";
1296
- this.teamId = "";
1297
- this.problemId = "";
1298
- this.timestamp = 0;
1299
- this.timestampUnit = "second";
1300
- }
1301
- isAccepted() {
1302
- return isAccepted(this.status);
1303
- }
1304
- isRejected() {
1305
- return isRejected(this.status);
1306
- }
1307
- isPending() {
1308
- return isPending(this.status);
1280
+ __publicField$a(this, "contestName");
1281
+ __publicField$a(this, "startTime");
1282
+ __publicField$a(this, "endTime");
1283
+ __publicField$a(this, "freezeTime");
1284
+ __publicField$a(this, "totalDurationTimestamp");
1285
+ __publicField$a(this, "freezeDurationTimestamp");
1286
+ __publicField$a(this, "unFreezeDurationTimestamp");
1287
+ __publicField$a(this, "logo");
1288
+ this.contestName = "";
1289
+ this.startTime = createDayJS();
1290
+ this.endTime = createDayJS();
1291
+ this.freezeTime = createDayJS();
1292
+ this.totalDurationTimestamp = 0;
1293
+ this.freezeDurationTimestamp = 0;
1294
+ this.unFreezeDurationTimestamp = 0;
1309
1295
  }
1310
- isNotCalculatedPenaltyStatus() {
1311
- return isNotCalculatedPenaltyStatus(this.status);
1296
+ }
1297
+ class ContestIndex {
1298
+ constructor() {
1299
+ __publicField$a(this, "contest");
1300
+ __publicField$a(this, "boardLink");
1301
+ this.contest = new Contest();
1302
+ this.boardLink = "";
1312
1303
  }
1313
- get timestampToMinute() {
1314
- if (this.timestampUnit === "nanosecond") {
1315
- return Math.floor(this.timestamp / 60 / 1e3 / 1e3 / 1e3);
1304
+ }
1305
+ function createContestIndex(contestIndexJSON) {
1306
+ const c = new ContestIndex();
1307
+ const cjc = contestIndexJSON.config;
1308
+ c.contest = createContest(cjc);
1309
+ c.boardLink = contestIndexJSON.board_link;
1310
+ return c;
1311
+ }
1312
+ function createContestIndexList(contestListJSON) {
1313
+ const contestIndexList = [];
1314
+ const dfs = (contestList) => {
1315
+ if (Object.prototype.hasOwnProperty.call(contestList, "config")) {
1316
+ contestIndexList.push(createContestIndex(contestList));
1317
+ } else {
1318
+ for (const k in contestList) {
1319
+ dfs(contestList[k]);
1320
+ }
1316
1321
  }
1317
- if (this.timestampUnit === "microsecond") {
1318
- return Math.floor(this.timestamp / 60 / 1e3 / 1e3);
1322
+ };
1323
+ dfs(contestListJSON);
1324
+ contestIndexList.sort((a, b) => {
1325
+ if (a.contest.startTime.isBefore(b.contest.startTime)) {
1326
+ return 1;
1319
1327
  }
1320
- if (this.timestampUnit === "millisecond") {
1321
- return Math.floor(this.timestamp / 60 / 1e3);
1328
+ if (a.contest.startTime.isAfter(b.contest.startTime)) {
1329
+ return -1;
1322
1330
  }
1323
- return Math.floor(this.timestamp / 60);
1324
- }
1325
- get timestampToSecond() {
1326
- if (this.timestampUnit === "nanosecond") {
1327
- return Math.floor(this.timestamp / 1e3 / 1e3 / 1e3);
1331
+ if (a.contest.endTime.isBefore(b.contest.endTime)) {
1332
+ return 1;
1328
1333
  }
1329
- if (this.timestampUnit === "microsecond") {
1330
- return Math.floor(this.timestamp / 1e3 / 1e3);
1334
+ if (a.contest.endTime.isAfter(b.contest.endTime)) {
1335
+ return -1;
1331
1336
  }
1332
- if (this.timestampUnit === "millisecond") {
1333
- return Math.floor(this.timestamp / 1e3);
1337
+ if (a.contest.name < b.contest.name) {
1338
+ return 1;
1334
1339
  }
1335
- return this.timestamp;
1336
- }
1337
- get timestampDisplayFormatWithSecond() {
1338
- const second = this.timestampToSecond;
1339
- const h = Math.floor(second / 3600);
1340
- const m = Math.floor(second % 3600 / 60);
1341
- const s = second % 60;
1342
- const f = (x) => x.toString().padStart(2, "0");
1343
- const res = `${f(h)}:${f(m)}:${f(s)}`;
1344
- return res;
1345
- }
1346
- get timestampDisplayFormatWithMilliSecond() {
1347
- let res = this.timestampDisplayFormatWithSecond;
1348
- if (this.timestampUnit === "millisecond") {
1349
- const fl = (this.timestamp % 1e3).toString().padStart(3, "0");
1350
- res += `.${fl}`;
1340
+ if (a.contest.name > b.contest.name) {
1341
+ return -1;
1351
1342
  }
1352
- return res;
1343
+ return 0;
1344
+ });
1345
+ return contestIndexList;
1346
+ }
1347
+
1348
+ class CodeforcesGymGhostDATConverter {
1349
+ constructor() {
1353
1350
  }
1354
- static compare(lhs, rhs) {
1355
- if (lhs.timestamp !== rhs.timestamp) {
1356
- return lhs.timestamp - rhs.timestamp;
1351
+ convert(rank) {
1352
+ let res = "";
1353
+ res += `@contest "${rank.contest.name}"
1354
+ @contlen ${Math.floor(dayjs__default.duration(rank.contest.endTime.diff(rank.contest.startTime)).asMinutes())}
1355
+ @problems ${rank.contest.problems.length}
1356
+ @teams ${rank.teams.length + 100}
1357
+ @submissions ${rank.submissions.length}
1358
+ `;
1359
+ rank.contest.problems.forEach((p) => {
1360
+ res += `@p ${p.label},${p.label},20,0
1361
+ `;
1362
+ });
1363
+ let teamIndex = 1;
1364
+ const teamIdMap = /* @__PURE__ */ new Map();
1365
+ const submissionsIdMap = /* @__PURE__ */ new Map();
1366
+ rank.teams.forEach((team) => {
1367
+ let name = team.name;
1368
+ if (team.organization) {
1369
+ name = `${team.organization} - ${name}`;
1370
+ }
1371
+ if (team.members) {
1372
+ name = `${name} - ${team.membersToString}`;
1373
+ }
1374
+ res += `@t ${teamIndex},0,1,"${name}"
1375
+ `;
1376
+ teamIdMap.set(team.id, teamIndex);
1377
+ teamIndex++;
1378
+ {
1379
+ const mp = /* @__PURE__ */ new Map();
1380
+ rank.contest.problems.forEach((p) => {
1381
+ mp.set(p.id, 0);
1382
+ });
1383
+ submissionsIdMap.set(team.id, mp);
1384
+ }
1385
+ });
1386
+ for (let i = 0; i < 100; i++) {
1387
+ res += `@t ${teamIndex},0,1,"\u041F\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043A\u043E\u043C\u0430\u043D\u0434\u0443"
1388
+ `;
1389
+ teamIndex++;
1357
1390
  }
1358
- if (lhs.teamId === rhs.teamId) {
1359
- if (lhs.isAccepted() && !rhs.isAccepted()) {
1360
- return -1;
1391
+ rank.getSubmissions().forEach((submission) => {
1392
+ const teamId = submission.teamId;
1393
+ const problemId = submission.problemId;
1394
+ const problem = rank.contest.problemsMap.get(problemId);
1395
+ const teamIndex2 = teamIdMap.get(teamId);
1396
+ if (!problem) {
1397
+ return;
1361
1398
  }
1362
- if (!lhs.isAccepted() && rhs.isAccepted()) {
1363
- return 1;
1399
+ if (!teamIndex2) {
1400
+ return;
1364
1401
  }
1402
+ const status = this.submissionStatusToCodeforcesGymDatStatus(submission.status);
1403
+ submissionsIdMap.get(teamId).set(problemId, submissionsIdMap.get(teamId).get(problemId) + 1);
1404
+ res += `@s ${teamIndex2},${problem.label},${submissionsIdMap.get(teamId)?.get(problemId)},${submission.timestampToSecond},${status}
1405
+ `;
1406
+ });
1407
+ return res;
1408
+ }
1409
+ submissionStatusToCodeforcesGymDatStatus(status) {
1410
+ if (isAccepted(status)) {
1411
+ return "OK";
1365
1412
  }
1366
- if (lhs.id < rhs.id) {
1367
- return -1;
1368
- } else if (lhs.id === rhs.id) {
1369
- return 0;
1370
- } else {
1371
- return 1;
1413
+ if (status === types.SubmissionStatus.WRONG_ANSWER) {
1414
+ return "WA";
1415
+ }
1416
+ if (status === types.SubmissionStatus.TIME_LIMIT_EXCEEDED) {
1417
+ return "TL";
1418
+ }
1419
+ if (status === types.SubmissionStatus.MEMORY_LIMIT_EXCEEDED) {
1420
+ return "ML";
1421
+ }
1422
+ if (status === types.SubmissionStatus.OUTPUT_LIMIT_EXCEEDED) {
1423
+ return "IL";
1424
+ }
1425
+ if (status === types.SubmissionStatus.PRESENTATION_ERROR) {
1426
+ return "PE";
1427
+ }
1428
+ if (status === types.SubmissionStatus.RUNTIME_ERROR) {
1429
+ return "RT";
1430
+ }
1431
+ if (status === types.SubmissionStatus.COMPILATION_ERROR || isNotCalculatedPenaltyStatus(status)) {
1432
+ return "CE";
1372
1433
  }
1434
+ if (isPending(status)) {
1435
+ return "PD";
1436
+ }
1437
+ return "RJ";
1373
1438
  }
1374
1439
  }
1375
- function createSubmission(submissionJSON) {
1376
- const s = new Submission();
1377
- s.id = String(submissionJSON.id ?? submissionJSON.submission_id ?? "");
1378
- s.teamId = String(submissionJSON.team_id);
1379
- s.problemId = String(submissionJSON.problem_id);
1380
- s.timestamp = submissionJSON.timestamp;
1381
- s.status = stringToSubmissionStatus(submissionJSON.status);
1382
- s.isIgnore = submissionJSON.is_ignore ?? false;
1383
- if (submissionJSON.time) {
1384
- s.time = submissionJSON.time;
1440
+
1441
+ class GeneralExcelConverter {
1442
+ constructor() {
1385
1443
  }
1386
- if (submissionJSON.language) {
1387
- s.language = submissionJSON.language;
1444
+ convert(oriRank) {
1445
+ const rank = ___default.cloneDeep(oriRank);
1446
+ rank.options.disableFilterTeamsByGroup();
1447
+ rank.options.disableFilterSubmissionByTimestamp();
1448
+ const workbook = XLSX__namespace.utils.book_new();
1449
+ for (const [k, v] of rank.contest.group) {
1450
+ rank.options.setGroup(k);
1451
+ rank.buildRank();
1452
+ const sheet = this.convertToSheet(rank);
1453
+ XLSX__namespace.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang));
1454
+ }
1455
+ return workbook;
1388
1456
  }
1389
- if (submissionJSON.reaction) {
1390
- s.reaction = submissionJSON.reaction;
1391
- }
1392
- return s;
1393
- }
1394
- function createSubmissions(submissionsJSON) {
1395
- if (Array.isArray(submissionsJSON)) {
1396
- return submissionsJSON.map((s, index) => createSubmission({ ...s, id: s.submission_id ?? String(index) }));
1397
- } else {
1398
- const submissions = Object.entries(submissionsJSON).map(
1399
- ([submissionId, s]) => createSubmission({ ...s, id: s.submission_id ?? submissionId })
1457
+ convertAndWrite(rank, filename) {
1458
+ return XLSX__namespace.writeFile(
1459
+ this.convert(rank),
1460
+ filename,
1461
+ {
1462
+ compression: true
1463
+ }
1400
1464
  );
1401
- return submissions;
1402
- }
1403
- }
1404
-
1405
- class Balloon {
1406
- constructor() {
1407
- this.problem = new Problem();
1408
- this.team = new Team();
1409
- this.submission = new Submission();
1410
- }
1411
- get key() {
1412
- return `balloon-${this.team.id}-${this.problem.id}`;
1413
- }
1414
- static compare(lhs, rhs) {
1415
- return Submission.compare(lhs.submission, rhs.submission);
1416
- }
1417
- }
1418
-
1419
- var GiantsType = /* @__PURE__ */ ((GiantsType2) => {
1420
- GiantsType2[GiantsType2["BLUE"] = 0] = "BLUE";
1421
- GiantsType2[GiantsType2["RED"] = 1] = "RED";
1422
- return GiantsType2;
1423
- })(GiantsType || {});
1424
- class Giants {
1425
- constructor(type = 0 /* BLUE */) {
1426
- this.type = type;
1427
- this.name = `${type === 0 /* BLUE */ ? "Blue" : "Red"} Team`;
1428
- this.teams = [];
1429
- this.filterOrganizations = [];
1430
- this.filterOrganizationMap = /* @__PURE__ */ new Map();
1431
- this.filterTeams = [];
1432
- this.filterTeamMap = /* @__PURE__ */ new Map();
1433
- }
1434
- setFilterOrganizations(filterOrganizations) {
1435
- const m = /* @__PURE__ */ new Map();
1436
- filterOrganizations.forEach((item) => {
1437
- m.set(item.value, item);
1438
- });
1439
- this.filterOrganizations = filterOrganizations;
1440
- this.filterOrganizationMap = m;
1441
- }
1442
- setFilterTeams(filterTeams) {
1443
- const m = /* @__PURE__ */ new Map();
1444
- filterTeams.forEach((item) => {
1445
- m.set(item.value, item);
1446
- });
1447
- this.filterTeams = filterTeams;
1448
- this.filterTeamMap = m;
1449
- }
1450
- refreshName() {
1451
- if (this.filterOrganizations.length > 0) {
1452
- this.name = this.filterOrganizations[0].text;
1453
- } else {
1454
- this.name = `${this.type === 0 /* BLUE */ ? "Blue" : "Red"} Team`;
1455
- }
1456
- return this.name;
1457
- }
1458
- get totalSolvedProblemNum() {
1459
- let total = 0;
1460
- this.teams.forEach((team) => {
1461
- total += team.solvedProblemNum;
1462
- });
1463
- return total;
1464
1465
  }
1465
- get totalPenalty() {
1466
- let total = 0;
1467
- this.teams.forEach((team) => {
1468
- total += team.penaltyToMinute;
1469
- });
1470
- return total;
1471
- }
1472
- get totalPenaltyToString() {
1473
- const penalty = this.totalPenalty;
1474
- const two = (a) => {
1475
- if (a < 10) {
1476
- return `0${a}`;
1466
+ convertToSheet(rank) {
1467
+ const aoa = this.convertToAoa(rank);
1468
+ const sheet = XLSX__namespace.utils.aoa_to_sheet(aoa);
1469
+ const cols = [];
1470
+ const head = aoa[1];
1471
+ for (let j = 0; j < head.length; j++) {
1472
+ let wch = 10;
1473
+ for (let i = 1; i < aoa.length; i++) {
1474
+ wch = Math.max(wch, stringWidth__default(aoa[i][j]) + 2);
1477
1475
  }
1478
- return String(a);
1479
- };
1480
- const h = Math.floor(penalty / 60);
1481
- const m = Math.floor(penalty % 60);
1482
- return [two(h), two(m)].join(":");
1483
- }
1484
- toJSON() {
1485
- return {
1486
- type: this.type,
1487
- name: this.name,
1488
- filterOrganizations: this.filterOrganizations,
1489
- filterTeams: this.filterTeams
1490
- };
1491
- }
1492
- }
1493
- class BattleOfGiants {
1494
- constructor() {
1495
- this.enable = false;
1496
- this.topX = 5;
1497
- this.equalTeams = true;
1498
- this.persist = false;
1499
- this.blueTeam = new Giants(0 /* BLUE */);
1500
- this.redTeam = new Giants(1 /* RED */);
1501
- }
1502
- ToBase64() {
1503
- return jsBase64.Base64.encode(JSON.stringify(this));
1504
- }
1505
- FromBase64(base64) {
1506
- if (base64.length === 0) {
1507
- return;
1476
+ cols.push({
1477
+ wch
1478
+ });
1508
1479
  }
1509
- if (jsBase64.Base64.isValid(base64) === false) {
1510
- return;
1480
+ sheet["!cols"] = cols;
1481
+ {
1482
+ const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
1483
+ const merges = [{ s: mergeRange.s, e: mergeRange.e }];
1484
+ sheet["!merges"] = merges;
1511
1485
  }
1512
- const j = JSON.parse(jsBase64.Base64.decode(base64));
1513
- this.enable = j.enable;
1514
- this.topX = j.topX;
1515
- this.equalTeams = j.equalTeams;
1516
- this.persist = j.persist;
1517
- this.blueTeam = new Giants(0 /* BLUE */);
1518
- this.blueTeam.name = j.blueTeam.name;
1519
- this.blueTeam.setFilterOrganizations(j.blueTeam.filterOrganizations);
1520
- this.blueTeam.setFilterTeams(j.blueTeam.filterTeams);
1521
- this.redTeam = new Giants(1 /* RED */);
1522
- this.redTeam.name = j.redTeam.name;
1523
- this.redTeam.setFilterOrganizations(j.redTeam.filterOrganizations);
1524
- this.redTeam.setFilterTeams(j.redTeam.filterTeams);
1525
- }
1526
- }
1527
-
1528
- class Group {
1529
- constructor() {
1530
- this.names = /* @__PURE__ */ new Map();
1531
- this.defaultLang = "zh-CN";
1532
- this.isDefault = false;
1533
- }
1534
- }
1535
-
1536
- class ContestOptions {
1537
- constructor() {
1538
- this.calculationOfPenalty = "in_minutes";
1539
- this.submissionTimestampUnit = "second";
1540
- this.submissionHasTimeField = false;
1541
- this.submissionHasLanguageField = false;
1542
- this.submissionEnableActionField = false;
1543
- }
1544
- }
1545
- function createContestOptions(contestOptionsJSON = {}) {
1546
- const j = contestOptionsJSON;
1547
- const o = new ContestOptions();
1548
- if (j.calculation_of_penalty) {
1549
- o.calculationOfPenalty = j.calculation_of_penalty;
1550
- }
1551
- if (j.submission_timestamp_unit) {
1552
- o.submissionTimestampUnit = j.submission_timestamp_unit;
1553
- }
1554
- if (j.submission_has_reaction) {
1555
- o.submissionEnableActionField = j.submission_has_reaction;
1556
- }
1557
- return o;
1558
- }
1559
-
1560
- class Contest {
1561
- constructor() {
1562
- this.id = "";
1563
- this.name = "";
1564
- this.startTime = createDayJS();
1565
- this.endTime = createDayJS();
1566
- this.freezeTime = createDayJS();
1567
- this.totalDurationTimestamp = 0;
1568
- this.freezeDurationTimestamp = 0;
1569
- this.unFreezeDurationTimestamp = 0;
1570
- this.penalty = 20 * 60;
1571
- this.problems = [];
1572
- this.problemsMap = /* @__PURE__ */ new Map();
1573
- this.statusTimeDisplay = {
1574
- correct: true,
1575
- incorrect: true,
1576
- pending: true
1486
+ const font = {
1487
+ name: "Arial Unicode MS",
1488
+ bold: false,
1489
+ italic: false,
1490
+ sz: 12
1577
1491
  };
1578
- this.group = /* @__PURE__ */ new Map();
1579
- this.tag = /* @__PURE__ */ new Map();
1580
- this.options = new ContestOptions();
1581
- }
1582
- getStartTime() {
1583
- return this.replayStartTime ?? this.startTime;
1584
- }
1585
- getEndTime() {
1586
- return this.replayEndTime ?? this.endTime;
1587
- }
1588
- getFreezeTime() {
1589
- return this.replayFreezeTime ?? this.freezeTime;
1590
- }
1591
- getContestDuration(timeFormat = "HH:mm:ss") {
1592
- return dayjs__default.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
1593
- }
1594
- getContestState(nowTime) {
1595
- const now = createDayJS(nowTime);
1596
- if (now.isBefore(this.getStartTime())) {
1597
- return types.ContestState.PENDING;
1598
- }
1599
- if (now.isSameOrAfter(this.getEndTime())) {
1600
- return types.ContestState.FINISHED;
1601
- }
1602
- if (now.isSameOrAfter(this.getFreezeTime())) {
1603
- return types.ContestState.FROZEN;
1604
- }
1605
- return types.ContestState.RUNNING;
1606
- }
1607
- getContestPendingTime(nowTime) {
1608
- let baseTime = createDayJS(nowTime);
1609
- if (baseTime.isAfter(this.getStartTime())) {
1610
- baseTime = this.getStartTime();
1611
- }
1612
- return getTimeDiff(Math.floor(dayjs__default.duration(this.getStartTime().diff(baseTime)).asSeconds()));
1613
- }
1614
- getContestElapsedTime(nowTime) {
1615
- let baseTime = createDayJS(nowTime);
1616
- if (baseTime.isAfter(this.getEndTime())) {
1617
- baseTime = this.getEndTime();
1618
- }
1619
- if (baseTime.isBefore(this.getStartTime())) {
1620
- baseTime = this.getStartTime();
1621
- }
1622
- return getTimeDiff(Math.floor(dayjs__default.duration(baseTime.diff(this.getStartTime())).asSeconds()));
1623
- }
1624
- getContestRemainingTime(nowTime) {
1625
- let baseTime = createDayJS(nowTime);
1626
- if (baseTime.isAfter(this.getEndTime())) {
1627
- baseTime = this.getEndTime();
1628
- }
1629
- if (baseTime.isBefore(this.getStartTime())) {
1630
- baseTime = this.getStartTime();
1631
- }
1632
- return getTimeDiff(Math.floor(dayjs__default.duration(this.getEndTime().diff(baseTime)).asSeconds()));
1633
- }
1634
- getContestProgressRatio(nowTime) {
1635
- const baseTime = createDayJS(nowTime);
1636
- if (this.getStartTime().isSameOrAfter(baseTime)) {
1637
- return 0;
1638
- }
1639
- if (this.getEndTime().isSameOrBefore(baseTime)) {
1640
- return 100;
1641
- }
1642
- const total = this.getEndTime().diff(this.getStartTime(), "s");
1643
- const pass = baseTime.diff(this.getStartTime(), "s");
1644
- return Math.round(pass * 100 / total);
1645
- }
1646
- isEnableAwards(group) {
1647
- if (!this.awards) {
1648
- return false;
1649
- }
1650
- if (!this.awards.has(group)) {
1651
- return false;
1652
- }
1653
- return true;
1654
- }
1655
- resetReplayTime() {
1656
- this.replayStartTime = void 0;
1657
- this.replayEndTime = void 0;
1658
- this.replayFreezeTime = void 0;
1659
- this.replayNowTime = void 0;
1660
- this.replayContestStartTimestamp = void 0;
1661
- }
1662
- setReplayTime(replayStartTimestamp) {
1663
- if (replayStartTimestamp === 0) {
1664
- this.resetReplayTime();
1665
- return;
1666
- }
1667
- const replayStartTime = createDayJS(replayStartTimestamp);
1668
- const diff = replayStartTime.diff(this.startTime, "s");
1669
- this.replayStartTime = this.startTime.add(diff, "s");
1670
- this.replayEndTime = this.endTime.add(diff, "s");
1671
- this.replayFreezeTime = this.freezeTime.add(diff, "s");
1672
- this.replayNowTime = createDayJS();
1673
- this.replayContestStartTimestamp = this.replayNowTime.diff(this.replayStartTime, "s");
1674
- }
1675
- }
1676
- function createContest(contestJSON) {
1677
- const c = new Contest();
1678
- c.name = contestJSON.contest_name;
1679
- c.startTime = createDayJS(contestJSON.start_time);
1680
- c.endTime = createDayJS(contestJSON.end_time);
1681
- c.totalDurationTimestamp = c.endTime.unix() - c.startTime.unix();
1682
- {
1683
- c.freezeTime = c.endTime;
1684
- c.freezeDurationTimestamp = 0;
1685
- if (contestJSON.frozen_time !== void 0 && contestJSON.frozen_time != null) {
1686
- const frozenTime = Number(contestJSON.frozen_time);
1687
- c.freezeTime = createDayJS(c.endTime.unix() - frozenTime);
1688
- c.freezeDurationTimestamp = frozenTime;
1492
+ const borderStyle = {
1493
+ style: "thin"
1494
+ };
1495
+ const cellStyle = {
1496
+ alignment: {
1497
+ vertical: "center",
1498
+ horizontal: "center"
1499
+ },
1500
+ border: {
1501
+ top: borderStyle,
1502
+ bottom: borderStyle,
1503
+ left: borderStyle,
1504
+ right: borderStyle
1505
+ },
1506
+ font
1507
+ };
1508
+ for (let i = 1; i < aoa.length; i++) {
1509
+ for (let j = 0; j < aoa[i].length; j++) {
1510
+ const cellAddress = XLSX__namespace.utils.encode_cell({ r: i, c: j });
1511
+ const cell = sheet[cellAddress];
1512
+ cell.s = cellStyle;
1513
+ }
1689
1514
  }
1690
- if (contestJSON.freeze_time !== void 0 && contestJSON.freeze_time !== null) {
1691
- c.freezeTime = createDayJS(contestJSON.freeze_time);
1692
- c.freezeDurationTimestamp = c.endTime.unix() - c.freezeTime.unix();
1515
+ {
1516
+ const cellAddress = XLSX__namespace.utils.encode_cell({ r: 0, c: 0 });
1517
+ const cell = sheet[cellAddress];
1518
+ const titleStyle = ___default.cloneDeep(cellStyle);
1519
+ titleStyle.font.sz = 28;
1520
+ titleStyle.font.bold = true;
1521
+ cell.s = titleStyle;
1693
1522
  }
1694
- c.unFreezeDurationTimestamp = c.totalDurationTimestamp - c.freezeDurationTimestamp;
1523
+ return sheet;
1695
1524
  }
1696
- c.penalty = contestJSON.penalty;
1697
- {
1698
- if (contestJSON.problem_id !== void 0 && contestJSON.problem_id !== null) {
1699
- c.problems = createProblemsByProblemIds(contestJSON.problem_id, contestJSON.balloon_color);
1700
- }
1701
- if (contestJSON.problems !== void 0 && contestJSON.problems !== null) {
1702
- c.problems = createProblems(contestJSON.problems);
1525
+ convertToAoa(rank) {
1526
+ const aoa = [];
1527
+ const enableAwards = rank.contest.isEnableAwards(rank.options.group);
1528
+ const enableMembers = (Array.isArray(rank.teams) && rank.teams[0]?.members) ?? false;
1529
+ const enableCoach = rank.teams[0]?.coach ?? false;
1530
+ {
1531
+ aoa.push([rank.contest.name]);
1703
1532
  }
1704
- c.problemsMap = new Map(c.problems.map((p) => [p.id, p]));
1705
- }
1706
- if (contestJSON.status_time_display !== void 0 && contestJSON.status_time_display !== null) {
1707
- c.statusTimeDisplay = {
1708
- correct: Boolean(contestJSON.status_time_display.correct ?? false),
1709
- incorrect: Boolean(contestJSON.status_time_display.incorrect ?? false),
1710
- pending: Boolean(contestJSON.status_time_display.pending ?? false)
1711
- };
1712
- }
1713
- c.badge = contestJSON.badge;
1714
- c.medal = contestJSON.medal;
1715
- (() => {
1716
- if (contestJSON.medal === void 0 || contestJSON.medal === null) {
1717
- return;
1533
+ {
1534
+ const head = [];
1535
+ head.push("Rank");
1536
+ if (rank.contest.organization) {
1537
+ head.push(`${rank.contest.organization} Rank`);
1538
+ head.push(rank.contest.organization);
1539
+ }
1540
+ head.push("Team", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dirt");
1541
+ if (enableAwards) {
1542
+ head.push("Medal");
1543
+ }
1544
+ if (enableMembers) {
1545
+ head.push("Member1", "Member2", "Member3");
1546
+ }
1547
+ if (enableCoach) {
1548
+ head.push("Coach");
1549
+ }
1550
+ head.push("Unofficial");
1551
+ head.push("Girl");
1552
+ aoa.push(head);
1718
1553
  }
1719
- c.awards = /* @__PURE__ */ new Map();
1720
- if (typeof contestJSON.medal === "string") ; else {
1721
- for (const k in contestJSON.medal) {
1722
- const v = contestJSON.medal[k];
1723
- {
1724
- const award = [];
1725
- let rank = 1;
1726
- const work = (key, medalType) => {
1727
- if (Object.keys(v).includes(key)) {
1728
- const a = new Award();
1729
- a.medalType = medalType;
1730
- a.minRank = rank;
1731
- rank += Number(v[key]);
1732
- a.maxRank = rank - 1;
1733
- award.push(a);
1734
- }
1735
- };
1736
- work("gold", MedalType.GOLD);
1737
- work("silver", MedalType.SILVER);
1738
- work("bronze", MedalType.BRONZE);
1739
- {
1740
- const a = new Award();
1741
- a.medalType = MedalType.HONORABLE;
1742
- a.minRank = rank;
1743
- a.maxRank = 1061109567;
1744
- award.push(a);
1745
- }
1746
- c.awards.set(k, award);
1554
+ for (const team of rank.teams) {
1555
+ const arr = [];
1556
+ arr.push(team.rank.toString());
1557
+ if (team.organization) {
1558
+ if (team.organizationRank !== -1) {
1559
+ arr.push(team.organizationRank.toString());
1560
+ } else {
1561
+ arr.push("");
1747
1562
  }
1563
+ arr.push(team.organization);
1748
1564
  }
1749
- }
1750
- })();
1751
- c.organization = contestJSON.organization;
1752
- {
1753
- const g = new Group();
1754
- g.names.set("en", "All");
1755
- g.names.set("zh-CN", "\u6240\u6709\u961F\u4F0D");
1756
- g.isDefault = true;
1757
- c.group.set("all", g);
1758
- }
1759
- for (const [k, v] of Object.entries(contestJSON?.group ?? {})) {
1760
- let key = k;
1761
- const g = new Group();
1762
- g.names.set("zh-CN", v);
1763
- if (k === "official") {
1764
- g.names.set("en", "Official");
1765
- }
1766
- if (k === "unofficial") {
1767
- g.names.set("en", "Unofficial");
1768
- }
1769
- if (k === "girl" || k === "girls") {
1770
- g.names.set("en", "Girls");
1771
- key = "girl";
1772
- }
1773
- c.group.set(key, g);
1774
- }
1775
- c.banner = contestJSON.banner;
1776
- if (c.banner) {
1777
- c.bannerMode = contestJSON.banner_mode ?? "ALL";
1778
- }
1779
- c.logo = contestJSON.logo;
1780
- c.boardLink = contestJSON.board_link;
1781
- if (contestJSON.options) {
1782
- c.options = createContestOptions(contestJSON.options);
1565
+ arr.push(team.name, team.solvedProblemNum.toString(), team.penaltyToMinute.toString());
1566
+ for (const p of team.problemStatistics) {
1567
+ if (p.isUnSubmitted) {
1568
+ arr.push("-");
1569
+ }
1570
+ if (p.isSolved) {
1571
+ arr.push(`+${p.totalCount}(${p.solvedTimestampToMinute})`);
1572
+ }
1573
+ if (p.isWrongAnswer) {
1574
+ arr.push(`-${p.failedCount}`);
1575
+ }
1576
+ if (p.isPending) {
1577
+ arr.push(`? ${p.failedCount} + ${p.pendingCount}`);
1578
+ }
1579
+ }
1580
+ arr.push(`${team.dirt}%`);
1581
+ if (enableAwards) {
1582
+ const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
1583
+ arr.push(medals.join(", "));
1584
+ }
1585
+ if (enableMembers) {
1586
+ const members = team.members;
1587
+ if (Array.isArray(members)) {
1588
+ arr.push(members[0] ?? "");
1589
+ arr.push(members[1] ?? "");
1590
+ arr.push(members[2] ?? "");
1591
+ } else {
1592
+ arr.push("", "", "");
1593
+ }
1594
+ }
1595
+ if (enableCoach) {
1596
+ if (typeof team.coach === "string") {
1597
+ arr.push(team.coach ?? "");
1598
+ } else {
1599
+ arr.push("");
1600
+ }
1601
+ }
1602
+ arr.push(team.isUnofficial ? "Y" : "N");
1603
+ arr.push(team.isGirl ? "Y" : "N");
1604
+ aoa.push(arr);
1605
+ }
1606
+ return aoa;
1783
1607
  }
1784
- return c;
1785
1608
  }
1786
1609
 
1787
- class ContestIndexConfig {
1788
- constructor() {
1789
- this.contestName = "";
1790
- this.startTime = createDayJS();
1791
- this.endTime = createDayJS();
1792
- this.freezeTime = createDayJS();
1793
- this.totalDurationTimestamp = 0;
1794
- this.freezeDurationTimestamp = 0;
1795
- this.unFreezeDurationTimestamp = 0;
1796
- }
1797
- }
1798
- class ContestIndex {
1610
+ class ICPCStandingsCsvConverter {
1799
1611
  constructor() {
1800
- this.contest = new Contest();
1801
- this.boardLink = "";
1802
1612
  }
1803
- }
1804
- function createContestIndex(contestIndexJSON) {
1805
- const c = new ContestIndex();
1806
- const cjc = contestIndexJSON.config;
1807
- c.contest = createContest(cjc);
1808
- c.boardLink = contestIndexJSON.board_link;
1809
- return c;
1810
- }
1811
- function createContestIndexList(contestListJSON) {
1812
- const contestIndexList = [];
1813
- const dfs = (contestList) => {
1814
- if (Object.prototype.hasOwnProperty.call(contestList, "config")) {
1815
- contestIndexList.push(createContestIndex(contestList));
1816
- } else {
1817
- for (const k in contestList) {
1818
- dfs(contestList[k]);
1819
- }
1820
- }
1821
- };
1822
- dfs(contestListJSON);
1823
- contestIndexList.sort((a, b) => {
1824
- if (a.contest.startTime.isBefore(b.contest.startTime)) {
1825
- return 1;
1826
- }
1827
- if (a.contest.startTime.isAfter(b.contest.startTime)) {
1828
- return -1;
1829
- }
1830
- if (a.contest.endTime.isBefore(b.contest.endTime)) {
1831
- return 1;
1832
- }
1833
- if (a.contest.endTime.isAfter(b.contest.endTime)) {
1834
- return -1;
1613
+ convert(oriRank) {
1614
+ const rank = ___default.cloneDeep(oriRank);
1615
+ rank.options.disableFilterTeamsByGroup();
1616
+ rank.options.disableFilterSubmissionByTimestamp();
1617
+ rank.options.setGroup("official");
1618
+ rank.buildRank();
1619
+ const resList = [];
1620
+ for (const team of rank.teams) {
1621
+ const res = {
1622
+ teamId: team.icpcID ?? "",
1623
+ rank: team.rank,
1624
+ medalCitation: this.getMedalCitation(team),
1625
+ problemsSolved: team.solvedProblemNum,
1626
+ totalTime: team.penaltyToMinute,
1627
+ lastProblemTime: team.lastSolvedProblemStatistics?.solvedTimestampToMinute ?? 0,
1628
+ siteCitation: rank.contest.name,
1629
+ citation: ordinal__default(team.rank),
1630
+ teamName: team.name,
1631
+ institution: team.organization
1632
+ };
1633
+ resList.push(res);
1835
1634
  }
1836
- if (a.contest.name < b.contest.name) {
1837
- return 1;
1635
+ const csv = Papa__default.unparse(resList);
1636
+ return csv;
1637
+ }
1638
+ getMedalCitation(team) {
1639
+ if (team.solvedProblemNum === 0) {
1640
+ return "";
1838
1641
  }
1839
- if (a.contest.name > b.contest.name) {
1840
- return -1;
1642
+ const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
1643
+ if (medals.length === 1) {
1644
+ const medal = medals[0];
1645
+ if (medal === "Gold") {
1646
+ return "Gold Medal";
1647
+ }
1648
+ if (medal === "Silver") {
1649
+ return "Silver Medal";
1650
+ }
1651
+ if (medal === "Bronze") {
1652
+ return "Bronze Medal";
1653
+ }
1654
+ if (medal === "Honorable") {
1655
+ return "Honorable Mention";
1656
+ }
1841
1657
  }
1842
- return 0;
1843
- });
1844
- return contestIndexList;
1658
+ return "";
1659
+ }
1845
1660
  }
1846
1661
 
1847
1662
  function getImageSource(image, asset_host) {
@@ -1860,8 +1675,56 @@ function getImageSource(image, asset_host) {
1860
1675
  return "";
1861
1676
  }
1862
1677
 
1678
+ var __defProp$9 = Object.defineProperty;
1679
+ var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1680
+ var __publicField$9 = (obj, key, value) => {
1681
+ __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
1682
+ return value;
1683
+ };
1684
+ class Person {
1685
+ constructor(name = "") {
1686
+ __publicField$9(this, "name");
1687
+ this.name = name;
1688
+ }
1689
+ toJSON() {
1690
+ return {
1691
+ name: this.name
1692
+ };
1693
+ }
1694
+ static fromJSON(iPerson) {
1695
+ if (typeof iPerson === "string") {
1696
+ iPerson = JSON.parse(iPerson);
1697
+ }
1698
+ const person = new Person();
1699
+ person.name = iPerson.name;
1700
+ return person;
1701
+ }
1702
+ }
1703
+ function createPersons(iPersons) {
1704
+ if (typeof iPersons === "string") {
1705
+ for (const c of " ,\u3001|") {
1706
+ if (iPersons.includes(c)) {
1707
+ return iPersons.split(c).map((name) => new Person(name));
1708
+ }
1709
+ }
1710
+ return [new Person(iPersons)];
1711
+ }
1712
+ return iPersons.map((name) => new Person(name));
1713
+ }
1714
+
1715
+ var __defProp$8 = Object.defineProperty;
1716
+ var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1717
+ var __publicField$8 = (obj, key, value) => {
1718
+ __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
1719
+ return value;
1720
+ };
1863
1721
  class RankStatistics {
1864
1722
  constructor() {
1723
+ __publicField$8(this, "teamSolvedNum");
1724
+ __publicField$8(this, "teamSolvedNumIndex");
1725
+ __publicField$8(this, "maxSolvedProblems");
1726
+ __publicField$8(this, "effectiveTeamNum");
1727
+ __publicField$8(this, "totalTeamNum");
1865
1728
  this.teamSolvedNum = [];
1866
1729
  this.teamSolvedNumIndex = [];
1867
1730
  this.maxSolvedProblems = 0;
@@ -1880,8 +1743,25 @@ class RankStatistics {
1880
1743
  }
1881
1744
  }
1882
1745
 
1746
+ var __defProp$7 = Object.defineProperty;
1747
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1748
+ var __publicField$7 = (obj, key, value) => {
1749
+ __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
1750
+ return value;
1751
+ };
1883
1752
  class RankOptions {
1884
1753
  constructor() {
1754
+ __publicField$7(this, "enableFilterSubmissionsByTimestamp");
1755
+ __publicField$7(this, "width");
1756
+ __publicField$7(this, "timestamp");
1757
+ __publicField$7(this, "enableFilterTeamsByGroup");
1758
+ __publicField$7(this, "group");
1759
+ __publicField$7(this, "filterOrganizations");
1760
+ __publicField$7(this, "filterOrganizationMap");
1761
+ __publicField$7(this, "filterTeams");
1762
+ __publicField$7(this, "filterTeamMap");
1763
+ __publicField$7(this, "enableAnimatedSubmissions");
1764
+ __publicField$7(this, "battleOfGiants");
1885
1765
  this.enableFilterSubmissionsByTimestamp = false;
1886
1766
  this.width = 0;
1887
1767
  this.timestamp = 0;
@@ -1963,6 +1843,18 @@ class RankOptions {
1963
1843
  }
1964
1844
  class Rank {
1965
1845
  constructor(contest, teams, submissions) {
1846
+ __publicField$7(this, "contest");
1847
+ __publicField$7(this, "teams");
1848
+ __publicField$7(this, "teamsMap");
1849
+ __publicField$7(this, "submissions");
1850
+ __publicField$7(this, "submissionsMap");
1851
+ __publicField$7(this, "organizations");
1852
+ __publicField$7(this, "originTeams");
1853
+ __publicField$7(this, "rankStatistics");
1854
+ __publicField$7(this, "options");
1855
+ __publicField$7(this, "balloons");
1856
+ __publicField$7(this, "languages");
1857
+ __publicField$7(this, "statuses");
1966
1858
  this.contest = contest;
1967
1859
  this.teams = ___default.cloneDeep(teams);
1968
1860
  this.teamsMap = new Map(this.teams.map((t) => [t.id, t]));
@@ -2040,8 +1932,8 @@ class Rank {
2040
1932
  );
2041
1933
  (() => {
2042
1934
  this.rankStatistics.reset();
2043
- this.rankStatistics.teamSolvedNum = Array(this.contest.problems.length + 1).fill(0);
2044
- this.rankStatistics.teamSolvedNumIndex = Array(this.contest.problems.length + 1).fill(0);
1935
+ this.rankStatistics.teamSolvedNum = Array.from({ length: this.contest.problems.length + 1 }).fill(0);
1936
+ this.rankStatistics.teamSolvedNumIndex = Array.from({ length: this.contest.problems.length + 1 }).fill(0);
2045
1937
  })();
2046
1938
  let preSubmissionTimestampToMinute = 0;
2047
1939
  const allSubmissions = this.getSubmissions();
@@ -2141,178 +2033,583 @@ class Rank {
2141
2033
  teamSolvedNumIndex[i] = current;
2142
2034
  }
2143
2035
  }
2144
- if (this.teams.length > 0) {
2145
- this.rankStatistics.maxSolvedProblems = this.teams[0].solvedProblemNum;
2036
+ if (this.teams.length > 0) {
2037
+ this.rankStatistics.maxSolvedProblems = this.teams[0].solvedProblemNum;
2038
+ }
2039
+ })();
2040
+ return this;
2041
+ }
2042
+ buildTeamRank() {
2043
+ let rank = 1;
2044
+ let originalRank = 1;
2045
+ let preTeam = null;
2046
+ for (const t of this.teams) {
2047
+ t.rank = rank++;
2048
+ t.originalRank = originalRank++;
2049
+ if (preTeam !== null) {
2050
+ if (t.isEqualRank(preTeam)) {
2051
+ t.rank = preTeam.rank;
2052
+ }
2053
+ }
2054
+ preTeam = t;
2055
+ }
2056
+ }
2057
+ buildOrgRank() {
2058
+ if (!this.contest.organization) {
2059
+ return;
2060
+ }
2061
+ let rank = 1;
2062
+ let preTeam = null;
2063
+ const se = /* @__PURE__ */ new Set();
2064
+ for (const t of this.teams) {
2065
+ const org = t.organization;
2066
+ if (se.has(org)) {
2067
+ continue;
2068
+ }
2069
+ se.add(org);
2070
+ t.organizationRank = rank++;
2071
+ if (preTeam !== null) {
2072
+ if (t.isEqualRank(preTeam)) {
2073
+ t.organizationRank = preTeam.organizationRank;
2074
+ }
2075
+ }
2076
+ preTeam = t;
2077
+ }
2078
+ }
2079
+ buildOrganizations() {
2080
+ if (!this.contest.organization) {
2081
+ return [];
2082
+ }
2083
+ const res = new Array();
2084
+ const se = /* @__PURE__ */ new Set();
2085
+ this.teams.forEach((t) => {
2086
+ const org = t.organization;
2087
+ if (se.has(org)) {
2088
+ return;
2089
+ }
2090
+ res.push(org);
2091
+ se.add(org);
2092
+ });
2093
+ res.sort();
2094
+ return res;
2095
+ }
2096
+ buildAwards() {
2097
+ if (this.contest.medal === "ccpc") {
2098
+ this.contest.awards = /* @__PURE__ */ new Map();
2099
+ const tot = this.rankStatistics.effectiveTeamNum;
2100
+ const award = [];
2101
+ const gold = new Award();
2102
+ const silver = new Award();
2103
+ const bronze = new Award();
2104
+ const honorable = new Award();
2105
+ {
2106
+ gold.medalType = MedalType.GOLD;
2107
+ gold.minRank = 1;
2108
+ gold.maxRank = Math.ceil(tot * 0.1);
2109
+ if (gold.maxRank >= gold.minRank) {
2110
+ award.push(gold);
2111
+ }
2112
+ }
2113
+ {
2114
+ silver.medalType = MedalType.SILVER;
2115
+ silver.minRank = gold.maxRank + 1;
2116
+ silver.maxRank = Math.ceil(tot * 0.3);
2117
+ if (silver.maxRank >= silver.minRank) {
2118
+ award.push(silver);
2119
+ }
2120
+ }
2121
+ {
2122
+ bronze.medalType = MedalType.BRONZE;
2123
+ bronze.minRank = silver.maxRank + 1;
2124
+ bronze.maxRank = Math.ceil(tot * 0.6);
2125
+ if (bronze.maxRank >= bronze.minRank) {
2126
+ award.push(bronze);
2127
+ }
2128
+ }
2129
+ {
2130
+ honorable.medalType = MedalType.HONORABLE;
2131
+ honorable.minRank = bronze.maxRank + 1;
2132
+ this.teams.forEach((t) => {
2133
+ if (t.solvedProblemNum > 0) {
2134
+ honorable.maxRank = Math.max(honorable.maxRank, t.rank);
2135
+ }
2136
+ });
2137
+ if (honorable.maxRank >= honorable.minRank) {
2138
+ award.push(honorable);
2139
+ }
2140
+ }
2141
+ this.contest.awards.set("official", award);
2142
+ }
2143
+ }
2144
+ filterTeamByOrg(team) {
2145
+ const o = this.options;
2146
+ if (o.enableFilterTeamsByGroup) {
2147
+ if (!team.group?.includes(o.group)) {
2148
+ return true;
2149
+ }
2150
+ }
2151
+ return false;
2152
+ }
2153
+ getSubmissions() {
2154
+ if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
2155
+ return this.submissions;
2156
+ }
2157
+ return this.submissions.filter((s) => {
2158
+ if (this.contest.replayContestStartTimestamp !== void 0) {
2159
+ if (s.timestampToSecond > this.contest.replayContestStartTimestamp) {
2160
+ return false;
2161
+ }
2162
+ }
2163
+ if (this.options.enableFilterSubmissionsByTimestamp) {
2164
+ if (s.timestampToSecond > this.options.timestamp) {
2165
+ return false;
2166
+ }
2146
2167
  }
2147
- })();
2148
- return this;
2168
+ return true;
2169
+ });
2149
2170
  }
2150
- buildTeamRank() {
2151
- let rank = 1;
2152
- let originalRank = 1;
2153
- let preTeam = null;
2154
- for (const t of this.teams) {
2155
- t.rank = rank++;
2156
- t.originalRank = originalRank++;
2157
- if (preTeam !== null) {
2158
- if (t.isEqualRank(preTeam)) {
2159
- t.rank = preTeam.rank;
2171
+ buildBalloons() {
2172
+ this.balloons = [];
2173
+ this.cleanRank();
2174
+ const allSubmissions = this.getSubmissions();
2175
+ for (let ix = 0; ix < allSubmissions.length; ix++) {
2176
+ const s = allSubmissions[ix];
2177
+ const teamId = s.teamId;
2178
+ const problemId = s.problemId;
2179
+ const team = this.teamsMap.get(teamId);
2180
+ const problem = this.contest.problemsMap.get(problemId);
2181
+ (() => {
2182
+ if (team === void 0 || problem === void 0) {
2183
+ return;
2160
2184
  }
2161
- }
2162
- preTeam = t;
2185
+ const problemStatistics = team.problemStatisticsMap.get(problemId);
2186
+ if (problemStatistics.isSolved) {
2187
+ return;
2188
+ }
2189
+ if (s.isAccepted()) {
2190
+ problemStatistics.isSolved = true;
2191
+ problemStatistics.solvedTimestamp = s.timestampToSecond;
2192
+ const b = new Balloon();
2193
+ b.team = team;
2194
+ b.problem = problem;
2195
+ b.submission = s;
2196
+ this.balloons.push(b);
2197
+ }
2198
+ })();
2163
2199
  }
2164
2200
  }
2165
- buildOrgRank() {
2166
- if (!this.contest.organization) {
2167
- return;
2201
+ setReplayTime(replayStartTimestamp) {
2202
+ this.contest.setReplayTime(replayStartTimestamp);
2203
+ }
2204
+ }
2205
+
2206
+ var __defProp$6 = Object.defineProperty;
2207
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2208
+ var __publicField$6 = (obj, key, value) => {
2209
+ __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
2210
+ return value;
2211
+ };
2212
+ class RatingHistory {
2213
+ constructor() {
2214
+ __publicField$6(this, "rank");
2215
+ __publicField$6(this, "rating");
2216
+ __publicField$6(this, "teamName");
2217
+ __publicField$6(this, "organization");
2218
+ __publicField$6(this, "members");
2219
+ __publicField$6(this, "coaches");
2220
+ __publicField$6(this, "contestID");
2221
+ __publicField$6(this, "contestName");
2222
+ __publicField$6(this, "contestLink");
2223
+ __publicField$6(this, "contestTime");
2224
+ this.rank = 0;
2225
+ this.rating = 0;
2226
+ this.teamName = "";
2227
+ this.organization = "";
2228
+ this.members = [];
2229
+ this.coaches = [];
2230
+ this.contestID = "";
2231
+ this.contestName = "";
2232
+ this.contestLink = "";
2233
+ this.contestTime = createDayJS();
2234
+ }
2235
+ toJSON() {
2236
+ return {
2237
+ rank: this.rank,
2238
+ rating: this.rating,
2239
+ teamName: this.teamName,
2240
+ organization: this.organization,
2241
+ members: this.members.map((member) => member.toJSON()),
2242
+ coaches: this.coaches.map((coach) => coach.toJSON()),
2243
+ contestID: this.contestID,
2244
+ contestName: this.contestName,
2245
+ contestLink: this.contestLink,
2246
+ contestTime: this.contestTime.toDate()
2247
+ };
2248
+ }
2249
+ static fromJSON(iRatingHistory) {
2250
+ if (typeof iRatingHistory === "string") {
2251
+ iRatingHistory = JSON.parse(iRatingHistory);
2168
2252
  }
2169
- let rank = 1;
2170
- let preTeam = null;
2171
- const se = /* @__PURE__ */ new Set();
2172
- for (const t of this.teams) {
2173
- const org = t.organization;
2174
- if (se.has(org)) {
2175
- continue;
2253
+ const ratingHistory = new RatingHistory();
2254
+ ratingHistory.rank = iRatingHistory.rank;
2255
+ ratingHistory.rating = iRatingHistory.rating;
2256
+ ratingHistory.teamName = iRatingHistory.teamName;
2257
+ ratingHistory.organization = iRatingHistory.organization;
2258
+ ratingHistory.members = iRatingHistory.members.map((iMember) => Person.fromJSON(iMember));
2259
+ ratingHistory.coaches = iRatingHistory.coaches.map((iCoach) => Person.fromJSON(iCoach));
2260
+ ratingHistory.contestID = iRatingHistory.contestID;
2261
+ ratingHistory.contestName = iRatingHistory.contestName;
2262
+ ratingHistory.contestLink = iRatingHistory.contestLink;
2263
+ ratingHistory.contestTime = createDayJS(iRatingHistory.contestTime);
2264
+ return ratingHistory;
2265
+ }
2266
+ }
2267
+
2268
+ var __defProp$5 = Object.defineProperty;
2269
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2270
+ var __publicField$5 = (obj, key, value) => {
2271
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
2272
+ return value;
2273
+ };
2274
+ class RatingUser {
2275
+ constructor() {
2276
+ __publicField$5(this, "id");
2277
+ __publicField$5(this, "name");
2278
+ __publicField$5(this, "organization");
2279
+ __publicField$5(this, "members");
2280
+ __publicField$5(this, "coaches");
2281
+ __publicField$5(this, "rating");
2282
+ __publicField$5(this, "minRating");
2283
+ __publicField$5(this, "maxRating");
2284
+ __publicField$5(this, "rank");
2285
+ __publicField$5(this, "oldRating");
2286
+ __publicField$5(this, "seed");
2287
+ __publicField$5(this, "delta");
2288
+ __publicField$5(this, "ratingHistories");
2289
+ this.id = "";
2290
+ this.name = "";
2291
+ this.organization = "";
2292
+ this.members = [];
2293
+ this.coaches = [];
2294
+ this.rating = 0;
2295
+ this.minRating = 1061109567;
2296
+ this.maxRating = -1061109567;
2297
+ this.rank = 0;
2298
+ this.oldRating = 0;
2299
+ this.seed = 1;
2300
+ this.delta = 0;
2301
+ this.ratingHistories = [];
2302
+ }
2303
+ UpdateRating(rating) {
2304
+ this.rating = rating;
2305
+ this.minRating = Math.min(this.minRating, rating);
2306
+ this.maxRating = Math.max(this.maxRating, rating);
2307
+ }
2308
+ toJSON() {
2309
+ return {
2310
+ id: this.id,
2311
+ name: this.name,
2312
+ organization: this.organization,
2313
+ members: this.members.map((member) => member.toJSON()),
2314
+ coaches: this.coaches.map((coach) => coach.toJSON()),
2315
+ rating: this.rating,
2316
+ minRating: this.minRating,
2317
+ maxRating: this.maxRating,
2318
+ ratingHistories: this.ratingHistories.map((ratingHistory) => ratingHistory.toJSON())
2319
+ };
2320
+ }
2321
+ static fromJSON(iRatingUser) {
2322
+ if (typeof iRatingUser === "string") {
2323
+ iRatingUser = JSON.parse(iRatingUser);
2324
+ }
2325
+ const ratingUser = new RatingUser();
2326
+ ratingUser.id = iRatingUser.id;
2327
+ ratingUser.name = iRatingUser.name;
2328
+ ratingUser.organization = iRatingUser.organization;
2329
+ ratingUser.members = iRatingUser.members.map((member) => Person.fromJSON(member));
2330
+ ratingUser.coaches = iRatingUser.coaches.map((coach) => Person.fromJSON(coach));
2331
+ ratingUser.rating = iRatingUser.rating;
2332
+ ratingUser.minRating = iRatingUser.minRating;
2333
+ ratingUser.maxRating = iRatingUser.maxRating;
2334
+ for (const iRatingHistory of iRatingUser.ratingHistories) {
2335
+ ratingUser.ratingHistories.push(RatingHistory.fromJSON(iRatingHistory));
2336
+ }
2337
+ return ratingUser;
2338
+ }
2339
+ }
2340
+
2341
+ var __defProp$4 = Object.defineProperty;
2342
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2343
+ var __publicField$4 = (obj, key, value) => {
2344
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
2345
+ return value;
2346
+ };
2347
+ class RatingCalculator {
2348
+ constructor() {
2349
+ __publicField$4(this, "users");
2350
+ this.users = [];
2351
+ }
2352
+ calculate() {
2353
+ this.calculateInternal();
2354
+ }
2355
+ calcP(userA, userB) {
2356
+ return 1 / (1 + 10 ** ((userB.oldRating - userA.oldRating) / 400));
2357
+ }
2358
+ getExSeed(users, rating, ownUser) {
2359
+ const exUser = new RatingUser();
2360
+ exUser.oldRating = rating;
2361
+ let res = 0;
2362
+ users.forEach((user) => {
2363
+ if (user.id !== ownUser.id) {
2364
+ res += this.calcP(user, exUser);
2176
2365
  }
2177
- se.add(org);
2178
- t.organizationRank = rank++;
2179
- if (preTeam !== null) {
2180
- if (t.isEqualRank(preTeam)) {
2181
- t.organizationRank = preTeam.organizationRank;
2182
- }
2366
+ });
2367
+ return res;
2368
+ }
2369
+ calcRating(users, rank, user) {
2370
+ let left = 1;
2371
+ let right = 8e3;
2372
+ while (right - left > 1) {
2373
+ const mid = Math.floor((left + right) / 2);
2374
+ if (this.getExSeed(users, mid, user) < rank) {
2375
+ right = mid;
2376
+ } else {
2377
+ left = mid;
2183
2378
  }
2184
- preTeam = t;
2185
2379
  }
2380
+ return left;
2186
2381
  }
2187
- buildOrganizations() {
2188
- if (!this.contest.organization) {
2189
- return [];
2190
- }
2191
- const res = new Array();
2192
- const se = /* @__PURE__ */ new Set();
2193
- this.teams.forEach((t) => {
2194
- const org = t.organization;
2195
- if (se.has(org)) {
2196
- return;
2382
+ calculateInternal() {
2383
+ for (let i = 0; i < this.users.length; i++) {
2384
+ const u = this.users[i];
2385
+ u.seed = 1;
2386
+ for (let j = 0; j < this.users.length; j++) {
2387
+ if (i !== j) {
2388
+ const otherUser = this.users[j];
2389
+ u.seed += this.calcP(otherUser, u);
2390
+ }
2197
2391
  }
2198
- res.push(org);
2199
- se.add(org);
2392
+ }
2393
+ let sumDelta = 0;
2394
+ for (let i = 0; i < this.users.length; i++) {
2395
+ const u = this.users[i];
2396
+ u.delta = Math.floor(
2397
+ (this.calcRating(this.users, Math.sqrt(u.rank * u.seed), u) - u.oldRating) / 2
2398
+ );
2399
+ sumDelta += u.delta;
2400
+ }
2401
+ let inc = Math.floor(-sumDelta / this.users.length) - 1;
2402
+ for (let i = 0; i < this.users.length; i++) {
2403
+ const u = this.users[i];
2404
+ u.delta += inc;
2405
+ }
2406
+ this.users = this.users.sort((a, b) => b.oldRating - a.oldRating);
2407
+ const s = Math.min(this.users.length, Math.floor(4 * Math.round(Math.sqrt(this.users.length))));
2408
+ let sumS = 0;
2409
+ for (let i = 0; i < s; i++) {
2410
+ sumS += this.users[i].delta;
2411
+ }
2412
+ inc = Math.min(Math.max(Math.floor(-sumS / s), -10), 0);
2413
+ this.users.forEach((u) => {
2414
+ u.delta += inc;
2415
+ u.UpdateRating(u.oldRating + u.delta);
2200
2416
  });
2201
- res.sort();
2202
- return res;
2417
+ this.users = this.users.sort((a, b) => a.rank - b.rank);
2203
2418
  }
2204
- buildAwards() {
2205
- if (this.contest.medal === "ccpc") {
2206
- this.contest.awards = /* @__PURE__ */ new Map();
2207
- const tot = this.rankStatistics.effectiveTeamNum;
2208
- const award = [];
2209
- const gold = new Award();
2210
- const silver = new Award();
2211
- const bronze = new Award();
2212
- const honorable = new Award();
2213
- {
2214
- gold.medalType = MedalType.GOLD;
2215
- gold.minRank = 1;
2216
- gold.maxRank = Math.ceil(tot * 0.1);
2217
- if (gold.maxRank >= gold.minRank) {
2218
- award.push(gold);
2219
- }
2220
- }
2221
- {
2222
- silver.medalType = MedalType.SILVER;
2223
- silver.minRank = gold.maxRank + 1;
2224
- silver.maxRank = Math.ceil(tot * 0.3);
2225
- if (silver.maxRank >= silver.minRank) {
2226
- award.push(silver);
2419
+ }
2420
+
2421
+ var __defProp$3 = Object.defineProperty;
2422
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2423
+ var __publicField$3 = (obj, key, value) => {
2424
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
2425
+ return value;
2426
+ };
2427
+ class Rating {
2428
+ constructor() {
2429
+ __publicField$3(this, "id");
2430
+ __publicField$3(this, "name");
2431
+ __publicField$3(this, "baseRating");
2432
+ __publicField$3(this, "contestIDs");
2433
+ __publicField$3(this, "users");
2434
+ __publicField$3(this, "ranks");
2435
+ __publicField$3(this, "userMap");
2436
+ this.id = "";
2437
+ this.name = "";
2438
+ this.baseRating = 1500;
2439
+ this.contestIDs = [];
2440
+ this.users = [];
2441
+ this.ranks = [];
2442
+ this.userMap = /* @__PURE__ */ new Map();
2443
+ }
2444
+ buildRating() {
2445
+ for (const rank of this.ranks) {
2446
+ rank.buildRank();
2447
+ const ratingCalculator = new RatingCalculator();
2448
+ for (const t of rank.teams) {
2449
+ const id = this.generateTeamId(t);
2450
+ let u = null;
2451
+ if (!this.userMap.has(id)) {
2452
+ u = new RatingUser();
2453
+ u.id = id;
2454
+ u.name = t.name;
2455
+ u.organization = t.organization;
2456
+ u.members = createPersons(t.members ?? []);
2457
+ u.coaches = createPersons(t.coach ?? []);
2458
+ u.rank = t.rank;
2459
+ u.oldRating = this.baseRating;
2460
+ u.UpdateRating(this.baseRating);
2461
+ this.userMap.set(id, u);
2462
+ this.users.push(u);
2463
+ ratingCalculator.users.push(u);
2464
+ } else {
2465
+ u = this.userMap.get(id);
2466
+ u.rank = t.rank;
2467
+ u.oldRating = u.rating;
2468
+ ratingCalculator.users.push(u);
2227
2469
  }
2228
- }
2229
- {
2230
- bronze.medalType = MedalType.BRONZE;
2231
- bronze.minRank = silver.maxRank + 1;
2232
- bronze.maxRank = Math.ceil(tot * 0.6);
2233
- if (bronze.maxRank >= bronze.minRank) {
2234
- award.push(bronze);
2470
+ {
2471
+ const h = new RatingHistory();
2472
+ h.rank = t.rank;
2473
+ h.rating = u.rating;
2474
+ h.teamName = t.name;
2475
+ h.organization = t.organization;
2476
+ h.members = createPersons(t.members ?? []);
2477
+ h.coaches = createPersons(t.coach ?? []);
2478
+ h.contestID = rank.contest.id;
2479
+ h.contestLink = h.contestID;
2480
+ h.contestName = rank.contest.name;
2481
+ h.contestTime = rank.contest.startTime;
2482
+ u.ratingHistories.push(h);
2235
2483
  }
2236
2484
  }
2237
- {
2238
- honorable.medalType = MedalType.HONORABLE;
2239
- honorable.minRank = bronze.maxRank + 1;
2240
- this.teams.forEach((t) => {
2241
- if (t.solvedProblemNum > 0) {
2242
- honorable.maxRank = Math.max(honorable.maxRank, t.rank);
2243
- }
2244
- });
2245
- if (honorable.maxRank >= honorable.minRank) {
2246
- award.push(honorable);
2247
- }
2485
+ ratingCalculator.calculate();
2486
+ for (const u of ratingCalculator.users) {
2487
+ u.ratingHistories.at(-1).rating = u.rating;
2248
2488
  }
2249
- this.contest.awards.set("official", award);
2250
2489
  }
2251
2490
  }
2252
- filterTeamByOrg(team) {
2253
- const o = this.options;
2254
- if (o.enableFilterTeamsByGroup) {
2255
- if (!team.group?.includes(o.group)) {
2256
- return true;
2257
- }
2491
+ generateTeamId(t) {
2492
+ const persons = createPersons(t.members ?? []);
2493
+ if (persons.length > 0) {
2494
+ return persons.map((person) => person.name.trim()).sort().join("|");
2258
2495
  }
2259
- return false;
2496
+ return `${t.organization}-${t.name}`;
2260
2497
  }
2261
- getSubmissions() {
2262
- if (this.contest.replayContestStartTimestamp === void 0 && this.options.enableFilterSubmissionsByTimestamp === false) {
2263
- return this.submissions;
2498
+ toJSON() {
2499
+ return {
2500
+ id: this.id,
2501
+ name: this.name,
2502
+ baseRating: this.baseRating,
2503
+ contestIDs: this.contestIDs,
2504
+ users: this.users.map((ratingUser) => ratingUser.toJSON())
2505
+ };
2506
+ }
2507
+ static fromJSON(iRating) {
2508
+ if (typeof iRating === "string") {
2509
+ iRating = JSON.parse(iRating);
2264
2510
  }
2265
- return this.submissions.filter((s) => {
2266
- if (this.contest.replayContestStartTimestamp !== void 0) {
2267
- if (s.timestampToSecond > this.contest.replayContestStartTimestamp) {
2268
- return false;
2269
- }
2270
- }
2271
- if (this.options.enableFilterSubmissionsByTimestamp) {
2272
- if (s.timestampToSecond > this.options.timestamp) {
2273
- return false;
2274
- }
2275
- }
2276
- return true;
2277
- });
2511
+ const rating = new Rating();
2512
+ rating.id = iRating.id;
2513
+ rating.name = iRating.name;
2514
+ rating.baseRating = iRating.baseRating;
2515
+ rating.contestIDs = iRating.contestIDs;
2516
+ for (const iUser of iRating.users) {
2517
+ rating.users.push(RatingUser.fromJSON(iUser));
2518
+ }
2519
+ return rating;
2278
2520
  }
2279
- buildBalloons() {
2280
- this.balloons = [];
2281
- this.cleanRank();
2282
- const allSubmissions = this.getSubmissions();
2283
- for (let ix = 0; ix < allSubmissions.length; ix++) {
2284
- const s = allSubmissions[ix];
2285
- const teamId = s.teamId;
2286
- const problemId = s.problemId;
2287
- const team = this.teamsMap.get(teamId);
2288
- const problem = this.contest.problemsMap.get(problemId);
2289
- (() => {
2290
- if (team === void 0 || problem === void 0) {
2291
- return;
2292
- }
2293
- const problemStatistics = team.problemStatisticsMap.get(problemId);
2294
- if (problemStatistics.isSolved) {
2295
- return;
2296
- }
2297
- if (s.isAccepted()) {
2298
- problemStatistics.isSolved = true;
2299
- problemStatistics.solvedTimestamp = s.timestampToSecond;
2300
- const b = new Balloon();
2301
- b.team = team;
2302
- b.problem = problem;
2303
- b.submission = s;
2304
- this.balloons.push(b);
2305
- }
2306
- })();
2521
+ }
2522
+
2523
+ var RatingLevel = /* @__PURE__ */ ((RatingLevel2) => {
2524
+ RatingLevel2["NEWBIE"] = "NEWBIE";
2525
+ RatingLevel2["PUPIL"] = "PUPIL";
2526
+ RatingLevel2["SPECIALIST"] = "SPECIALIST";
2527
+ RatingLevel2["EXPERT"] = "EXPERT";
2528
+ RatingLevel2["CANDIDATE_MASTER"] = "CANDIDATE_MASTER";
2529
+ RatingLevel2["MASTER"] = "MASTER";
2530
+ RatingLevel2["INTERNATIONAL_MASTER"] = "INTERNATIONAL_MASTER";
2531
+ RatingLevel2["GRANDMASTER"] = "GRANDMASTER";
2532
+ RatingLevel2["INTERNATIONAL_GRANDMASTER"] = "INTERNATIONAL_GRANDMASTER";
2533
+ RatingLevel2["LEGENDARY_GRANDMASTER"] = "LEGENDARY_GRANDMASTER";
2534
+ return RatingLevel2;
2535
+ })(RatingLevel || {});
2536
+ const RatingLevelToString = {
2537
+ ["NEWBIE" /* NEWBIE */]: "Newbie",
2538
+ ["PUPIL" /* PUPIL */]: "Pupil",
2539
+ ["SPECIALIST" /* SPECIALIST */]: "Specialist",
2540
+ ["EXPERT" /* EXPERT */]: "Expert",
2541
+ ["CANDIDATE_MASTER" /* CANDIDATE_MASTER */]: "Candidate Master",
2542
+ ["MASTER" /* MASTER */]: "Master",
2543
+ ["INTERNATIONAL_MASTER" /* INTERNATIONAL_MASTER */]: "International Master",
2544
+ ["GRANDMASTER" /* GRANDMASTER */]: "Grandmaster",
2545
+ ["INTERNATIONAL_GRANDMASTER" /* INTERNATIONAL_GRANDMASTER */]: "International Grandmaster",
2546
+ ["LEGENDARY_GRANDMASTER" /* LEGENDARY_GRANDMASTER */]: "Legendary Grandmaster"
2547
+ };
2548
+ class RatingUtility {
2549
+ static getRatingLevel(rating) {
2550
+ if (rating >= 3e3) {
2551
+ return "LEGENDARY_GRANDMASTER" /* LEGENDARY_GRANDMASTER */;
2552
+ } else if (rating >= 2600) {
2553
+ return "INTERNATIONAL_GRANDMASTER" /* INTERNATIONAL_GRANDMASTER */;
2554
+ } else if (rating >= 2400) {
2555
+ return "GRANDMASTER" /* GRANDMASTER */;
2556
+ } else if (rating >= 2300) {
2557
+ return "INTERNATIONAL_MASTER" /* INTERNATIONAL_MASTER */;
2558
+ } else if (rating >= 2100) {
2559
+ return "MASTER" /* MASTER */;
2560
+ } else if (rating >= 1900) {
2561
+ return "CANDIDATE_MASTER" /* CANDIDATE_MASTER */;
2562
+ } else if (rating >= 1600) {
2563
+ return "EXPERT" /* EXPERT */;
2564
+ } else if (rating >= 1400) {
2565
+ return "SPECIALIST" /* SPECIALIST */;
2566
+ } else if (rating >= 1200) {
2567
+ return "PUPIL" /* PUPIL */;
2307
2568
  }
2569
+ return "NEWBIE" /* NEWBIE */;
2308
2570
  }
2309
- setReplayTime(replayStartTimestamp) {
2310
- this.contest.setReplayTime(replayStartTimestamp);
2571
+ static getRatingLevelClass(ratingLevel) {
2572
+ if (typeof ratingLevel === "number") {
2573
+ return this.getRatingLevelClass(this.getRatingLevel(ratingLevel));
2574
+ }
2575
+ switch (ratingLevel) {
2576
+ case "NEWBIE" /* NEWBIE */:
2577
+ return "user-gray";
2578
+ case "PUPIL" /* PUPIL */:
2579
+ return "user-green";
2580
+ case "SPECIALIST" /* SPECIALIST */:
2581
+ return "user-cyan";
2582
+ case "EXPERT" /* EXPERT */:
2583
+ return "user-blue";
2584
+ case "CANDIDATE_MASTER" /* CANDIDATE_MASTER */:
2585
+ return "user-violet";
2586
+ case "MASTER" /* MASTER */:
2587
+ return "user-orange";
2588
+ case "INTERNATIONAL_MASTER" /* INTERNATIONAL_MASTER */:
2589
+ return "user-orange";
2590
+ case "GRANDMASTER" /* GRANDMASTER */:
2591
+ return "user-red";
2592
+ case "INTERNATIONAL_GRANDMASTER" /* INTERNATIONAL_GRANDMASTER */:
2593
+ return "user-red";
2594
+ case "LEGENDARY_GRANDMASTER" /* LEGENDARY_GRANDMASTER */:
2595
+ return "user-legendary";
2596
+ }
2311
2597
  }
2312
2598
  }
2313
2599
 
2600
+ var __defProp$2 = Object.defineProperty;
2601
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2602
+ var __publicField$2 = (obj, key, value) => {
2603
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
2604
+ return value;
2605
+ };
2314
2606
  class ResolverOperation {
2315
2607
  constructor() {
2608
+ __publicField$2(this, "id");
2609
+ __publicField$2(this, "team");
2610
+ __publicField$2(this, "problemIx");
2611
+ __publicField$2(this, "beforeTeamProblemStatistics");
2612
+ __publicField$2(this, "afterTeamProblemStatistics");
2316
2613
  this.id = 0;
2317
2614
  this.team = new Team();
2318
2615
  this.problemIx = 0;
@@ -2321,6 +2618,12 @@ class ResolverOperation {
2321
2618
  }
2322
2619
  }
2323
2620
 
2621
+ var __defProp$1 = Object.defineProperty;
2622
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2623
+ var __publicField$1 = (obj, key, value) => {
2624
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
2625
+ return value;
2626
+ };
2324
2627
  class Resolver extends Rank {
2325
2628
  constructor(contest, teams, submissions) {
2326
2629
  submissions.sort(Submission.compare);
@@ -2345,6 +2648,10 @@ class Resolver extends Rank {
2345
2648
  afterFreezeSubmissions = submissions.slice(ix, -1);
2346
2649
  }
2347
2650
  super(contest, teams, beforeFreezeSubmissions);
2651
+ __publicField$1(this, "finalRank");
2652
+ __publicField$1(this, "operations");
2653
+ __publicField$1(this, "beforeFreezeSubmissions");
2654
+ __publicField$1(this, "afterFreezeSubmissions");
2348
2655
  this.finalRank = new Rank(contest, teams, submissions);
2349
2656
  this.operations = [];
2350
2657
  this.beforeFreezeSubmissions = beforeFreezeSubmissions;
@@ -2411,11 +2718,29 @@ class Resolver extends Rank {
2411
2718
  }
2412
2719
  }
2413
2720
 
2721
+ var __defProp = Object.defineProperty;
2722
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2723
+ var __publicField = (obj, key, value) => {
2724
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
2725
+ return value;
2726
+ };
2414
2727
  class ResolverVue extends Resolver {
2415
2728
  constructor(contest, teams, submissions) {
2416
2729
  super(contest, teams, submissions);
2417
- this.FLASHING_TIME_MS = 100;
2418
- this.ROLLING_TIME_MS = 600;
2730
+ __publicField(this, "FLASHING_TIME_MS", 100);
2731
+ __publicField(this, "ROLLING_TIME_MS", 600);
2732
+ __publicField(this, "maxIndex");
2733
+ __publicField(this, "currentIndex");
2734
+ __publicField(this, "maxOpIndex");
2735
+ __publicField(this, "currentOpIndex");
2736
+ __publicField(this, "oldRank");
2737
+ __publicField(this, "newRank");
2738
+ __publicField(this, "currentTeamId");
2739
+ __publicField(this, "currentProblemIndex");
2740
+ __publicField(this, "problemFlashingEnded");
2741
+ __publicField(this, "duringAnimation");
2742
+ __publicField(this, "startScrollUp");
2743
+ __publicField(this, "startScrollDown");
2419
2744
  this.maxIndex = 0;
2420
2745
  this.currentIndex = 0;
2421
2746
  this.maxOpIndex = 0;