@xcpcio/core 0.14.0 → 0.15.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 +72 -33
- package/dist/index.d.ts +10 -7
- package/dist/index.mjs +72 -34
- package/package.json +2 -2
- package/src/award.ts +16 -5
- package/src/contest.ts +12 -0
- package/src/export/general-excel.ts +49 -18
- package/src/team.ts +2 -0
package/dist/index.cjs
CHANGED
|
@@ -285,13 +285,59 @@ class CodeforcesGymGhostDATConverter {
|
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
var MedalType = /* @__PURE__ */ ((MedalType2) => {
|
|
289
|
+
MedalType2["UNKNOWN"] = "Unknown";
|
|
290
|
+
MedalType2["GOLD"] = "Gold";
|
|
291
|
+
MedalType2["SILVER"] = "Silver";
|
|
292
|
+
MedalType2["BRONZE"] = "Bronze";
|
|
293
|
+
MedalType2["HONORABLE"] = "Honorable";
|
|
294
|
+
return MedalType2;
|
|
295
|
+
})(MedalType || {});
|
|
296
|
+
class Award {
|
|
297
|
+
constructor() {
|
|
298
|
+
this.medalType = "Unknown" /* UNKNOWN */;
|
|
299
|
+
this.minRank = 0;
|
|
300
|
+
this.maxRank = 0;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function isValidMedalType(medal) {
|
|
304
|
+
const validMedalType = [
|
|
305
|
+
"Gold" /* GOLD */,
|
|
306
|
+
"Silver" /* SILVER */,
|
|
307
|
+
"Bronze" /* BRONZE */,
|
|
308
|
+
"Honorable" /* HONORABLE */
|
|
309
|
+
];
|
|
310
|
+
return validMedalType.includes(medal);
|
|
311
|
+
}
|
|
312
|
+
|
|
288
313
|
class GeneralExcelConverter {
|
|
289
314
|
constructor() {
|
|
290
315
|
}
|
|
291
|
-
convert(
|
|
316
|
+
convert(oriRank) {
|
|
317
|
+
const rank = ___default.cloneDeep(oriRank);
|
|
318
|
+
rank.options.disableFilterTeamsByGroup();
|
|
319
|
+
rank.options.disableFilterSubmissionByTimestamp();
|
|
292
320
|
const workbook = XLSX__namespace.utils.book_new();
|
|
321
|
+
for (const [k, v] of rank.contest.group) {
|
|
322
|
+
rank.options.setGroup(k);
|
|
323
|
+
rank.buildRank();
|
|
324
|
+
const sheet = this.convertToSheet(rank);
|
|
325
|
+
XLSX__namespace.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang));
|
|
326
|
+
}
|
|
327
|
+
return workbook;
|
|
328
|
+
}
|
|
329
|
+
convertAndWrite(rank, filename) {
|
|
330
|
+
return XLSX__namespace.writeFile(
|
|
331
|
+
this.convert(rank),
|
|
332
|
+
filename,
|
|
333
|
+
{
|
|
334
|
+
compression: true
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
convertToSheet(rank) {
|
|
293
339
|
const aoa = this.convertToAoa(rank);
|
|
294
|
-
const
|
|
340
|
+
const sheet = XLSX__namespace.utils.aoa_to_sheet(aoa);
|
|
295
341
|
const cols = [];
|
|
296
342
|
const head = aoa[1];
|
|
297
343
|
for (let j = 0; j < head.length; j++) {
|
|
@@ -303,11 +349,11 @@ class GeneralExcelConverter {
|
|
|
303
349
|
wch
|
|
304
350
|
});
|
|
305
351
|
}
|
|
306
|
-
|
|
352
|
+
sheet["!cols"] = cols;
|
|
307
353
|
{
|
|
308
354
|
const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
|
|
309
355
|
const merges = [{ s: mergeRange.s, e: mergeRange.e }];
|
|
310
|
-
|
|
356
|
+
sheet["!merges"] = merges;
|
|
311
357
|
}
|
|
312
358
|
const font = {
|
|
313
359
|
name: "Arial Unicode MS",
|
|
@@ -334,32 +380,23 @@ class GeneralExcelConverter {
|
|
|
334
380
|
for (let i = 1; i < aoa.length; i++) {
|
|
335
381
|
for (let j = 0; j < aoa[i].length; j++) {
|
|
336
382
|
const cellAddress = XLSX__namespace.utils.encode_cell({ r: i, c: j });
|
|
337
|
-
const cell =
|
|
383
|
+
const cell = sheet[cellAddress];
|
|
338
384
|
cell.s = cellStyle;
|
|
339
385
|
}
|
|
340
386
|
}
|
|
341
387
|
{
|
|
342
388
|
const cellAddress = XLSX__namespace.utils.encode_cell({ r: 0, c: 0 });
|
|
343
|
-
const cell =
|
|
389
|
+
const cell = sheet[cellAddress];
|
|
344
390
|
const titleStyle = ___default.cloneDeep(cellStyle);
|
|
345
391
|
titleStyle.font.sz = 28;
|
|
346
392
|
titleStyle.font.bold = true;
|
|
347
393
|
cell.s = titleStyle;
|
|
348
394
|
}
|
|
349
|
-
|
|
350
|
-
return workbook;
|
|
351
|
-
}
|
|
352
|
-
convertAndWrite(rank, filename) {
|
|
353
|
-
return XLSX__namespace.writeFile(
|
|
354
|
-
this.convert(rank),
|
|
355
|
-
filename,
|
|
356
|
-
{
|
|
357
|
-
compression: true
|
|
358
|
-
}
|
|
359
|
-
);
|
|
395
|
+
return sheet;
|
|
360
396
|
}
|
|
361
397
|
convertToAoa(rank) {
|
|
362
398
|
const aoa = [];
|
|
399
|
+
const enableAwards = rank.contest.isEnableAwards(rank.options.group);
|
|
363
400
|
{
|
|
364
401
|
aoa.push([rank.contest.name]);
|
|
365
402
|
}
|
|
@@ -371,6 +408,9 @@ class GeneralExcelConverter {
|
|
|
371
408
|
head.push(rank.contest.organization);
|
|
372
409
|
}
|
|
373
410
|
head.push("Name", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dict");
|
|
411
|
+
if (enableAwards) {
|
|
412
|
+
head.push("Medal");
|
|
413
|
+
}
|
|
374
414
|
aoa.push(head);
|
|
375
415
|
}
|
|
376
416
|
for (const team of rank.teams) {
|
|
@@ -400,28 +440,16 @@ class GeneralExcelConverter {
|
|
|
400
440
|
}
|
|
401
441
|
}
|
|
402
442
|
arr.push(`${team.dict}%`);
|
|
443
|
+
if (enableAwards) {
|
|
444
|
+
const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
|
|
445
|
+
arr.push(medals.join(", "));
|
|
446
|
+
}
|
|
403
447
|
aoa.push(arr);
|
|
404
448
|
}
|
|
405
449
|
return aoa;
|
|
406
450
|
}
|
|
407
451
|
}
|
|
408
452
|
|
|
409
|
-
var MedalType = /* @__PURE__ */ ((MedalType2) => {
|
|
410
|
-
MedalType2[MedalType2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
411
|
-
MedalType2[MedalType2["GOLD"] = 1] = "GOLD";
|
|
412
|
-
MedalType2[MedalType2["SILVER"] = 2] = "SILVER";
|
|
413
|
-
MedalType2[MedalType2["BRONZE"] = 3] = "BRONZE";
|
|
414
|
-
MedalType2[MedalType2["HONORABLE"] = 4] = "HONORABLE";
|
|
415
|
-
return MedalType2;
|
|
416
|
-
})(MedalType || {});
|
|
417
|
-
class Award {
|
|
418
|
-
constructor() {
|
|
419
|
-
this.medalType = 0 /* UNKNOWN */;
|
|
420
|
-
this.minRank = 0;
|
|
421
|
-
this.maxRank = 0;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
453
|
function calcDict(attemptedNum, solvedNum) {
|
|
426
454
|
if (solvedNum === 0) {
|
|
427
455
|
return 0;
|
|
@@ -625,6 +653,15 @@ class Contest {
|
|
|
625
653
|
const pass = baseTime.diff(this.startTime, "s");
|
|
626
654
|
return Math.round(pass * 100 / total);
|
|
627
655
|
}
|
|
656
|
+
isEnableAwards(group) {
|
|
657
|
+
if (!this.awards) {
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
if (!this.awards.has(group)) {
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
628
665
|
}
|
|
629
666
|
function createContest(contestJSON) {
|
|
630
667
|
const c = new Contest();
|
|
@@ -851,6 +888,7 @@ class Team {
|
|
|
851
888
|
this.problemStatisticsMap = /* @__PURE__ */ new Map();
|
|
852
889
|
this.submissions = [];
|
|
853
890
|
this.placeChartPoints = [];
|
|
891
|
+
this.awards = [];
|
|
854
892
|
}
|
|
855
893
|
get penaltyToMinute() {
|
|
856
894
|
return Math.floor(this.penalty / 60);
|
|
@@ -1427,4 +1465,5 @@ exports.isAccepted = isAccepted;
|
|
|
1427
1465
|
exports.isNotCalculatedPenaltyStatus = isNotCalculatedPenaltyStatus;
|
|
1428
1466
|
exports.isPending = isPending;
|
|
1429
1467
|
exports.isRejected = isRejected;
|
|
1468
|
+
exports.isValidMedalType = isValidMedalType;
|
|
1430
1469
|
exports.stringToSubmissionStatus = stringToSubmissionStatus;
|
package/dist/index.d.ts
CHANGED
|
@@ -88,11 +88,11 @@ declare class Group {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
declare enum MedalType {
|
|
91
|
-
UNKNOWN =
|
|
92
|
-
GOLD =
|
|
93
|
-
SILVER =
|
|
94
|
-
BRONZE =
|
|
95
|
-
HONORABLE =
|
|
91
|
+
UNKNOWN = "Unknown",
|
|
92
|
+
GOLD = "Gold",
|
|
93
|
+
SILVER = "Silver",
|
|
94
|
+
BRONZE = "Bronze",
|
|
95
|
+
HONORABLE = "Honorable"
|
|
96
96
|
}
|
|
97
97
|
declare class Award {
|
|
98
98
|
medalType: MedalType;
|
|
@@ -100,6 +100,7 @@ declare class Award {
|
|
|
100
100
|
maxRank: number;
|
|
101
101
|
constructor();
|
|
102
102
|
}
|
|
103
|
+
declare function isValidMedalType(medal: MedalType): boolean;
|
|
103
104
|
type Awards = Map<string, Award[]>;
|
|
104
105
|
|
|
105
106
|
declare class Contest {
|
|
@@ -130,6 +131,7 @@ declare class Contest {
|
|
|
130
131
|
getContestElapsedTime(nowTime?: Date): string;
|
|
131
132
|
getContestRemainingTime(nowTime?: Date): string;
|
|
132
133
|
getContestProgressRatio(nowTime?: Date): number;
|
|
134
|
+
isEnableAwards(group: string): boolean;
|
|
133
135
|
}
|
|
134
136
|
declare function createContest(contestJSON: Contest$1): Contest;
|
|
135
137
|
|
|
@@ -233,8 +235,9 @@ declare class CodeforcesGymGhostDATConverter {
|
|
|
233
235
|
|
|
234
236
|
declare class GeneralExcelConverter {
|
|
235
237
|
constructor();
|
|
236
|
-
convert(
|
|
238
|
+
convert(oriRank: Rank): XLSX.WorkBook;
|
|
237
239
|
convertAndWrite(rank: Rank, filename: string): any;
|
|
240
|
+
private convertToSheet;
|
|
238
241
|
private convertToAoa;
|
|
239
242
|
}
|
|
240
243
|
|
|
@@ -284,4 +287,4 @@ declare function isRejected(status: SubmissionStatus): boolean;
|
|
|
284
287
|
declare function isPending(status: SubmissionStatus): boolean;
|
|
285
288
|
declare function isNotCalculatedPenaltyStatus(status: SubmissionStatus): boolean;
|
|
286
289
|
|
|
287
|
-
export { Award, Awards, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
|
|
290
|
+
export { Award, Awards, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
package/dist/index.mjs
CHANGED
|
@@ -255,13 +255,59 @@ class CodeforcesGymGhostDATConverter {
|
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
var MedalType = /* @__PURE__ */ ((MedalType2) => {
|
|
259
|
+
MedalType2["UNKNOWN"] = "Unknown";
|
|
260
|
+
MedalType2["GOLD"] = "Gold";
|
|
261
|
+
MedalType2["SILVER"] = "Silver";
|
|
262
|
+
MedalType2["BRONZE"] = "Bronze";
|
|
263
|
+
MedalType2["HONORABLE"] = "Honorable";
|
|
264
|
+
return MedalType2;
|
|
265
|
+
})(MedalType || {});
|
|
266
|
+
class Award {
|
|
267
|
+
constructor() {
|
|
268
|
+
this.medalType = "Unknown" /* UNKNOWN */;
|
|
269
|
+
this.minRank = 0;
|
|
270
|
+
this.maxRank = 0;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function isValidMedalType(medal) {
|
|
274
|
+
const validMedalType = [
|
|
275
|
+
"Gold" /* GOLD */,
|
|
276
|
+
"Silver" /* SILVER */,
|
|
277
|
+
"Bronze" /* BRONZE */,
|
|
278
|
+
"Honorable" /* HONORABLE */
|
|
279
|
+
];
|
|
280
|
+
return validMedalType.includes(medal);
|
|
281
|
+
}
|
|
282
|
+
|
|
258
283
|
class GeneralExcelConverter {
|
|
259
284
|
constructor() {
|
|
260
285
|
}
|
|
261
|
-
convert(
|
|
286
|
+
convert(oriRank) {
|
|
287
|
+
const rank = _.cloneDeep(oriRank);
|
|
288
|
+
rank.options.disableFilterTeamsByGroup();
|
|
289
|
+
rank.options.disableFilterSubmissionByTimestamp();
|
|
262
290
|
const workbook = XLSX.utils.book_new();
|
|
291
|
+
for (const [k, v] of rank.contest.group) {
|
|
292
|
+
rank.options.setGroup(k);
|
|
293
|
+
rank.buildRank();
|
|
294
|
+
const sheet = this.convertToSheet(rank);
|
|
295
|
+
XLSX.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang));
|
|
296
|
+
}
|
|
297
|
+
return workbook;
|
|
298
|
+
}
|
|
299
|
+
convertAndWrite(rank, filename) {
|
|
300
|
+
return XLSX.writeFile(
|
|
301
|
+
this.convert(rank),
|
|
302
|
+
filename,
|
|
303
|
+
{
|
|
304
|
+
compression: true
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
convertToSheet(rank) {
|
|
263
309
|
const aoa = this.convertToAoa(rank);
|
|
264
|
-
const
|
|
310
|
+
const sheet = XLSX.utils.aoa_to_sheet(aoa);
|
|
265
311
|
const cols = [];
|
|
266
312
|
const head = aoa[1];
|
|
267
313
|
for (let j = 0; j < head.length; j++) {
|
|
@@ -273,11 +319,11 @@ class GeneralExcelConverter {
|
|
|
273
319
|
wch
|
|
274
320
|
});
|
|
275
321
|
}
|
|
276
|
-
|
|
322
|
+
sheet["!cols"] = cols;
|
|
277
323
|
{
|
|
278
324
|
const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
|
|
279
325
|
const merges = [{ s: mergeRange.s, e: mergeRange.e }];
|
|
280
|
-
|
|
326
|
+
sheet["!merges"] = merges;
|
|
281
327
|
}
|
|
282
328
|
const font = {
|
|
283
329
|
name: "Arial Unicode MS",
|
|
@@ -304,32 +350,23 @@ class GeneralExcelConverter {
|
|
|
304
350
|
for (let i = 1; i < aoa.length; i++) {
|
|
305
351
|
for (let j = 0; j < aoa[i].length; j++) {
|
|
306
352
|
const cellAddress = XLSX.utils.encode_cell({ r: i, c: j });
|
|
307
|
-
const cell =
|
|
353
|
+
const cell = sheet[cellAddress];
|
|
308
354
|
cell.s = cellStyle;
|
|
309
355
|
}
|
|
310
356
|
}
|
|
311
357
|
{
|
|
312
358
|
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: 0 });
|
|
313
|
-
const cell =
|
|
359
|
+
const cell = sheet[cellAddress];
|
|
314
360
|
const titleStyle = _.cloneDeep(cellStyle);
|
|
315
361
|
titleStyle.font.sz = 28;
|
|
316
362
|
titleStyle.font.bold = true;
|
|
317
363
|
cell.s = titleStyle;
|
|
318
364
|
}
|
|
319
|
-
|
|
320
|
-
return workbook;
|
|
321
|
-
}
|
|
322
|
-
convertAndWrite(rank, filename) {
|
|
323
|
-
return XLSX.writeFile(
|
|
324
|
-
this.convert(rank),
|
|
325
|
-
filename,
|
|
326
|
-
{
|
|
327
|
-
compression: true
|
|
328
|
-
}
|
|
329
|
-
);
|
|
365
|
+
return sheet;
|
|
330
366
|
}
|
|
331
367
|
convertToAoa(rank) {
|
|
332
368
|
const aoa = [];
|
|
369
|
+
const enableAwards = rank.contest.isEnableAwards(rank.options.group);
|
|
333
370
|
{
|
|
334
371
|
aoa.push([rank.contest.name]);
|
|
335
372
|
}
|
|
@@ -341,6 +378,9 @@ class GeneralExcelConverter {
|
|
|
341
378
|
head.push(rank.contest.organization);
|
|
342
379
|
}
|
|
343
380
|
head.push("Name", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dict");
|
|
381
|
+
if (enableAwards) {
|
|
382
|
+
head.push("Medal");
|
|
383
|
+
}
|
|
344
384
|
aoa.push(head);
|
|
345
385
|
}
|
|
346
386
|
for (const team of rank.teams) {
|
|
@@ -370,28 +410,16 @@ class GeneralExcelConverter {
|
|
|
370
410
|
}
|
|
371
411
|
}
|
|
372
412
|
arr.push(`${team.dict}%`);
|
|
413
|
+
if (enableAwards) {
|
|
414
|
+
const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
|
|
415
|
+
arr.push(medals.join(", "));
|
|
416
|
+
}
|
|
373
417
|
aoa.push(arr);
|
|
374
418
|
}
|
|
375
419
|
return aoa;
|
|
376
420
|
}
|
|
377
421
|
}
|
|
378
422
|
|
|
379
|
-
var MedalType = /* @__PURE__ */ ((MedalType2) => {
|
|
380
|
-
MedalType2[MedalType2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
381
|
-
MedalType2[MedalType2["GOLD"] = 1] = "GOLD";
|
|
382
|
-
MedalType2[MedalType2["SILVER"] = 2] = "SILVER";
|
|
383
|
-
MedalType2[MedalType2["BRONZE"] = 3] = "BRONZE";
|
|
384
|
-
MedalType2[MedalType2["HONORABLE"] = 4] = "HONORABLE";
|
|
385
|
-
return MedalType2;
|
|
386
|
-
})(MedalType || {});
|
|
387
|
-
class Award {
|
|
388
|
-
constructor() {
|
|
389
|
-
this.medalType = 0 /* UNKNOWN */;
|
|
390
|
-
this.minRank = 0;
|
|
391
|
-
this.maxRank = 0;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
423
|
function calcDict(attemptedNum, solvedNum) {
|
|
396
424
|
if (solvedNum === 0) {
|
|
397
425
|
return 0;
|
|
@@ -595,6 +623,15 @@ class Contest {
|
|
|
595
623
|
const pass = baseTime.diff(this.startTime, "s");
|
|
596
624
|
return Math.round(pass * 100 / total);
|
|
597
625
|
}
|
|
626
|
+
isEnableAwards(group) {
|
|
627
|
+
if (!this.awards) {
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
if (!this.awards.has(group)) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
598
635
|
}
|
|
599
636
|
function createContest(contestJSON) {
|
|
600
637
|
const c = new Contest();
|
|
@@ -821,6 +858,7 @@ class Team {
|
|
|
821
858
|
this.problemStatisticsMap = /* @__PURE__ */ new Map();
|
|
822
859
|
this.submissions = [];
|
|
823
860
|
this.placeChartPoints = [];
|
|
861
|
+
this.awards = [];
|
|
824
862
|
}
|
|
825
863
|
get penaltyToMinute() {
|
|
826
864
|
return Math.floor(this.penalty / 60);
|
|
@@ -1360,4 +1398,4 @@ class Resolver extends Rank {
|
|
|
1360
1398
|
}
|
|
1361
1399
|
}
|
|
1362
1400
|
|
|
1363
|
-
export { Award, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
|
|
1401
|
+
export { Award, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "XCPCIO Core",
|
|
5
5
|
"author": "Dup4 <lyuzhi.pan@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"lodash": "^4.17.21",
|
|
45
45
|
"string-width": "^6.1.0",
|
|
46
46
|
"xlsx-js-style": "^1.2.0",
|
|
47
|
-
"@xcpcio/types": "0.
|
|
47
|
+
"@xcpcio/types": "0.15.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@babel/types": "^7.22.4",
|
package/src/award.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export enum MedalType {
|
|
2
|
-
UNKNOWN,
|
|
3
|
-
GOLD,
|
|
4
|
-
SILVER,
|
|
5
|
-
BRONZE,
|
|
6
|
-
HONORABLE,
|
|
2
|
+
UNKNOWN = "Unknown",
|
|
3
|
+
GOLD = "Gold",
|
|
4
|
+
SILVER = "Silver",
|
|
5
|
+
BRONZE = "Bronze",
|
|
6
|
+
HONORABLE = "Honorable",
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export class Award {
|
|
@@ -18,4 +18,15 @@ export class Award {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export function isValidMedalType(medal: MedalType): boolean {
|
|
22
|
+
const validMedalType = [
|
|
23
|
+
MedalType.GOLD,
|
|
24
|
+
MedalType.SILVER,
|
|
25
|
+
MedalType.BRONZE,
|
|
26
|
+
MedalType.HONORABLE,
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
return validMedalType.includes(medal);
|
|
30
|
+
}
|
|
31
|
+
|
|
21
32
|
export type Awards = Map<string, Award[]>;
|
package/src/contest.ts
CHANGED
|
@@ -136,6 +136,18 @@ export class Contest {
|
|
|
136
136
|
|
|
137
137
|
return Math.round((pass * 100) / total);
|
|
138
138
|
}
|
|
139
|
+
|
|
140
|
+
isEnableAwards(group: string): boolean {
|
|
141
|
+
if (!this.awards) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!this.awards.has(group)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
139
151
|
}
|
|
140
152
|
|
|
141
153
|
export function createContest(contestJSON: IContest): Contest {
|
|
@@ -2,15 +2,43 @@ import _ from "lodash";
|
|
|
2
2
|
import * as XLSX from "xlsx-js-style";
|
|
3
3
|
import stringWidth from "string-width";
|
|
4
4
|
|
|
5
|
+
import { isValidMedalType } from "../award";
|
|
5
6
|
import type { Rank } from "../rank";
|
|
6
7
|
|
|
7
8
|
export class GeneralExcelConverter {
|
|
8
9
|
constructor() {}
|
|
9
10
|
|
|
10
|
-
public convert(
|
|
11
|
+
public convert(oriRank: Rank): XLSX.WorkBook {
|
|
12
|
+
const rank = _.cloneDeep(oriRank);
|
|
13
|
+
|
|
14
|
+
rank.options.disableFilterTeamsByGroup();
|
|
15
|
+
rank.options.disableFilterSubmissionByTimestamp();
|
|
16
|
+
|
|
11
17
|
const workbook = XLSX.utils.book_new();
|
|
18
|
+
|
|
19
|
+
for (const [k, v] of rank.contest.group) {
|
|
20
|
+
rank.options.setGroup(k);
|
|
21
|
+
rank.buildRank();
|
|
22
|
+
|
|
23
|
+
const sheet = this.convertToSheet(rank);
|
|
24
|
+
XLSX.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang) as string);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return workbook;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public convertAndWrite(rank: Rank, filename: string): any {
|
|
31
|
+
return XLSX.writeFile(
|
|
32
|
+
this.convert(rank),
|
|
33
|
+
filename,
|
|
34
|
+
{
|
|
35
|
+
compression: true,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private convertToSheet(rank: Rank): XLSX.WorkSheet {
|
|
12
40
|
const aoa = this.convertToAoa(rank);
|
|
13
|
-
const
|
|
41
|
+
const sheet = XLSX.utils.aoa_to_sheet(aoa);
|
|
14
42
|
|
|
15
43
|
const cols = [];
|
|
16
44
|
const head = aoa[1];
|
|
@@ -25,12 +53,12 @@ export class GeneralExcelConverter {
|
|
|
25
53
|
});
|
|
26
54
|
}
|
|
27
55
|
|
|
28
|
-
|
|
56
|
+
sheet["!cols"] = cols;
|
|
29
57
|
|
|
30
58
|
{
|
|
31
59
|
const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
|
|
32
60
|
const merges = [{ s: mergeRange.s, e: mergeRange.e }];
|
|
33
|
-
|
|
61
|
+
sheet["!merges"] = merges;
|
|
34
62
|
}
|
|
35
63
|
|
|
36
64
|
const font = {
|
|
@@ -61,37 +89,28 @@ export class GeneralExcelConverter {
|
|
|
61
89
|
for (let i = 1; i < aoa.length; i++) {
|
|
62
90
|
for (let j = 0; j < aoa[i].length; j++) {
|
|
63
91
|
const cellAddress = XLSX.utils.encode_cell({ r: i, c: j });
|
|
64
|
-
const cell =
|
|
92
|
+
const cell = sheet[cellAddress];
|
|
65
93
|
cell.s = cellStyle;
|
|
66
94
|
}
|
|
67
95
|
}
|
|
68
96
|
|
|
69
97
|
{
|
|
70
98
|
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: 0 });
|
|
71
|
-
const cell =
|
|
99
|
+
const cell = sheet[cellAddress];
|
|
72
100
|
const titleStyle = _.cloneDeep(cellStyle);
|
|
73
101
|
titleStyle.font.sz = 28;
|
|
74
102
|
titleStyle.font.bold = true;
|
|
75
103
|
cell.s = titleStyle;
|
|
76
104
|
}
|
|
77
105
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return workbook;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public convertAndWrite(rank: Rank, filename: string): any {
|
|
84
|
-
return XLSX.writeFile(
|
|
85
|
-
this.convert(rank),
|
|
86
|
-
filename,
|
|
87
|
-
{
|
|
88
|
-
compression: true,
|
|
89
|
-
});
|
|
106
|
+
return sheet;
|
|
90
107
|
}
|
|
91
108
|
|
|
92
109
|
private convertToAoa(rank: Rank): string[][] {
|
|
93
110
|
const aoa: string[][] = [];
|
|
94
111
|
|
|
112
|
+
const enableAwards = rank.contest.isEnableAwards(rank.options.group);
|
|
113
|
+
|
|
95
114
|
{
|
|
96
115
|
aoa.push([rank.contest.name]);
|
|
97
116
|
}
|
|
@@ -106,6 +125,11 @@ export class GeneralExcelConverter {
|
|
|
106
125
|
}
|
|
107
126
|
|
|
108
127
|
head.push("Name", "Solved", "Penalty", ...rank.contest.problems.map(p => p.label), "Dict");
|
|
128
|
+
|
|
129
|
+
if (enableAwards) {
|
|
130
|
+
head.push("Medal");
|
|
131
|
+
}
|
|
132
|
+
|
|
109
133
|
aoa.push(head);
|
|
110
134
|
}
|
|
111
135
|
|
|
@@ -145,6 +169,13 @@ export class GeneralExcelConverter {
|
|
|
145
169
|
|
|
146
170
|
arr.push(`${team.dict}%`);
|
|
147
171
|
|
|
172
|
+
if (enableAwards) {
|
|
173
|
+
const medals = team.awards
|
|
174
|
+
.filter(a => isValidMedalType(a))
|
|
175
|
+
.map(a => a.toString());
|
|
176
|
+
arr.push(medals.join(", "));
|
|
177
|
+
}
|
|
178
|
+
|
|
148
179
|
aoa.push(arr);
|
|
149
180
|
}
|
|
150
181
|
|