@rhseung/ps-cli 1.5.0 → 1.7.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.
@@ -495,207 +495,6 @@ var chalk = createChalk();
495
495
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
496
496
  var source_default = chalk;
497
497
 
498
- // src/utils/tier.ts
499
- import gradient from "gradient-string";
500
- var TIER_NAMES = [
501
- void 0,
502
- "Bronze V",
503
- "Bronze IV",
504
- "Bronze III",
505
- "Bronze II",
506
- "Bronze I",
507
- "Silver V",
508
- "Silver IV",
509
- "Silver III",
510
- "Silver II",
511
- "Silver I",
512
- "Gold V",
513
- "Gold IV",
514
- "Gold III",
515
- "Gold II",
516
- "Gold I",
517
- "Platinum V",
518
- "Platinum IV",
519
- "Platinum III",
520
- "Platinum II",
521
- "Platinum I",
522
- "Diamond V",
523
- "Diamond IV",
524
- "Diamond III",
525
- "Diamond II",
526
- "Diamond I",
527
- "Ruby V",
528
- "Ruby IV",
529
- "Ruby III",
530
- "Ruby II",
531
- "Ruby I",
532
- "Master"
533
- ];
534
- var TIER_COLORS = [
535
- void 0,
536
- "#9d4900",
537
- "#a54f00",
538
- "#ad5600",
539
- "#b55d0a",
540
- "#c67739",
541
- "#38546e",
542
- "#3d5a74",
543
- "#435f7a",
544
- "#496580",
545
- "#4e6a86",
546
- "#d28500",
547
- "#df8f00",
548
- "#ec9a00",
549
- "#f9a518",
550
- "#ffb028",
551
- "#00c78b",
552
- "#00d497",
553
- "#27e2a4",
554
- "#3ef0b1",
555
- "#51fdbd",
556
- "#009ee5",
557
- "#00a9f0",
558
- "#00b4fc",
559
- "#2bbfff",
560
- "#41caff",
561
- "#e0004c",
562
- "#ea0053",
563
- "#f5005a",
564
- "#ff0062",
565
- "#ff3071",
566
- "#b300e0"
567
- ];
568
- var TIER_IMAGE_BASE_URL = "https://d2gd6pc034wcta.cloudfront.net/tier";
569
- var MASTER_TIER_GRADIENT = [
570
- { r: 255, g: 124, b: 168 },
571
- { r: 180, g: 145, b: 255 },
572
- { r: 124, g: 249, b: 255 }
573
- ];
574
- var TIER_MIN_RATINGS = [
575
- 0,
576
- // Unrated (tier 0): 0-29
577
- 30,
578
- // Bronze V (tier 1)
579
- 60,
580
- // Bronze IV (tier 2)
581
- 90,
582
- // Bronze III (tier 3)
583
- 120,
584
- // Bronze II (tier 4)
585
- 150,
586
- // Bronze I (tier 5)
587
- 200,
588
- // Silver V (tier 6)
589
- 300,
590
- // Silver IV (tier 7)
591
- 400,
592
- // Silver III (tier 8)
593
- 500,
594
- // Silver II (tier 9)
595
- 650,
596
- // Silver I (tier 10)
597
- 800,
598
- // Gold V (tier 11)
599
- 950,
600
- // Gold IV (tier 12)
601
- 1100,
602
- // Gold III (tier 13)
603
- 1250,
604
- // Gold II (tier 14)
605
- 1400,
606
- // Gold I (tier 15)
607
- 1600,
608
- // Platinum V (tier 16)
609
- 1750,
610
- // Platinum IV (tier 17)
611
- 1900,
612
- // Platinum III (tier 18)
613
- 2e3,
614
- // Platinum II (tier 19)
615
- 2100,
616
- // Platinum I (tier 20)
617
- 2200,
618
- // Diamond V (tier 21)
619
- 2300,
620
- // Diamond IV (tier 22)
621
- 2400,
622
- // Diamond III (tier 23)
623
- 2500,
624
- // Diamond II (tier 24)
625
- 2600,
626
- // Diamond I (tier 25)
627
- 2700,
628
- // Ruby V (tier 26)
629
- 2800,
630
- // Ruby IV (tier 27)
631
- 2850,
632
- // Ruby III (tier 28)
633
- 2900,
634
- // Ruby II (tier 29)
635
- 2950,
636
- // Ruby I (tier 30)
637
- 3e3
638
- // Master (tier 31)
639
- ];
640
- function getTierMinRating(tier) {
641
- if (tier >= 0 && tier < TIER_MIN_RATINGS.length) {
642
- return TIER_MIN_RATINGS[tier] ?? 0;
643
- }
644
- return 0;
645
- }
646
- function getNextTierMinRating(tier) {
647
- if (tier === 31) {
648
- return null;
649
- }
650
- if (tier >= 0 && tier < TIER_MIN_RATINGS.length - 1) {
651
- return TIER_MIN_RATINGS[tier + 1] ?? null;
652
- }
653
- return null;
654
- }
655
- function calculateTierProgress(currentRating, tier) {
656
- if (tier === 31) {
657
- return 100;
658
- }
659
- const currentTierMin = getTierMinRating(tier);
660
- const nextTierMin = getNextTierMinRating(tier);
661
- if (nextTierMin === null) {
662
- return 100;
663
- }
664
- if (currentRating < currentTierMin) {
665
- return 0;
666
- }
667
- if (currentRating >= nextTierMin) {
668
- return 100;
669
- }
670
- const progress = (currentRating - currentTierMin) / (nextTierMin - currentTierMin) * 100;
671
- return Math.max(0, Math.min(100, progress));
672
- }
673
- function getTierName(level) {
674
- if (level === 0) return "Unrated";
675
- if (level >= 1 && level < TIER_NAMES.length) {
676
- return TIER_NAMES[level] || "Unrated";
677
- }
678
- return "Unrated";
679
- }
680
- function getTierColor(level) {
681
- if (level === 0) return "#2d2d2d";
682
- if (level === 31) {
683
- return gradient([...MASTER_TIER_GRADIENT]);
684
- }
685
- if (level >= 1 && level < TIER_COLORS.length) {
686
- return TIER_COLORS[level] || "#2d2d2d";
687
- }
688
- return "#2d2d2d";
689
- }
690
- function getTierImageUrl(level) {
691
- return `${TIER_IMAGE_BASE_URL}/${level}.svg`;
692
- }
693
-
694
498
  export {
695
- source_default,
696
- getNextTierMinRating,
697
- calculateTierProgress,
698
- getTierName,
699
- getTierColor,
700
- getTierImageUrl
499
+ source_default
701
500
  };
