@xcpcio/core 0.32.0 → 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 {
@@ -871,6 +887,9 @@ class Balloon {
871
887
  get key() {
872
888
  return `balloon-${this.team.id}-${this.problem.id}`;
873
889
  }
890
+ static compare(lhs, rhs) {
891
+ return Submission.compare(lhs.submission, rhs.submission);
892
+ }
874
893
  }
875
894
 
876
895
  class Group {
@@ -1190,7 +1209,7 @@ class RankOptions {
1190
1209
  this.filterOrganizationMap = /* @__PURE__ */ new Map();
1191
1210
  this.filterTeams = [];
1192
1211
  this.filterTeamMap = /* @__PURE__ */ new Map();
1193
- this.enableDynamicSubmissions = false;
1212
+ this.enableAnimatedSubmissions = false;
1194
1213
  }
1195
1214
  setWidth(width, contest) {
1196
1215
  this.width = width;
@@ -1646,6 +1665,7 @@ exports.createTeams = createTeams;
1646
1665
  exports.getImageSource = getImageSource;
1647
1666
  exports.getTimeDiff = getTimeDiff;
1648
1667
  exports.getTimestamp = getTimestamp;
1668
+ exports.getWhiteOrBlackColor = getWhiteOrBlackColor;
1649
1669
  exports.isAccepted = isAccepted;
1650
1670
  exports.isNotCalculatedPenaltyStatus = isNotCalculatedPenaltyStatus;
1651
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,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,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 {
@@ -841,6 +856,9 @@ class Balloon {
841
856
  get key() {
842
857
  return `balloon-${this.team.id}-${this.problem.id}`;
843
858
  }
859
+ static compare(lhs, rhs) {
860
+ return Submission.compare(lhs.submission, rhs.submission);
861
+ }
844
862
  }
845
863
 
846
864
  class Group {
@@ -1160,7 +1178,7 @@ class RankOptions {
1160
1178
  this.filterOrganizationMap = /* @__PURE__ */ new Map();
1161
1179
  this.filterTeams = [];
1162
1180
  this.filterTeamMap = /* @__PURE__ */ new Map();
1163
- this.enableDynamicSubmissions = false;
1181
+ this.enableAnimatedSubmissions = false;
1164
1182
  }
1165
1183
  setWidth(width, contest) {
1166
1184
  this.width = width;
@@ -1581,4 +1599,4 @@ class Resolver extends Rank {
1581
1599
  }
1582
1600
  }
1583
1601
 
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 };
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.32.0",
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.32.0"
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,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,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";