@xcpcio/core 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2008 -1683
- package/dist/index.d.cts +519 -0
- package/dist/index.d.mts +519 -0
- package/dist/index.d.ts +127 -127
- package/dist/index.mjs +1990 -1663
- package/package.json +21 -21
- package/src/balloon.ts +1 -1
- package/src/battle-of-giants.ts +3 -2
- package/src/contest-index.ts +2 -3
- package/src/contest.ts +6 -6
- package/src/export/cf.ts +2 -2
- package/src/export/general-excel.ts +5 -3
- package/src/export/icpc-standings-csv.ts +4 -3
- package/src/index.ts +6 -7
- package/src/problem.ts +3 -3
- package/src/rank.ts +12 -12
- package/src/rating/index.ts +1 -1
- package/src/rating/rating-history.ts +3 -3
- package/src/rating/rating.ts +2 -3
- package/src/resolver-vue.ts +4 -3
- package/src/resolver.ts +7 -6
- package/src/team.ts +6 -6
- package/src/utils/dayjs.ts +4 -4
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
|
|
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
|
|
13
|
-
import
|
|
14
|
+
import timezone from 'dayjs/plugin/timezone';
|
|
15
|
+
import utc from 'dayjs/plugin/utc';
|
|
14
16
|
import stringWidth from 'string-width';
|
|
15
|
-
import
|
|
17
|
+
import * as XLSX from 'xlsx-js-style';
|
|
16
18
|
import ordinal from 'ordinal';
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
183
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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 (
|
|
245
|
-
return
|
|
444
|
+
if (this.timestampUnit === "microsecond") {
|
|
445
|
+
return Math.floor(this.timestamp / 60 / 1e3 / 1e3);
|
|
246
446
|
}
|
|
247
|
-
if (
|
|
248
|
-
return
|
|
447
|
+
if (this.timestampUnit === "millisecond") {
|
|
448
|
+
return Math.floor(this.timestamp / 60 / 1e3);
|
|
249
449
|
}
|
|
250
|
-
|
|
251
|
-
|
|
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 (
|
|
254
|
-
return
|
|
456
|
+
if (this.timestampUnit === "microsecond") {
|
|
457
|
+
return Math.floor(this.timestamp / 1e3 / 1e3);
|
|
255
458
|
}
|
|
256
|
-
if (
|
|
257
|
-
return
|
|
459
|
+
if (this.timestampUnit === "millisecond") {
|
|
460
|
+
return Math.floor(this.timestamp / 1e3);
|
|
258
461
|
}
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
263
|
-
|
|
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 (
|
|
266
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
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
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (
|
|
404
|
-
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
655
|
+
});
|
|
656
|
+
if (totalTeams === 0 || acceptedProblemNums === 0) {
|
|
657
|
+
return 0;
|
|
409
658
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
495
|
-
if (
|
|
496
|
-
return
|
|
682
|
+
calcAwards(awards) {
|
|
683
|
+
if (!awards) {
|
|
684
|
+
return;
|
|
497
685
|
}
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
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
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
|
528
|
-
if (
|
|
529
|
-
|
|
713
|
+
static compare(lhs, rhs) {
|
|
714
|
+
if (lhs.solvedProblemNum !== rhs.solvedProblemNum) {
|
|
715
|
+
return rhs.solvedProblemNum - lhs.solvedProblemNum;
|
|
530
716
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
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
|
-
|
|
763
|
+
if (teamJSON.icpc_id) {
|
|
764
|
+
t.icpcID = teamJSON.icpc_id;
|
|
765
|
+
}
|
|
766
|
+
return t;
|
|
553
767
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
579
|
-
this
|
|
580
|
-
this
|
|
581
|
-
this.
|
|
582
|
-
this.
|
|
583
|
-
this.
|
|
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
|
-
|
|
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
|
|
604
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
this
|
|
636
|
-
this
|
|
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
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
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
|
-
|
|
657
|
-
if (
|
|
658
|
-
|
|
659
|
-
}
|
|
660
|
-
|
|
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
|
|
852
|
+
return this.name;
|
|
673
853
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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
|
|
866
|
+
return total;
|
|
696
867
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
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
|
-
|
|
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
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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
|
-
|
|
735
|
-
|
|
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
|
-
|
|
741
|
-
this.
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
this.
|
|
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
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
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
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
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
|
-
|
|
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
|
|
829
|
-
this
|
|
830
|
-
this
|
|
831
|
-
this.
|
|
832
|
-
this.
|
|
833
|
-
this.
|
|
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
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
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
|
|
953
|
-
this
|
|
954
|
-
this
|
|
955
|
-
this
|
|
956
|
-
this
|
|
957
|
-
|
|
958
|
-
|
|
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
|
-
|
|
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
|
-
|
|
973
|
-
|
|
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
|
-
|
|
991
|
-
|
|
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
|
-
|
|
1011
|
-
return this.
|
|
1045
|
+
getContestDuration(timeFormat = "HH:mm:ss") {
|
|
1046
|
+
return dayjs.duration(this.getEndTime().diff(this.getStartTime())).format(timeFormat);
|
|
1012
1047
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
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
|
-
|
|
1017
|
-
|
|
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
|
-
|
|
1020
|
-
|
|
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
|
-
|
|
1023
|
-
|
|
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
|
-
|
|
1026
|
-
|
|
1088
|
+
getContestProgressRatio(nowTime) {
|
|
1089
|
+
const baseTime = createDayJS(nowTime);
|
|
1090
|
+
if (this.getStartTime().isSameOrAfter(baseTime)) {
|
|
1027
1091
|
return 0;
|
|
1028
1092
|
}
|
|
1029
|
-
|
|
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
|
-
|
|
1032
|
-
|
|
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
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
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 (
|
|
1156
|
-
|
|
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
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
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
|
-
|
|
1164
|
-
|
|
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
|
-
|
|
1170
|
-
|
|
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
|
-
|
|
1173
|
-
|
|
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
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
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
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
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
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
if (
|
|
1195
|
-
|
|
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 (
|
|
1198
|
-
|
|
1220
|
+
if (k === "unofficial") {
|
|
1221
|
+
g.names.set("en", "Unofficial");
|
|
1199
1222
|
}
|
|
1200
|
-
if (
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
return 1;
|
|
1223
|
+
if (k === "girl" || k === "girls") {
|
|
1224
|
+
g.names.set("en", "Girls");
|
|
1225
|
+
key = "girl";
|
|
1204
1226
|
}
|
|
1205
|
-
|
|
1227
|
+
c.group.set(key, g);
|
|
1206
1228
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
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
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
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
|
-
|
|
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
|
|
1259
|
-
this
|
|
1260
|
-
this
|
|
1261
|
-
this
|
|
1262
|
-
this
|
|
1263
|
-
this
|
|
1264
|
-
this
|
|
1265
|
-
this
|
|
1266
|
-
this.
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
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
|
-
|
|
1278
|
-
|
|
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
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
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
|
-
|
|
1285
|
-
|
|
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 (
|
|
1288
|
-
return
|
|
1297
|
+
if (a.contest.startTime.isAfter(b.contest.startTime)) {
|
|
1298
|
+
return -1;
|
|
1289
1299
|
}
|
|
1290
|
-
|
|
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 (
|
|
1297
|
-
return
|
|
1303
|
+
if (a.contest.endTime.isAfter(b.contest.endTime)) {
|
|
1304
|
+
return -1;
|
|
1298
1305
|
}
|
|
1299
|
-
if (
|
|
1300
|
-
return
|
|
1306
|
+
if (a.contest.name < b.contest.name) {
|
|
1307
|
+
return 1;
|
|
1301
1308
|
}
|
|
1302
|
-
|
|
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
|
|
1312
|
+
return 0;
|
|
1313
|
+
});
|
|
1314
|
+
return contestIndexList;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
class CodeforcesGymGhostDATConverter {
|
|
1318
|
+
constructor() {
|
|
1320
1319
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
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
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
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 (!
|
|
1330
|
-
return
|
|
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 (
|
|
1334
|
-
return
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
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
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
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
|
-
|
|
1354
|
-
|
|
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
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
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
|
-
|
|
1440
|
-
const
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1443
|
-
|
|
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
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
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
|
-
|
|
1477
|
-
|
|
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
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
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
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
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
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
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
|
-
|
|
1492
|
+
return sheet;
|
|
1662
1493
|
}
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
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
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
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
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
{
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
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
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
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
|
|
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
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
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
|
-
|
|
1804
|
-
|
|
1604
|
+
const csv = Papa.unparse(resList);
|
|
1605
|
+
return csv;
|
|
1606
|
+
}
|
|
1607
|
+
getMedalCitation(team) {
|
|
1608
|
+
if (team.solvedProblemNum === 0) {
|
|
1609
|
+
return "";
|
|
1805
1610
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
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
|
|
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
|
-
|
|
2137
|
+
return true;
|
|
2138
|
+
});
|
|
2116
2139
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
for (
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
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
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
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
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
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
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
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
|
-
|
|
2166
|
-
|
|
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
|
-
|
|
2169
|
-
return res;
|
|
2386
|
+
this.users = this.users.sort((a, b) => a.rank - b.rank);
|
|
2170
2387
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
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
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
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
|
-
|
|
2206
|
-
|
|
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
|
-
|
|
2220
|
-
const
|
|
2221
|
-
if (
|
|
2222
|
-
|
|
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
|
|
2465
|
+
return `${t.organization}-${t.name}`;
|
|
2227
2466
|
}
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
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
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
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
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
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
|
-
|
|
2277
|
-
|
|
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
|
|
2385
|
-
this
|
|
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;
|