@@ -9924,8 +9924,10 @@ var config = new Conf({
9924
9924
  autoOpenEditor: false,
9925
9925
  // 기본값: 자동 열기 비활성화
9926
9926
  solvedAcHandle: void 0,
9927
- problemDir: "problems"
9927
+ problemDir: "problems",
9928
9928
  // 기본값: problems 디렉토리
9929
+ solvingDir: "solving"
9930
+ // 기본값: solving 디렉토리
9929
9931
  }
9930
9932
  });
9931
9933
  var projectConfigCache = null;
@@ -10014,44 +10016,339 @@ function getProblemDir() {
10014
10016
  }
10015
10017
  return config.get("problemDir") ?? "problems";
10016
10018
  }
10019
+ function getSolvingDir() {
10020
+ const projectConfig = getProjectConfigSync();
10021
+ if (projectConfig?.solvingDir !== void 0) {
10022
+ return projectConfig.solvingDir;
10023
+ }
10024
+ return config.get("solvingDir") ?? "solving";
10025
+ }
10026
+ function getArchiveStrategy() {
10027
+ const projectConfig = getProjectConfigSync();
10028
+ if (projectConfig?.archiveStrategy !== void 0) {
10029
+ return projectConfig.archiveStrategy;
10030
+ }
10031
+ return config.get("archiveStrategy") ?? "flat";
10032
+ }
10033
+
10034
+ // src/utils/tier.ts
10035
+ import gradient from "gradient-string";
10036
+ var TIER_NAMES = [
10037
+ void 0,
10038
+ "Bronze V",
10039
+ "Bronze IV",
10040
+ "Bronze III",
10041
+ "Bronze II",
10042
+ "Bronze I",
10043
+ "Silver V",
10044
+ "Silver IV",
10045
+ "Silver III",
10046
+ "Silver II",
10047
+ "Silver I",
10048
+ "Gold V",
10049
+ "Gold IV",
10050
+ "Gold III",
10051
+ "Gold II",
10052
+ "Gold I",
10053
+ "Platinum V",
10054
+ "Platinum IV",
10055
+ "Platinum III",
10056
+ "Platinum II",
10057
+ "Platinum I",
10058
+ "Diamond V",
10059
+ "Diamond IV",
10060
+ "Diamond III",
10061
+ "Diamond II",
10062
+ "Diamond I",
10063
+ "Ruby V",
10064
+ "Ruby IV",
10065
+ "Ruby III",
10066
+ "Ruby II",
10067
+ "Ruby I",
10068
+ "Master"
10069
+ ];
10070
+ var TIER_COLORS = [
10071
+ void 0,
10072
+ "#9d4900",
10073
+ "#a54f00",
10074
+ "#ad5600",
10075
+ "#b55d0a",
10076
+ "#c67739",
10077
+ "#38546e",
10078
+ "#3d5a74",
10079
+ "#435f7a",
10080
+ "#496580",
10081
+ "#4e6a86",
10082
+ "#d28500",
10083
+ "#df8f00",
10084
+ "#ec9a00",
10085
+ "#f9a518",
10086
+ "#ffb028",
10087
+ "#00c78b",
10088
+ "#00d497",
10089
+ "#27e2a4",
10090
+ "#3ef0b1",
10091
+ "#51fdbd",
10092
+ "#009ee5",
10093
+ "#00a9f0",
10094
+ "#00b4fc",
10095
+ "#2bbfff",
10096
+ "#41caff",
10097
+ "#e0004c",
10098
+ "#ea0053",
10099
+ "#f5005a",
10100
+ "#ff0062",
10101
+ "#ff3071",
10102
+ "#b300e0"
10103
+ ];
10104
+ var TIER_IMAGE_BASE_URL = "https://d2gd6pc034wcta.cloudfront.net/tier";
10105
+ var MASTER_TIER_GRADIENT = [
10106
+ { r: 255, g: 124, b: 168 },
10107
+ { r: 180, g: 145, b: 255 },
10108
+ { r: 124, g: 249, b: 255 }
10109
+ ];
10110
+ var TIER_MIN_RATINGS = [
10111
+ 0,
10112
+ // Unrated (tier 0): 0-29
10113
+ 30,
10114
+ // Bronze V (tier 1)
10115
+ 60,
10116
+ // Bronze IV (tier 2)
10117
+ 90,
10118
+ // Bronze III (tier 3)
10119
+ 120,
10120
+ // Bronze II (tier 4)
10121
+ 150,
10122
+ // Bronze I (tier 5)
10123
+ 200,
10124
+ // Silver V (tier 6)
10125
+ 300,
10126
+ // Silver IV (tier 7)
10127
+ 400,
10128
+ // Silver III (tier 8)
10129
+ 500,
10130
+ // Silver II (tier 9)
10131
+ 650,
10132
+ // Silver I (tier 10)
10133
+ 800,
10134
+ // Gold V (tier 11)
10135
+ 950,
10136
+ // Gold IV (tier 12)
10137
+ 1100,
10138
+ // Gold III (tier 13)
10139
+ 1250,
10140
+ // Gold II (tier 14)
10141
+ 1400,
10142
+ // Gold I (tier 15)
10143
+ 1600,
10144
+ // Platinum V (tier 16)
10145
+ 1750,
10146
+ // Platinum IV (tier 17)
10147
+ 1900,
10148
+ // Platinum III (tier 18)
10149
+ 2e3,
10150
+ // Platinum II (tier 19)
10151
+ 2100,
10152
+ // Platinum I (tier 20)
10153
+ 2200,
10154
+ // Diamond V (tier 21)
10155
+ 2300,
10156
+ // Diamond IV (tier 22)
10157
+ 2400,
10158
+ // Diamond III (tier 23)
10159
+ 2500,
10160
+ // Diamond II (tier 24)
10161
+ 2600,
10162
+ // Diamond I (tier 25)
10163
+ 2700,
10164
+ // Ruby V (tier 26)
10165
+ 2800,
10166
+ // Ruby IV (tier 27)
10167
+ 2850,
10168
+ // Ruby III (tier 28)
10169
+ 2900,
10170
+ // Ruby II (tier 29)
10171
+ 2950,
10172
+ // Ruby I (tier 30)
10173
+ 3e3
10174
+ // Master (tier 31)
10175
+ ];
10176
+ function getTierMinRating(tier) {
10177
+ if (tier >= 0 && tier < TIER_MIN_RATINGS.length) {
10178
+ return TIER_MIN_RATINGS[tier] ?? 0;
10179
+ }
10180
+ return 0;
10181
+ }
10182
+ function getNextTierMinRating(tier) {
10183
+ if (tier === 31) {
10184
+ return null;
10185
+ }
10186
+ if (tier >= 0 && tier < TIER_MIN_RATINGS.length - 1) {
10187
+ return TIER_MIN_RATINGS[tier + 1] ?? null;
10188
+ }
10189
+ return null;
10190
+ }
10191
+ function calculateTierProgress(currentRating, tier) {
10192
+ if (tier === 31) {
10193
+ return 100;
10194
+ }
10195
+ const currentTierMin = getTierMinRating(tier);
10196
+ const nextTierMin = getNextTierMinRating(tier);
10197
+ if (nextTierMin === null) {
10198
+ return 100;
10199
+ }
10200
+ if (currentRating < currentTierMin) {
10201
+ return 0;
10202
+ }
10203
+ if (currentRating >= nextTierMin) {
10204
+ return 100;
10205
+ }
10206
+ const progress = (currentRating - currentTierMin) / (nextTierMin - currentTierMin) * 100;
10207
+ return Math.max(0, Math.min(100, progress));
10208
+ }
10209
+ function getTierName(level) {
10210
+ if (level === 0) return "Unrated";
10211
+ if (level >= 1 && level < TIER_NAMES.length) {
10212
+ return TIER_NAMES[level] || "Unrated";
10213
+ }
10214
+ return "Unrated";
10215
+ }
10216
+ function getTierColor(level) {
10217
+ if (level === 0) return "#2d2d2d";
10218
+ if (level === 31) {
10219
+ return gradient([...MASTER_TIER_GRADIENT]);
10220
+ }
10221
+ if (level >= 1 && level < TIER_COLORS.length) {
10222
+ return TIER_COLORS[level] || "#2d2d2d";
10223
+ }
10224
+ return "#2d2d2d";
10225
+ }
10226
+ function getTierImageUrl(level) {
10227
+ return `${TIER_IMAGE_BASE_URL}/${level}.svg`;
10228
+ }
10017
10229
 
