@xcpcio/core 0.31.1 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -15,6 +15,8 @@ const relativeTime = require('dayjs/plugin/relativeTime');
15
15
  const _ = require('lodash');
16
16
  const XLSX = require('xlsx-js-style');
17
17
  const stringWidth = require('string-width');
18
+ const colorDiff = require('color-diff');
19
+ const chroma = require('chroma-js');
18
20
 
19
21
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
20
22
 
@@ -42,6 +44,7 @@ const relativeTime__default = /*#__PURE__*/_interopDefaultLegacy(relativeTime);
42
44
  const ___default = /*#__PURE__*/_interopDefaultLegacy(_);
43
45
  const XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
44
46
  const stringWidth__default = /*#__PURE__*/_interopDefaultLegacy(stringWidth);
47
+ const chroma__default = /*#__PURE__*/_interopDefaultLegacy(chroma);
45
48
 
46
49
  function stringToSubmissionStatus(status) {
47
50
  status = status.toUpperCase().replace(" ", "_");
@@ -462,6 +465,18 @@ function calcDirt(attemptedNum, solvedNum) {
462
465
  return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
463
466
  }
464
467
 
468
+ function getWhiteOrBlackColor(background) {
469
+ const [R, G, B] = chroma__default(background).rgb();
470
+ const color = { R, G, B };
471
+ const palette = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
472
+ const f = colorDiff.furthest(color, palette);
473
+ if (f.R === 0 && f.G === 0 && f.B === 0) {
474
+ return "#000";
475
+ } else {
476
+ return "#fff";
477
+ }
478
+ }
479
+
465
480
  class ProblemStatistics {
466
481
  constructor() {
467
482
  this.acceptedNum = 0;
@@ -496,6 +511,10 @@ class Problem {
496
511
  this.label = "";
497
512
  this.name = "";
498
513
  this.statistics = new ProblemStatistics();
514
+ this.balloonColor = {
515
+ background_color: "#a0f0a0",
516
+ color: "#000"
517
+ };
499
518
  }
500
519
  }
501
520
  function createProblem(problemJSON) {
@@ -505,20 +524,14 @@ function createProblem(problemJSON) {
505
524
  p.name = problemJSON.name ?? "";
506
525
  p.timeLimit = problemJSON.time_limit;
507
526
  p.memoryLimit = problemJSON.memory_limit;
508
- p.balloonColor = problemJSON.balloon_color;
527
+ if (problemJSON.balloon_color) {
528
+ p.balloonColor = problemJSON.balloon_color;
529
+ }
530
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
509
531
  return p;
510
532
  }
511
533
  function createProblems(problemsJSON) {
512
- return problemsJSON.map((pJSON) => {
513
- const p = new Problem();
514
- p.id = pJSON.id;
515
- p.label = pJSON.label;
516
- p.name = pJSON.name ?? "";
517
- p.timeLimit = pJSON.time_limit;
518
- p.memoryLimit = pJSON.memory_limit;
519
- p.balloonColor = pJSON.balloon_color;
520
- return p;
521
- });
534
+ return problemsJSON.map((pJSON) => createProblem(pJSON));
522
535
  }
523
536
  function createProblemsByProblemIds(problemIds, balloonColors) {
524
537
  const problems = problemIds.map((label, index) => {
@@ -532,6 +545,9 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
532
545
  problems[index].balloonColor = balloonColors[index];
533
546
  }
534
547
  }
548
+ problems.forEach((p) => {
549
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
550
+ });
535
551
  return problems;
536
552
  }
537
553
  class TeamProblemStatistics {
@@ -826,7 +842,13 @@ class Submission {
826
842
  return 1;
827
843
  }
828
844
  }
829
- return 0;
845
+ if (lhs.id < rhs.id) {
846
+ return -1;
847
+ } else if (lhs.id === rhs.id) {
848
+ return 0;
849
+ } else {
850
+ return 1;
851
+ }
830
852
  }
831
853
  }
832
854
  function createSubmission(submissionJSON) {
@@ -865,6 +887,9 @@ class Balloon {
865
887
  get key() {
866
888
  return `balloon-${this.team.id}-${this.problem.id}`;
867
889
  }
890
+ static compare(lhs, rhs) {
891
+ return Submission.compare(lhs.submission, rhs.submission);
892
+ }
868
893
  }
869
894
 
870
895
  class Group {
@@ -1184,6 +1209,7 @@ class RankOptions {
1184
1209
  this.filterOrganizationMap = /* @__PURE__ */ new Map();
1185
1210
  this.filterTeams = [];
1186
1211
  this.filterTeamMap = /* @__PURE__ */ new Map();
1212
+ this.enableAnimatedSubmissions = false;
1187
1213
  }
1188
1214
  setWidth(width, contest) {
1189
1215
  this.width = width;
@@ -1639,6 +1665,7 @@ exports.createTeams = createTeams;
1639
1665
  exports.getImageSource = getImageSource;
1640
1666
  exports.getTimeDiff = getTimeDiff;
1641
1667
  exports.getTimestamp = getTimestamp;
1668
+ exports.getWhiteOrBlackColor = getWhiteOrBlackColor;
1642
1669
  exports.isAccepted = isAccepted;
1643
1670
  exports.isNotCalculatedPenaltyStatus = isNotCalculatedPenaltyStatus;
1644
1671
  exports.isPending = isPending;
package/dist/index.d.ts CHANGED
@@ -47,7 +47,7 @@ declare class Problem {
47
47
  name: string;
48
48
  timeLimit?: string;
49
49
  memoryLimit?: string;
50
- balloonColor?: BalloonColor;
50
+ balloonColor: BalloonColor;
51
51
  statistics: ProblemStatistics;
52
52
  constructor();
53
53
  }
@@ -83,6 +83,8 @@ declare class TeamProblemStatistics {
83
83
 
84
84
  declare function calcDirt(attemptedNum: number, solvedNum: number): number;
85
85
 
86
+ declare function getWhiteOrBlackColor(background: string): "#000" | "#fff";
87
+
86
88
  declare function createDayJS(time?: Date | string | number | undefined): dayjs.Dayjs;
87
89
  declare function getTimestamp(time: number | dayjs.Dayjs): number;
88
90
  declare function getTimeDiff(seconds: number): string;
@@ -210,6 +212,7 @@ declare class Balloon {
210
212
  submission: Submission;
211
213
  constructor();
212
214
  get key(): string;
215
+ static compare(lhs: Balloon, rhs: Balloon): number;
213
216
  }
214
217
  type Balloons = Array<Balloon>;
215
218
 
@@ -227,6 +230,7 @@ declare class RankOptions {
227
230
  filterOrganizationMap: Map<string, SelectOptionItem>;
228
231
  filterTeams: Array<SelectOptionItem>;
229
232
  filterTeamMap: Map<string, SelectOptionItem>;
233
+ enableAnimatedSubmissions: boolean;
230
234
  constructor();
231
235
  setWidth(width: number, contest: Contest): void;
232
236
  disableFilterSubmissionByTimestamp(): void;
@@ -320,4 +324,4 @@ declare function isRejected(status: SubmissionStatus): boolean;
320
324
  declare function isPending(status: SubmissionStatus): boolean;
321
325
  declare function isNotCalculatedPenaltyStatus(status: SubmissionStatus): boolean;
322
326
 
323
- export { Award, Awards, Balloon, Balloons, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
327
+ export { Award, Awards, Balloon, Balloons, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
package/dist/index.mjs CHANGED
@@ -12,6 +12,8 @@ import relativeTime from 'dayjs/plugin/relativeTime';
12
12
  import _ from 'lodash';
13
13
  import * as XLSX from 'xlsx-js-style';
14
14
  import stringWidth from 'string-width';
15
+ import { furthest } from 'color-diff';
16
+ import chroma from 'chroma-js';
15
17
 
16
18
  function stringToSubmissionStatus(status) {
17
19
  status = status.toUpperCase().replace(" ", "_");
@@ -432,6 +434,18 @@ function calcDirt(attemptedNum, solvedNum) {
432
434
  return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
433
435
  }
434
436
 
437
+ function getWhiteOrBlackColor(background) {
438
+ const [R, G, B] = chroma(background).rgb();
439
+ const color = { R, G, B };
440
+ const palette = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
441
+ const f = furthest(color, palette);
442
+ if (f.R === 0 && f.G === 0 && f.B === 0) {
443
+ return "#000";
444
+ } else {
445
+ return "#fff";
446
+ }
447
+ }
448
+
435
449
  class ProblemStatistics {
436
450
  constructor() {
437
451
  this.acceptedNum = 0;
@@ -466,6 +480,10 @@ class Problem {
466
480
  this.label = "";
467
481
  this.name = "";
468
482
  this.statistics = new ProblemStatistics();
483
+ this.balloonColor = {
484
+ background_color: "#a0f0a0",
485
+ color: "#000"
486
+ };
469
487
  }
470
488
  }
471
489
  function createProblem(problemJSON) {
@@ -475,20 +493,14 @@ function createProblem(problemJSON) {
475
493
  p.name = problemJSON.name ?? "";
476
494
  p.timeLimit = problemJSON.time_limit;
477
495
  p.memoryLimit = problemJSON.memory_limit;
478
- p.balloonColor = problemJSON.balloon_color;
496
+ if (problemJSON.balloon_color) {
497
+ p.balloonColor = problemJSON.balloon_color;
498
+ }
499
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
479
500
  return p;
480
501
  }
481
502
  function createProblems(problemsJSON) {
482
- return problemsJSON.map((pJSON) => {
483
- const p = new Problem();
484
- p.id = pJSON.id;
485
- p.label = pJSON.label;
486
- p.name = pJSON.name ?? "";
487
- p.timeLimit = pJSON.time_limit;
488
- p.memoryLimit = pJSON.memory_limit;
489
- p.balloonColor = pJSON.balloon_color;
490
- return p;
491
- });
503
+ return problemsJSON.map((pJSON) => createProblem(pJSON));
492
504
  }
493
505
  function createProblemsByProblemIds(problemIds, balloonColors) {
494
506
  const problems = problemIds.map((label, index) => {
@@ -502,6 +514,9 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
502
514
  problems[index].balloonColor = balloonColors[index];
503
515
  }
504
516
  }
517
+ problems.forEach((p) => {
518
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
519
+ });
505
520
  return problems;
506
521
  }
507
522
  class TeamProblemStatistics {
@@ -796,7 +811,13 @@ class Submission {
796
811
  return 1;
797
812
  }
798
813
  }
799
- return 0;
814
+ if (lhs.id < rhs.id) {
815
+ return -1;
816
+ } else if (lhs.id === rhs.id) {
817
+ return 0;
818
+ } else {
819
+ return 1;
820
+ }
800
821
  }
801
822
  }
802
823
  function createSubmission(submissionJSON) {
@@ -835,6 +856,9 @@ class Balloon {
835
856
  get key() {
836
857
  return `balloon-${this.team.id}-${this.problem.id}`;
837
858
  }
859
+ static compare(lhs, rhs) {
860
+ return Submission.compare(lhs.submission, rhs.submission);
861
+ }
838
862
  }
839
863
 
840
864
  class Group {
@@ -1154,6 +1178,7 @@ class RankOptions {
1154
1178
  this.filterOrganizationMap = /* @__PURE__ */ new Map();
1155
1179
  this.filterTeams = [];
1156
1180
  this.filterTeamMap = /* @__PURE__ */ new Map();
1181
+ this.enableAnimatedSubmissions = false;
1157
1182
  }
1158
1183
  setWidth(width, contest) {
1159
1184
  this.width = width;
@@ -1574,4 +1599,4 @@ class Resolver extends Rank {
1574
1599
  }
1575
1600
  }
1576
1601
 
1577
- export { Award, Balloon, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
1602
+ export { Award, Balloon, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xcpcio/core",
3
- "version": "0.31.1",
3
+ "version": "0.33.0",
4
4
  "description": "XCPCIO Core",
5
5
  "author": "Dup4 <lyuzhi.pan@gmail.com>",
6
6
  "license": "MIT",
@@ -40,14 +40,18 @@
40
40
  "dist"
41
41
  ],
42
42
  "dependencies": {
43
+ "chroma-js": "^2.4.2",
44
+ "color-diff": "^1.4.0",
43
45
  "dayjs": "^1.11.8",
44
46
  "lodash": "^4.17.21",
45
47
  "string-width": "^6.1.0",
46
48
  "xlsx-js-style": "^1.2.0",
47
- "@xcpcio/types": "0.31.1"
49
+ "@xcpcio/types": "0.33.0"
48
50
  },
49
51
  "devDependencies": {
50
52
  "@babel/types": "^7.22.4",
53
+ "@types/chroma-js": "^2.4.2",
54
+ "@types/color-diff": "^1.2.3",
51
55
  "@types/lodash": "^4.14.195",
52
56
  "@types/node": "^17.0.45",
53
57
  "@typescript-eslint/eslint-plugin": "^5.59.9",
package/src/balloon.ts CHANGED
@@ -16,6 +16,10 @@ export class Balloon {
16
16
  get key() {
17
17
  return `balloon-${this.team.id}-${this.problem.id}`;
18
18
  }
19
+
20
+ static compare(lhs: Balloon, rhs: Balloon): number {
21
+ return Submission.compare(lhs.submission, rhs.submission);
22
+ }
19
23
  }
20
24
 
21
25
  export type Balloons = Array<Balloon>;
package/src/problem.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { BalloonColor, Problem as IProblem, Problems as IProblems } from "@xcpcio/types";
2
2
 
3
3
  import type { Submissions } from "./submission";
4
- import { calcDirt } from "./utils";
4
+ import { calcDirt, getWhiteOrBlackColor } from "./utils";
5
5
 
6
6
  export class ProblemStatistics {
7
7
  acceptedNum: number;
@@ -59,7 +59,7 @@ export class Problem {
59
59
  timeLimit?: string;
60
60
  memoryLimit?: string;
61
61
 
62
- balloonColor?: BalloonColor;
62
+ balloonColor: BalloonColor;
63
63
 
64
64
  statistics: ProblemStatistics;
65
65
 
@@ -70,6 +70,11 @@ export class Problem {
70
70
  this.name = "";
71
71
 
72
72
  this.statistics = new ProblemStatistics();
73
+
74
+ this.balloonColor = {
75
+ background_color: "#a0f0a0",
76
+ color: "#000",
77
+ };
73
78
  }
74
79
  }
75
80
 
@@ -86,27 +91,17 @@ export function createProblem(problemJSON: IProblem): Problem {
86
91
  p.timeLimit = problemJSON.time_limit;
87
92
  p.memoryLimit = problemJSON.memory_limit;
88
93
 
89
- p.balloonColor = problemJSON.balloon_color;
94
+ if (problemJSON.balloon_color) {
95
+ p.balloonColor = problemJSON.balloon_color;
96
+ }
97
+
98
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color as string);
90
99
 
91
100
  return p;
92
101
  }
93
102
 
94
103
  export function createProblems(problemsJSON: IProblems): Problems {
95
- return problemsJSON.map((pJSON) => {
96
- const p = new Problem();
97
-
98
- p.id = pJSON.id;
99
- p.label = pJSON.label;
100
-
101
- p.name = pJSON.name ?? "";
102
-
103
- p.timeLimit = pJSON.time_limit;
104
- p.memoryLimit = pJSON.memory_limit;
105
-
106
- p.balloonColor = pJSON.balloon_color;
107
-
108
- return p;
109
- });
104
+ return problemsJSON.map(pJSON => createProblem(pJSON));
110
105
  }
111
106
 
112
107
  export function createProblemsByProblemIds(problemIds: string[], balloonColors?: BalloonColor[]): Problems {
@@ -124,6 +119,10 @@ export function createProblemsByProblemIds(problemIds: string[], balloonColors?:
124
119
  }
125
120
  }
126
121
 
122
+ problems.forEach((p) => {
123
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color as string);
124
+ });
125
+
127
126
  return problems;
128
127
  }
129
128
 
package/src/rank.ts CHANGED
@@ -29,6 +29,8 @@ export class RankOptions {
29
29
  filterTeams: Array<SelectOptionItem>;
30
30
  filterTeamMap: Map<string, SelectOptionItem>;
31
31
 
32
+ enableAnimatedSubmissions: boolean;
33
+
32
34
  constructor() {
33
35
  this.enableFilterSubmissionsByTimestamp = false;
34
36
  this.width = 0;
@@ -42,6 +44,8 @@ export class RankOptions {
42
44
 
43
45
  this.filterTeams = [];
44
46
  this.filterTeamMap = new Map<string, SelectOptionItem>();
47
+
48
+ this.enableAnimatedSubmissions = false;
45
49
  }
46
50
 
47
51
  setWidth(width: number, contest: Contest) {
package/src/submission.ts CHANGED
@@ -118,7 +118,13 @@ export class Submission {
118
118
  }
119
119
  }
120
120
 
121
- return 0;
121
+ if (lhs.id < rhs.id) {
122
+ return -1;
123
+ } else if (lhs.id === rhs.id) {
124
+ return 0;
125
+ } else {
126
+ return 1;
127
+ }
122
128
  }
123
129
  }
124
130
 
@@ -0,0 +1,16 @@
1
+ import { furthest } from "color-diff";
2
+ import chroma from "chroma-js";
3
+
4
+ export function getWhiteOrBlackColor(background: string) {
5
+ const [R, G, B] = chroma(background).rgb();
6
+ const color = { R, G, B };
7
+ const palette = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
8
+
9
+ const f = furthest(color, palette);
10
+
11
+ if (f.R === 0 && f.G === 0 && f.B === 0) {
12
+ return "#000";
13
+ } else {
14
+ return "#fff";
15
+ }
16
+ }
@@ -1,2 +1,3 @@
1
1
  export * from "./calc";
2
+ export * from "./color";
2
3
  export * from "./dayjs";