@xcpcio/core 0.32.0 → 0.33.1

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,21 @@ 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 = [
472
+ { R: 0, G: 0, B: 0 },
473
+ { R: 255, G: 255, B: 255 }
474
+ ];
475
+ const f = colorDiff.furthest(color, palette);
476
+ if (f.R === 0 && f.G === 0 && f.B === 0) {
477
+ return "#000";
478
+ } else {
479
+ return "#fff";
480
+ }
481
+ }
482
+
465
483
  class ProblemStatistics {
466
484
  constructor() {
467
485
  this.acceptedNum = 0;
@@ -496,6 +514,10 @@ class Problem {
496
514
  this.label = "";
497
515
  this.name = "";
498
516
  this.statistics = new ProblemStatistics();
517
+ this.balloonColor = {
518
+ background_color: "#a0f0a0",
519
+ color: "#000"
520
+ };
499
521
  }
500
522
  }
501
523
  function createProblem(problemJSON) {
@@ -505,20 +527,14 @@ function createProblem(problemJSON) {
505
527
  p.name = problemJSON.name ?? "";
506
528
  p.timeLimit = problemJSON.time_limit;
507
529
  p.memoryLimit = problemJSON.memory_limit;
508
- p.balloonColor = problemJSON.balloon_color;
530
+ if (problemJSON.balloon_color) {
531
+ p.balloonColor = ___default.cloneDeep(problemJSON.balloon_color);
532
+ }
533
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
509
534
  return p;
510
535
  }
511
536
  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
- });
537
+ return problemsJSON.map((pJSON) => createProblem(pJSON));
522
538
  }
523
539
  function createProblemsByProblemIds(problemIds, balloonColors) {
524
540
  const problems = problemIds.map((label, index) => {
@@ -529,9 +545,12 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
529
545
  });
530
546
  if (balloonColors !== void 0 && balloonColors !== null) {
531
547
  for (const index in balloonColors) {
532
- problems[index].balloonColor = balloonColors[index];
548
+ problems[index].balloonColor = ___default.cloneDeep(balloonColors[index]);
533
549
  }
534
550
  }
551
+ problems.forEach((p) => {
552
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
553
+ });
535
554
  return problems;
536
555
  }
