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