10018
10230
  // src/utils/problem-id.ts
10019
10231
  import { join as join2 } from "path";
10232
+ function sanitizeFileName(name) {
10233
+ return name.replace(/[<>:"/\\|?*]/g, "").replace(/\s+/g, "-").toLowerCase().trim();
10234
+ }
10235
+ function getTierDirName(level) {
10236
+ const tierName = getTierName(level);
10237
+ if (tierName === "Unrated") {
10238
+ return "unrated";
10239
+ }
10240
+ return sanitizeFileName(tierName);
10241
+ }
10242
+ function getArchiveSubPath(problemId, strategy = "flat", problem) {
10243
+ switch (strategy) {
10244
+ case "flat":
10245
+ return "";
10246
+ case "by-range": {
10247
+ const range = Math.floor(problemId / 1e3) * 1e3;
10248
+ return String(range).padStart(5, "0");
10249
+ }
10250
+ case "by-tier": {
10251
+ if (!problem) {
10252
+ return "";
10253
+ }
10254
+ return getTierDirName(problem.level);
10255
+ }
10256
+ case "by-tag": {
10257
+ if (!problem || !problem.tags || problem.tags.length === 0) {
10258
+ return "";
10259
+ }
10260
+ return sanitizeFileName(problem.tags[0]);
10261
+ }
10262
+ default:
10263
+ return "";
10264
+ }
10265
+ }
10020
10266
  function detectProblemIdFromPath(cwd = process.cwd()) {
10021
10267
  const problemDir = getProblemDir();
10268
+ const solvingDir = getSolvingDir();
10269
+ const archiveStrategy = getArchiveStrategy();
10022
10270
  const normalizedPath = cwd.replace(/\\/g, "/");
10023
- if (problemDir === "." || problemDir === "") {
10271
+ const dirsToCheck = [problemDir, solvingDir].filter(
10272
+ (dir) => dir && dir !== "." && dir !== ""
10273
+ );
10274
+ if (dirsToCheck.length === 0) {
10024
10275
  const segments = normalizedPath.split("/").filter(Boolean);
10025
10276
  const lastSegment = segments[segments.length - 1];
10026
10277
  if (lastSegment) {
10027
- const problemId2 = parseInt(lastSegment, 10);
10028
- if (!isNaN(problemId2) && problemId2 > 0 && lastSegment === problemId2.toString()) {
10029
- return problemId2;
10278
+ const problemId = parseInt(lastSegment, 10);
10279
+ if (!isNaN(problemId) && problemId > 0 && lastSegment === problemId.toString()) {
10280
+ return problemId;
10030
10281
  }
10031
10282
  }
10032
10283
  return null;
10033
10284
  }
10034
- const dirPattern = `/${problemDir}/`;
10035
- const dirIndex = normalizedPath.indexOf(dirPattern);
10036
- if (dirIndex === -1) {
10037
- return null;
10038
- }
10039
- const afterDir = normalizedPath.substring(dirIndex + dirPattern.length);
10040
- if (!afterDir) {
10041
- return null;
10042
- }
10043
- const firstSegment = afterDir.split("/")[0];
10044
- if (!firstSegment) {
10045
- return null;
10046
- }
10047
- const problemId = parseInt(firstSegment, 10);
10048
- if (isNaN(problemId) || problemId <= 0) {
10049
- return null;
10050
- }
10051
- if (firstSegment !== problemId.toString()) {
10052
- return null;
10285
+ for (const dir of dirsToCheck) {
10286
+ const dirPattern = `/${dir}/`;
10287
+ const dirIndex = normalizedPath.indexOf(dirPattern);
10288
+ if (dirIndex === -1) {
10289
+ continue;
10290
+ }
10291
+ const afterDir = normalizedPath.substring(dirIndex + dirPattern.length);
10292
+ if (!afterDir) {
10293
+ continue;
10294
+ }
10295
+ const segments = afterDir.split("/").filter(Boolean);
10296
+ if (segments.length === 0) {
10297
+ continue;
10298
+ }
10299
+ let problemId = null;
10300
+ if (archiveStrategy === "flat") {
10301
+ const firstSegment = segments[0];
10302
+ if (firstSegment) {
10303
+ const id = parseInt(firstSegment, 10);
10304
+ if (!isNaN(id) && id > 0 && firstSegment === id.toString() && segments.length === 1) {
10305
+ problemId = id;
10306
+ }
10307
+ }
10308
+ } else if (archiveStrategy === "by-range") {
10309
+ if (segments.length === 2) {
10310
+ const secondSegment = segments[1];
10311
+ if (secondSegment) {
10312
+ const id = parseInt(secondSegment, 10);
10313
+ if (!isNaN(id) && id > 0 && secondSegment === id.toString()) {
10314
+ problemId = id;
10315
+ }
10316
+ }
10317
+ }
10318
+ } else if (archiveStrategy === "by-tier" || archiveStrategy === "by-tag") {
10319
+ if (segments.length === 2) {
10320
+ const secondSegment = segments[1];
10321
+ if (secondSegment) {
10322
+ const id = parseInt(secondSegment, 10);
10323
+ if (!isNaN(id) && id > 0 && secondSegment === id.toString()) {
10324
+ problemId = id;
10325
+ }
10326
+ }
10327
+ }
10328
+ }
10329
+ if (!problemId) {
10330
+ const lastSegment = segments[segments.length - 1];
10331
+ if (lastSegment) {
10332
+ const id = parseInt(lastSegment, 10);
10333
+ if (!isNaN(id) && id > 0 && lastSegment === id.toString() && segments.length === 1) {
10334
+ problemId = id;
10335
+ }
10336
+ }
10337
+ if (!problemId && segments.length === 2) {
10338
+ const secondSegment = segments[1];
10339
+ if (secondSegment) {
10340
+ const id = parseInt(secondSegment, 10);
10341
+ if (!isNaN(id) && id > 0 && secondSegment === id.toString()) {
10342
+ problemId = id;
10343
+ }
10344
+ }
10345
+ }
10346
+ }
10347
+ if (problemId) {
10348
+ return problemId;
10349
+ }
10053
10350
  }
10054
- return problemId;
10351
+ return null;
10055
10352
  }
10056
10353
  function getProblemId(args, cwd = process.cwd()) {
10057
10354
  if (args.length > 0 && args[0]) {
@@ -10062,19 +10359,45 @@ function getProblemId(args, cwd = process.cwd()) {
10062
10359
  }
10063
10360
  return detectProblemIdFromPath(cwd);
10064
10361
  }
10065
- function getProblemDirPath(problemId, cwd = process.cwd()) {
10362
+ function getProblemDirPath(problemId, cwd = process.cwd(), problem) {
10066
10363
  const problemDir = getProblemDir();
10364
+ const archiveStrategy = getArchiveStrategy();
10067
10365
  const projectRoot = findProjectRoot(cwd);
10068
10366
  const baseDir = projectRoot || cwd;
10367
+ const subPath = getArchiveSubPath(problemId, archiveStrategy, problem);
10069
10368
  if (problemDir === "." || problemDir === "") {
10369
+ if (subPath) {
10370
+ return join2(baseDir, subPath, problemId.toString());
10371
+ }
10070
10372
  return join2(baseDir, problemId.toString());
10071
10373
  }
10374
+ if (subPath) {
10375
+ return join2(baseDir, problemDir, subPath, problemId.toString());
10376
+ }
10072
10377
  return join2(baseDir, problemDir, problemId.toString());
10073
10378
  }
10379
+ function getSolvingDirPath(problemId, cwd = process.cwd(), _) {
10380
+ const solvingDir = getSolvingDir();
10381
+ const projectRoot = findProjectRoot(cwd);
10382
+ const baseDir = projectRoot || cwd;
10383
+ if (solvingDir === "." || solvingDir === "") {
10384
+ return join2(baseDir, problemId.toString());
10385
+ }
10386
+ return join2(baseDir, solvingDir, problemId.toString());
10387
+ }
10074
10388
 
10075
10389
  // src/utils/execution-context.ts
10390
+ import { access } from "fs/promises";
10076
10391
  import { readdir } from "fs/promises";
10077
10392
  import { join as join3 } from "path";
10393
+ async function directoryExists(dirPath) {
10394
+ try {
10395
+ await access(dirPath);
10396
+ return true;
10397
+ } catch {
10398
+ return false;
10399
+ }
10400
+ }
10078
10401
  async function resolveProblemContext(args, options = {}) {
10079
10402
  const { requireId = false } = options;
10080
10403
  const currentPathProblemId = detectProblemIdFromPath(process.cwd());
@@ -10085,7 +10408,24 @@ async function resolveProblemContext(args, options = {}) {
10085
10408
  );
10086
10409
  }
10087
10410
  const isCurrentDir = problemId === null || problemId !== null && currentPathProblemId === problemId;
10088
- const problemDir = problemId && !isCurrentDir ? getProblemDirPath(problemId) : process.cwd();
10411
+ let problemDir;
10412
+ if (problemId && !isCurrentDir) {
10413
+ const solvingDirPath = getSolvingDirPath(problemId);
10414
+ const problemDirPath = getProblemDirPath(problemId);
10415
+ const solvingDirExists = await directoryExists(solvingDirPath);
10416
+ if (solvingDirExists) {
10417
+ problemDir = solvingDirPath;
10418
+ } else {
10419
+ const problemDirExists = await directoryExists(problemDirPath);
10420
+ if (problemDirExists) {
10421
+ problemDir = problemDirPath;
10422
+ } else {
10423
+ problemDir = solvingDirPath;
10424
+ }
10425
+ }
10426
+ } else {
10427
+ problemDir = process.cwd();
10428
+ }
10089
10429
  return {
10090
10430
  problemId,
10091
10431
  problemDir,
@@ -10249,14 +10589,23 @@ var CommandBuilder = class {
10249
10589
 
10250
10590
  export {
10251
10591
  Command,
10592
+ findProjectRoot,
10252
10593
  getDefaultLanguage,
10253
10594
  getEditor,
10254
10595
  getAutoOpenEditor,
10255
10596
  getSolvedAcHandle,
10256
10597
  getProblemDir,
10598
+ getSolvingDir,
10599
+ getArchiveStrategy,
10600
+ getNextTierMinRating,
10601
+ calculateTierProgress,
10602
+ getTierName,
10603
+ getTierColor,
10604
+ getTierImageUrl,
10257
10605
  detectProblemIdFromPath,
10258
10606
  getProblemId,
10259
10607
  getProblemDirPath,
10608
+ getSolvingDirPath,
10260
10609
  resolveProblemContext,
10261
10610
  resolveLanguage,
10262
10611
  findSolutionFile,