537
556
  class TeamProblemStatistics {
@@ -871,6 +890,9 @@ class Balloon {
871
890
  get key() {
872
891
  return `balloon-${this.team.id}-${this.problem.id}`;
873
892
  }
893
+ static compare(lhs, rhs) {
894
+ return Submission.compare(lhs.submission, rhs.submission);
895
+ }
874
896
  }
875
897
 
876
898
  class Group {
@@ -1190,7 +1212,7 @@ class RankOptions {
1190
1212
  this.filterOrganizationMap = /* @__PURE__ */ new Map();
1191
1213
  this.filterTeams = [];
1192
1214
  this.filterTeamMap = /* @__PURE__ */ new Map();
1193
- this.enableDynamicSubmissions = false;
1215
+ this.enableAnimatedSubmissions = false;
1194
1216
  }
1195
1217
  setWidth(width, contest) {
1196
1218
  this.width = width;
@@ -1646,6 +1668,7 @@ exports.createTeams = createTeams;
1646
1668
  exports.getImageSource = getImageSource;
1647
1669
  exports.getTimeDiff = getTimeDiff;
1648
1670
  exports.getTimestamp = getTimestamp;
1671
+ exports.getWhiteOrBlackColor = getWhiteOrBlackColor;
1649
1672
  exports.isAccepted = isAccepted;
1650
1673
  exports.isNotCalculatedPenaltyStatus = isNotCalculatedPenaltyStatus;
1651
1674
  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,7 +230,7 @@ declare class RankOptions {
227
230
  filterOrganizationMap: Map<string, SelectOptionItem>;
228
231
  filterTeams: Array<SelectOptionItem>;
229
232
  filterTeamMap: Map<string, SelectOptionItem>;
230
- enableDynamicSubmissions: boolean;
233
+ enableAnimatedSubmissions: boolean;
231
234
  constructor();
232
235
  setWidth(width: number, contest: Contest): void;
233
236
  disableFilterSubmissionByTimestamp(): void;
@@ -321,4 +324,4 @@ declare function isRejected(status: SubmissionStatus): boolean;
321
324
  declare function isPending(status: SubmissionStatus): boolean;
322
325
  declare function isNotCalculatedPenaltyStatus(status: SubmissionStatus): boolean;
323
326
 
324
- 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,21 @@ 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 = [
441
+ { R: 0, G: 0, B: 0 },
442
+ { R: 255, G: 255, B: 255 }
443
+ ];
444
+ const f = furthest(color, palette);
445
+ if (f.R === 0 && f.G === 0 && f.B === 0) {
446
+ return "#000";
447
+ } else {
448
+ return "#fff";
449
+ }
450
+ }
451
+
435
452
  class ProblemStatistics {
436
453
  constructor() {
437
454
  this.acceptedNum = 0;
@@ -466,6 +483,10 @@ class Problem {
466
483
  this.label = "";
467
484
  this.name = "";
468
485
  this.statistics = new ProblemStatistics();
486
+ this.balloonColor = {
487
+ background_color: "#a0f0a0",
488
+ color: "#000"
489
+ };
469
490
  }
470
491
  }
471
492
  function createProblem(problemJSON) {
@@ -475,20 +496,14 @@ function createProblem(problemJSON) {
475
496
  p.name = problemJSON.name ?? "";
476
497
  p.timeLimit = problemJSON.time_limit;
477
498
  p.memoryLimit = problemJSON.memory_limit;
478
- p.balloonColor = problemJSON.balloon_color;
499
+ if (problemJSON.balloon_color) {
500
+ p.balloonColor = _.cloneDeep(problemJSON.balloon_color);
501
+ }
502
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
479
503
  return p;
480
504
  }
481
505
  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
- });
506
+ return problemsJSON.map((pJSON) => createProblem(pJSON));
492
507
  }
493
508
  function createProblemsByProblemIds(problemIds, balloonColors) {
494
509
  const problems = problemIds.map((label, index) => {
@@ -499,9 +514,12 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
499
514
  });
500
515
  if (balloonColors !== void 0 && balloonColors !== null) {
501
516
  for (const index in balloonColors) {
502
- problems[index].balloonColor = balloonColors[index];
517
+ problems[index].balloonColor = _.cloneDeep(balloonColors[index]);
503
518
  }
504
519
  }
520
+ problems.forEach((p) => {
521
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
522
+ });
505
523
  return problems;
506
524
  }
507
525
  class TeamProblemStatistics {
@@ -841,6 +859,9 @@ class Balloon {
841
859
  get key() {
842
860
  return `balloon-${this.team.id}-${this.problem.id}`;
843
861
  }
862
+ static compare(lhs, rhs) {
863
+ return Submission.compare(lhs.submission, rhs.submission);
864
+ }
844
865
  }
845
866
 
846
867
  class Group {
@@ -1160,7 +1181,7 @@ class RankOptions {
1160
1181
  this.filterOrganizationMap = /* @__PURE__ */ new Map();
1161
1182
  this.filterTeams = [];
1162
1183
  this.filterTeamMap = /* @__PURE__ */ new Map();
1163
- this.enableDynamicSubmissions = false;
1184
+ this.enableAnimatedSubmissions = false;
1164
1185
  }
1165
1186
  setWidth(width, contest) {
1166
1187
  this.width = width;
@@ -1581,4 +1602,4 @@ class Resolver extends Rank {
1581
1602
  }
1582
1603
  }
1583
1604
 
1584
- 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 };
1605
+ 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.32.0",
3
+ "version": "0.33.1",
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.32.0"
49
+ "@xcpcio/types": "0.33.1"
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,9 @@
1
+ import _ from "lodash";
2
+
1
3
  import type { BalloonColor, Problem as IProblem, Problems as IProblems } from "@xcpcio/types";
2
4
 
3
5
  import type { Submissions } from "./submission";
4
- import { calcDirt } from "./utils";
6
+ import { calcDirt, getWhiteOrBlackColor } from "./utils";
5
7
 
6
8
  export class ProblemStatistics {
7
9
  acceptedNum: number;
@@ -59,7 +61,7 @@ export class Problem {
59
61
  timeLimit?: string;
60
62
  memoryLimit?: string;
61
63
 
62
- balloonColor?: BalloonColor;
64
+ balloonColor: BalloonColor;
63
65
 
64
66
  statistics: ProblemStatistics;
65
67
 
@@ -70,6 +72,11 @@ export class Problem {
70
72
  this.name = "";
71
73
 
72
74
  this.statistics = new ProblemStatistics();
75
+
76
+ this.balloonColor = {
77
+ background_color: "#a0f0a0",
78
+ color: "#000",
79
+ };
73
80
  }
74
81
  }
75
82
 
@@ -86,27 +93,17 @@ export function createProblem(problemJSON: IProblem): Problem {
86
93
  p.timeLimit = problemJSON.time_limit;
87
94
  p.memoryLimit = problemJSON.memory_limit;
88
95
 
89
- p.balloonColor = problemJSON.balloon_color;
96
+ if (problemJSON.balloon_color) {
97
+ p.balloonColor = _.cloneDeep(problemJSON.balloon_color);
98
+ }
99
+
100
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color as string);
90
101
 
91
102
  return p;
92
103
  }
93
104
 
94
105
  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
- });
106
+ return problemsJSON.map(pJSON => createProblem(pJSON));
110
107
  }
111
108
 
112
109
  export function createProblemsByProblemIds(problemIds: string[], balloonColors?: BalloonColor[]): Problems {
@@ -120,10 +117,14 @@ export function createProblemsByProblemIds(problemIds: string[], balloonColors?:
120
117
 
121
118
  if (balloonColors !== undefined && balloonColors !== null) {
122
119
  for (const index in balloonColors) {
123
- problems[index].balloonColor = balloonColors[index];
120
+ problems[index].balloonColor = _.cloneDeep(balloonColors[index]);
124
121
  }
125
122
  }
126
123
 
124
+ problems.forEach((p) => {
125
+ p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color as string);
126
+ });
127
+
127
128
  return problems;
128
129
  }
129
130
 
package/src/rank.ts CHANGED
@@ -29,7 +29,7 @@ export class RankOptions {
29
29
  filterTeams: Array<SelectOptionItem>;
30
30
  filterTeamMap: Map<string, SelectOptionItem>;
31
31
 
32
- enableDynamicSubmissions: boolean;
32
+ enableAnimatedSubmissions: boolean;
33
33
 
34
34
  constructor() {
35
35
  this.enableFilterSubmissionsByTimestamp = false;
@@ -45,7 +45,7 @@ export class RankOptions {
45
45
  this.filterTeams = [];
46
46
  this.filterTeamMap = new Map<string, SelectOptionItem>();
47
47
 
48
- this.enableDynamicSubmissions = false;
48
+ this.enableAnimatedSubmissions = false;
49
49
  }
50
50
 
51
51
  setWidth(width: number, contest: Contest) {
@@ -0,0 +1,19 @@
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 = [
8
+ { R: 0, G: 0, B: 0 },
9
+ { R: 255, G: 255, B: 255 },
10
+ ];
11
+
12
+ const f = furthest(color, palette);
13
+
14
+ if (f.R === 0 && f.G === 0 && f.B === 0) {
15
+ return "#000";
16
+ } else {
17
+ return "#fff";
18
+ }
19
+ }
@@ -1,2 +1,3 @@
1
1
  export * from "./calc";
2
+ export * from "./color";
2
3
  export * from "./dayjs";