@juki-team/commons 0.1.40 → 0.1.42

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.
@@ -600,6 +600,9 @@ exports.WebSocketSubscriptionEvent = void 0;
600
600
  WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK"] = "UNSUBSCRIBE_CLIENT_TRACK";
601
601
  WebSocketSubscriptionEvent["SUBSCRIBE_USER_NOTIFICATION"] = "SUBSCRIBE_USER_NOTIFICATION";
602
602
  WebSocketSubscriptionEvent["UNSUBSCRIBE_USER_NOTIFICATION"] = "UNSUBSCRIBE_USER_NOTIFICATION";
603
+ // an administrator watching the data (screenshots, location, device) sent by another client
604
+ WebSocketSubscriptionEvent["SUBSCRIBE_CLIENT_TRACK_DATA"] = "SUBSCRIBE_CLIENT_TRACK_DATA";
605
+ WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK_DATA"] = "UNSUBSCRIBE_CLIENT_TRACK_DATA";
603
606
  })(exports.WebSocketSubscriptionEvent || (exports.WebSocketSubscriptionEvent = {}));
604
607
  exports.WebSocketResponseEvent = void 0;
605
608
  (function (WebSocketResponseEvent) {
@@ -623,6 +626,20 @@ exports.WebSocketResponseEvent = void 0;
623
626
  WebSocketResponseEvent["USER_NOTIFICATION_SUBMISSION"] = "USER_NOTIFICATION_SUBMISSION";
624
627
  WebSocketResponseEvent["USER_NOTIFICATION_CONTEST_CLARIFICATION"] = "USER_NOTIFICATION_CONTEST_CLARIFICATION";
625
628
  })(exports.WebSocketResponseEvent || (exports.WebSocketResponseEvent = {}));
629
+ /**
630
+ * Roles of a contest, with the same names as the contest members in the DB.
631
+ * Each role has its own Ably channel: `contest:{contestKey}:{role}` (see `CHANNEL_CONTEST`).
632
+ * The inclusions follow `getContestAccessPermissions`:
633
+ * spectators ⊇ managers ⊇ administrators, spectators ⊇ participants, spectators ⊇ guests
634
+ */
635
+ exports.ContestChannelRole = void 0;
636
+ (function (ContestChannelRole) {
637
+ ContestChannelRole["ADMINISTRATORS"] = "administrators";
638
+ ContestChannelRole["MANAGERS"] = "managers";
639
+ ContestChannelRole["PARTICIPANTS"] = "participants";
640
+ ContestChannelRole["GUESTS"] = "guests";
641
+ ContestChannelRole["SPECTATORS"] = "spectators";
642
+ })(exports.ContestChannelRole || (exports.ContestChannelRole = {}));
626
643
 
627
644
  exports.DataViewMode = void 0;
628
645
  (function (DataViewMode) {
@@ -1380,21 +1397,6 @@ const COURSE_ROLE = {
1380
1397
  [CourseRole.SUPER_ADMIN]: { value: CourseRole.SUPER_ADMIN, label: 'super admin', level: 0 },
1381
1398
  };
1382
1399
 
1383
- const isWorksheetAssignment = (assignment) => {
1384
- return assignment.type === exports.AssignmentClass.WORKSHEET;
1385
- };
1386
- const isCourseAssignment = (assignment) => {
1387
- return assignment.type === exports.AssignmentClass.COURSE;
1388
- };
1389
- const isContestAssignment = (assignment) => {
1390
- return assignment.type === exports.AssignmentClass.CONTEST;
1391
- };
1392
-
1393
- const getAssignmentCommentKey = (classKey, cycleKey, sessionKey, assignmentKey) => `class:${classKey}|cycle:${cycleKey}|session:${sessionKey}|assignment:${assignmentKey}`;
1394
- const getAssignmentUserCommentKey = (classKey, cycleKey, sessionKey, assignmentKey, userNickname, userCompany) => `class:${classKey}|cycle:${cycleKey}|session:${sessionKey}|assignment:${assignmentKey}|user_nickname:${userNickname}|user_company:${userCompany}`;
1395
- const getProblemCommentKey = (problemKey) => `problem:${problemKey}`;
1396
- const getContestCommentKey = (contestKey) => `contest:${contestKey}`;
1397
-
1398
1400
  function isStringJson(str) {
1399
1401
  try {
1400
1402
  if (typeof str === 'string') {
@@ -1582,484 +1584,384 @@ const areArraysDifferent = (a, b) => {
1582
1584
  return false;
1583
1585
  };
1584
1586
 
1585
- const isEndlessContest = (settings) => {
1586
- return settings?.startTimestamp === MIN_DATE.getTime()
1587
- && settings?.frozenTimestamp === MAX_DATE.getTime()
1588
- && settings?.quietTimestamp === MAX_DATE.getTime()
1589
- && settings?.endTimestamp === MAX_DATE.getTime()
1590
- && settings?.penalty === 0;
1591
- };
1592
- const isGlobalContest = (settings) => {
1593
- return settings?.startTimestamp === 0
1594
- && settings?.frozenTimestamp === 0
1595
- && settings?.quietTimestamp === 0
1596
- && settings?.endTimestamp === 0
1597
- && settings?.penalty === 0;
1598
- };
1599
- const isPastContest = (settings) => {
1600
- return Date.now() > (settings?.endTimestamp ?? 0);
1601
- };
1602
- const isFutureContest = (settings) => {
1603
- return (settings?.startTimestamp ?? 0) > Date.now();
1604
- };
1605
-
1606
- const getDocumentAccess = (document) => {
1607
- switch (true) {
1608
- case (document?.members?.rankAdministrators === exports.EntityMembersRank.NONE || document?.members?.rankAdministrators === exports.EntityMembersRank.CLOSE)
1609
- && document?.members?.rankManagers === exports.EntityMembersRank.OPEN
1610
- && (document?.members?.rankGuests === exports.EntityMembersRank.NONE || document?.members?.rankGuests === exports.EntityMembersRank.CLOSE || document?.members?.rankGuests === exports.EntityMembersRank.OPEN)
1611
- && document?.members?.rankSpectators === exports.EntityMembersRank.OPEN
1612
- && (document?.members?.rankParticipants === exports.EntityMembersRank.NONE || document?.members?.rankParticipants === exports.EntityMembersRank.CLOSE || document?.members?.rankParticipants === exports.EntityMembersRank.OPEN):
1613
- return exports.EntityAccess.EXPOSED;
1614
- case (document?.members?.rankAdministrators === exports.EntityMembersRank.NONE || document?.members?.rankAdministrators === exports.EntityMembersRank.CLOSE)
1615
- && document?.members?.rankManagers === exports.EntityMembersRank.CLOSE
1616
- && (document?.members?.rankGuests === exports.EntityMembersRank.NONE || document?.members?.rankGuests === exports.EntityMembersRank.CLOSE || document?.members?.rankGuests === exports.EntityMembersRank.OPEN)
1617
- && document?.members?.rankSpectators === exports.EntityMembersRank.OPEN
1618
- && (document?.members?.rankParticipants === exports.EntityMembersRank.NONE || document?.members?.rankParticipants === exports.EntityMembersRank.CLOSE || document?.members?.rankParticipants === exports.EntityMembersRank.OPEN):
1619
- return exports.EntityAccess.PUBLIC;
1620
- case (document?.members?.rankAdministrators === exports.EntityMembersRank.NONE || document?.members?.rankAdministrators === exports.EntityMembersRank.CLOSE)
1621
- && document?.members?.rankManagers === exports.EntityMembersRank.CLOSE
1622
- && (document?.members?.rankGuests === exports.EntityMembersRank.NONE || document?.members?.rankGuests === exports.EntityMembersRank.CLOSE || document?.members?.rankGuests === exports.EntityMembersRank.OPEN)
1623
- && document?.members?.rankSpectators === exports.EntityMembersRank.CLOSE
1624
- && (document?.members?.rankParticipants === exports.EntityMembersRank.NONE || document?.members?.rankParticipants === exports.EntityMembersRank.CLOSE || document?.members?.rankParticipants === exports.EntityMembersRank.OPEN):
1625
- return exports.EntityAccess.RESTRICTED;
1626
- case document?.members?.rankAdministrators === exports.EntityMembersRank.NONE
1627
- && document?.members?.rankManagers === exports.EntityMembersRank.NONE
1628
- && document?.members?.rankGuests === exports.EntityMembersRank.NONE
1629
- && document?.members?.rankSpectators === exports.EntityMembersRank.NONE
1630
- && document?.members?.rankParticipants === exports.EntityMembersRank.NONE:
1631
- return exports.EntityAccess.PRIVATE;
1632
- default:
1633
- return exports.EntityAccess.PRIVATE;
1634
- }
1635
- };
1636
- const isUserMember = (member) => {
1637
- return typeof member.userId === 'string';
1638
- };
1639
- const isTeamMember = (member) => {
1640
- return typeof member.teamId === 'string';
1641
- };
1642
- const toEntityMembersDTO = (members) => {
1643
- return {
1644
- rankAdministrators: members.rankAdministrators,
1645
- administrators: Object.keys(members.administrators),
1646
- rankManagers: members.rankManagers,
1647
- managers: Object.keys(members.managers),
1648
- rankParticipants: members.rankParticipants,
1649
- participants: Object.keys(members.participants),
1650
- rankGuests: members.rankGuests,
1651
- guests: Object.keys(members.guests),
1652
- rankSpectators: members.rankSpectators,
1653
- spectators: Object.keys(members.spectators),
1654
- };
1655
- };
1587
+ const YEARS = range(1970, 2100);
1588
+ const MONTH_NAMES = [
1589
+ 'January',
1590
+ 'February',
1591
+ 'March',
1592
+ 'April',
1593
+ 'May',
1594
+ 'June',
1595
+ 'July',
1596
+ 'August',
1597
+ 'September',
1598
+ 'October',
1599
+ 'November',
1600
+ 'December',
1601
+ ];
1602
+ const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
1603
+ const HOURS = range(0, 24);
1604
+ const MINUTES = range(0, 60);
1605
+ const SECONDS = range(0, 60);
1606
+ const MILLISECONDS = range(0, 1000);
1607
+ const MAX_DATE = new Date(8640000000000000);
1608
+ const MIN_DATE = new Date(0);
1656
1609
 
1657
- function removeExtension(fileName) {
1658
- const i = fileName.lastIndexOf('.');
1659
- return i !== -1 ? fileName.substring(0, i) : fileName;
1660
- }
1610
+ const SUPPORT_EMAIL = 'support@juki.app';
1611
+ const JUKI_APP_EMAIL_TEMPLATE = `<div style="width: 100%; background: #F2F2F2;">
1612
+ <div style="background: #164066; width: 100%;">
1613
+ <div style="height: 56px; color: white; width: 100px; margin: 0 auto">
1614
+ <img
1615
+ src="https://images.juki.pub/assets/juki-app-horizontal-white-logo.svg"
1616
+ alt="juki app logo"
1617
+ height="56px"
1618
+ style="padding:10px; box-sizing: border-box"
1619
+ />
1620
+ </div>
1621
+ </div>
1622
+ <div style="padding: 24px; color: #333333; font-family: sans-serif; font-size: 16px; line-height: 24px;">
1623
+ <div style="max-width: 520px; margin: 0 auto; padding: 24px; background: white; border-radius: 6px;">
1624
+ <section style="padding: 0 0 1em 0; border-bottom: 1px solid #828282;">
1625
+ {{content}}
1626
+ </section>
1627
+ <div style="font-size: 14px; text-align: center; color: #828282; line-height: 16px; padding-top: 1em">
1628
+ <p style="margin: 0;">
1629
+ Si tú no realizaste la solicitud, escribenos a
1630
+ <a href="mailto:${SUPPORT_EMAIL}" style="color: #2468A6; text-decoration: none;">
1631
+ ${SUPPORT_EMAIL}
1632
+ </a>
1633
+ </p>
1634
+ <p style="margin: 0;">
1635
+ Este mensaje fue enviado por el equipo de
1636
+ <a href="https://juki.app" style="color: #2468A6; text-decoration: none;">
1637
+ juki.app
1638
+ </a>
1639
+ </p>
1640
+ </div>
1641
+ </div>
1642
+ </div>
1643
+ </div>`;
1661
1644
 
1662
- // https://dev.to/jsmccrumb/asynchronous-setinterval-4j69
1663
- const asyncIntervals = [];
1664
- const runAsyncInterval = async (cb, interval, intervalIndex) => {
1665
- await cb();
1666
- if (asyncIntervals[intervalIndex]) {
1667
- setTimeout(() => runAsyncInterval(cb, interval, intervalIndex), interval);
1668
- }
1669
- };
1670
- const setAsyncInterval = (cb, interval) => {
1671
- if (cb && typeof cb === 'function') {
1672
- const intervalIndex = asyncIntervals.length;
1673
- asyncIntervals.push(true);
1674
- void runAsyncInterval(cb, interval, intervalIndex);
1675
- return intervalIndex;
1676
- }
1677
- else {
1678
- throw new Error('Callback must be a function');
1679
- }
1680
- };
1681
- const clearAsyncInterval = (intervalIndex) => {
1682
- if (asyncIntervals[intervalIndex]) {
1683
- asyncIntervals[intervalIndex] = false;
1684
- }
1685
- };
1645
+ const EMPTY_DOCUMENT_MEMBERS = () => ({
1646
+ access: exports.EntityAccess.PRIVATE,
1647
+ managers: {},
1648
+ spectators: {},
1649
+ });
1650
+ const EMPTY_ENTITY_MEMBERS = () => ({
1651
+ rankAdministrators: exports.EntityMembersRank.CLOSE,
1652
+ administrators: {},
1653
+ rankManagers: exports.EntityMembersRank.CLOSE,
1654
+ managers: {},
1655
+ rankGuests: exports.EntityMembersRank.CLOSE,
1656
+ guests: {},
1657
+ rankSpectators: exports.EntityMembersRank.CLOSE,
1658
+ spectators: {},
1659
+ rankParticipants: exports.EntityMembersRank.CLOSE,
1660
+ participants: {},
1661
+ });
1686
1662
 
1687
- const getDataOfTestCase = (testCase, timeLimit, memoryLimit) => {
1688
- const { timeUsed, memoryUsed, exitCode } = getDataLog(testCase?.log);
1689
- const timeLimitExceeded = timeUsed > timeLimit;
1690
- const memoryLimitExceeded = memoryUsed > memoryLimit;
1691
- const runtimeError = exitCode !== 0;
1692
- const compilationError = testCase?.status === exports.SubmissionRunStatus.COMPILATION_ERROR;
1693
- return {
1694
- compilationError,
1695
- timeUsed,
1696
- timeLimitExceeded: timeLimitExceeded,
1697
- memoryUsed,
1698
- memoryLimitExceeded: memoryLimitExceeded,
1699
- exitCode,
1700
- runtimeError,
1701
- failed: !!testCase?.log && (timeLimitExceeded || memoryLimitExceeded || runtimeError),
1702
- };
1703
- };
1704
- const getVerdictFromTestCase = (testCaseValue, timeLimit, memoryLimit) => {
1705
- const { compilationError, timeLimitExceeded, memoryLimitExceeded, runtimeError, timeUsed, memoryUsed, exitCode, } = getDataOfTestCase(testCaseValue, timeLimit, memoryLimit);
1706
- return {
1707
- verdict: compilationError
1708
- ? exports.ProblemVerdict.CE
1709
- : timeLimitExceeded
1710
- ? exports.ProblemVerdict.TLE
1711
- : memoryLimitExceeded
1712
- ? exports.ProblemVerdict.MLE
1713
- : runtimeError
1714
- ? exports.ProblemVerdict.RE
1715
- : testCaseValue.out === testCaseValue.testOut
1716
- ? exports.ProblemVerdict.AC
1717
- : testCaseValue.withPE && testCaseValue.out.split(' ').join('').split('\n').join('') === testCaseValue.testOut.split(' ').join('').split('\n').join('')
1718
- ? exports.ProblemVerdict.PE
1719
- : !testCaseValue.withPE && testCaseValue.out.split(' ').join('').split('\n').join('') === testCaseValue.testOut.split(' ').join('').split('\n').join('')
1720
- ? exports.ProblemVerdict.AC
1721
- : exports.ProblemVerdict.WA,
1722
- timeUsed,
1723
- memoryUsed,
1724
- exitCode,
1725
- };
1726
- };
1727
- const mergeVerdicts = (first, second) => {
1728
- let verdict = first.verdict;
1729
- if (second.verdict === exports.ProblemVerdict.RE) {
1730
- verdict = exports.ProblemVerdict.RE;
1731
- }
1732
- else if (second.verdict === exports.ProblemVerdict.TLE && verdict != exports.ProblemVerdict.RE) {
1733
- verdict = exports.ProblemVerdict.TLE;
1734
- }
1735
- else if (second.verdict === exports.ProblemVerdict.MLE
1736
- && verdict !== exports.ProblemVerdict.TLE
1737
- && verdict !== exports.ProblemVerdict.RE) {
1738
- verdict = exports.ProblemVerdict.MLE;
1739
- }
1740
- else if (second.verdict === exports.ProblemVerdict.WA
1741
- && verdict !== exports.ProblemVerdict.MLE
1742
- && verdict !== exports.ProblemVerdict.TLE
1743
- && verdict !== exports.ProblemVerdict.RE) {
1744
- verdict = exports.ProblemVerdict.WA;
1745
- }
1746
- else if (second.verdict === exports.ProblemVerdict.PE
1747
- && verdict !== exports.ProblemVerdict.WA
1748
- && verdict !== exports.ProblemVerdict.MLE
1749
- && verdict !== exports.ProblemVerdict.TLE
1750
- && verdict !== exports.ProblemVerdict.RE) {
1751
- verdict = exports.ProblemVerdict.PE;
1752
- }
1753
- else if (second.verdict === exports.ProblemVerdict.PA
1754
- && verdict !== exports.ProblemVerdict.PE
1755
- && verdict !== exports.ProblemVerdict.WA
1756
- && verdict !== exports.ProblemVerdict.MLE
1757
- && verdict !== exports.ProblemVerdict.TLE
1758
- && verdict !== exports.ProblemVerdict.RE) {
1759
- verdict = exports.ProblemVerdict.PA;
1760
- }
1761
- else if (second.verdict === exports.ProblemVerdict.AC
1762
- && verdict !== exports.ProblemVerdict.PA
1763
- && verdict !== exports.ProblemVerdict.PE
1764
- && verdict !== exports.ProblemVerdict.WA
1765
- && verdict !== exports.ProblemVerdict.MLE
1766
- && verdict !== exports.ProblemVerdict.TLE
1767
- && verdict !== exports.ProblemVerdict.RE) {
1768
- verdict = exports.ProblemVerdict.AC;
1769
- }
1770
- return {
1771
- timeUsed: Math.max(first.timeUsed, second.timeUsed),
1772
- memoryUsed: Math.max(first.memoryUsed, second.memoryUsed),
1773
- exitCode: first.exitCode || second.exitCode,
1774
- verdict,
1775
- };
1663
+ const JUDGE = {
1664
+ // [Judge.CUSTOMER]: {
1665
+ // value: Judge.CUSTOMER,
1666
+ // label: '',
1667
+ // logo: 'https://images.juki.pub/c/juki-judge-logo-horizontal-color.svg',
1668
+ // logoSize: [ 883.991, 435 ],
1669
+ // url: '',
1670
+ // // getLoginUrl: () => '',
1671
+ // // getProfileUrl: () => '',
1672
+ // // getSubmitUrl: () => '',
1673
+ // // getSubmissionUrl: () => '',
1674
+ // // getProblemUrl: (key: string) => `/problem/view/${key}`,
1675
+ // // getUserSubmissionsUrl: () => '',
1676
+ // },
1677
+ [exports.Judge.JUKI_JUDGE]: {
1678
+ value: exports.Judge.JUKI_JUDGE,
1679
+ label: 'Juki Judge',
1680
+ logo: 'https://images.juki.pub/c/juki-judge-logo-horizontal-color.svg',
1681
+ logoSize: [883.991, 435],
1682
+ url: 'https://judge.juki.app',
1683
+ // getLoginUrl: () => '',
1684
+ // getProfileUrl: () => '',
1685
+ // getSubmitUrl: () => '',
1686
+ // getSubmissionUrl: () => '',
1687
+ // getProblemUrl: (key: string) => `https://judge.juki.app/problem/view/${key}`,
1688
+ // getUserSubmissionsUrl: () => '',
1689
+ },
1690
+ [exports.Judge.CODEFORCES]: {
1691
+ value: exports.Judge.CODEFORCES,
1692
+ label: 'Codeforces',
1693
+ logo: 'https://images.juki.pub/c/codeforces-logo-horizontal-color.svg',
1694
+ logoSize: [1232.75, 145.12],
1695
+ url: 'https://codeforces.com',
1696
+ // getLoginUrl: () => 'https://codeforces.com/enter',
1697
+ // getProfileUrl: () => '',
1698
+ // getSubmitUrl: () => 'https://codeforces.com/problemset/submit',
1699
+ // getSubmissionUrl: (problemKey: string, submissionId: string) => {
1700
+ // const [ contestId ] = problemKey.split('-');
1701
+ // return `https://codeforces.com/problemset/submission/${contestId}/${submissionId}`;
1702
+ // },
1703
+ // getProblemUrl: (problemKey: string) => {
1704
+ // const [ contestId, index ] = problemKey.split('-');
1705
+ // return `https://codeforces.com/problemset/problem/${contestId}/${index}`;
1706
+ // },
1707
+ // getUserSubmissionsUrl: () => '',
1708
+ },
1709
+ [exports.Judge.CODEFORCES_GYM]: {
1710
+ value: exports.Judge.CODEFORCES_GYM,
1711
+ label: 'Codeforces Gym',
1712
+ logo: 'https://images.juki.pub/c/codeforces-logo-horizontal-color.svg',
1713
+ logoSize: [1232.75, 145.12],
1714
+ url: 'https://codeforces.com',
1715
+ // getLoginUrl: () => 'https://codeforces.com/enter',
1716
+ // getProfileUrl: () => '',
1717
+ // getSubmitUrl: (problemKey: string) => {
1718
+ // const [ gymContestId, index ] = problemKey.split('-');
1719
+ // return `https://codeforces.com/gym/${gymContestId}/submit`;
1720
+ // },
1721
+ // getSubmissionUrl: (problemKey: string, submissionId: string) => {
1722
+ // const [ gymContestId ] = problemKey.split('-');
1723
+ // return `https://codeforces.com/gym/${gymContestId}/submission/${submissionId}`;
1724
+ // },
1725
+ // getProblemUrl: (problemKey: string) => {
1726
+ // const [ gymContestId, index ] = problemKey.split('-');
1727
+ // return `https://codeforces.com/gym/${gymContestId}/problem/${index}`;
1728
+ // },
1729
+ // getUserSubmissionsUrl: () => '',
1730
+ },
1731
+ [exports.Judge.JV_UMSA]: {
1732
+ value: exports.Judge.JV_UMSA,
1733
+ label: 'Juez Virtual UMSA',
1734
+ logo: 'https://images.juki.pub/c/codeforces-logo-horizontal-color.svg',
1735
+ logoSize: [1232.75, 145.12],
1736
+ url: 'https://jv.umsa.bo',
1737
+ // getLoginUrl: () => 'https://jv.umsa.bo/oj/login.php',
1738
+ // getProfileUrl: () => 'https://jv.umsa.bo/oj/userInfo.php',
1739
+ // getSubmitUrl: (problemKey: string) => {
1740
+ // // single problem: '1019'
1741
+ // // cib problem: '1019-A'
1742
+ // const isContestProblem = problemKey.includes('-');
1743
+ // // A -> 0, B -> 1, C -> 2, D -> 3, E -> 4, F -> 5, G -> 6, H -> 7, I -> 8, J -> 9
1744
+ // const params = problemKey.split('-');
1745
+ // return isContestProblem
1746
+ // ? `https://jv.umsa.bo/oj/submitpage.php?cid=${params[0]}&pid=${params[1].charCodeAt(0) - 65}`
1747
+ // : `https://jv.umsa.bo/oj/submitpage.php?id=${problemKey}`;
1748
+ // },
1749
+ // getSubmissionUrl: (problemKey: string, submissionId: string, username: string) => {
1750
+ // // return `https://jv.umsa.bo/status.php?problem_id=&user_id=${username}&language=-1&jresult=-1`;
1751
+ // return `https://jv.umsa.bo/oj/showsource.php?id=${submissionId}`;
1752
+ // },
1753
+ // getProblemUrl: (problemKey: string) => {
1754
+ // const isContestProblem = problemKey.includes('-');
1755
+ // const params = problemKey.split('-');
1756
+ // return isContestProblem
1757
+ // ? `https://jv.umsa.bo/oj/problem.php?cid=${params[0]}&pid=${params[1].charCodeAt(0) - 65}`
1758
+ // : `https://jv.umsa.bo/oj/problem.php?id=${problemKey}`;
1759
+ // },
1760
+ // getUserSubmissionsUrl: (username: string) => `https://jv.umsa.bo/oj/status.php?user_id=${username}`,
1761
+ },
1762
+ [exports.Judge.UVA_ONLINE_JUDGE]: {
1763
+ value: exports.Judge.UVA_ONLINE_JUDGE,
1764
+ label: 'Uva Online Judge',
1765
+ logo: 'https://images.juki.pub/c/uva-online-judge-logo-color.png',
1766
+ logoSize: [150, 135.994],
1767
+ url: 'https://onlinejudge.org',
1768
+ },
1769
+ [exports.Judge.AT_CODER]: {
1770
+ value: exports.Judge.AT_CODER,
1771
+ label: 'AtCoder',
1772
+ logo: 'https://images.juki.pub/c/at-coder-logo-color.png',
1773
+ logoSize: [762.997, 675],
1774
+ url: 'https://atcoder.jp',
1775
+ },
1776
+ [exports.Judge.CODECHEF]: {
1777
+ value: exports.Judge.CODECHEF,
1778
+ label: 'Codechef',
1779
+ logo: 'https://images.juki.pub/c/codechef-logo-color.svg',
1780
+ logoSize: [1207.7, 453.17],
1781
+ url: 'https://www.codechef.com',
1782
+ },
1783
+ [exports.Judge.TOPCODER]: {
1784
+ value: exports.Judge.TOPCODER,
1785
+ label: 'Topcoder',
1786
+ logo: 'https://images.juki.pub/c/topcoder-logo-color.png',
1787
+ logoSize: [971.99, 415.99],
1788
+ url: 'https://www.topcoder.com',
1789
+ },
1790
+ [exports.Judge.LEETCODE]: {
1791
+ value: exports.Judge.LEETCODE,
1792
+ label: 'LeetCode',
1793
+ logo: 'https://images.juki.pub/assets/leetcode-logo-color.svg',
1794
+ logoSize: [95, 111],
1795
+ url: 'https://leetcode.com',
1796
+ // getProblemUrl: (problemKey: string) => {
1797
+ // return `https://leetcode.com/problems/${problemKey.replace('PL-', '')}`;
1798
+ // },
1799
+ // getProfileUrl: (userNickname: string) => {
1800
+ // return `https://leetcode.com/u/${userNickname}`;
1801
+ // },
1802
+ // getSubmissionUrl: (problemKey: string, submissionId: string, username: string, submissionRunId: string) => {
1803
+ // return `https://leetcode.com/problems/${problemKey.replace('PL-', '')}/submissions/${submissionRunId}`;
1804
+ // },
1805
+ },
1776
1806
  };
1777
- const getDataLog = (log) => {
1778
- const lines = log?.split?.('\n') || [];
1779
- let timeUsed = 0;
1780
- let memoryUsed = 0;
1781
- let exitCode = -1;
1782
- if (lines.length > 4) {
1783
- for (const line of lines) {
1784
- if (line.startsWith('time:')) {
1785
- timeUsed = +line.split(':')[1];
1786
- if (Number.isNaN(timeUsed)) {
1787
- timeUsed = 0;
1788
- }
1789
- timeUsed *= 1000;
1790
- }
1791
- else if (line.startsWith('max-rss:')) {
1792
- memoryUsed = parseInt(line.split(':')[1], 10); // en KB
1793
- }
1794
- else if (line.startsWith('exitcode:')) {
1795
- exitCode = parseInt(line.split(':')[1], 10);
1796
- }
1797
- }
1798
- }
1799
- else if (lines.length >= 3) {
1800
- timeUsed = +lines[0];
1801
- memoryUsed = +lines[1];
1802
- exitCode = +lines[2];
1803
- }
1804
- return {
1805
- timeUsed: Number.isNaN(timeUsed) ? 0 : timeUsed,
1806
- memoryUsed: Number.isNaN(memoryUsed) ? 0 : memoryUsed,
1807
- exitCode: Number.isNaN(exitCode) ? -1 : exitCode,
1808
- };
1807
+ const RUNNER_ACCEPTED_PROBLEM_MODES = [
1808
+ exports.ProblemScoringMode.TOTAL,
1809
+ exports.ProblemScoringMode.SUBTASK,
1810
+ exports.ProblemScoringMode.PARTIAL,
1811
+ ];
1812
+ const RUNNER_ACCEPTED_PROBLEM_TYPES = [
1813
+ exports.ProblemType.STANDARD,
1814
+ exports.ProblemType.DYNAMIC,
1815
+ ];
1816
+ const RUNNER_ACCEPTED_PROGRAMMING_LANGUAGES = [
1817
+ exports.CodeLanguage.C_11,
1818
+ exports.CodeLanguage.CPP_11,
1819
+ exports.CodeLanguage.CPP_20,
1820
+ exports.CodeLanguage.JAVA_21,
1821
+ exports.CodeLanguage.PYTHON_3,
1822
+ exports.CodeLanguage.PYTHON_PYPY_3,
1823
+ exports.CodeLanguage.JAVASCRIPT_NODE_JS_22,
1824
+ exports.CodeLanguage.PSEUDOCODE_PSEINT,
1825
+ ];
1826
+ const ACCEPTED_PROGRAMMING_LANGUAGES = [
1827
+ ...RUNNER_ACCEPTED_PROGRAMMING_LANGUAGES,
1828
+ ];
1829
+ const PROBLEM_VERDICT = {
1830
+ [exports.ProblemVerdict.NONE]: { value: exports.ProblemVerdict.NONE, label: 'none', color: '#555555' },
1831
+ [exports.ProblemVerdict.PENDING]: { value: exports.ProblemVerdict.PENDING, label: 'pending', color: '#79B6FD' },
1832
+ [exports.ProblemVerdict.HIDDEN]: { value: exports.ProblemVerdict.HIDDEN, label: 'hidden', color: '#555555' },
1833
+ [exports.ProblemVerdict.AC]: { value: exports.ProblemVerdict.AC, label: 'accepted', color: '#43D787' },
1834
+ [exports.ProblemVerdict.PE]: { value: exports.ProblemVerdict.PE, label: 'presentation error', color: '#55db93' },
1835
+ [exports.ProblemVerdict.PA]: { value: exports.ProblemVerdict.PA, label: 'partial accepted', color: '#55db93' },
1836
+ [exports.ProblemVerdict.CE]: { value: exports.ProblemVerdict.CE, label: 'compilation error', color: '#FE9F9F' },
1837
+ [exports.ProblemVerdict.RE]: { value: exports.ProblemVerdict.RE, label: 'runtime error', color: '#FE9F9F' },
1838
+ [exports.ProblemVerdict.TLE]: { value: exports.ProblemVerdict.TLE, label: 'time limit exceed', color: '#FE9F9F' },
1839
+ [exports.ProblemVerdict.MLE]: { value: exports.ProblemVerdict.MLE, label: 'memory limit exceed', color: '#FE9F9F' },
1840
+ [exports.ProblemVerdict.WA]: { value: exports.ProblemVerdict.WA, label: 'wrong answer', color: '#FE9F9F' },
1809
1841
  };
1810
-
1811
- function memorySizeOf(obj) {
1812
- let bytes = 0;
1813
- function sizeOf(obj) {
1814
- if (obj !== null && obj !== undefined) {
1815
- switch (typeof obj) {
1816
- case "number":
1817
- bytes += 8;
1818
- break;
1819
- case "string":
1820
- bytes += obj.length * 2;
1821
- break;
1822
- case "boolean":
1823
- bytes += 4;
1824
- break;
1825
- case "object":
1826
- const objClass = Object.prototype.toString.call(obj).slice(8, -1);
1827
- if (objClass === "Object" || objClass === "Array") {
1828
- for (const key in obj) {
1829
- if (!obj.hasOwnProperty(key))
1830
- continue;
1831
- bytes += key.length * 2;
1832
- sizeOf(obj[key]);
1833
- }
1834
- }
1835
- else
1836
- bytes += obj.toString().length * 2;
1837
- break;
1838
- }
1839
- }
1840
- return bytes;
1841
- }
1842
- return sizeOf(obj);
1843
- }
1844
-
1845
- /* eslint-disable no-extend-native */
1846
- Date.prototype.changeYear = function (year) {
1847
- const newDate = new Date(this);
1848
- newDate.setFullYear(year);
1849
- return newDate;
1850
- };
1851
- Date.prototype.changeMonth = function (monthIndex) {
1852
- const newDate = new Date(this);
1853
- newDate.setMonth(monthIndex);
1854
- return newDate;
1855
- };
1856
- Date.prototype.changeDay = function (date) {
1857
- const newDate = new Date(this);
1858
- newDate.setDate(date);
1859
- return newDate;
1860
- };
1861
- Date.prototype.changeHours = function (hours) {
1862
- const newDate = new Date(this);
1863
- newDate.setHours(hours);
1864
- return newDate;
1865
- };
1866
- Date.prototype.changeMinutes = function (minutes) {
1867
- const newDate = new Date(this);
1868
- newDate.setMinutes(minutes);
1869
- return newDate;
1870
- };
1871
- Date.prototype.changeSeconds = function (seconds) {
1872
- const newDate = new Date(this);
1873
- newDate.setSeconds(seconds);
1874
- return newDate;
1875
- };
1876
- Date.prototype.changeMilliseconds = function (milliseconds) {
1877
- const newDate = new Date(this);
1878
- newDate.setMilliseconds(milliseconds);
1879
- return newDate;
1880
- };
1881
- Date.prototype.decreaseYear = function (count = 1) {
1882
- return this.changeYear(this.getFullYear() - count);
1883
- };
1884
- Date.prototype.increaseYear = function (count = 1) {
1885
- return this.changeYear(this.getFullYear() + count);
1886
- };
1887
- Date.prototype.decreaseMonth = function () {
1888
- const newDate = new Date(this);
1889
- newDate.setMonth(newDate.getMonth() - 1);
1890
- return newDate;
1891
- };
1892
- Date.prototype.increaseMonth = function () {
1893
- const newDate = new Date(this);
1894
- newDate.setMonth(newDate.getMonth() + 1);
1895
- return newDate;
1896
- };
1897
- Date.prototype.increaseDay = function () {
1898
- const newDate = new Date(this);
1899
- newDate.setDate(newDate.getDate() + 1);
1900
- return newDate;
1901
- };
1902
- Date.prototype.decreaseDay = function () {
1903
- const newDate = new Date(this);
1904
- newDate.setDate(newDate.getDate() - 1);
1905
- return newDate;
1906
- };
1907
- Date.prototype.startOfYear = function () {
1908
- const newDate = new Date(this);
1909
- newDate.setMonth(0);
1910
- return newDate.startOfMonth();
1911
- };
1912
- Date.prototype.endOfYear = function () {
1913
- const nextMonth = this.increaseYear().startOfYear();
1914
- return new Date(nextMonth.getTime() - 1);
1915
- };
1916
- Date.prototype.startOfMonth = function () {
1917
- const newDate = new Date(this);
1918
- newDate.setDate(1);
1919
- return newDate.startOfDay();
1920
- };
1921
- Date.prototype.endOfMonth = function () {
1922
- const nextMonth = this.increaseMonth().startOfMonth();
1923
- return new Date(nextMonth.getTime() - 1);
1924
- };
1925
- Date.prototype.startOfWeek = function () {
1926
- const newDate = new Date(this);
1927
- while (newDate.getDay()) {
1928
- newDate.setDate(newDate.getDate() - 1);
1929
- }
1930
- return newDate.startOfDay();
1931
- };
1932
- Date.prototype.endOfWeek = function () {
1933
- const newDate = new Date(this);
1934
- while (newDate.getDay() < 6) {
1935
- newDate.setDate(newDate.getDate() - 1);
1936
- }
1937
- return newDate.endOfDay();
1938
- };
1939
- Date.prototype.startOfDay = function () {
1940
- const newDate = new Date(this);
1941
- newDate.setHours(0, 0, 0, 0);
1942
- return newDate;
1943
- };
1944
- Date.prototype.endOfDay = function () {
1945
- const newDate = new Date(this);
1946
- newDate.setHours(23, 59, 59, 999);
1947
- return newDate;
1948
- };
1949
- Date.prototype.startOfHour = function () {
1950
- const newDate = new Date(this);
1951
- newDate.setMinutes(0, 0, 0);
1952
- return newDate;
1953
- };
1954
- Date.prototype.endOfHour = function () {
1955
- const newDate = new Date(this);
1956
- newDate.setMinutes(59, 59, 999);
1957
- return newDate;
1958
- };
1959
- Date.prototype.startOfMinute = function () {
1960
- const newDate = new Date(this);
1961
- newDate.setSeconds(0, 0);
1962
- return newDate;
1842
+ const PROBLEM_VERDICTS = [
1843
+ exports.ProblemVerdict.NONE,
1844
+ exports.ProblemVerdict.PENDING,
1845
+ exports.ProblemVerdict.AC,
1846
+ exports.ProblemVerdict.PE,
1847
+ exports.ProblemVerdict.PA,
1848
+ exports.ProblemVerdict.CE,
1849
+ exports.ProblemVerdict.RE,
1850
+ exports.ProblemVerdict.TLE,
1851
+ exports.ProblemVerdict.MLE,
1852
+ exports.ProblemVerdict.WA,
1853
+ ];
1854
+ const SUBMISSION_RUN_STATUS = {
1855
+ [exports.SubmissionRunStatus.NONE]: { value: exports.SubmissionRunStatus.NONE, label: 'none' }, // status
1856
+ [exports.SubmissionRunStatus.RECEIVED]: { value: exports.SubmissionRunStatus.RECEIVED, label: 'received' }, // state
1857
+ [exports.SubmissionRunStatus.COMPILING]: { value: exports.SubmissionRunStatus.COMPILING, label: 'compiling' }, // state
1858
+ [exports.SubmissionRunStatus.COMPILED]: { value: exports.SubmissionRunStatus.COMPILED, label: 'compiled' }, // status
1859
+ [exports.SubmissionRunStatus.COMPILATION_ERROR]: { value: exports.SubmissionRunStatus.COMPILATION_ERROR, label: 'compilation error' }, // status
1860
+ [exports.SubmissionRunStatus.FETCHING_TEST_CASES]: {
1861
+ value: exports.SubmissionRunStatus.FETCHING_TEST_CASES,
1862
+ label: 'fetching test cases',
1863
+ }, // state
1864
+ [exports.SubmissionRunStatus.RUNNING_TEST_CASE]: { value: exports.SubmissionRunStatus.RUNNING_TEST_CASE, label: 'running test case' }, // state
1865
+ [exports.SubmissionRunStatus.RUNNING_TEST_CASES]: {
1866
+ value: exports.SubmissionRunStatus.RUNNING_TEST_CASES,
1867
+ label: 'running test cases',
1868
+ }, // state
1869
+ [exports.SubmissionRunStatus.RUNNING_SAMPLE_TEST_CASES]: {
1870
+ value: exports.SubmissionRunStatus.RUNNING_SAMPLE_TEST_CASES,
1871
+ label: 'running sample cases',
1872
+ }, // state
1873
+ [exports.SubmissionRunStatus.EXECUTED_TEST_CASE]: {
1874
+ value: exports.SubmissionRunStatus.EXECUTED_TEST_CASE,
1875
+ label: 'executed test case',
1876
+ }, // status
1877
+ [exports.SubmissionRunStatus.FAILED_TEST_CASE]: { value: exports.SubmissionRunStatus.FAILED_TEST_CASE, label: 'failed test case' }, // status
1878
+ [exports.SubmissionRunStatus.JUDGING_TEST_CASE]: { value: exports.SubmissionRunStatus.JUDGING_TEST_CASE, label: 'judging test case' }, // state
1879
+ [exports.SubmissionRunStatus.GRADING]: { value: exports.SubmissionRunStatus.GRADING, label: 'grading' }, // status
1880
+ [exports.SubmissionRunStatus.FAILED]: { value: exports.SubmissionRunStatus.FAILED, label: 'failed' }, // status
1881
+ [exports.SubmissionRunStatus.COMPLETED]: { value: exports.SubmissionRunStatus.COMPLETED, label: 'completed' }, // status
1963
1882
  };
1964
- Date.prototype.endOfMinute = function () {
1965
- const newDate = new Date(this);
1966
- newDate.setSeconds(59, 999);
1967
- return newDate;
1883
+ const RUNNER_TYPE = {
1884
+ [exports.RunnerType.HIGH_PERFORMANCE]: { value: exports.RunnerType.HIGH_PERFORMANCE, label: 'high performance' },
1885
+ [exports.RunnerType.LOW_PERFORMANCE]: { value: exports.RunnerType.LOW_PERFORMANCE, label: 'low performance' },
1968
1886
  };
1969
- Date.prototype.startOfSecond = function () {
1970
- const newDate = new Date(this);
1971
- newDate.setMilliseconds(0);
1972
- return newDate;
1887
+
1888
+ const PROBLEM_INPUT = {
1889
+ [exports.ProblemInput.STANDARD]: { value: exports.ProblemInput.STANDARD, label: 'standard' },
1890
+ [exports.ProblemInput.INTERACTIVE]: { value: exports.ProblemInput.INTERACTIVE, label: 'interactive' },
1973
1891
  };
1974
- Date.prototype.endOfSecond = function () {
1975
- const newDate = new Date(this);
1976
- newDate.setMilliseconds(999);
1977
- return newDate;
1892
+ const PROBLEM_OUTPUT = {
1893
+ [exports.ProblemOutput.STANDARD]: { value: exports.ProblemOutput.STANDARD, label: 'standard' },
1894
+ [exports.ProblemOutput.DYNAMIC]: { value: exports.ProblemOutput.DYNAMIC, label: 'dynamic' },
1895
+ [exports.ProblemOutput.INTERACTIVE]: { value: exports.ProblemOutput.INTERACTIVE, label: 'interactive' },
1978
1896
  };
1979
- Date.prototype.isToday = function () {
1980
- const today = new Date();
1981
- return this.isSameDay(today);
1897
+ const PROBLEM_MODES = [exports.ProblemScoringMode.TOTAL, exports.ProblemScoringMode.SUBTASK, exports.ProblemScoringMode.PARTIAL];
1898
+ const PROBLEM_MODE = {
1899
+ [exports.ProblemScoringMode.TOTAL]: {
1900
+ value: exports.ProblemScoringMode.TOTAL,
1901
+ label: 'total',
1902
+ description: 'if all test cases are Accepted the result is Accepted '
1903
+ + 'otherwise it will be Runtime Error, Time Limited Exceeded, Memory Limited Exceeded, Wrong Answer or Presentation Error in that order.',
1904
+ },
1905
+ [exports.ProblemScoringMode.SUBTASK]: {
1906
+ value: exports.ProblemScoringMode.SUBTASK,
1907
+ label: 'subtask',
1908
+ description: 'the test cases are grouped and each group of test cases is assigned a score, '
1909
+ + 'if all test cases in a group are Accepted then the score assigned to that group of test cases is added to total score, '
1910
+ + 'if total score is equal to the sum of the assigned scores of all groups of test cases then the result is Accepted, '
1911
+ + 'otherwise if the total score is greater than zero the result is Partial Accepted with the total accumulated score, '
1912
+ + 'otherwise it will be Runtime Error, Time Limited Exceeded, Memory Limited Exceeded, Wrong Answer or Presentation Error in that order.',
1913
+ },
1914
+ [exports.ProblemScoringMode.PARTIAL]: {
1915
+ value: exports.ProblemScoringMode.PARTIAL,
1916
+ label: 'partial',
1917
+ description: 'the test cases are grouped and each group is associated with X points, '
1918
+ + 'and each test case in a group scores X points ',
1919
+ },
1982
1920
  };
1983
- Date.prototype.isEqual = function (date) {
1984
- return this.getTime() === date.getTime();
1921
+ const PROBLEM_TYPES = [exports.ProblemType.STANDARD, exports.ProblemType.DYNAMIC, exports.ProblemType.INTERACTIVE];
1922
+ const PROBLEM_TYPE = {
1923
+ [exports.ProblemType.STANDARD]: {
1924
+ value: exports.ProblemType.STANDARD,
1925
+ label: 'standard',
1926
+ description: 'The contestant submit a single source code in one of the allowed programming languages. '
1927
+ + 'The source code is either standalone or to be compiled. '
1928
+ + 'The resulting user\'s executable does I/O standard input and output. '
1929
+ + 'The output produced by the contestant\'s program is then compared to the correct output using a simple diff algorithm.',
1930
+ },
1931
+ [exports.ProblemType.INTERACTIVE]: {
1932
+ value: exports.ProblemType.INTERACTIVE, label: 'interactive', description: 'developing..',
1933
+ },
1934
+ [exports.ProblemType.DYNAMIC]: {
1935
+ value: exports.ProblemType.DYNAMIC,
1936
+ label: 'dynamic',
1937
+ description: 'The contestant submit a single source code in one of the allowed programming languages. '
1938
+ + 'The user\'s source code is either standalone or to be compiled. '
1939
+ + 'The resulting user\'s executable does I/O standard input and output. '
1940
+ + 'The output produced by the contestant\'s program is saved. '
1941
+ + 'The problem editor save a single source code in C++ 17. '
1942
+ + 'The editor\'s source code can read judge input filepath argv[1], judge output filepath argv[2], user\'s output filepath argv[3], user\'s error filepath argv[4], user\'s log filepath argv[5], user\'s source filepath argv[6] and submission information filepath argv[7] (companyId, submitId, runId, userId, contestId, problemId, language, userNickname, timestamp). '
1943
+ + 'The resulting editor\'s executable should be "AC" or a number between 1 and 100 for partial accepted',
1944
+ },
1985
1945
  };
1986
- Date.prototype.isSameYear = function (date) {
1987
- return this.getFullYear() === date.getFullYear();
1988
- };
1989
- Date.prototype.isSameMonth = function (date) {
1990
- return this.isSameYear(date) && this.getMonth() === date.getMonth();
1991
- };
1992
- Date.prototype.isSameDay = function (date) {
1993
- return this.isSameMonth(date) && this.getDate() === date.getDate();
1994
- };
1995
- Date.prototype.isSameHour = function (date) {
1996
- return this.isSameDay(date) && this.getHours() === date.getHours();
1997
- };
1998
- Date.prototype.isSameMinute = function (date) {
1999
- return this.isSameHour(date) && this.getMinutes() === date.getMinutes();
2000
- };
2001
- Date.prototype.isSameSecond = function (date) {
2002
- return this.isSameMinute(date) && this.getSeconds() === date.getSeconds();
2003
- };
2004
- Date.prototype.isSameMillisecond = function (date) {
2005
- return this.isEqual(date);
2006
- };
2007
- Date.prototype.isValidDate = function () {
2008
- return this instanceof Date && !isNaN(this.getTime());
2009
- };
2010
- Date.prototype.isYearAfter = function (date) {
2011
- return this.getFullYear() > date.getFullYear();
2012
- };
2013
- Date.prototype.isMonthAfter = function (date) {
2014
- return this.isYearAfter(date) || (this.isSameYear(date) && this.getMonth() > date.getMonth());
2015
- };
2016
- Date.prototype.isDayAfter = function (date) {
2017
- return this.isMonthAfter(date) || (this.isSameMonth(date) && this.getDate() > date.getDate());
2018
- };
2019
- Date.prototype.isHoursAfter = function (date) {
2020
- return this.isDayAfter(date) || (this.isSameDay(date) && this.getHours() > date.getHours());
2021
- };
2022
- Date.prototype.isMinutesAfter = function (date) {
2023
- return this.isHoursAfter(date) || (this.isSameHour(date) && this.getMinutes() > date.getMinutes());
2024
- };
2025
- Date.prototype.isSecondsAfter = function (date) {
2026
- return this.isMinutesAfter(date) || (this.isSameMinute(date) && this.getSeconds() > date.getSeconds());
2027
- };
2028
- Date.prototype.isMillisecondsAfter = function (date) {
2029
- return this.isSecondsAfter(date) || (this.isSameSecond(date) && this.getMilliseconds() > date.getMilliseconds());
2030
- };
2031
- Date.prototype.isAfter = function (date) {
2032
- return this.getTime() > date.getTime();
2033
- };
2034
- Date.prototype.isYearBefore = function (date) {
2035
- return this.getFullYear() < date.getFullYear();
2036
- };
2037
- Date.prototype.isMonthBefore = function (date) {
2038
- return this.isYearBefore(date) || (this.isSameYear(date) && this.getMonth() < date.getMonth());
2039
- };
2040
- Date.prototype.isDayBefore = function (date) {
2041
- return this.isMonthBefore(date) || (this.isSameMonth(date) && this.getDate() < date.getDate());
2042
- };
2043
- Date.prototype.isHoursBefore = function (date) {
2044
- return this.isDayBefore(date) || (this.isSameDay(date) && this.getHours() < date.getHours());
2045
- };
2046
- Date.prototype.isMinutesBefore = function (date) {
2047
- return this.isHoursBefore(date) || (this.isSameHour(date) && this.getMinutes() < date.getMinutes());
2048
- };
2049
- Date.prototype.isSecondsBefore = function (date) {
2050
- return this.isMinutesBefore(date) || (this.isSameMinute(date) && this.getSeconds() < date.getSeconds());
2051
- };
2052
- Date.prototype.isMillisecondsBefore = function (date) {
2053
- return this.isSecondsBefore(date) || (this.isSameSecond(date) && this.getMilliseconds() < date.getMilliseconds());
2054
- };
2055
- Date.prototype.isBefore = function (date) {
2056
- return this.getTime() < date.getTime();
2057
- };
2058
- Date.prototype.isWithinInterval = function ({ start, end }, cmp = '[]') {
2059
- return (cmp.charAt(0) === '[' ? this.isEqual(start) || this.isAfter(start) : this.isAfter(start)) &&
2060
- (cmp.charAt(1) === '[' ? this.isEqual(end) || this.isBefore(end) : this.isBefore(end));
1946
+ const PROBLEM_ROLE = {
1947
+ [exports.Role.RESTRICTED]: { value: exports.Role.RESTRICTED, label: 'restricted', level: 7 },
1948
+ [exports.Role.GUEST]: { value: exports.Role.GUEST, label: 'guest', level: 6 },
1949
+ [exports.Role.REGULAR]: { value: exports.Role.REGULAR, label: 'regular', level: 5 },
1950
+ [exports.Role.CREATOR]: { value: exports.Role.CREATOR, label: 'creator', level: 4 },
1951
+ [exports.Role.MANAGER]: { value: exports.Role.MANAGER, label: 'manager', level: 3 },
1952
+ [exports.Role.MASTER]: { value: exports.Role.MASTER, label: 'master', level: 2 },
1953
+ [exports.Role.ADMIN]: { value: exports.Role.ADMIN, label: 'admin', level: 1 },
1954
+ [exports.Role.SUPER_ADMIN]: { value: exports.Role.SUPER_ADMIN, label: 'super admin', level: 0 },
2061
1955
  };
2062
1956
 
1957
+ const _TYPE = ':type';
1958
+ const _KEY = ':key';
1959
+ const _TAB = ':tab';
1960
+ const _SUB_TAB = ':subTab?';
1961
+ const _SUB_SUB_TAB = ':subSubTab?';
1962
+ const PAGE = 'page';
1963
+ const PAGE_SIZE = 'size';
1964
+
2063
1965
  const ERROR = {
2064
1966
  // Http Errors
2065
1967
  [exports.ErrorCode.ERR500]: { value: exports.ErrorCode.ERR500, message: 'internal server error', status: 500 },
@@ -2217,1144 +2119,1377 @@ const ERROR = {
2217
2119
  [exports.ErrorCode.ERR0820]: { value: exports.ErrorCode.ERR0820, message: 'file is archived', status: 400 },
2218
2120
  };
2219
2121
 
2220
- class JkError extends Error {
2221
- constructor(code, custom) {
2222
- const message = custom?.message || ERROR[code].message;
2223
- super(message);
2224
- this.message = message;
2225
- this.code = code;
2226
- if (custom?.stack) {
2227
- this.stack = custom.stack;
2228
- }
2229
- if (custom?.data) {
2230
- this.data = custom.data;
2231
- }
2232
- }
2233
- }
2234
-
2235
- /* eslint-disable no-extend-native */
2236
- Number.prototype.padStart = function (maxLength, fillString = '0') {
2237
- return (this + '').padStart(maxLength, fillString);
2122
+ const FILE_TYPE = {
2123
+ [exports.FileType.FILE]: { value: exports.FileType.FILE, label: 'file' },
2124
+ [exports.FileType.FOLDER]: { value: exports.FileType.FOLDER, label: 'folder' },
2238
2125
  };
2239
- Number.prototype.padEnd = function (maxLength, fillString = '0') {
2240
- return (this + '').padEnd(maxLength, fillString);
2126
+ const FILE_ROLE = {
2127
+ [exports.Role.RESTRICTED]: { value: exports.Role.RESTRICTED, label: 'restricted', level: 5 },
2128
+ [exports.Role.GUEST]: { value: exports.Role.GUEST, label: 'guest', level: 4 },
2129
+ [exports.Role.REGULAR]: { value: exports.Role.REGULAR, label: 'regular', level: 3 },
2130
+ [exports.Role.MASTER]: { value: exports.Role.MASTER, label: 'master', level: 2 },
2131
+ [exports.Role.ADMIN]: { value: exports.Role.ADMIN, label: 'admin', level: 1 },
2132
+ [exports.Role.SUPER_ADMIN]: { value: exports.Role.SUPER_ADMIN, label: 'super admin', level: 0 },
2241
2133
  };
2242
-
2243
- function toJkError(err) {
2244
- const error = new Error();
2245
- let code = err?.code;
2246
- if (!(code in exports.ErrorCode)) {
2247
- code = exports.ErrorCode.ERR500;
2248
- }
2249
- return new JkError(code, {
2250
- message: err?.message || error.message,
2251
- stack: err?.stack || error.stack,
2252
- data: err?.data || null,
2253
- });
2254
- }
2255
- function errorsResponse(message, ...errors) {
2256
- return {
2257
- success: false,
2258
- message: message,
2259
- errors: errors.map(error => ({
2260
- code: error.code,
2261
- message: error.message,
2262
- detail: error.stack || new Error().stack || '',
2263
- data: error.data,
2264
- })),
2265
- };
2266
- }
2267
- function contentResponse(message, content) {
2268
- return {
2269
- success: true,
2270
- message,
2271
- content,
2272
- };
2273
- }
2274
- function contentsResponse(message, contents, meta) {
2275
- return {
2276
- success: true,
2277
- message,
2278
- contents,
2279
- meta,
2280
- };
2281
- }
2282
- const cleanRequest = (responseText) => {
2283
- if (!isStringJson(responseText)) {
2284
- // this occurs when the endpoint don't exits or server is down
2285
- const response = {
2286
- success: false,
2287
- message: ERROR[exports.ErrorCode.ERR9999].message,
2288
- errors: [{ code: exports.ErrorCode.ERR9999, detail: '', message: ERROR[exports.ErrorCode.ERR9999].message }],
2289
- };
2290
- consoleError({ message: 'response is not string json, success false on cleaning request', responseText, response });
2291
- // jukiApiManager.reportError({ message: 'success false on cleaning request', responseText, response });
2292
- return response;
2293
- }
2294
- const responseJson = JSON.parse(responseText);
2295
- if (typeof responseJson.success === 'boolean') {
2296
- if (responseJson.success === true && typeof responseJson.message === 'string' && responseJson.content) { // V1
2297
- return {
2298
- success: true,
2299
- message: responseJson.message,
2300
- content: responseJson.content,
2301
- };
2302
- }
2303
- else if (responseJson.success === true && typeof responseJson.message === 'string' && Array.isArray(responseJson.contents) && responseJson.meta) { // V1
2304
- return {
2305
- success: true,
2306
- message: responseJson.message,
2307
- contents: responseJson.contents,
2308
- meta: responseJson.meta,
2309
- };
2310
- }
2311
- else if (responseJson.success === false && typeof responseJson.message === 'string' && Array.isArray(responseJson.errors)) { // V1
2312
- const response = {
2313
- success: false,
2314
- message: responseJson.message,
2315
- errors: responseJson.errors,
2316
- };
2317
- consoleError({ message: 'success false on cleaning request', responseText, response });
2318
- // jukiApiManager.reportError({ message: 'success false on cleaning request', responseText, response });
2319
- return response;
2320
- }
2321
- }
2322
- const response = {
2323
- success: false,
2324
- message: ERROR[exports.ErrorCode.ERR9998].message,
2325
- errors: [{ code: exports.ErrorCode.ERR9998, detail: '', message: ERROR[exports.ErrorCode.ERR9998].message }],
2326
- };
2327
- consoleError({ message: 'success false on cleaning request', responseText, response });
2328
- // jukiApiManager.reportError({ message: 'success false on cleaning request', responseText, response });
2329
- return response;
2134
+ const ENTITY_STATE = {
2135
+ [exports.EntityState.RELEASED]: {
2136
+ value: exports.EntityState.RELEASED,
2137
+ label: 'released',
2138
+ },
2139
+ [exports.EntityState.ARCHIVED]: {
2140
+ value: exports.EntityState.ARCHIVED,
2141
+ label: 'archived',
2142
+ },
2330
2143
  };
2331
- const getDefaultMeta = (contents, sort) => {
2332
- return { sort: sort ?? [], page: 1, size: contents.length, totalElements: contents.length, filter: {} };
2144
+ const ENTITY_ACCESS = {
2145
+ [exports.EntityAccess.PRIVATE]: {
2146
+ value: exports.EntityAccess.PRIVATE,
2147
+ label: 'private',
2148
+ description: 'the record will be visible and editable only to the owner',
2149
+ },
2150
+ [exports.EntityAccess.RESTRICTED]: {
2151
+ value: exports.EntityAccess.RESTRICTED,
2152
+ label: 'restricted',
2153
+ description: 'the record will be visible to viewers and the owner and editable to editors and the owner',
2154
+ },
2155
+ [exports.EntityAccess.PUBLIC]: {
2156
+ value: exports.EntityAccess.PUBLIC,
2157
+ label: 'public',
2158
+ description: 'the record will be visible to anyone and editable to editors and the owner',
2159
+ },
2160
+ [exports.EntityAccess.EXPOSED]: {
2161
+ value: exports.EntityAccess.EXPOSED,
2162
+ label: 'exposed',
2163
+ description: 'the record will be visible and editable to anyone',
2164
+ },
2333
2165
  };
2334
2166
 
2335
- const isWebsocketSubscription = (event) => {
2336
- return (Object.values(exports.WebSocketSubscriptionEvent).includes(event?.event) || Object.values(exports.WebSocketMessageEvent).includes(event?.event))
2337
- && typeof event?.clientId === 'string' && !!event.clientId;
2338
- };
2339
- // Custom CHANNEL_PUBLISH_MESSAGES
2340
- const isPingWebSocketEventDTO = (event) => {
2341
- return isWebsocketSubscription(event)
2342
- && event?.event === exports.WebSocketMessageEvent.PING;
2167
+ const SYSTEM_ROLE = {
2168
+ [SystemRole.GUEST]: { value: SystemRole.GUEST, label: 'guest', level: 5 },
2169
+ [SystemRole.REGULAR]: { value: SystemRole.REGULAR, label: 'regular', level: 4 },
2170
+ [SystemRole.MANAGER]: { value: SystemRole.MANAGER, label: 'manager', level: 3 },
2171
+ [SystemRole.MASTER]: { value: SystemRole.MASTER, label: 'master', level: 2 },
2172
+ [SystemRole.ADMIN]: { value: SystemRole.ADMIN, label: 'admin', level: 1 },
2173
+ [SystemRole.SUPER_ADMIN]: { value: SystemRole.SUPER_ADMIN, label: 'super admin', level: 0 },
2343
2174
  };
2344
- const isClientTrackLocationWebSocketEventDTO = (event) => {
2345
- return isWebsocketSubscription(event)
2346
- && event?.event === exports.WebSocketMessageEvent.CLIENT_TRACK_LOCATION;
2175
+
2176
+ const MEMBER_ROLE = {
2177
+ [MemberRole.COACH]: { value: MemberRole.COACH, label: 'coach' },
2178
+ [MemberRole.CO_COACH]: { value: MemberRole.CO_COACH, label: 'co-coach' },
2179
+ [MemberRole.STAFF]: { value: MemberRole.STAFF, label: 'staff' },
2180
+ [MemberRole.ATTENDEE]: { value: MemberRole.ATTENDEE, label: 'attendee' },
2181
+ [MemberRole.RESERVE]: { value: MemberRole.RESERVE, label: 'reserve' },
2182
+ [MemberRole.CONTESTANT]: { value: MemberRole.CONTESTANT, label: 'contestant' },
2347
2183
  };
2348
- const isClientTrackScreenshotWebSocketEventDTO = (event) => {
2349
- return isWebsocketSubscription(event)
2350
- && event?.event === exports.WebSocketMessageEvent.CLIENT_TRACK_SCREENSHOT;
2351
- };
2352
- const isClientTrackDeviceWebSocketEventDTO = (event) => {
2353
- return isWebsocketSubscription(event)
2354
- && event?.event === exports.WebSocketMessageEvent.CLIENT_TRACK_DEVICE;
2184
+ const TEAM_ROLE = {
2185
+ [TeamRole.RESTRICTED]: { value: TeamRole.RESTRICTED, label: 'restricted', level: 5 },
2186
+ [TeamRole.GUEST]: { value: TeamRole.GUEST, label: 'guest', level: 4 },
2187
+ [TeamRole.REGULAR]: { value: TeamRole.REGULAR, label: 'regular', level: 3 },
2188
+ [TeamRole.MANAGER]: { value: TeamRole.MANAGER, label: 'manager', level: 2 },
2189
+ [TeamRole.ADMIN]: { value: TeamRole.ADMIN, label: 'admin', level: 1 },
2190
+ [TeamRole.SUPER_ADMIN]: { value: TeamRole.SUPER_ADMIN, label: 'super admin', level: 0 },
2355
2191
  };
2356
- const isChatCompletionsWebSocketEventDTO = (event) => {
2357
- return isWebsocketSubscription(event)
2358
- && event?.event === exports.WebSocketMessageEvent.CHAT_COMPLETIONS;
2192
+
2193
+ const ONE_SECOND = 1000;
2194
+ const SEC_30 = ONE_SECOND * 30;
2195
+ const SEC_60 = ONE_SECOND * 60;
2196
+ const SEC_90 = ONE_SECOND * 90;
2197
+ const SEC_120 = ONE_SECOND * 120;
2198
+ const ONE_MINUTE = ONE_SECOND * 60;
2199
+ const ONE_HOUR = ONE_MINUTE * 60;
2200
+ const ONE_DAY = ONE_HOUR * 24;
2201
+ const ONE_WEEK = ONE_DAY * 7;
2202
+
2203
+ const USER_STATUS = {
2204
+ [UserStatus.ACTIVE]: { value: UserStatus.ACTIVE, label: 'active' },
2205
+ [UserStatus.REPORTED]: { value: UserStatus.REPORTED, label: 'reported' },
2206
+ [UserStatus.ARCHIVED]: { value: UserStatus.ARCHIVED, label: 'archived' },
2359
2207
  };
2360
- // CHANNEL_PUBLISH_SUBSCRIPTIONS
2361
- const isSubscribeCodeRunStatusWebSocketEventDTO = (event) => {
2362
- return isWebsocketSubscription(event)
2363
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CODE_RUN_STATUS
2364
- && typeof event?.runId === 'string' && !!event.runId;
2208
+ const USER_ROLE = {
2209
+ [UserRole.RESTRICTED]: { value: UserRole.RESTRICTED, label: 'restricted', level: 6 },
2210
+ [UserRole.GUEST]: { value: UserRole.GUEST, label: 'guest', level: 5 },
2211
+ [UserRole.LIMITED]: { value: UserRole.LIMITED, label: 'limited', level: 4 },
2212
+ [UserRole.REGULAR]: { value: UserRole.REGULAR, label: 'regular', level: 3 },
2213
+ [UserRole.MANAGER]: { value: UserRole.MANAGER, label: 'manager', level: 2 },
2214
+ [UserRole.ADMIN]: { value: UserRole.ADMIN, label: 'admin', level: 1 },
2215
+ [UserRole.SUPER_ADMIN]: { value: UserRole.SUPER_ADMIN, label: 'super admin', level: 0 },
2365
2216
  };
2366
- const isUnsubscribeCodeRunStatusWebSocketEventDTO = (event) => {
2367
- return isWebsocketSubscription(event)
2368
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CODE_RUN_STATUS
2369
- && typeof event?.runId === 'string' && !!event.runId;
2217
+ const EMPTY_USER_PERMISSIONS = {
2218
+ users: {
2219
+ create: false,
2220
+ manage: false,
2221
+ administrate: false,
2222
+ },
2223
+ problems: {
2224
+ create: false,
2225
+ manage: false,
2226
+ },
2227
+ submissions: {
2228
+ manage: false,
2229
+ },
2230
+ contests: {
2231
+ create: false,
2232
+ manage: false,
2233
+ },
2234
+ company: {
2235
+ manage: false,
2236
+ administrate: false,
2237
+ },
2238
+ services: {
2239
+ administrate: false,
2240
+ },
2370
2241
  };
2371
- const isSubscribeSubmissionRunStatusWebSocketEventDTO = (event) => {
2372
- return isWebsocketSubscription(event)
2373
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSION_RUN_STATUS
2374
- && typeof event?.submitId === 'string' && !!event.submitId;
2242
+
2243
+ // LEGACY channels (fan-out per client through the subscriptions registry in Redis)
2244
+ const CHANNEL_PUBLISH_SUBSCRIPTIONS = 'pub:subscriptions';
2245
+ const CHANNEL_SUBSCRIBE_NOTIFICATIONS = 'sub:notifications';
2246
+ const CHANNEL_SUBSCRIBE_CLIENT = (clientId) => `sub:client:${clientId}`;
2247
+ const CHANNEL_PUBLISH_MESSAGES = 'pub:messages';
2248
+ const CHANNEL_PRESENCE_CLIENT = 'pre:client';
2249
+ // TOPIC channels
2250
+ // The backend publishes each event once on the channel of its topic and Ably does the fan-out.
2251
+ // Who can subscribe to each channel is decided by the API in the Ably token (capability), never by the client.
2252
+ // Dynamic segments are encoded so a key can never inject a `:` (the Ably segment separator used by the wildcards).
2253
+ const segment = (value) => encodeURIComponent(value);
2254
+ /** private: events of one session (code runs, requested data, client track commands) */
2255
+ const CHANNEL_SESSION = (sessionId) => `session:${segment(sessionId)}`;
2256
+ /** private: events of one user (own submissions while the contest is frozen, notifications) */
2257
+ const CHANNEL_USER = (userId) => `user:${segment(userId)}`;
2258
+ /** public: status of a submission when it is visible to everyone */
2259
+ const CHANNEL_SUBMISSION = (submitId) => `submission:${segment(submitId)}`;
2260
+ /** public: changes of a problem */
2261
+ const CHANNEL_PROBLEM = (problemKey) => `problem:${segment(problemKey)}`;
2262
+ /** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
2263
+ const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${role}`;
2264
+ /** system administrators only: data sent by a tracked client (screenshots, location, device) */
2265
+ const CHANNEL_CLIENT_TRACK = (trackedClientId) => `client-track:${segment(trackedClientId)}`;
2266
+ // capability resources (wildcards) of the public channels
2267
+ const CHANNEL_SUBMISSION_ALL = 'submission:*';
2268
+ const CHANNEL_PROBLEM_ALL = 'problem:*';
2269
+ const CHANNEL_CLIENT_TRACK_ALL = 'client-track:*';
2270
+ /**
2271
+ * Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
2272
+ */
2273
+ const getContestChannelParams = (channel) => {
2274
+ const [namespace, contestKey, role, ...rest] = channel.split(':');
2275
+ if (namespace !== 'contest' || !contestKey || rest.length || !Object.values(exports.ContestChannelRole).includes(role)) {
2276
+ return null;
2277
+ }
2278
+ return { contestKey: decodeURIComponent(contestKey), role: role };
2375
2279
  };
2376
- const isUnsubscribeSubmissionRunStatusWebSocketEventDTO = (event) => {
2377
- return isWebsocketSubscription(event)
2378
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSION_RUN_STATUS
2379
- && typeof event?.submitId === 'string' && !!event.submitId;
2280
+
2281
+ const NEW_PAGE_SHEET = () => ({
2282
+ id: uuid.v4(),
2283
+ type: exports.WorksheetType.NEW_PAGE,
2284
+ title: '',
2285
+ points: 0,
2286
+ });
2287
+ const ASPECT_RATIO = {
2288
+ [exports.AspectRatio.RATIO_21_9]: {
2289
+ aspectRatio: exports.AspectRatio.RATIO_21_9,
2290
+ width: 2520,
2291
+ height: 1080,
2292
+ decimal: 21 / 9,
2293
+ label: 'ultrawide',
2294
+ },
2295
+ [exports.AspectRatio.RATIO_20_9]: {
2296
+ aspectRatio: exports.AspectRatio.RATIO_20_9,
2297
+ width: 2400,
2298
+ height: 1080,
2299
+ decimal: 20 / 9,
2300
+ label: 'mobile wide',
2301
+ },
2302
+ [exports.AspectRatio.RATIO_16_9]: {
2303
+ aspectRatio: exports.AspectRatio.RATIO_16_9,
2304
+ width: 1920,
2305
+ height: 1080,
2306
+ decimal: 16 / 9,
2307
+ label: 'widescreen',
2308
+ },
2309
+ [exports.AspectRatio.RATIO_16_10]: {
2310
+ aspectRatio: exports.AspectRatio.RATIO_16_10,
2311
+ width: 1920,
2312
+ height: 1200,
2313
+ decimal: 16 / 10,
2314
+ label: 'widescreen tall',
2315
+ },
2316
+ [exports.AspectRatio.RATIO_3_2]: {
2317
+ aspectRatio: exports.AspectRatio.RATIO_3_2,
2318
+ width: 1440,
2319
+ height: 960,
2320
+ decimal: 3 / 2,
2321
+ label: 'balanced',
2322
+ },
2323
+ [exports.AspectRatio.RATIO_4_3]: {
2324
+ aspectRatio: exports.AspectRatio.RATIO_4_3,
2325
+ width: 1024,
2326
+ height: 768,
2327
+ decimal: 4 / 3,
2328
+ label: 'standard',
2329
+ },
2330
+ [exports.AspectRatio.RATIO_5_4]: {
2331
+ aspectRatio: exports.AspectRatio.RATIO_5_4,
2332
+ width: 1280,
2333
+ height: 1024,
2334
+ decimal: 5 / 4,
2335
+ label: 'square old',
2336
+ },
2337
+ [exports.AspectRatio.RATIO_1_1]: {
2338
+ aspectRatio: exports.AspectRatio.RATIO_1_1,
2339
+ width: 1000,
2340
+ height: 1000,
2341
+ decimal: 1,
2342
+ label: 'square',
2343
+ },
2380
2344
  };
2381
- const isSubscribeGetDataWebSocketEventDTO = (event) => {
2382
- return isWebsocketSubscription(event)
2383
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_GET_DATA;
2345
+
2346
+ exports.ContestProblemBlockedByType = void 0;
2347
+ (function (ContestProblemBlockedByType) {
2348
+ ContestProblemBlockedByType["UNMET_PREREQUISITES"] = "UNMET_PREREQUISITES";
2349
+ ContestProblemBlockedByType["MAX_ACCEPTED_SUBMISSIONS_ACHIEVED"] = "MAX_ACCEPTED_SUBMISSIONS_ACHIEVED";
2350
+ ContestProblemBlockedByType["START_TIME_IN_THE_FUTURE"] = "START_TIME_IN_THE_FUTURE";
2351
+ ContestProblemBlockedByType["END_TIME_IN_THE_PAST"] = "END_TIME_IN_THE_PAST";
2352
+ })(exports.ContestProblemBlockedByType || (exports.ContestProblemBlockedByType = {}));
2353
+
2354
+ exports.MemberType = void 0;
2355
+ (function (MemberType) {
2356
+ MemberType["USER"] = "USER";
2357
+ MemberType["TEAM"] = "TEAM";
2358
+ })(exports.MemberType || (exports.MemberType = {}));
2359
+
2360
+ const isWorksheetAssignment = (assignment) => {
2361
+ return assignment.type === exports.AssignmentClass.WORKSHEET;
2384
2362
  };
2385
- const isUnsubscribeGetDataWebSocketEventDTO = (event) => {
2386
- return isWebsocketSubscription(event)
2387
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_GET_DATA;
2363
+ const isCourseAssignment = (assignment) => {
2364
+ return assignment.type === exports.AssignmentClass.COURSE;
2388
2365
  };
2389
- const isSubscribeProblemCrawledWebSocketEventDTO = (event) => {
2390
- return isWebsocketSubscription(event)
2391
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_PROBLEM_CRAWLED;
2366
+ const isContestAssignment = (assignment) => {
2367
+ return assignment.type === exports.AssignmentClass.CONTEST;
2392
2368
  };
2393
- const isUnsubscribeProblemCrawledWebSocketEventDTO = (event) => {
2394
- return isWebsocketSubscription(event)
2395
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_PROBLEM_CRAWLED;
2369
+
2370
+ const getAssignmentCommentKey = (classKey, cycleKey, sessionKey, assignmentKey) => `class:${classKey}|cycle:${cycleKey}|session:${sessionKey}|assignment:${assignmentKey}`;
2371
+ const getAssignmentUserCommentKey = (classKey, cycleKey, sessionKey, assignmentKey, userNickname, userCompany) => `class:${classKey}|cycle:${cycleKey}|session:${sessionKey}|assignment:${assignmentKey}|user_nickname:${userNickname}|user_company:${userCompany}`;
2372
+ const getProblemCommentKey = (problemKey) => `problem:${problemKey}`;
2373
+ const getContestCommentKey = (contestKey) => `contest:${contestKey}`;
2374
+
2375
+ const isEndlessContest = (settings) => {
2376
+ return settings?.startTimestamp === MIN_DATE.getTime()
2377
+ && settings?.frozenTimestamp === MAX_DATE.getTime()
2378
+ && settings?.quietTimestamp === MAX_DATE.getTime()
2379
+ && settings?.endTimestamp === MAX_DATE.getTime()
2380
+ && settings?.penalty === 0;
2396
2381
  };
2397
- const isSubscribeSubmissionsCrawlWebSocketEventDTO = (event) => {
2398
- return isWebsocketSubscription(event)
2399
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSIONS_CRAWL;
2382
+ const isGlobalContest = (settings) => {
2383
+ return settings?.startTimestamp === 0
2384
+ && settings?.frozenTimestamp === 0
2385
+ && settings?.quietTimestamp === 0
2386
+ && settings?.endTimestamp === 0
2387
+ && settings?.penalty === 0;
2400
2388
  };
2401
- const isUnsubscribeSubmissionsCrawlWebSocketEventDTO = (event) => {
2402
- return isWebsocketSubscription(event)
2403
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSIONS_CRAWL;
2389
+ const isPastContest = (settings) => {
2390
+ return Date.now() > (settings?.endTimestamp ?? 0);
2404
2391
  };
2405
- const isSubscribeContestChangesWebSocketEventDTO = (event) => {
2406
- return isWebsocketSubscription(event)
2407
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CONTEST_CHANGES;
2392
+ const isFutureContest = (settings) => {
2393
+ return (settings?.startTimestamp ?? 0) > Date.now();
2408
2394
  };
2409
- const isUnsubscribeContestChangesWebSocketEventDTO = (event) => {
2410
- return isWebsocketSubscription(event)
2411
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CONTEST_CHANGES;
2395
+
2396
+ const getDocumentAccess = (document) => {
2397
+ switch (true) {
2398
+ case (document?.members?.rankAdministrators === exports.EntityMembersRank.NONE || document?.members?.rankAdministrators === exports.EntityMembersRank.CLOSE)
2399
+ && document?.members?.rankManagers === exports.EntityMembersRank.OPEN
2400
+ && (document?.members?.rankGuests === exports.EntityMembersRank.NONE || document?.members?.rankGuests === exports.EntityMembersRank.CLOSE || document?.members?.rankGuests === exports.EntityMembersRank.OPEN)
2401
+ && document?.members?.rankSpectators === exports.EntityMembersRank.OPEN
2402
+ && (document?.members?.rankParticipants === exports.EntityMembersRank.NONE || document?.members?.rankParticipants === exports.EntityMembersRank.CLOSE || document?.members?.rankParticipants === exports.EntityMembersRank.OPEN):
2403
+ return exports.EntityAccess.EXPOSED;
2404
+ case (document?.members?.rankAdministrators === exports.EntityMembersRank.NONE || document?.members?.rankAdministrators === exports.EntityMembersRank.CLOSE)
2405
+ && document?.members?.rankManagers === exports.EntityMembersRank.CLOSE
2406
+ && (document?.members?.rankGuests === exports.EntityMembersRank.NONE || document?.members?.rankGuests === exports.EntityMembersRank.CLOSE || document?.members?.rankGuests === exports.EntityMembersRank.OPEN)
2407
+ && document?.members?.rankSpectators === exports.EntityMembersRank.OPEN
2408
+ && (document?.members?.rankParticipants === exports.EntityMembersRank.NONE || document?.members?.rankParticipants === exports.EntityMembersRank.CLOSE || document?.members?.rankParticipants === exports.EntityMembersRank.OPEN):
2409
+ return exports.EntityAccess.PUBLIC;
2410
+ case (document?.members?.rankAdministrators === exports.EntityMembersRank.NONE || document?.members?.rankAdministrators === exports.EntityMembersRank.CLOSE)
2411
+ && document?.members?.rankManagers === exports.EntityMembersRank.CLOSE
2412
+ && (document?.members?.rankGuests === exports.EntityMembersRank.NONE || document?.members?.rankGuests === exports.EntityMembersRank.CLOSE || document?.members?.rankGuests === exports.EntityMembersRank.OPEN)
2413
+ && document?.members?.rankSpectators === exports.EntityMembersRank.CLOSE
2414
+ && (document?.members?.rankParticipants === exports.EntityMembersRank.NONE || document?.members?.rankParticipants === exports.EntityMembersRank.CLOSE || document?.members?.rankParticipants === exports.EntityMembersRank.OPEN):
2415
+ return exports.EntityAccess.RESTRICTED;
2416
+ case document?.members?.rankAdministrators === exports.EntityMembersRank.NONE
2417
+ && document?.members?.rankManagers === exports.EntityMembersRank.NONE
2418
+ && document?.members?.rankGuests === exports.EntityMembersRank.NONE
2419
+ && document?.members?.rankSpectators === exports.EntityMembersRank.NONE
2420
+ && document?.members?.rankParticipants === exports.EntityMembersRank.NONE:
2421
+ return exports.EntityAccess.PRIVATE;
2422
+ default:
2423
+ return exports.EntityAccess.PRIVATE;
2424
+ }
2412
2425
  };
2413
- const isSubscribeClientTrackWebSocketEventDTO = (event) => {
2414
- return isWebsocketSubscription(event)
2415
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK;
2426
+ const isUserMember = (member) => {
2427
+ return typeof member.userId === 'string';
2416
2428
  };
2417
- const isUnsubscribeClientTrackWebSocketEventDTO = (event) => {
2418
- return isWebsocketSubscription(event)
2419
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK;
2429
+ const isTeamMember = (member) => {
2430
+ return typeof member.teamId === 'string';
2420
2431
  };
2421
- const isSubscribeUserNotificationWebSocketEventDTO = (event) => {
2422
- return isWebsocketSubscription(event)
2423
- && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_USER_NOTIFICATION;
2432
+ const toEntityMembersDTO = (members) => {
2433
+ return {
2434
+ rankAdministrators: members.rankAdministrators,
2435
+ administrators: Object.keys(members.administrators),
2436
+ rankManagers: members.rankManagers,
2437
+ managers: Object.keys(members.managers),
2438
+ rankParticipants: members.rankParticipants,
2439
+ participants: Object.keys(members.participants),
2440
+ rankGuests: members.rankGuests,
2441
+ guests: Object.keys(members.guests),
2442
+ rankSpectators: members.rankSpectators,
2443
+ spectators: Object.keys(members.spectators),
2444
+ };
2424
2445
  };
2425
- const isUnsubscribeUserNotificationWebSocketEventDTO = (event) => {
2426
- return isWebsocketSubscription(event)
2427
- && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
2446
+
2447
+ function removeExtension(fileName) {
2448
+ const i = fileName.lastIndexOf('.');
2449
+ return i !== -1 ? fileName.substring(0, i) : fileName;
2450
+ }
2451
+
2452
+ // https://dev.to/jsmccrumb/asynchronous-setinterval-4j69
2453
+ const asyncIntervals = [];
2454
+ const runAsyncInterval = async (cb, interval, intervalIndex) => {
2455
+ await cb();
2456
+ if (asyncIntervals[intervalIndex]) {
2457
+ setTimeout(() => runAsyncInterval(cb, interval, intervalIndex), interval);
2458
+ }
2428
2459
  };
2429
- // is WebSocketResponseEventDTO, CHANNEL_SUBSCRIBE_CLIENT
2430
- const isWebSocketResponseEventDTO = (event) => {
2431
- return Object.values(exports.WebSocketResponseEvent).includes(event?.event)
2432
- && typeof event?.key === 'string'
2433
- && typeof event?.connectionId === 'string'
2434
- && typeof event?.messageTimestamp === 'number' && !!event.messageTimestamp;
2460
+ const setAsyncInterval = (cb, interval) => {
2461
+ if (cb && typeof cb === 'function') {
2462
+ const intervalIndex = asyncIntervals.length;
2463
+ asyncIntervals.push(true);
2464
+ void runAsyncInterval(cb, interval, intervalIndex);
2465
+ return intervalIndex;
2466
+ }
2467
+ else {
2468
+ throw new Error('Callback must be a function');
2469
+ }
2435
2470
  };
2436
- const isPongWebSocketResponseEventDTO = (event) => {
2437
- return isWebSocketResponseEventDTO(event)
2438
- && event?.event === exports.WebSocketResponseEvent.PONG
2439
- && !!event?.data;
2471
+ const clearAsyncInterval = (intervalIndex) => {
2472
+ if (asyncIntervals[intervalIndex]) {
2473
+ asyncIntervals[intervalIndex] = false;
2474
+ }
2440
2475
  };
2441
- const isCodeRunStatusMessageWebSocketResponseEventDTO = (event) => {
2442
- return isWebSocketResponseEventDTO(event)
2443
- && event?.event === exports.WebSocketResponseEvent.CODE_RUN_STATUS
2444
- && typeof event?.runId === 'string' && !!event.runId
2445
- && event?.status in exports.SubmissionRunStatus;
2476
+
2477
+ const getDataOfTestCase = (testCase, timeLimit, memoryLimit) => {
2478
+ const { timeUsed, memoryUsed, exitCode } = getDataLog(testCase?.log);
2479
+ const timeLimitExceeded = timeUsed > timeLimit;
2480
+ const memoryLimitExceeded = memoryUsed > memoryLimit;
2481
+ const runtimeError = exitCode !== 0;
2482
+ const compilationError = testCase?.status === exports.SubmissionRunStatus.COMPILATION_ERROR;
2483
+ return {
2484
+ compilationError,
2485
+ timeUsed,
2486
+ timeLimitExceeded: timeLimitExceeded,
2487
+ memoryUsed,
2488
+ memoryLimitExceeded: memoryLimitExceeded,
2489
+ exitCode,
2490
+ runtimeError,
2491
+ failed: !!testCase?.log && (timeLimitExceeded || memoryLimitExceeded || runtimeError),
2492
+ };
2446
2493
  };
2447
- const isSubmissionRunStatusMessageWebSocketResponseEventDTO = (event) => {
2448
- return isWebSocketResponseEventDTO(event)
2449
- && event?.event === exports.WebSocketResponseEvent.SUBMISSION_RUN_STATUS
2450
- && typeof event?.submitId === 'string' && !!event.submitId
2451
- && event?.status in exports.SubmissionRunStatus
2452
- && event?.verdict in exports.ProblemVerdict
2453
- && typeof event?.points === 'number';
2494
+ const getVerdictFromTestCase = (testCaseValue, timeLimit, memoryLimit) => {
2495
+ const { compilationError, timeLimitExceeded, memoryLimitExceeded, runtimeError, timeUsed, memoryUsed, exitCode, } = getDataOfTestCase(testCaseValue, timeLimit, memoryLimit);
2496
+ return {
2497
+ verdict: compilationError
2498
+ ? exports.ProblemVerdict.CE
2499
+ : timeLimitExceeded
2500
+ ? exports.ProblemVerdict.TLE
2501
+ : memoryLimitExceeded
2502
+ ? exports.ProblemVerdict.MLE
2503
+ : runtimeError
2504
+ ? exports.ProblemVerdict.RE
2505
+ : testCaseValue.out === testCaseValue.testOut
2506
+ ? exports.ProblemVerdict.AC
2507
+ : testCaseValue.withPE && testCaseValue.out.split(' ').join('').split('\n').join('') === testCaseValue.testOut.split(' ').join('').split('\n').join('')
2508
+ ? exports.ProblemVerdict.PE
2509
+ : !testCaseValue.withPE && testCaseValue.out.split(' ').join('').split('\n').join('') === testCaseValue.testOut.split(' ').join('').split('\n').join('')
2510
+ ? exports.ProblemVerdict.AC
2511
+ : exports.ProblemVerdict.WA,
2512
+ timeUsed,
2513
+ memoryUsed,
2514
+ exitCode,
2515
+ };
2454
2516
  };
2455
- const isUserMessageWebSocketResponseEventDTO = (event) => {
2456
- return isWebSocketResponseEventDTO(event)
2457
- && event?.event === exports.WebSocketResponseEvent.USER_MESSAGE
2458
- && typeof event?.user?.nickname === 'string' && !!event.user?.nickname
2459
- && typeof event?.user?.imageUrl === 'string' && !!event.user?.imageUrl
2460
- && typeof event?.user?.company?.key === 'string' && !!event.user?.company?.key
2461
- && !!event?.content;
2517
+ const mergeVerdicts = (first, second) => {
2518
+ let verdict = first.verdict;
2519
+ if (second.verdict === exports.ProblemVerdict.RE) {
2520
+ verdict = exports.ProblemVerdict.RE;
2521
+ }
2522
+ else if (second.verdict === exports.ProblemVerdict.TLE && verdict != exports.ProblemVerdict.RE) {
2523
+ verdict = exports.ProblemVerdict.TLE;
2524
+ }
2525
+ else if (second.verdict === exports.ProblemVerdict.MLE
2526
+ && verdict !== exports.ProblemVerdict.TLE
2527
+ && verdict !== exports.ProblemVerdict.RE) {
2528
+ verdict = exports.ProblemVerdict.MLE;
2529
+ }
2530
+ else if (second.verdict === exports.ProblemVerdict.WA
2531
+ && verdict !== exports.ProblemVerdict.MLE
2532
+ && verdict !== exports.ProblemVerdict.TLE
2533
+ && verdict !== exports.ProblemVerdict.RE) {
2534
+ verdict = exports.ProblemVerdict.WA;
2535
+ }
2536
+ else if (second.verdict === exports.ProblemVerdict.PE
2537
+ && verdict !== exports.ProblemVerdict.WA
2538
+ && verdict !== exports.ProblemVerdict.MLE
2539
+ && verdict !== exports.ProblemVerdict.TLE
2540
+ && verdict !== exports.ProblemVerdict.RE) {
2541
+ verdict = exports.ProblemVerdict.PE;
2542
+ }
2543
+ else if (second.verdict === exports.ProblemVerdict.PA
2544
+ && verdict !== exports.ProblemVerdict.PE
2545
+ && verdict !== exports.ProblemVerdict.WA
2546
+ && verdict !== exports.ProblemVerdict.MLE
2547
+ && verdict !== exports.ProblemVerdict.TLE
2548
+ && verdict !== exports.ProblemVerdict.RE) {
2549
+ verdict = exports.ProblemVerdict.PA;
2550
+ }
2551
+ else if (second.verdict === exports.ProblemVerdict.AC
2552
+ && verdict !== exports.ProblemVerdict.PA
2553
+ && verdict !== exports.ProblemVerdict.PE
2554
+ && verdict !== exports.ProblemVerdict.WA
2555
+ && verdict !== exports.ProblemVerdict.MLE
2556
+ && verdict !== exports.ProblemVerdict.TLE
2557
+ && verdict !== exports.ProblemVerdict.RE) {
2558
+ verdict = exports.ProblemVerdict.AC;
2559
+ }
2560
+ return {
2561
+ timeUsed: Math.max(first.timeUsed, second.timeUsed),
2562
+ memoryUsed: Math.max(first.memoryUsed, second.memoryUsed),
2563
+ exitCode: first.exitCode || second.exitCode,
2564
+ verdict,
2565
+ };
2462
2566
  };
2463
- const isSendDataWebSocketResponseEventDTO = (event) => {
2464
- return [
2465
- exports.WebSocketResponseEvent.SEND_DATA_ECS_TASK_DEFINITIONS_LIST,
2466
- exports.WebSocketResponseEvent.SEND_DATA_EC2_INSTANCES_LIST,
2467
- exports.WebSocketResponseEvent.SEND_DATA_ECS_TASKS_LIST,
2468
- exports.WebSocketResponseEvent.SEND_DATA_SSM_SESSIONS_LIST,
2469
- exports.WebSocketResponseEvent.SEND_DATA_RUN_COMMAND,
2470
- exports.WebSocketResponseEvent.SEND_DATA_CLIENT_TRACK,
2471
- exports.WebSocketResponseEvent.SEND_DATA_CHAT_COMPLETIONS,
2472
- ].includes(event?.event)
2473
- && typeof event?.dataId === 'string' && !!event.dataId
2474
- && !!event?.content;
2567
+ const getDataLog = (log) => {
2568
+ const lines = log?.split?.('\n') || [];
2569
+ let timeUsed = 0;
2570
+ let memoryUsed = 0;
2571
+ let exitCode = -1;
2572
+ if (lines.length > 4) {
2573
+ for (const line of lines) {
2574
+ if (line.startsWith('time:')) {
2575
+ timeUsed = +line.split(':')[1];
2576
+ if (Number.isNaN(timeUsed)) {
2577
+ timeUsed = 0;
2578
+ }
2579
+ timeUsed *= 1000;
2580
+ }
2581
+ else if (line.startsWith('max-rss:')) {
2582
+ memoryUsed = parseInt(line.split(':')[1], 10); // en KB
2583
+ }
2584
+ else if (line.startsWith('exitcode:')) {
2585
+ exitCode = parseInt(line.split(':')[1], 10);
2586
+ }
2587
+ }
2588
+ }
2589
+ else if (lines.length >= 3) {
2590
+ timeUsed = +lines[0];
2591
+ memoryUsed = +lines[1];
2592
+ exitCode = +lines[2];
2593
+ }
2594
+ return {
2595
+ timeUsed: Number.isNaN(timeUsed) ? 0 : timeUsed,
2596
+ memoryUsed: Number.isNaN(memoryUsed) ? 0 : memoryUsed,
2597
+ exitCode: Number.isNaN(exitCode) ? -1 : exitCode,
2598
+ };
2475
2599
  };
2476
- const isSendDataEcsTaskDefinitionListWebSocketResponseEventDTO = (event) => {
2477
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
2478
- && event?.event === exports.WebSocketResponseEvent.SEND_DATA_ECS_TASK_DEFINITIONS_LIST;
2600
+
2601
+ function memorySizeOf(obj) {
2602
+ let bytes = 0;
2603
+ function sizeOf(obj) {
2604
+ if (obj !== null && obj !== undefined) {
2605
+ switch (typeof obj) {
2606
+ case "number":
2607
+ bytes += 8;
2608
+ break;
2609
+ case "string":
2610
+ bytes += obj.length * 2;
2611
+ break;
2612
+ case "boolean":
2613
+ bytes += 4;
2614
+ break;
2615
+ case "object":
2616
+ const objClass = Object.prototype.toString.call(obj).slice(8, -1);
2617
+ if (objClass === "Object" || objClass === "Array") {
2618
+ for (const key in obj) {
2619
+ if (!obj.hasOwnProperty(key))
2620
+ continue;
2621
+ bytes += key.length * 2;
2622
+ sizeOf(obj[key]);
2623
+ }
2624
+ }
2625
+ else
2626
+ bytes += obj.toString().length * 2;
2627
+ break;
2628
+ }
2629
+ }
2630
+ return bytes;
2631
+ }
2632
+ return sizeOf(obj);
2633
+ }
2634
+
2635
+ /* eslint-disable no-extend-native */
2636
+ Date.prototype.changeYear = function (year) {
2637
+ const newDate = new Date(this);
2638
+ newDate.setFullYear(year);
2639
+ return newDate;
2479
2640
  };
2480
- const isSendDataEc2InstancesListWebSocketResponseEventDTO = (event) => {
2481
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
2482
- && event?.event === exports.WebSocketResponseEvent.SEND_DATA_EC2_INSTANCES_LIST;
2641
+ Date.prototype.changeMonth = function (monthIndex) {
2642
+ const newDate = new Date(this);
2643
+ newDate.setMonth(monthIndex);
2644
+ return newDate;
2483
2645
  };
2484
- const isSendDataEcsTasksListWebSocketResponseEventDTO = (event) => {
2485
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
2486
- && event?.event === exports.WebSocketResponseEvent.SEND_DATA_ECS_TASKS_LIST;
2646
+ Date.prototype.changeDay = function (date) {
2647
+ const newDate = new Date(this);
2648
+ newDate.setDate(date);
2649
+ return newDate;
2487
2650
  };
2488
- const isSendDataSsmSessionsListWebSocketResponseEventDTO = (event) => {
2489
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
2490
- && event?.event === exports.WebSocketResponseEvent.SEND_DATA_SSM_SESSIONS_LIST;
2651
+ Date.prototype.changeHours = function (hours) {
2652
+ const newDate = new Date(this);
2653
+ newDate.setHours(hours);
2654
+ return newDate;
2491
2655
  };
2492
- const isSendDataRunCommandWebSocketResponseEventDTO = (event) => {
2493
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
2494
- && event?.event === exports.WebSocketResponseEvent.SEND_DATA_RUN_COMMAND;
2656
+ Date.prototype.changeMinutes = function (minutes) {
2657
+ const newDate = new Date(this);
2658
+ newDate.setMinutes(minutes);
2659
+ return newDate;
2495
2660
  };
2496
- const isSendDataClientTrackWebSocketResponseEventDTO = (event) => {
2497
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
2498
- && event?.event === exports.WebSocketResponseEvent.SEND_DATA_CLIENT_TRACK;
2661
+ Date.prototype.changeSeconds = function (seconds) {
2662
+ const newDate = new Date(this);
2663
+ newDate.setSeconds(seconds);
2664
+ return newDate;
2499
2665
  };
2500
- const isSenDataChatCompletionsWebSocketResponseEventDTO = (event) => {
2501
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
2502
- && event?.event === exports.WebSocketResponseEvent.SEND_DATA_CHAT_COMPLETIONS;
2666
+ Date.prototype.changeMilliseconds = function (milliseconds) {
2667
+ const newDate = new Date(this);
2668
+ newDate.setMilliseconds(milliseconds);
2669
+ return newDate;
2503
2670
  };
2504
- const isProblemCrawledWebSocketResponseEventDTO = (event) => {
2505
- return isWebSocketResponseEventDTO(event)
2506
- && event?.event === exports.WebSocketResponseEvent.PROBLEM_CRAWLED
2507
- && !!event?.content;
2671
+ Date.prototype.decreaseYear = function (count = 1) {
2672
+ return this.changeYear(this.getFullYear() - count);
2508
2673
  };
2509
- const isSubmissionsCrawlWebSocketResponseEventDTO = (event) => {
2510
- return isWebSocketResponseEventDTO(event)
2511
- && event?.event === exports.WebSocketResponseEvent.SUBMISSIONS_CRAWL
2512
- && !!event?.content;
2674
+ Date.prototype.increaseYear = function (count = 1) {
2675
+ return this.changeYear(this.getFullYear() + count);
2513
2676
  };
2514
- const isContestChangesWebSocketResponseEventDTO = (event) => {
2515
- return isWebSocketResponseEventDTO(event)
2516
- && event?.event === exports.WebSocketResponseEvent.CONTEST_CHANGES
2517
- && !!event?.content;
2677
+ Date.prototype.decreaseMonth = function () {
2678
+ const newDate = new Date(this);
2679
+ newDate.setMonth(newDate.getMonth() - 1);
2680
+ return newDate;
2518
2681
  };
2519
- const isClientTrackWebSocketResponseEventDTO = (event) => {
2520
- return isWebSocketResponseEventDTO(event)
2521
- && event?.event === exports.WebSocketResponseEvent.CLIENT_TRACK;
2682
+ Date.prototype.increaseMonth = function () {
2683
+ const newDate = new Date(this);
2684
+ newDate.setMonth(newDate.getMonth() + 1);
2685
+ return newDate;
2522
2686
  };
2523
- const isUserNotificationWebSocketResponseEventDTO = (event) => {
2524
- return [
2525
- exports.WebSocketResponseEvent.USER_NOTIFICATION_SUBMISSION,
2526
- exports.WebSocketResponseEvent.USER_NOTIFICATION_CONTEST_CLARIFICATION,
2527
- ].includes(event?.event)
2528
- && !!event?.content;
2687
+ Date.prototype.increaseDay = function () {
2688
+ const newDate = new Date(this);
2689
+ newDate.setDate(newDate.getDate() + 1);
2690
+ return newDate;
2529
2691
  };
2530
- const isUserNotificationSubmissionWebSocketResponseEventDTO = (event) => {
2531
- return isWebSocketResponseEventDTO(event) && isUserNotificationWebSocketResponseEventDTO(event)
2532
- && event?.event === exports.WebSocketResponseEvent.USER_NOTIFICATION_SUBMISSION;
2692
+ Date.prototype.decreaseDay = function () {
2693
+ const newDate = new Date(this);
2694
+ newDate.setDate(newDate.getDate() - 1);
2695
+ return newDate;
2533
2696
  };
2534
- const isUserNotificationContestClarificationWebSocketResponseEventDTO = (event) => {
2535
- return isWebSocketResponseEventDTO(event) && isUserNotificationWebSocketResponseEventDTO(event)
2536
- && event?.event === exports.WebSocketResponseEvent.USER_NOTIFICATION_CONTEST_CLARIFICATION;
2697
+ Date.prototype.startOfYear = function () {
2698
+ const newDate = new Date(this);
2699
+ newDate.setMonth(0);
2700
+ return newDate.startOfMonth();
2537
2701
  };
2538
- // generic
2539
- const getWebSocketResponseEventKey = (event, clientId, id) => {
2540
- return `${event}-${clientId}-${id}`;
2702
+ Date.prototype.endOfYear = function () {
2703
+ const nextMonth = this.increaseYear().startOfYear();
2704
+ return new Date(nextMonth.getTime() - 1);
2541
2705
  };
2542
-
2543
- function splitTime(timeRemaining) {
2544
- const remaining = [];
2545
- // const aYearMilliseconds = 1000 * 60 * 60 * 24 * 365;
2546
- // const remainingYears = Math.floor(timeRemaining / aYearMilliseconds);
2547
- // remaining.push({ remaining: remainingYears, label: 'years', milliseconds: aYearMilliseconds });
2548
- // const aWeekMilliseconds = 1000 * 60 * 60 * 24 * 7;
2549
- // const remainingWeeks = Math.floor((timeRemaining % aYearMilliseconds) / aWeekMilliseconds);
2550
- // remaining.push({ remaining: remainingWeeks, label: 'weeks', milliseconds: aWeekMilliseconds });
2551
- const aSecondMilliseconds = 1000;
2552
- const aMinuteMilliseconds = aSecondMilliseconds * 60;
2553
- const aHourMilliseconds = aMinuteMilliseconds * 60;
2554
- const aDayMilliseconds = aHourMilliseconds * 24;
2555
- const aWeekMilliseconds = aDayMilliseconds * 7;
2556
- const remainingWeeks = Math.floor(timeRemaining / aWeekMilliseconds);
2557
- remaining.push({
2558
- remaining: remainingWeeks,
2559
- label: remainingWeeks === 1 ? 'week' : 'weeks',
2560
- abbreviatedLabel: 'w',
2561
- milliseconds: aWeekMilliseconds,
2562
- digits: 2,
2563
- });
2564
- const remainingDays = Math.floor((timeRemaining % aWeekMilliseconds) / aDayMilliseconds);
2565
- remaining.push({
2566
- remaining: remainingDays,
2567
- label: remainingDays === 1 ? 'day' : 'days',
2568
- abbreviatedLabel: 'd',
2569
- milliseconds: aDayMilliseconds,
2570
- digits: 2,
2571
- });
2572
- const remainingHours = Math.floor((timeRemaining % aDayMilliseconds) / aHourMilliseconds);
2573
- remaining.push({
2574
- remaining: remainingHours,
2575
- label: remainingHours === 1 ? 'hour' : 'hours',
2576
- abbreviatedLabel: 'h',
2577
- milliseconds: aHourMilliseconds,
2578
- digits: 2,
2579
- });
2580
- const remainingMinutes = Math.floor((timeRemaining % aHourMilliseconds) / aMinuteMilliseconds);
2581
- remaining.push({
2582
- remaining: remainingMinutes,
2583
- label: remainingMinutes === 1 ? 'minute' : 'minutes',
2584
- abbreviatedLabel: 'm',
2585
- milliseconds: aMinuteMilliseconds,
2586
- digits: 2,
2587
- });
2588
- const remainingSeconds = Math.floor((timeRemaining % aMinuteMilliseconds) / aSecondMilliseconds);
2589
- remaining.push({
2590
- remaining: remainingSeconds,
2591
- label: remainingSeconds === 1 ? 'second' : 'seconds',
2592
- abbreviatedLabel: 's',
2593
- milliseconds: aSecondMilliseconds,
2594
- digits: 2,
2595
- });
2596
- const remainingMilliseconds = Math.floor(timeRemaining % aSecondMilliseconds);
2597
- remaining.push({
2598
- remaining: remainingMilliseconds,
2599
- label: remainingMilliseconds === 1 ? 'millisecond' : 'milliseconds',
2600
- abbreviatedLabel: 'ms',
2601
- milliseconds: 1,
2602
- digits: 3,
2603
- });
2604
- // while (remaining[0].remaining <= 0) {
2605
- // remaining.shift();
2606
- // if (remaining.length === 3) {
2607
- // break;
2608
- // }
2609
- // }
2610
- return remaining;
2611
- }
2612
- function normalizeToLocalStartOfDay(timestamp) {
2613
- const date = new Date(timestamp);
2614
- return new Date(date.getFullYear(), date.getMonth(), date.getDate());
2615
- }
2616
- function normalizeToLocalStartOfHour(timestamp) {
2617
- const date = new Date(timestamp);
2618
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours());
2619
- }
2620
- function normalizeToLocalStartOfMinutes(timestamp) {
2621
- const date = new Date(timestamp);
2622
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
2623
- }
2624
- function normalizeToLocalStartOfSeconds(timestamp) {
2625
- const date = new Date(timestamp);
2626
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
2627
- }
2628
- const getYears = (d) => d.getFullYear();
2629
- const getMonths = (d) => d.getFullYear() * 12 + d.getMonth();
2630
- const getDays = (d) => {
2631
- return Math.floor(normalizeToLocalStartOfDay(d).getTime() / ONE_DAY);
2706
+ Date.prototype.startOfMonth = function () {
2707
+ const newDate = new Date(this);
2708
+ newDate.setDate(1);
2709
+ return newDate.startOfDay();
2632
2710
  };
2633
- const getHours = (d) => {
2634
- return Math.floor(normalizeToLocalStartOfHour(d).getTime() / ONE_HOUR);
2711
+ Date.prototype.endOfMonth = function () {
2712
+ const nextMonth = this.increaseMonth().startOfMonth();
2713
+ return new Date(nextMonth.getTime() - 1);
2635
2714
  };
2636
- const getMinutes = (d) => {
2637
- return Math.floor(normalizeToLocalStartOfMinutes(d).getTime() / ONE_MINUTE);
2715
+ Date.prototype.startOfWeek = function () {
2716
+ const newDate = new Date(this);
2717
+ while (newDate.getDay()) {
2718
+ newDate.setDate(newDate.getDate() - 1);
2719
+ }
2720
+ return newDate.startOfDay();
2638
2721
  };
2639
- const getSeconds = (d) => {
2640
- return Math.floor(normalizeToLocalStartOfSeconds(d).getTime() / 1000);
2722
+ Date.prototype.endOfWeek = function () {
2723
+ const newDate = new Date(this);
2724
+ while (newDate.getDay() < 6) {
2725
+ newDate.setDate(newDate.getDate() - 1);
2726
+ }
2727
+ return newDate.endOfDay();
2641
2728
  };
2642
- const getMilliseconds = (d) => d.getTime();
2643
-
2644
- const getUserKey = (userNickname, userCompanyKey) => {
2645
- return userNickname + '|' + userCompanyKey;
2729
+ Date.prototype.startOfDay = function () {
2730
+ const newDate = new Date(this);
2731
+ newDate.setHours(0, 0, 0, 0);
2732
+ return newDate;
2646
2733
  };
2647
- const getParamsOfUserKey = (userKey) => {
2648
- const [userNickname, userCompanyKey] = userKey.split('|');
2649
- return { userNickname, userCompanyKey };
2734
+ Date.prototype.endOfDay = function () {
2735
+ const newDate = new Date(this);
2736
+ newDate.setHours(23, 59, 59, 999);
2737
+ return newDate;
2650
2738
  };
2651
- const getClientId = (sessionId, uiId) => {
2652
- return `${sessionId}|${uiId}`;
2739
+ Date.prototype.startOfHour = function () {
2740
+ const newDate = new Date(this);
2741
+ newDate.setMinutes(0, 0, 0);
2742
+ return newDate;
2653
2743
  };
2654
- const getParamsOfClientId = (clientId) => {
2655
- const [sessionId, uiId] = clientId.split('|');
2656
- return { sessionId, uiId };
2744
+ Date.prototype.endOfHour = function () {
2745
+ const newDate = new Date(this);
2746
+ newDate.setMinutes(59, 59, 999);
2747
+ return newDate;
2657
2748
  };
2658
-
2659
- const NEW_PAGE_SHEET = () => ({
2660
- id: uuid.v4(),
2661
- type: exports.WorksheetType.NEW_PAGE,
2662
- title: '',
2663
- points: 0,
2664
- });
2665
- const ASPECT_RATIO = {
2666
- [exports.AspectRatio.RATIO_21_9]: {
2667
- aspectRatio: exports.AspectRatio.RATIO_21_9,
2668
- width: 2520,
2669
- height: 1080,
2670
- decimal: 21 / 9,
2671
- label: 'ultrawide',
2672
- },
2673
- [exports.AspectRatio.RATIO_20_9]: {
2674
- aspectRatio: exports.AspectRatio.RATIO_20_9,
2675
- width: 2400,
2676
- height: 1080,
2677
- decimal: 20 / 9,
2678
- label: 'mobile wide',
2679
- },
2680
- [exports.AspectRatio.RATIO_16_9]: {
2681
- aspectRatio: exports.AspectRatio.RATIO_16_9,
2682
- width: 1920,
2683
- height: 1080,
2684
- decimal: 16 / 9,
2685
- label: 'widescreen',
2686
- },
2687
- [exports.AspectRatio.RATIO_16_10]: {
2688
- aspectRatio: exports.AspectRatio.RATIO_16_10,
2689
- width: 1920,
2690
- height: 1200,
2691
- decimal: 16 / 10,
2692
- label: 'widescreen tall',
2693
- },
2694
- [exports.AspectRatio.RATIO_3_2]: {
2695
- aspectRatio: exports.AspectRatio.RATIO_3_2,
2696
- width: 1440,
2697
- height: 960,
2698
- decimal: 3 / 2,
2699
- label: 'balanced',
2700
- },
2701
- [exports.AspectRatio.RATIO_4_3]: {
2702
- aspectRatio: exports.AspectRatio.RATIO_4_3,
2703
- width: 1024,
2704
- height: 768,
2705
- decimal: 4 / 3,
2706
- label: 'standard',
2707
- },
2708
- [exports.AspectRatio.RATIO_5_4]: {
2709
- aspectRatio: exports.AspectRatio.RATIO_5_4,
2710
- width: 1280,
2711
- height: 1024,
2712
- decimal: 5 / 4,
2713
- label: 'square old',
2714
- },
2715
- [exports.AspectRatio.RATIO_1_1]: {
2716
- aspectRatio: exports.AspectRatio.RATIO_1_1,
2717
- width: 1000,
2718
- height: 1000,
2719
- decimal: 1,
2720
- label: 'square',
2721
- },
2749
+ Date.prototype.startOfMinute = function () {
2750
+ const newDate = new Date(this);
2751
+ newDate.setSeconds(0, 0);
2752
+ return newDate;
2722
2753
  };
2723
-
2724
- const getWorksheetsInPages = (initialSheets) => {
2725
- const sheets = [...initialSheets];
2726
- if (sheets[0]?.type !== exports.WorksheetType.NEW_PAGE) {
2727
- sheets.unshift(NEW_PAGE_SHEET());
2728
- }
2729
- let newPage = sheets[0];
2730
- let content = [];
2731
- const sheetsByPages = [];
2732
- for (let i = 1; i < sheets.length; i++) {
2733
- const sheet = sheets[i];
2734
- if (sheet.type === exports.WorksheetType.NEW_PAGE) {
2735
- sheetsByPages.push({
2736
- header: newPage,
2737
- content: [...content],
2738
- });
2739
- newPage = sheet;
2740
- content = [];
2741
- }
2742
- else {
2743
- content.push(sheet);
2744
- }
2745
- }
2746
- sheetsByPages.push({
2747
- header: newPage,
2748
- content: [...content],
2749
- });
2750
- return sheetsByPages;
2754
+ Date.prototype.endOfMinute = function () {
2755
+ const newDate = new Date(this);
2756
+ newDate.setSeconds(59, 999);
2757
+ return newDate;
2751
2758
  };
2752
- const getSummaryWorksheetsInPages = (initialSheets) => {
2753
- const sheets = [...initialSheets];
2754
- if (sheets[0]?.type !== exports.WorksheetType.NEW_PAGE) {
2755
- sheets.unshift(NEW_PAGE_SHEET());
2756
- }
2757
- let newPage = sheets[0];
2758
- let content = [];
2759
- const sheetsByPages = [];
2760
- for (let i = 1; i < sheets.length; i++) {
2761
- const sheet = sheets[i];
2762
- if (sheet.type === exports.WorksheetType.NEW_PAGE) {
2763
- sheetsByPages.push({
2764
- header: newPage,
2765
- content: content.map(c => ({
2766
- id: c.id,
2767
- type: c.type,
2768
- title: c.title,
2769
- points: c.points,
2770
- })),
2771
- });
2772
- newPage = sheet;
2773
- content = [];
2774
- }
2775
- else {
2776
- content.push(sheet);
2777
- }
2778
- }
2779
- sheetsByPages.push({
2780
- header: newPage,
2781
- content: [...content],
2782
- });
2783
- return sheetsByPages;
2759
+ Date.prototype.startOfSecond = function () {
2760
+ const newDate = new Date(this);
2761
+ newDate.setMilliseconds(0);
2762
+ return newDate;
2784
2763
  };
2785
- const getTotalExercisesOfSummaryWorksheetsInPages = (content) => content.reduce((sum, { content }) => sum + content.reduce((sum, { type }) => sum + +(type === exports.WorksheetType.QUIZ_OPTIONS || type === exports.WorksheetType.QUIZ_PROBLEM || type === exports.WorksheetType.QUIZ_TEXT), 0), 0);
2786
- const isBasicWorksheet = (value) => {
2787
- return typeof value?.id == 'string' && value.id
2788
- && Object.values(exports.WorksheetType).includes(value?.type)
2789
- && typeof value?.title == 'string'
2790
- && typeof value?.points == 'number';
2764
+ Date.prototype.endOfSecond = function () {
2765
+ const newDate = new Date(this);
2766
+ newDate.setMilliseconds(999);
2767
+ return newDate;
2791
2768
  };
2792
- const isJkmdSheet = (value) => {
2793
- return isBasicWorksheet(value)
2794
- && value?.type === exports.WorksheetType.JK_MD
2795
- && typeof value?.content == 'string';
2769
+ Date.prototype.isToday = function () {
2770
+ const today = new Date();
2771
+ return this.isSameDay(today);
2796
2772
  };
2797
- const isCodeEditorSheet = (value) => {
2798
- return isBasicWorksheet(value)
2799
- && value?.type === exports.WorksheetType.CODE_EDITOR
2800
- && typeof value?.sourceCode === 'object' && value?.sourceCode !== null
2801
- && value?.testCases === 'object' && value?.testCases !== null
2802
- && Array.isArray(value?.languages)
2803
- && typeof value?.height == 'number';
2773
+ Date.prototype.isEqual = function (date) {
2774
+ return this.getTime() === date.getTime();
2804
2775
  };
2805
- const isQuizProblemSheet = (value) => {
2806
- return isBasicWorksheet(value)
2807
- && value?.type === exports.WorksheetType.QUIZ_PROBLEM
2808
- && Object.values(exports.Judge).includes(value?.problemJudge) || typeof value?.problemJudge === 'string'
2809
- && typeof value?.problemKey == 'string'
2810
- && Array.isArray(value?.languages)
2811
- && typeof value?.height == 'number';
2776
+ Date.prototype.isSameYear = function (date) {
2777
+ return this.getFullYear() === date.getFullYear();
2812
2778
  };
2813
- const isQuizOptionsSheet = (value) => {
2814
- return isBasicWorksheet(value)
2815
- && value?.type === exports.WorksheetType.QUIZ_OPTIONS
2816
- && typeof value?.description == 'string'
2817
- && Array.isArray(value?.options)
2818
- && value?.options.every((option) => typeof option?.label == 'string' && typeof option?.correct == 'boolean' && typeof option?.id == 'string')
2819
- && typeof value?.multiple == 'boolean'
2820
- && (value?.scoringMode === 'TOTAL' || value?.scoringMode === 'PARTIAL');
2779
+ Date.prototype.isSameMonth = function (date) {
2780
+ return this.isSameYear(date) && this.getMonth() === date.getMonth();
2821
2781
  };
2822
- const isQuizTextSheet = (value) => {
2823
- return isBasicWorksheet(value)
2824
- && value?.type === exports.WorksheetType.QUIZ_TEXT
2825
- && typeof value?.description == 'string'
2826
- && typeof value?.answer == 'string'
2827
- && ['text', 'number', 'textarea'].includes(value?.inputType);
2782
+ Date.prototype.isSameDay = function (date) {
2783
+ return this.isSameMonth(date) && this.getDate() === date.getDate();
2784
+ };
2785
+ Date.prototype.isSameHour = function (date) {
2786
+ return this.isSameDay(date) && this.getHours() === date.getHours();
2787
+ };
2788
+ Date.prototype.isSameMinute = function (date) {
2789
+ return this.isSameHour(date) && this.getMinutes() === date.getMinutes();
2790
+ };
2791
+ Date.prototype.isSameSecond = function (date) {
2792
+ return this.isSameMinute(date) && this.getSeconds() === date.getSeconds();
2793
+ };
2794
+ Date.prototype.isSameMillisecond = function (date) {
2795
+ return this.isEqual(date);
2796
+ };
2797
+ Date.prototype.isValidDate = function () {
2798
+ return this instanceof Date && !isNaN(this.getTime());
2799
+ };
2800
+ Date.prototype.isYearAfter = function (date) {
2801
+ return this.getFullYear() > date.getFullYear();
2802
+ };
2803
+ Date.prototype.isMonthAfter = function (date) {
2804
+ return this.isYearAfter(date) || (this.isSameYear(date) && this.getMonth() > date.getMonth());
2805
+ };
2806
+ Date.prototype.isDayAfter = function (date) {
2807
+ return this.isMonthAfter(date) || (this.isSameMonth(date) && this.getDate() > date.getDate());
2808
+ };
2809
+ Date.prototype.isHoursAfter = function (date) {
2810
+ return this.isDayAfter(date) || (this.isSameDay(date) && this.getHours() > date.getHours());
2811
+ };
2812
+ Date.prototype.isMinutesAfter = function (date) {
2813
+ return this.isHoursAfter(date) || (this.isSameHour(date) && this.getMinutes() > date.getMinutes());
2814
+ };
2815
+ Date.prototype.isSecondsAfter = function (date) {
2816
+ return this.isMinutesAfter(date) || (this.isSameMinute(date) && this.getSeconds() > date.getSeconds());
2817
+ };
2818
+ Date.prototype.isMillisecondsAfter = function (date) {
2819
+ return this.isSecondsAfter(date) || (this.isSameSecond(date) && this.getMilliseconds() > date.getMilliseconds());
2820
+ };
2821
+ Date.prototype.isAfter = function (date) {
2822
+ return this.getTime() > date.getTime();
2823
+ };
2824
+ Date.prototype.isYearBefore = function (date) {
2825
+ return this.getFullYear() < date.getFullYear();
2826
+ };
2827
+ Date.prototype.isMonthBefore = function (date) {
2828
+ return this.isYearBefore(date) || (this.isSameYear(date) && this.getMonth() < date.getMonth());
2829
+ };
2830
+ Date.prototype.isDayBefore = function (date) {
2831
+ return this.isMonthBefore(date) || (this.isSameMonth(date) && this.getDate() < date.getDate());
2832
+ };
2833
+ Date.prototype.isHoursBefore = function (date) {
2834
+ return this.isDayBefore(date) || (this.isSameDay(date) && this.getHours() < date.getHours());
2835
+ };
2836
+ Date.prototype.isMinutesBefore = function (date) {
2837
+ return this.isHoursBefore(date) || (this.isSameHour(date) && this.getMinutes() < date.getMinutes());
2838
+ };
2839
+ Date.prototype.isSecondsBefore = function (date) {
2840
+ return this.isMinutesBefore(date) || (this.isSameMinute(date) && this.getSeconds() < date.getSeconds());
2841
+ };
2842
+ Date.prototype.isMillisecondsBefore = function (date) {
2843
+ return this.isSecondsBefore(date) || (this.isSameSecond(date) && this.getMilliseconds() < date.getMilliseconds());
2844
+ };
2845
+ Date.prototype.isBefore = function (date) {
2846
+ return this.getTime() < date.getTime();
2847
+ };
2848
+ Date.prototype.isWithinInterval = function ({ start, end }, cmp = '[]') {
2849
+ return (cmp.charAt(0) === '[' ? this.isEqual(start) || this.isAfter(start) : this.isAfter(start)) &&
2850
+ (cmp.charAt(1) === '[' ? this.isEqual(end) || this.isBefore(end) : this.isBefore(end));
2828
2851
  };
2829
2852
 
2830
- const YEARS = range(1970, 2100);
2831
- const MONTH_NAMES = [
2832
- 'January',
2833
- 'February',
2834
- 'March',
2835
- 'April',
2836
- 'May',
2837
- 'June',
2838
- 'July',
2839
- 'August',
2840
- 'September',
2841
- 'October',
2842
- 'November',
2843
- 'December',
2844
- ];
2845
- const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
2846
- const HOURS = range(0, 24);
2847
- const MINUTES = range(0, 60);
2848
- const SECONDS = range(0, 60);
2849
- const MILLISECONDS = range(0, 1000);
2850
- const MAX_DATE = new Date(8640000000000000);
2851
- const MIN_DATE = new Date(0);
2853
+ class JkError extends Error {
2854
+ constructor(code, custom) {
2855
+ const message = custom?.message || ERROR[code].message;
2856
+ super(message);
2857
+ this.message = message;
2858
+ this.code = code;
2859
+ if (custom?.stack) {
2860
+ this.stack = custom.stack;
2861
+ }
2862
+ if (custom?.data) {
2863
+ this.data = custom.data;
2864
+ }
2865
+ }
2866
+ }
2852
2867
 
2853
- const SUPPORT_EMAIL = 'support@juki.app';
2854
- const JUKI_APP_EMAIL_TEMPLATE = `<div style="width: 100%; background: #F2F2F2;">
2855
- <div style="background: #164066; width: 100%;">
2856
- <div style="height: 56px; color: white; width: 100px; margin: 0 auto">
2857
- <img
2858
- src="https://images.juki.pub/assets/juki-app-horizontal-white-logo.svg"
2859
- alt="juki app logo"
2860
- height="56px"
2861
- style="padding:10px; box-sizing: border-box"
2862
- />
2863
- </div>
2864
- </div>
2865
- <div style="padding: 24px; color: #333333; font-family: sans-serif; font-size: 16px; line-height: 24px;">
2866
- <div style="max-width: 520px; margin: 0 auto; padding: 24px; background: white; border-radius: 6px;">
2867
- <section style="padding: 0 0 1em 0; border-bottom: 1px solid #828282;">
2868
- {{content}}
2869
- </section>
2870
- <div style="font-size: 14px; text-align: center; color: #828282; line-height: 16px; padding-top: 1em">
2871
- <p style="margin: 0;">
2872
- Si tú no realizaste la solicitud, escribenos a
2873
- <a href="mailto:${SUPPORT_EMAIL}" style="color: #2468A6; text-decoration: none;">
2874
- ${SUPPORT_EMAIL}
2875
- </a>
2876
- </p>
2877
- <p style="margin: 0;">
2878
- Este mensaje fue enviado por el equipo de
2879
- <a href="https://juki.app" style="color: #2468A6; text-decoration: none;">
2880
- juki.app
2881
- </a>
2882
- </p>
2883
- </div>
2884
- </div>
2885
- </div>
2886
- </div>`;
2868
+ /* eslint-disable no-extend-native */
2869
+ Number.prototype.padStart = function (maxLength, fillString = '0') {
2870
+ return (this + '').padStart(maxLength, fillString);
2871
+ };
2872
+ Number.prototype.padEnd = function (maxLength, fillString = '0') {
2873
+ return (this + '').padEnd(maxLength, fillString);
2874
+ };
2887
2875
 
2888
- const EMPTY_DOCUMENT_MEMBERS = () => ({
2889
- access: exports.EntityAccess.PRIVATE,
2890
- managers: {},
2891
- spectators: {},
2892
- });
2893
- const EMPTY_ENTITY_MEMBERS = () => ({
2894
- rankAdministrators: exports.EntityMembersRank.CLOSE,
2895
- administrators: {},
2896
- rankManagers: exports.EntityMembersRank.CLOSE,
2897
- managers: {},
2898
- rankGuests: exports.EntityMembersRank.CLOSE,
2899
- guests: {},
2900
- rankSpectators: exports.EntityMembersRank.CLOSE,
2901
- spectators: {},
2902
- rankParticipants: exports.EntityMembersRank.CLOSE,
2903
- participants: {},
2904
- });
2876
+ function toJkError(err) {
2877
+ const error = new Error();
2878
+ let code = err?.code;
2879
+ if (!(code in exports.ErrorCode)) {
2880
+ code = exports.ErrorCode.ERR500;
2881
+ }
2882
+ return new JkError(code, {
2883
+ message: err?.message || error.message,
2884
+ stack: err?.stack || error.stack,
2885
+ data: err?.data || null,
2886
+ });
2887
+ }
2888
+ function errorsResponse(message, ...errors) {
2889
+ return {
2890
+ success: false,
2891
+ message: message,
2892
+ errors: errors.map(error => ({
2893
+ code: error.code,
2894
+ message: error.message,
2895
+ detail: error.stack || new Error().stack || '',
2896
+ data: error.data,
2897
+ })),
2898
+ };
2899
+ }
2900
+ function contentResponse(message, content) {
2901
+ return {
2902
+ success: true,
2903
+ message,
2904
+ content,
2905
+ };
2906
+ }
2907
+ function contentsResponse(message, contents, meta) {
2908
+ return {
2909
+ success: true,
2910
+ message,
2911
+ contents,
2912
+ meta,
2913
+ };
2914
+ }
2915
+ const cleanRequest = (responseText) => {
2916
+ if (!isStringJson(responseText)) {
2917
+ // this occurs when the endpoint don't exits or server is down
2918
+ const response = {
2919
+ success: false,
2920
+ message: ERROR[exports.ErrorCode.ERR9999].message,
2921
+ errors: [{ code: exports.ErrorCode.ERR9999, detail: '', message: ERROR[exports.ErrorCode.ERR9999].message }],
2922
+ };
2923
+ consoleError({ message: 'response is not string json, success false on cleaning request', responseText, response });
2924
+ // jukiApiManager.reportError({ message: 'success false on cleaning request', responseText, response });
2925
+ return response;
2926
+ }
2927
+ const responseJson = JSON.parse(responseText);
2928
+ if (typeof responseJson.success === 'boolean') {
2929
+ if (responseJson.success === true && typeof responseJson.message === 'string' && responseJson.content) { // V1
2930
+ return {
2931
+ success: true,
2932
+ message: responseJson.message,
2933
+ content: responseJson.content,
2934
+ };
2935
+ }
2936
+ else if (responseJson.success === true && typeof responseJson.message === 'string' && Array.isArray(responseJson.contents) && responseJson.meta) { // V1
2937
+ return {
2938
+ success: true,
2939
+ message: responseJson.message,
2940
+ contents: responseJson.contents,
2941
+ meta: responseJson.meta,
2942
+ };
2943
+ }
2944
+ else if (responseJson.success === false && typeof responseJson.message === 'string' && Array.isArray(responseJson.errors)) { // V1
2945
+ const response = {
2946
+ success: false,
2947
+ message: responseJson.message,
2948
+ errors: responseJson.errors,
2949
+ };
2950
+ consoleError({ message: 'success false on cleaning request', responseText, response });
2951
+ // jukiApiManager.reportError({ message: 'success false on cleaning request', responseText, response });
2952
+ return response;
2953
+ }
2954
+ }
2955
+ const response = {
2956
+ success: false,
2957
+ message: ERROR[exports.ErrorCode.ERR9998].message,
2958
+ errors: [{ code: exports.ErrorCode.ERR9998, detail: '', message: ERROR[exports.ErrorCode.ERR9998].message }],
2959
+ };
2960
+ consoleError({ message: 'success false on cleaning request', responseText, response });
2961
+ // jukiApiManager.reportError({ message: 'success false on cleaning request', responseText, response });
2962
+ return response;
2963
+ };
2964
+ const getDefaultMeta = (contents, sort) => {
2965
+ return { sort: sort ?? [], page: 1, size: contents.length, totalElements: contents.length, filter: {} };
2966
+ };
2905
2967
 
2906
- const JUDGE = {
2907
- // [Judge.CUSTOMER]: {
2908
- // value: Judge.CUSTOMER,
2909
- // label: '',
2910
- // logo: 'https://images.juki.pub/c/juki-judge-logo-horizontal-color.svg',
2911
- // logoSize: [ 883.991, 435 ],
2912
- // url: '',
2913
- // // getLoginUrl: () => '',
2914
- // // getProfileUrl: () => '',
2915
- // // getSubmitUrl: () => '',
2916
- // // getSubmissionUrl: () => '',
2917
- // // getProblemUrl: (key: string) => `/problem/view/${key}`,
2918
- // // getUserSubmissionsUrl: () => '',
2919
- // },
2920
- [exports.Judge.JUKI_JUDGE]: {
2921
- value: exports.Judge.JUKI_JUDGE,
2922
- label: 'Juki Judge',
2923
- logo: 'https://images.juki.pub/c/juki-judge-logo-horizontal-color.svg',
2924
- logoSize: [883.991, 435],
2925
- url: 'https://judge.juki.app',
2926
- // getLoginUrl: () => '',
2927
- // getProfileUrl: () => '',
2928
- // getSubmitUrl: () => '',
2929
- // getSubmissionUrl: () => '',
2930
- // getProblemUrl: (key: string) => `https://judge.juki.app/problem/view/${key}`,
2931
- // getUserSubmissionsUrl: () => '',
2932
- },
2933
- [exports.Judge.CODEFORCES]: {
2934
- value: exports.Judge.CODEFORCES,
2935
- label: 'Codeforces',
2936
- logo: 'https://images.juki.pub/c/codeforces-logo-horizontal-color.svg',
2937
- logoSize: [1232.75, 145.12],
2938
- url: 'https://codeforces.com',
2939
- // getLoginUrl: () => 'https://codeforces.com/enter',
2940
- // getProfileUrl: () => '',
2941
- // getSubmitUrl: () => 'https://codeforces.com/problemset/submit',
2942
- // getSubmissionUrl: (problemKey: string, submissionId: string) => {
2943
- // const [ contestId ] = problemKey.split('-');
2944
- // return `https://codeforces.com/problemset/submission/${contestId}/${submissionId}`;
2945
- // },
2946
- // getProblemUrl: (problemKey: string) => {
2947
- // const [ contestId, index ] = problemKey.split('-');
2948
- // return `https://codeforces.com/problemset/problem/${contestId}/${index}`;
2949
- // },
2950
- // getUserSubmissionsUrl: () => '',
2951
- },
2952
- [exports.Judge.CODEFORCES_GYM]: {
2953
- value: exports.Judge.CODEFORCES_GYM,
2954
- label: 'Codeforces Gym',
2955
- logo: 'https://images.juki.pub/c/codeforces-logo-horizontal-color.svg',
2956
- logoSize: [1232.75, 145.12],
2957
- url: 'https://codeforces.com',
2958
- // getLoginUrl: () => 'https://codeforces.com/enter',
2959
- // getProfileUrl: () => '',
2960
- // getSubmitUrl: (problemKey: string) => {
2961
- // const [ gymContestId, index ] = problemKey.split('-');
2962
- // return `https://codeforces.com/gym/${gymContestId}/submit`;
2963
- // },
2964
- // getSubmissionUrl: (problemKey: string, submissionId: string) => {
2965
- // const [ gymContestId ] = problemKey.split('-');
2966
- // return `https://codeforces.com/gym/${gymContestId}/submission/${submissionId}`;
2967
- // },
2968
- // getProblemUrl: (problemKey: string) => {
2969
- // const [ gymContestId, index ] = problemKey.split('-');
2970
- // return `https://codeforces.com/gym/${gymContestId}/problem/${index}`;
2971
- // },
2972
- // getUserSubmissionsUrl: () => '',
2973
- },
2974
- [exports.Judge.JV_UMSA]: {
2975
- value: exports.Judge.JV_UMSA,
2976
- label: 'Juez Virtual UMSA',
2977
- logo: 'https://images.juki.pub/c/codeforces-logo-horizontal-color.svg',
2978
- logoSize: [1232.75, 145.12],
2979
- url: 'https://jv.umsa.bo',
2980
- // getLoginUrl: () => 'https://jv.umsa.bo/oj/login.php',
2981
- // getProfileUrl: () => 'https://jv.umsa.bo/oj/userInfo.php',
2982
- // getSubmitUrl: (problemKey: string) => {
2983
- // // single problem: '1019'
2984
- // // cib problem: '1019-A'
2985
- // const isContestProblem = problemKey.includes('-');
2986
- // // A -> 0, B -> 1, C -> 2, D -> 3, E -> 4, F -> 5, G -> 6, H -> 7, I -> 8, J -> 9
2987
- // const params = problemKey.split('-');
2988
- // return isContestProblem
2989
- // ? `https://jv.umsa.bo/oj/submitpage.php?cid=${params[0]}&pid=${params[1].charCodeAt(0) - 65}`
2990
- // : `https://jv.umsa.bo/oj/submitpage.php?id=${problemKey}`;
2991
- // },
2992
- // getSubmissionUrl: (problemKey: string, submissionId: string, username: string) => {
2993
- // // return `https://jv.umsa.bo/status.php?problem_id=&user_id=${username}&language=-1&jresult=-1`;
2994
- // return `https://jv.umsa.bo/oj/showsource.php?id=${submissionId}`;
2995
- // },
2996
- // getProblemUrl: (problemKey: string) => {
2997
- // const isContestProblem = problemKey.includes('-');
2998
- // const params = problemKey.split('-');
2999
- // return isContestProblem
3000
- // ? `https://jv.umsa.bo/oj/problem.php?cid=${params[0]}&pid=${params[1].charCodeAt(0) - 65}`
3001
- // : `https://jv.umsa.bo/oj/problem.php?id=${problemKey}`;
3002
- // },
3003
- // getUserSubmissionsUrl: (username: string) => `https://jv.umsa.bo/oj/status.php?user_id=${username}`,
3004
- },
3005
- [exports.Judge.UVA_ONLINE_JUDGE]: {
3006
- value: exports.Judge.UVA_ONLINE_JUDGE,
3007
- label: 'Uva Online Judge',
3008
- logo: 'https://images.juki.pub/c/uva-online-judge-logo-color.png',
3009
- logoSize: [150, 135.994],
3010
- url: 'https://onlinejudge.org',
3011
- },
3012
- [exports.Judge.AT_CODER]: {
3013
- value: exports.Judge.AT_CODER,
3014
- label: 'AtCoder',
3015
- logo: 'https://images.juki.pub/c/at-coder-logo-color.png',
3016
- logoSize: [762.997, 675],
3017
- url: 'https://atcoder.jp',
3018
- },
3019
- [exports.Judge.CODECHEF]: {
3020
- value: exports.Judge.CODECHEF,
3021
- label: 'Codechef',
3022
- logo: 'https://images.juki.pub/c/codechef-logo-color.svg',
3023
- logoSize: [1207.7, 453.17],
3024
- url: 'https://www.codechef.com',
3025
- },
3026
- [exports.Judge.TOPCODER]: {
3027
- value: exports.Judge.TOPCODER,
3028
- label: 'Topcoder',
3029
- logo: 'https://images.juki.pub/c/topcoder-logo-color.png',
3030
- logoSize: [971.99, 415.99],
3031
- url: 'https://www.topcoder.com',
3032
- },
3033
- [exports.Judge.LEETCODE]: {
3034
- value: exports.Judge.LEETCODE,
3035
- label: 'LeetCode',
3036
- logo: 'https://images.juki.pub/assets/leetcode-logo-color.svg',
3037
- logoSize: [95, 111],
3038
- url: 'https://leetcode.com',
3039
- // getProblemUrl: (problemKey: string) => {
3040
- // return `https://leetcode.com/problems/${problemKey.replace('PL-', '')}`;
3041
- // },
3042
- // getProfileUrl: (userNickname: string) => {
3043
- // return `https://leetcode.com/u/${userNickname}`;
3044
- // },
3045
- // getSubmissionUrl: (problemKey: string, submissionId: string, username: string, submissionRunId: string) => {
3046
- // return `https://leetcode.com/problems/${problemKey.replace('PL-', '')}/submissions/${submissionRunId}`;
3047
- // },
3048
- },
2968
+ const isWebsocketSubscription = (event) => {
2969
+ return (Object.values(exports.WebSocketSubscriptionEvent).includes(event?.event) || Object.values(exports.WebSocketMessageEvent).includes(event?.event))
2970
+ && typeof event?.clientId === 'string' && !!event.clientId;
3049
2971
  };
3050
- const RUNNER_ACCEPTED_PROBLEM_MODES = [
3051
- exports.ProblemScoringMode.TOTAL,
3052
- exports.ProblemScoringMode.SUBTASK,
3053
- exports.ProblemScoringMode.PARTIAL,
3054
- ];
3055
- const RUNNER_ACCEPTED_PROBLEM_TYPES = [
3056
- exports.ProblemType.STANDARD,
3057
- exports.ProblemType.DYNAMIC,
3058
- ];
3059
- const RUNNER_ACCEPTED_PROGRAMMING_LANGUAGES = [
3060
- exports.CodeLanguage.C_11,
3061
- exports.CodeLanguage.CPP_11,
3062
- exports.CodeLanguage.CPP_20,
3063
- exports.CodeLanguage.JAVA_21,
3064
- exports.CodeLanguage.PYTHON_3,
3065
- exports.CodeLanguage.PYTHON_PYPY_3,
3066
- exports.CodeLanguage.JAVASCRIPT_NODE_JS_22,
3067
- exports.CodeLanguage.PSEUDOCODE_PSEINT,
3068
- ];
3069
- const ACCEPTED_PROGRAMMING_LANGUAGES = [
3070
- ...RUNNER_ACCEPTED_PROGRAMMING_LANGUAGES,
3071
- ];
3072
- const PROBLEM_VERDICT = {
3073
- [exports.ProblemVerdict.NONE]: { value: exports.ProblemVerdict.NONE, label: 'none', color: '#555555' },
3074
- [exports.ProblemVerdict.PENDING]: { value: exports.ProblemVerdict.PENDING, label: 'pending', color: '#79B6FD' },
3075
- [exports.ProblemVerdict.HIDDEN]: { value: exports.ProblemVerdict.HIDDEN, label: 'hidden', color: '#555555' },
3076
- [exports.ProblemVerdict.AC]: { value: exports.ProblemVerdict.AC, label: 'accepted', color: '#43D787' },
3077
- [exports.ProblemVerdict.PE]: { value: exports.ProblemVerdict.PE, label: 'presentation error', color: '#55db93' },
3078
- [exports.ProblemVerdict.PA]: { value: exports.ProblemVerdict.PA, label: 'partial accepted', color: '#55db93' },
3079
- [exports.ProblemVerdict.CE]: { value: exports.ProblemVerdict.CE, label: 'compilation error', color: '#FE9F9F' },
3080
- [exports.ProblemVerdict.RE]: { value: exports.ProblemVerdict.RE, label: 'runtime error', color: '#FE9F9F' },
3081
- [exports.ProblemVerdict.TLE]: { value: exports.ProblemVerdict.TLE, label: 'time limit exceed', color: '#FE9F9F' },
3082
- [exports.ProblemVerdict.MLE]: { value: exports.ProblemVerdict.MLE, label: 'memory limit exceed', color: '#FE9F9F' },
3083
- [exports.ProblemVerdict.WA]: { value: exports.ProblemVerdict.WA, label: 'wrong answer', color: '#FE9F9F' },
2972
+ // Custom CHANNEL_PUBLISH_MESSAGES
2973
+ const isPingWebSocketEventDTO = (event) => {
2974
+ return isWebsocketSubscription(event)
2975
+ && event?.event === exports.WebSocketMessageEvent.PING;
2976
+ };
2977
+ const isClientTrackLocationWebSocketEventDTO = (event) => {
2978
+ return isWebsocketSubscription(event)
2979
+ && event?.event === exports.WebSocketMessageEvent.CLIENT_TRACK_LOCATION;
2980
+ };
2981
+ const isClientTrackScreenshotWebSocketEventDTO = (event) => {
2982
+ return isWebsocketSubscription(event)
2983
+ && event?.event === exports.WebSocketMessageEvent.CLIENT_TRACK_SCREENSHOT;
2984
+ };
2985
+ const isClientTrackDeviceWebSocketEventDTO = (event) => {
2986
+ return isWebsocketSubscription(event)
2987
+ && event?.event === exports.WebSocketMessageEvent.CLIENT_TRACK_DEVICE;
2988
+ };
2989
+ const isChatCompletionsWebSocketEventDTO = (event) => {
2990
+ return isWebsocketSubscription(event)
2991
+ && event?.event === exports.WebSocketMessageEvent.CHAT_COMPLETIONS;
2992
+ };
2993
+ // CHANNEL_PUBLISH_SUBSCRIPTIONS
2994
+ const isSubscribeCodeRunStatusWebSocketEventDTO = (event) => {
2995
+ return isWebsocketSubscription(event)
2996
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CODE_RUN_STATUS
2997
+ && typeof event?.runId === 'string' && !!event.runId;
2998
+ };
2999
+ const isUnsubscribeCodeRunStatusWebSocketEventDTO = (event) => {
3000
+ return isWebsocketSubscription(event)
3001
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CODE_RUN_STATUS
3002
+ && typeof event?.runId === 'string' && !!event.runId;
3003
+ };
3004
+ const isSubscribeSubmissionRunStatusWebSocketEventDTO = (event) => {
3005
+ return isWebsocketSubscription(event)
3006
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSION_RUN_STATUS
3007
+ && typeof event?.submitId === 'string' && !!event.submitId;
3008
+ };
3009
+ const isUnsubscribeSubmissionRunStatusWebSocketEventDTO = (event) => {
3010
+ return isWebsocketSubscription(event)
3011
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSION_RUN_STATUS
3012
+ && typeof event?.submitId === 'string' && !!event.submitId;
3013
+ };
3014
+ const isSubscribeGetDataWebSocketEventDTO = (event) => {
3015
+ return isWebsocketSubscription(event)
3016
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_GET_DATA;
3017
+ };
3018
+ const isUnsubscribeGetDataWebSocketEventDTO = (event) => {
3019
+ return isWebsocketSubscription(event)
3020
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_GET_DATA;
3021
+ };
3022
+ const isSubscribeProblemCrawledWebSocketEventDTO = (event) => {
3023
+ return isWebsocketSubscription(event)
3024
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_PROBLEM_CRAWLED;
3025
+ };
3026
+ const isUnsubscribeProblemCrawledWebSocketEventDTO = (event) => {
3027
+ return isWebsocketSubscription(event)
3028
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_PROBLEM_CRAWLED;
3029
+ };
3030
+ const isSubscribeSubmissionsCrawlWebSocketEventDTO = (event) => {
3031
+ return isWebsocketSubscription(event)
3032
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSIONS_CRAWL;
3033
+ };
3034
+ const isUnsubscribeSubmissionsCrawlWebSocketEventDTO = (event) => {
3035
+ return isWebsocketSubscription(event)
3036
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSIONS_CRAWL;
3037
+ };
3038
+ const isSubscribeContestChangesWebSocketEventDTO = (event) => {
3039
+ return isWebsocketSubscription(event)
3040
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CONTEST_CHANGES;
3041
+ };
3042
+ const isUnsubscribeContestChangesWebSocketEventDTO = (event) => {
3043
+ return isWebsocketSubscription(event)
3044
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CONTEST_CHANGES;
3045
+ };
3046
+ const isSubscribeClientTrackWebSocketEventDTO = (event) => {
3047
+ return isWebsocketSubscription(event)
3048
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK;
3049
+ };
3050
+ const isUnsubscribeClientTrackWebSocketEventDTO = (event) => {
3051
+ return isWebsocketSubscription(event)
3052
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK;
3053
+ };
3054
+ const isSubscribeUserNotificationWebSocketEventDTO = (event) => {
3055
+ return isWebsocketSubscription(event)
3056
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_USER_NOTIFICATION;
3057
+ };
3058
+ const isUnsubscribeUserNotificationWebSocketEventDTO = (event) => {
3059
+ return isWebsocketSubscription(event)
3060
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
3061
+ };
3062
+ const isSubscribeClientTrackDataWebSocketEventDTO = (event) => {
3063
+ return isWebsocketSubscription(event)
3064
+ && event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK_DATA
3065
+ && typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
3066
+ };
3067
+ const isUnsubscribeClientTrackDataWebSocketEventDTO = (event) => {
3068
+ return isWebsocketSubscription(event)
3069
+ && event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK_DATA
3070
+ && typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
3071
+ };
3072
+ // is WebSocketResponseEventDTO, CHANNEL_SUBSCRIBE_CLIENT
3073
+ const isWebSocketResponseEventDTO = (event) => {
3074
+ return Object.values(exports.WebSocketResponseEvent).includes(event?.event)
3075
+ && typeof event?.key === 'string'
3076
+ && typeof event?.connectionId === 'string'
3077
+ && typeof event?.messageTimestamp === 'number' && !!event.messageTimestamp;
3078
+ };
3079
+ const isPongWebSocketResponseEventDTO = (event) => {
3080
+ return isWebSocketResponseEventDTO(event)
3081
+ && event?.event === exports.WebSocketResponseEvent.PONG
3082
+ && !!event?.data;
3083
+ };
3084
+ const isCodeRunStatusMessageWebSocketResponseEventDTO = (event) => {
3085
+ return isWebSocketResponseEventDTO(event)
3086
+ && event?.event === exports.WebSocketResponseEvent.CODE_RUN_STATUS
3087
+ && typeof event?.runId === 'string' && !!event.runId
3088
+ && event?.status in exports.SubmissionRunStatus;
3089
+ };
3090
+ const isSubmissionRunStatusMessageWebSocketResponseEventDTO = (event) => {
3091
+ return isWebSocketResponseEventDTO(event)
3092
+ && event?.event === exports.WebSocketResponseEvent.SUBMISSION_RUN_STATUS
3093
+ && typeof event?.submitId === 'string' && !!event.submitId
3094
+ && event?.status in exports.SubmissionRunStatus
3095
+ && event?.verdict in exports.ProblemVerdict
3096
+ && typeof event?.points === 'number';
3097
+ };
3098
+ const isUserMessageWebSocketResponseEventDTO = (event) => {
3099
+ return isWebSocketResponseEventDTO(event)
3100
+ && event?.event === exports.WebSocketResponseEvent.USER_MESSAGE
3101
+ && typeof event?.user?.nickname === 'string' && !!event.user?.nickname
3102
+ && typeof event?.user?.imageUrl === 'string' && !!event.user?.imageUrl
3103
+ && typeof event?.user?.company?.key === 'string' && !!event.user?.company?.key
3104
+ && !!event?.content;
3105
+ };
3106
+ const isSendDataWebSocketResponseEventDTO = (event) => {
3107
+ return [
3108
+ exports.WebSocketResponseEvent.SEND_DATA_ECS_TASK_DEFINITIONS_LIST,
3109
+ exports.WebSocketResponseEvent.SEND_DATA_EC2_INSTANCES_LIST,
3110
+ exports.WebSocketResponseEvent.SEND_DATA_ECS_TASKS_LIST,
3111
+ exports.WebSocketResponseEvent.SEND_DATA_SSM_SESSIONS_LIST,
3112
+ exports.WebSocketResponseEvent.SEND_DATA_RUN_COMMAND,
3113
+ exports.WebSocketResponseEvent.SEND_DATA_CLIENT_TRACK,
3114
+ exports.WebSocketResponseEvent.SEND_DATA_CHAT_COMPLETIONS,
3115
+ ].includes(event?.event)
3116
+ && typeof event?.dataId === 'string' && !!event.dataId
3117
+ && !!event?.content;
3118
+ };
3119
+ const isSendDataEcsTaskDefinitionListWebSocketResponseEventDTO = (event) => {
3120
+ return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3121
+ && event?.event === exports.WebSocketResponseEvent.SEND_DATA_ECS_TASK_DEFINITIONS_LIST;
3122
+ };
3123
+ const isSendDataEc2InstancesListWebSocketResponseEventDTO = (event) => {
3124
+ return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3125
+ && event?.event === exports.WebSocketResponseEvent.SEND_DATA_EC2_INSTANCES_LIST;
3126
+ };
3127
+ const isSendDataEcsTasksListWebSocketResponseEventDTO = (event) => {
3128
+ return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3129
+ && event?.event === exports.WebSocketResponseEvent.SEND_DATA_ECS_TASKS_LIST;
3130
+ };
3131
+ const isSendDataSsmSessionsListWebSocketResponseEventDTO = (event) => {
3132
+ return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3133
+ && event?.event === exports.WebSocketResponseEvent.SEND_DATA_SSM_SESSIONS_LIST;
3134
+ };
3135
+ const isSendDataRunCommandWebSocketResponseEventDTO = (event) => {
3136
+ return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3137
+ && event?.event === exports.WebSocketResponseEvent.SEND_DATA_RUN_COMMAND;
3138
+ };
3139
+ const isSendDataClientTrackWebSocketResponseEventDTO = (event) => {
3140
+ return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3141
+ && event?.event === exports.WebSocketResponseEvent.SEND_DATA_CLIENT_TRACK;
3142
+ };
3143
+ const isSenDataChatCompletionsWebSocketResponseEventDTO = (event) => {
3144
+ return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3145
+ && event?.event === exports.WebSocketResponseEvent.SEND_DATA_CHAT_COMPLETIONS;
3084
3146
  };
3085
- const PROBLEM_VERDICTS = [
3086
- exports.ProblemVerdict.NONE,
3087
- exports.ProblemVerdict.PENDING,
3088
- exports.ProblemVerdict.AC,
3089
- exports.ProblemVerdict.PE,
3090
- exports.ProblemVerdict.PA,
3091
- exports.ProblemVerdict.CE,
3092
- exports.ProblemVerdict.RE,
3093
- exports.ProblemVerdict.TLE,
3094
- exports.ProblemVerdict.MLE,
3095
- exports.ProblemVerdict.WA,
3096
- ];
3097
- const SUBMISSION_RUN_STATUS = {
3098
- [exports.SubmissionRunStatus.NONE]: { value: exports.SubmissionRunStatus.NONE, label: 'none' }, // status
3099
- [exports.SubmissionRunStatus.RECEIVED]: { value: exports.SubmissionRunStatus.RECEIVED, label: 'received' }, // state
3100
- [exports.SubmissionRunStatus.COMPILING]: { value: exports.SubmissionRunStatus.COMPILING, label: 'compiling' }, // state
3101
- [exports.SubmissionRunStatus.COMPILED]: { value: exports.SubmissionRunStatus.COMPILED, label: 'compiled' }, // status
3102
- [exports.SubmissionRunStatus.COMPILATION_ERROR]: { value: exports.SubmissionRunStatus.COMPILATION_ERROR, label: 'compilation error' }, // status
3103
- [exports.SubmissionRunStatus.FETCHING_TEST_CASES]: {
3104
- value: exports.SubmissionRunStatus.FETCHING_TEST_CASES,
3105
- label: 'fetching test cases',
3106
- }, // state
3107
- [exports.SubmissionRunStatus.RUNNING_TEST_CASE]: { value: exports.SubmissionRunStatus.RUNNING_TEST_CASE, label: 'running test case' }, // state
3108
- [exports.SubmissionRunStatus.RUNNING_TEST_CASES]: {
3109
- value: exports.SubmissionRunStatus.RUNNING_TEST_CASES,
3110
- label: 'running test cases',
3111
- }, // state
3112
- [exports.SubmissionRunStatus.RUNNING_SAMPLE_TEST_CASES]: {
3113
- value: exports.SubmissionRunStatus.RUNNING_SAMPLE_TEST_CASES,
3114
- label: 'running sample cases',
3115
- }, // state
3116
- [exports.SubmissionRunStatus.EXECUTED_TEST_CASE]: {
3117
- value: exports.SubmissionRunStatus.EXECUTED_TEST_CASE,
3118
- label: 'executed test case',
3119
- }, // status
3120
- [exports.SubmissionRunStatus.FAILED_TEST_CASE]: { value: exports.SubmissionRunStatus.FAILED_TEST_CASE, label: 'failed test case' }, // status
3121
- [exports.SubmissionRunStatus.JUDGING_TEST_CASE]: { value: exports.SubmissionRunStatus.JUDGING_TEST_CASE, label: 'judging test case' }, // state
3122
- [exports.SubmissionRunStatus.GRADING]: { value: exports.SubmissionRunStatus.GRADING, label: 'grading' }, // status
3123
- [exports.SubmissionRunStatus.FAILED]: { value: exports.SubmissionRunStatus.FAILED, label: 'failed' }, // status
3124
- [exports.SubmissionRunStatus.COMPLETED]: { value: exports.SubmissionRunStatus.COMPLETED, label: 'completed' }, // status
3147
+ const isProblemCrawledWebSocketResponseEventDTO = (event) => {
3148
+ return isWebSocketResponseEventDTO(event)
3149
+ && event?.event === exports.WebSocketResponseEvent.PROBLEM_CRAWLED
3150
+ && !!event?.content;
3125
3151
  };
3126
- const RUNNER_TYPE = {
3127
- [exports.RunnerType.HIGH_PERFORMANCE]: { value: exports.RunnerType.HIGH_PERFORMANCE, label: 'high performance' },
3128
- [exports.RunnerType.LOW_PERFORMANCE]: { value: exports.RunnerType.LOW_PERFORMANCE, label: 'low performance' },
3152
+ const isSubmissionsCrawlWebSocketResponseEventDTO = (event) => {
3153
+ return isWebSocketResponseEventDTO(event)
3154
+ && event?.event === exports.WebSocketResponseEvent.SUBMISSIONS_CRAWL
3155
+ && !!event?.content;
3129
3156
  };
3130
-
3131
- const PROBLEM_INPUT = {
3132
- [exports.ProblemInput.STANDARD]: { value: exports.ProblemInput.STANDARD, label: 'standard' },
3133
- [exports.ProblemInput.INTERACTIVE]: { value: exports.ProblemInput.INTERACTIVE, label: 'interactive' },
3157
+ const isContestChangesWebSocketResponseEventDTO = (event) => {
3158
+ return isWebSocketResponseEventDTO(event)
3159
+ && event?.event === exports.WebSocketResponseEvent.CONTEST_CHANGES
3160
+ && !!event?.content;
3134
3161
  };
3135
- const PROBLEM_OUTPUT = {
3136
- [exports.ProblemOutput.STANDARD]: { value: exports.ProblemOutput.STANDARD, label: 'standard' },
3137
- [exports.ProblemOutput.DYNAMIC]: { value: exports.ProblemOutput.DYNAMIC, label: 'dynamic' },
3138
- [exports.ProblemOutput.INTERACTIVE]: { value: exports.ProblemOutput.INTERACTIVE, label: 'interactive' },
3162
+ const isClientTrackWebSocketResponseEventDTO = (event) => {
3163
+ return isWebSocketResponseEventDTO(event)
3164
+ && event?.event === exports.WebSocketResponseEvent.CLIENT_TRACK;
3139
3165
  };
3140
- const PROBLEM_MODES = [exports.ProblemScoringMode.TOTAL, exports.ProblemScoringMode.SUBTASK, exports.ProblemScoringMode.PARTIAL];
3141
- const PROBLEM_MODE = {
3142
- [exports.ProblemScoringMode.TOTAL]: {
3143
- value: exports.ProblemScoringMode.TOTAL,
3144
- label: 'total',
3145
- description: 'if all test cases are Accepted the result is Accepted '
3146
- + 'otherwise it will be Runtime Error, Time Limited Exceeded, Memory Limited Exceeded, Wrong Answer or Presentation Error in that order.',
3147
- },
3148
- [exports.ProblemScoringMode.SUBTASK]: {
3149
- value: exports.ProblemScoringMode.SUBTASK,
3150
- label: 'subtask',
3151
- description: 'the test cases are grouped and each group of test cases is assigned a score, '
3152
- + 'if all test cases in a group are Accepted then the score assigned to that group of test cases is added to total score, '
3153
- + 'if total score is equal to the sum of the assigned scores of all groups of test cases then the result is Accepted, '
3154
- + 'otherwise if the total score is greater than zero the result is Partial Accepted with the total accumulated score, '
3155
- + 'otherwise it will be Runtime Error, Time Limited Exceeded, Memory Limited Exceeded, Wrong Answer or Presentation Error in that order.',
3156
- },
3157
- [exports.ProblemScoringMode.PARTIAL]: {
3158
- value: exports.ProblemScoringMode.PARTIAL,
3159
- label: 'partial',
3160
- description: 'the test cases are grouped and each group is associated with X points, '
3161
- + 'and each test case in a group scores X points ',
3162
- },
3166
+ const isUserNotificationWebSocketResponseEventDTO = (event) => {
3167
+ return [
3168
+ exports.WebSocketResponseEvent.USER_NOTIFICATION_SUBMISSION,
3169
+ exports.WebSocketResponseEvent.USER_NOTIFICATION_CONTEST_CLARIFICATION,
3170
+ ].includes(event?.event)
3171
+ && !!event?.content;
3163
3172
  };
3164
- const PROBLEM_TYPES = [exports.ProblemType.STANDARD, exports.ProblemType.DYNAMIC, exports.ProblemType.INTERACTIVE];
3165
- const PROBLEM_TYPE = {
3166
- [exports.ProblemType.STANDARD]: {
3167
- value: exports.ProblemType.STANDARD,
3168
- label: 'standard',
3169
- description: 'The contestant submit a single source code in one of the allowed programming languages. '
3170
- + 'The source code is either standalone or to be compiled. '
3171
- + 'The resulting user\'s executable does I/O standard input and output. '
3172
- + 'The output produced by the contestant\'s program is then compared to the correct output using a simple diff algorithm.',
3173
- },
3174
- [exports.ProblemType.INTERACTIVE]: {
3175
- value: exports.ProblemType.INTERACTIVE, label: 'interactive', description: 'developing..',
3176
- },
3177
- [exports.ProblemType.DYNAMIC]: {
3178
- value: exports.ProblemType.DYNAMIC,
3179
- label: 'dynamic',
3180
- description: 'The contestant submit a single source code in one of the allowed programming languages. '
3181
- + 'The user\'s source code is either standalone or to be compiled. '
3182
- + 'The resulting user\'s executable does I/O standard input and output. '
3183
- + 'The output produced by the contestant\'s program is saved. '
3184
- + 'The problem editor save a single source code in C++ 17. '
3185
- + 'The editor\'s source code can read judge input filepath argv[1], judge output filepath argv[2], user\'s output filepath argv[3], user\'s error filepath argv[4], user\'s log filepath argv[5], user\'s source filepath argv[6] and submission information filepath argv[7] (companyId, submitId, runId, userId, contestId, problemId, language, userNickname, timestamp). '
3186
- + 'The resulting editor\'s executable should be "AC" or a number between 1 and 100 for partial accepted',
3187
- },
3173
+ const isUserNotificationSubmissionWebSocketResponseEventDTO = (event) => {
3174
+ return isWebSocketResponseEventDTO(event) && isUserNotificationWebSocketResponseEventDTO(event)
3175
+ && event?.event === exports.WebSocketResponseEvent.USER_NOTIFICATION_SUBMISSION;
3188
3176
  };
3189
- const PROBLEM_ROLE = {
3190
- [exports.Role.RESTRICTED]: { value: exports.Role.RESTRICTED, label: 'restricted', level: 7 },
3191
- [exports.Role.GUEST]: { value: exports.Role.GUEST, label: 'guest', level: 6 },
3192
- [exports.Role.REGULAR]: { value: exports.Role.REGULAR, label: 'regular', level: 5 },
3193
- [exports.Role.CREATOR]: { value: exports.Role.CREATOR, label: 'creator', level: 4 },
3194
- [exports.Role.MANAGER]: { value: exports.Role.MANAGER, label: 'manager', level: 3 },
3195
- [exports.Role.MASTER]: { value: exports.Role.MASTER, label: 'master', level: 2 },
3196
- [exports.Role.ADMIN]: { value: exports.Role.ADMIN, label: 'admin', level: 1 },
3197
- [exports.Role.SUPER_ADMIN]: { value: exports.Role.SUPER_ADMIN, label: 'super admin', level: 0 },
3177
+ const isUserNotificationContestClarificationWebSocketResponseEventDTO = (event) => {
3178
+ return isWebSocketResponseEventDTO(event) && isUserNotificationWebSocketResponseEventDTO(event)
3179
+ && event?.event === exports.WebSocketResponseEvent.USER_NOTIFICATION_CONTEST_CLARIFICATION;
3180
+ };
3181
+ // generic
3182
+ const getWebSocketResponseEventKey = (event, clientId, id) => {
3183
+ return `${event}-${clientId}-${id}`;
3184
+ };
3185
+ const isWebSocketChannelsMessageDTO = (message) => {
3186
+ return Array.isArray(message?.channels)
3187
+ && message.channels.every((channel) => typeof channel === 'string' && !!channel)
3188
+ && Object.values(exports.WebSocketResponseEvent).includes(message?.event?.event);
3189
+ };
3190
+ /**
3191
+ * Key used by the client to dispatch a response received on a TOPIC channel to its subscribers.
3192
+ * It is the same key that `getKeyWebSocketEventDTO` (base-ui) computes for the subscription.
3193
+ * Returns null when the response is not addressed to this client.
3194
+ */
3195
+ const getWebSocketResponseEventKeyOfResponse = (response, clientId) => {
3196
+ if (isCodeRunStatusMessageWebSocketResponseEventDTO(response)) {
3197
+ return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.CODE_RUN_STATUS, clientId, response.runId);
3198
+ }
3199
+ if (isSubmissionRunStatusMessageWebSocketResponseEventDTO(response)) {
3200
+ return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.SUBMISSION_RUN_STATUS, clientId, response.submitId);
3201
+ }
3202
+ if (isSendDataWebSocketResponseEventDTO(response)) {
3203
+ return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.SEND_DATA_, clientId, response.dataId);
3204
+ }
3205
+ if (isContestChangesWebSocketResponseEventDTO(response)) {
3206
+ return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.CONTEST_CHANGES, clientId, response.content.contestKey);
3207
+ }
3208
+ if (isProblemCrawledWebSocketResponseEventDTO(response)) {
3209
+ return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.PROBLEM_CRAWLED, clientId, response.content.problemKey);
3210
+ }
3211
+ if (isSubmissionsCrawlWebSocketResponseEventDTO(response)) {
3212
+ return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.SUBMISSIONS_CRAWL, clientId, join([response.content.contestKey, response.content.problemKeys]));
3213
+ }
3214
+ if (isClientTrackWebSocketResponseEventDTO(response)) {
3215
+ // the command is sent to the session channel, `key` holds the targeted client
3216
+ return response.key === clientId ? getWebSocketResponseEventKey(exports.WebSocketResponseEvent.CLIENT_TRACK, clientId, '*') : null;
3217
+ }
3218
+ if (isUserNotificationWebSocketResponseEventDTO(response)) {
3219
+ return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.USER_NOTIFICATION_, clientId, '*');
3220
+ }
3221
+ return null;
3222
+ };
3223
+ /**
3224
+ * TOPIC channel that the client has to attach to receive the events of a subscription,
3225
+ * or null when the events arrive by the private channels (session / user) the client is always attached to.
3226
+ * Ably rejects the attach if the token has no capability for the channel.
3227
+ */
3228
+ const getChannelOfWebSocketSubscribeEvent = (event) => {
3229
+ if (isSubscribeSubmissionRunStatusWebSocketEventDTO(event)) {
3230
+ return CHANNEL_SUBMISSION(event.submitId);
3231
+ }
3232
+ if (isSubscribeProblemCrawledWebSocketEventDTO(event)) {
3233
+ return CHANNEL_PROBLEM(event.problemKey);
3234
+ }
3235
+ if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
3236
+ return CHANNEL_CONTEST(event.contestKey, exports.ContestChannelRole.SPECTATORS);
3237
+ }
3238
+ if (isSubscribeClientTrackDataWebSocketEventDTO(event)) {
3239
+ return CHANNEL_CLIENT_TRACK(event.trackedClientId);
3240
+ }
3241
+ return null;
3242
+ };
3243
+ /**
3244
+ * Contest whose role channels the client needs (the API grants them when the token is requested with this contest).
3245
+ */
3246
+ const getContestKeyOfWebSocketSubscribeEvent = (event) => {
3247
+ if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
3248
+ return event.contestKey;
3249
+ }
3250
+ return null;
3251
+ };
3252
+
3253
+ function splitTime(timeRemaining) {
3254
+ const remaining = [];
3255
+ // const aYearMilliseconds = 1000 * 60 * 60 * 24 * 365;
3256
+ // const remainingYears = Math.floor(timeRemaining / aYearMilliseconds);
3257
+ // remaining.push({ remaining: remainingYears, label: 'years', milliseconds: aYearMilliseconds });
3258
+ // const aWeekMilliseconds = 1000 * 60 * 60 * 24 * 7;
3259
+ // const remainingWeeks = Math.floor((timeRemaining % aYearMilliseconds) / aWeekMilliseconds);
3260
+ // remaining.push({ remaining: remainingWeeks, label: 'weeks', milliseconds: aWeekMilliseconds });
3261
+ const aSecondMilliseconds = 1000;
3262
+ const aMinuteMilliseconds = aSecondMilliseconds * 60;
3263
+ const aHourMilliseconds = aMinuteMilliseconds * 60;
3264
+ const aDayMilliseconds = aHourMilliseconds * 24;
3265
+ const aWeekMilliseconds = aDayMilliseconds * 7;
3266
+ const remainingWeeks = Math.floor(timeRemaining / aWeekMilliseconds);
3267
+ remaining.push({
3268
+ remaining: remainingWeeks,
3269
+ label: remainingWeeks === 1 ? 'week' : 'weeks',
3270
+ abbreviatedLabel: 'w',
3271
+ milliseconds: aWeekMilliseconds,
3272
+ digits: 2,
3273
+ });
3274
+ const remainingDays = Math.floor((timeRemaining % aWeekMilliseconds) / aDayMilliseconds);
3275
+ remaining.push({
3276
+ remaining: remainingDays,
3277
+ label: remainingDays === 1 ? 'day' : 'days',
3278
+ abbreviatedLabel: 'd',
3279
+ milliseconds: aDayMilliseconds,
3280
+ digits: 2,
3281
+ });
3282
+ const remainingHours = Math.floor((timeRemaining % aDayMilliseconds) / aHourMilliseconds);
3283
+ remaining.push({
3284
+ remaining: remainingHours,
3285
+ label: remainingHours === 1 ? 'hour' : 'hours',
3286
+ abbreviatedLabel: 'h',
3287
+ milliseconds: aHourMilliseconds,
3288
+ digits: 2,
3289
+ });
3290
+ const remainingMinutes = Math.floor((timeRemaining % aHourMilliseconds) / aMinuteMilliseconds);
3291
+ remaining.push({
3292
+ remaining: remainingMinutes,
3293
+ label: remainingMinutes === 1 ? 'minute' : 'minutes',
3294
+ abbreviatedLabel: 'm',
3295
+ milliseconds: aMinuteMilliseconds,
3296
+ digits: 2,
3297
+ });
3298
+ const remainingSeconds = Math.floor((timeRemaining % aMinuteMilliseconds) / aSecondMilliseconds);
3299
+ remaining.push({
3300
+ remaining: remainingSeconds,
3301
+ label: remainingSeconds === 1 ? 'second' : 'seconds',
3302
+ abbreviatedLabel: 's',
3303
+ milliseconds: aSecondMilliseconds,
3304
+ digits: 2,
3305
+ });
3306
+ const remainingMilliseconds = Math.floor(timeRemaining % aSecondMilliseconds);
3307
+ remaining.push({
3308
+ remaining: remainingMilliseconds,
3309
+ label: remainingMilliseconds === 1 ? 'millisecond' : 'milliseconds',
3310
+ abbreviatedLabel: 'ms',
3311
+ milliseconds: 1,
3312
+ digits: 3,
3313
+ });
3314
+ // while (remaining[0].remaining <= 0) {
3315
+ // remaining.shift();
3316
+ // if (remaining.length === 3) {
3317
+ // break;
3318
+ // }
3319
+ // }
3320
+ return remaining;
3321
+ }
3322
+ function normalizeToLocalStartOfDay(timestamp) {
3323
+ const date = new Date(timestamp);
3324
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
3325
+ }
3326
+ function normalizeToLocalStartOfHour(timestamp) {
3327
+ const date = new Date(timestamp);
3328
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours());
3329
+ }
3330
+ function normalizeToLocalStartOfMinutes(timestamp) {
3331
+ const date = new Date(timestamp);
3332
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
3333
+ }
3334
+ function normalizeToLocalStartOfSeconds(timestamp) {
3335
+ const date = new Date(timestamp);
3336
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
3337
+ }
3338
+ const getYears = (d) => d.getFullYear();
3339
+ const getMonths = (d) => d.getFullYear() * 12 + d.getMonth();
3340
+ const getDays = (d) => {
3341
+ return Math.floor(normalizeToLocalStartOfDay(d).getTime() / ONE_DAY);
3198
3342
  };
3343
+ const getHours = (d) => {
3344
+ return Math.floor(normalizeToLocalStartOfHour(d).getTime() / ONE_HOUR);
3345
+ };
3346
+ const getMinutes = (d) => {
3347
+ return Math.floor(normalizeToLocalStartOfMinutes(d).getTime() / ONE_MINUTE);
3348
+ };
3349
+ const getSeconds = (d) => {
3350
+ return Math.floor(normalizeToLocalStartOfSeconds(d).getTime() / 1000);
3351
+ };
3352
+ const getMilliseconds = (d) => d.getTime();
3199
3353
 
3200
- const _TYPE = ':type';
3201
- const _KEY = ':key';
3202
- const _TAB = ':tab';
3203
- const _SUB_TAB = ':subTab?';
3204
- const _SUB_SUB_TAB = ':subSubTab?';
3205
- const PAGE = 'page';
3206
- const PAGE_SIZE = 'size';
3207
-
3208
- const FILE_TYPE = {
3209
- [exports.FileType.FILE]: { value: exports.FileType.FILE, label: 'file' },
3210
- [exports.FileType.FOLDER]: { value: exports.FileType.FOLDER, label: 'folder' },
3354
+ const getUserKey = (userNickname, userCompanyKey) => {
3355
+ return userNickname + '|' + userCompanyKey;
3211
3356
  };
3212
- const FILE_ROLE = {
3213
- [exports.Role.RESTRICTED]: { value: exports.Role.RESTRICTED, label: 'restricted', level: 5 },
3214
- [exports.Role.GUEST]: { value: exports.Role.GUEST, label: 'guest', level: 4 },
3215
- [exports.Role.REGULAR]: { value: exports.Role.REGULAR, label: 'regular', level: 3 },
3216
- [exports.Role.MASTER]: { value: exports.Role.MASTER, label: 'master', level: 2 },
3217
- [exports.Role.ADMIN]: { value: exports.Role.ADMIN, label: 'admin', level: 1 },
3218
- [exports.Role.SUPER_ADMIN]: { value: exports.Role.SUPER_ADMIN, label: 'super admin', level: 0 },
3357
+ const getParamsOfUserKey = (userKey) => {
3358
+ const [userNickname, userCompanyKey] = userKey.split('|');
3359
+ return { userNickname, userCompanyKey };
3219
3360
  };
3220
- const ENTITY_STATE = {
3221
- [exports.EntityState.RELEASED]: {
3222
- value: exports.EntityState.RELEASED,
3223
- label: 'released',
3224
- },
3225
- [exports.EntityState.ARCHIVED]: {
3226
- value: exports.EntityState.ARCHIVED,
3227
- label: 'archived',
3228
- },
3361
+ const getClientId = (sessionId, uiId) => {
3362
+ return `${sessionId}|${uiId}`;
3229
3363
  };
3230
- const ENTITY_ACCESS = {
3231
- [exports.EntityAccess.PRIVATE]: {
3232
- value: exports.EntityAccess.PRIVATE,
3233
- label: 'private',
3234
- description: 'the record will be visible and editable only to the owner',
3235
- },
3236
- [exports.EntityAccess.RESTRICTED]: {
3237
- value: exports.EntityAccess.RESTRICTED,
3238
- label: 'restricted',
3239
- description: 'the record will be visible to viewers and the owner and editable to editors and the owner',
3240
- },
3241
- [exports.EntityAccess.PUBLIC]: {
3242
- value: exports.EntityAccess.PUBLIC,
3243
- label: 'public',
3244
- description: 'the record will be visible to anyone and editable to editors and the owner',
3245
- },
3246
- [exports.EntityAccess.EXPOSED]: {
3247
- value: exports.EntityAccess.EXPOSED,
3248
- label: 'exposed',
3249
- description: 'the record will be visible and editable to anyone',
3250
- },
3364
+ const getParamsOfClientId = (clientId) => {
3365
+ const [sessionId, uiId] = clientId.split('|');
3366
+ return { sessionId, uiId };
3251
3367
  };
3252
3368
 
3253
- const SYSTEM_ROLE = {
3254
- [SystemRole.GUEST]: { value: SystemRole.GUEST, label: 'guest', level: 5 },
3255
- [SystemRole.REGULAR]: { value: SystemRole.REGULAR, label: 'regular', level: 4 },
3256
- [SystemRole.MANAGER]: { value: SystemRole.MANAGER, label: 'manager', level: 3 },
3257
- [SystemRole.MASTER]: { value: SystemRole.MASTER, label: 'master', level: 2 },
3258
- [SystemRole.ADMIN]: { value: SystemRole.ADMIN, label: 'admin', level: 1 },
3259
- [SystemRole.SUPER_ADMIN]: { value: SystemRole.SUPER_ADMIN, label: 'super admin', level: 0 },
3369
+ const getWorksheetsInPages = (initialSheets) => {
3370
+ const sheets = [...initialSheets];
3371
+ if (sheets[0]?.type !== exports.WorksheetType.NEW_PAGE) {
3372
+ sheets.unshift(NEW_PAGE_SHEET());
3373
+ }
3374
+ let newPage = sheets[0];
3375
+ let content = [];
3376
+ const sheetsByPages = [];
3377
+ for (let i = 1; i < sheets.length; i++) {
3378
+ const sheet = sheets[i];
3379
+ if (sheet.type === exports.WorksheetType.NEW_PAGE) {
3380
+ sheetsByPages.push({
3381
+ header: newPage,
3382
+ content: [...content],
3383
+ });
3384
+ newPage = sheet;
3385
+ content = [];
3386
+ }
3387
+ else {
3388
+ content.push(sheet);
3389
+ }
3390
+ }
3391
+ sheetsByPages.push({
3392
+ header: newPage,
3393
+ content: [...content],
3394
+ });
3395
+ return sheetsByPages;
3260
3396
  };
3261
-
3262
- const MEMBER_ROLE = {
3263
- [MemberRole.COACH]: { value: MemberRole.COACH, label: 'coach' },
3264
- [MemberRole.CO_COACH]: { value: MemberRole.CO_COACH, label: 'co-coach' },
3265
- [MemberRole.STAFF]: { value: MemberRole.STAFF, label: 'staff' },
3266
- [MemberRole.ATTENDEE]: { value: MemberRole.ATTENDEE, label: 'attendee' },
3267
- [MemberRole.RESERVE]: { value: MemberRole.RESERVE, label: 'reserve' },
3268
- [MemberRole.CONTESTANT]: { value: MemberRole.CONTESTANT, label: 'contestant' },
3397
+ const getSummaryWorksheetsInPages = (initialSheets) => {
3398
+ const sheets = [...initialSheets];
3399
+ if (sheets[0]?.type !== exports.WorksheetType.NEW_PAGE) {
3400
+ sheets.unshift(NEW_PAGE_SHEET());
3401
+ }
3402
+ let newPage = sheets[0];
3403
+ let content = [];
3404
+ const sheetsByPages = [];
3405
+ for (let i = 1; i < sheets.length; i++) {
3406
+ const sheet = sheets[i];
3407
+ if (sheet.type === exports.WorksheetType.NEW_PAGE) {
3408
+ sheetsByPages.push({
3409
+ header: newPage,
3410
+ content: content.map(c => ({
3411
+ id: c.id,
3412
+ type: c.type,
3413
+ title: c.title,
3414
+ points: c.points,
3415
+ })),
3416
+ });
3417
+ newPage = sheet;
3418
+ content = [];
3419
+ }
3420
+ else {
3421
+ content.push(sheet);
3422
+ }
3423
+ }
3424
+ sheetsByPages.push({
3425
+ header: newPage,
3426
+ content: [...content],
3427
+ });
3428
+ return sheetsByPages;
3269
3429
  };
3270
- const TEAM_ROLE = {
3271
- [TeamRole.RESTRICTED]: { value: TeamRole.RESTRICTED, label: 'restricted', level: 5 },
3272
- [TeamRole.GUEST]: { value: TeamRole.GUEST, label: 'guest', level: 4 },
3273
- [TeamRole.REGULAR]: { value: TeamRole.REGULAR, label: 'regular', level: 3 },
3274
- [TeamRole.MANAGER]: { value: TeamRole.MANAGER, label: 'manager', level: 2 },
3275
- [TeamRole.ADMIN]: { value: TeamRole.ADMIN, label: 'admin', level: 1 },
3276
- [TeamRole.SUPER_ADMIN]: { value: TeamRole.SUPER_ADMIN, label: 'super admin', level: 0 },
3430
+ const getTotalExercisesOfSummaryWorksheetsInPages = (content) => content.reduce((sum, { content }) => sum + content.reduce((sum, { type }) => sum + +(type === exports.WorksheetType.QUIZ_OPTIONS || type === exports.WorksheetType.QUIZ_PROBLEM || type === exports.WorksheetType.QUIZ_TEXT), 0), 0);
3431
+ const isBasicWorksheet = (value) => {
3432
+ return typeof value?.id == 'string' && value.id
3433
+ && Object.values(exports.WorksheetType).includes(value?.type)
3434
+ && typeof value?.title == 'string'
3435
+ && typeof value?.points == 'number';
3277
3436
  };
3278
-
3279
- const ONE_SECOND = 1000;
3280
- const SEC_30 = ONE_SECOND * 30;
3281
- const SEC_60 = ONE_SECOND * 60;
3282
- const SEC_90 = ONE_SECOND * 90;
3283
- const SEC_120 = ONE_SECOND * 120;
3284
- const ONE_MINUTE = ONE_SECOND * 60;
3285
- const ONE_HOUR = ONE_MINUTE * 60;
3286
- const ONE_DAY = ONE_HOUR * 24;
3287
- const ONE_WEEK = ONE_DAY * 7;
3288
-
3289
- const USER_STATUS = {
3290
- [UserStatus.ACTIVE]: { value: UserStatus.ACTIVE, label: 'active' },
3291
- [UserStatus.REPORTED]: { value: UserStatus.REPORTED, label: 'reported' },
3292
- [UserStatus.ARCHIVED]: { value: UserStatus.ARCHIVED, label: 'archived' },
3437
+ const isJkmdSheet = (value) => {
3438
+ return isBasicWorksheet(value)
3439
+ && value?.type === exports.WorksheetType.JK_MD
3440
+ && typeof value?.content == 'string';
3293
3441
  };
3294
- const USER_ROLE = {
3295
- [UserRole.RESTRICTED]: { value: UserRole.RESTRICTED, label: 'restricted', level: 6 },
3296
- [UserRole.GUEST]: { value: UserRole.GUEST, label: 'guest', level: 5 },
3297
- [UserRole.LIMITED]: { value: UserRole.LIMITED, label: 'limited', level: 4 },
3298
- [UserRole.REGULAR]: { value: UserRole.REGULAR, label: 'regular', level: 3 },
3299
- [UserRole.MANAGER]: { value: UserRole.MANAGER, label: 'manager', level: 2 },
3300
- [UserRole.ADMIN]: { value: UserRole.ADMIN, label: 'admin', level: 1 },
3301
- [UserRole.SUPER_ADMIN]: { value: UserRole.SUPER_ADMIN, label: 'super admin', level: 0 },
3442
+ const isCodeEditorSheet = (value) => {
3443
+ return isBasicWorksheet(value)
3444
+ && value?.type === exports.WorksheetType.CODE_EDITOR
3445
+ && typeof value?.sourceCode === 'object' && value?.sourceCode !== null
3446
+ && value?.testCases === 'object' && value?.testCases !== null
3447
+ && Array.isArray(value?.languages)
3448
+ && typeof value?.height == 'number';
3302
3449
  };
3303
- const EMPTY_USER_PERMISSIONS = {
3304
- users: {
3305
- create: false,
3306
- manage: false,
3307
- administrate: false,
3308
- },
3309
- problems: {
3310
- create: false,
3311
- manage: false,
3312
- },
3313
- submissions: {
3314
- manage: false,
3315
- },
3316
- contests: {
3317
- create: false,
3318
- manage: false,
3319
- },
3320
- company: {
3321
- manage: false,
3322
- administrate: false,
3323
- },
3324
- services: {
3325
- administrate: false,
3326
- },
3450
+ const isQuizProblemSheet = (value) => {
3451
+ return isBasicWorksheet(value)
3452
+ && value?.type === exports.WorksheetType.QUIZ_PROBLEM
3453
+ && Object.values(exports.Judge).includes(value?.problemJudge) || typeof value?.problemJudge === 'string'
3454
+ && typeof value?.problemKey == 'string'
3455
+ && Array.isArray(value?.languages)
3456
+ && typeof value?.height == 'number';
3457
+ };
3458
+ const isQuizOptionsSheet = (value) => {
3459
+ return isBasicWorksheet(value)
3460
+ && value?.type === exports.WorksheetType.QUIZ_OPTIONS
3461
+ && typeof value?.description == 'string'
3462
+ && Array.isArray(value?.options)
3463
+ && value?.options.every((option) => typeof option?.label == 'string' && typeof option?.correct == 'boolean' && typeof option?.id == 'string')
3464
+ && typeof value?.multiple == 'boolean'
3465
+ && (value?.scoringMode === 'TOTAL' || value?.scoringMode === 'PARTIAL');
3466
+ };
3467
+ const isQuizTextSheet = (value) => {
3468
+ return isBasicWorksheet(value)
3469
+ && value?.type === exports.WorksheetType.QUIZ_TEXT
3470
+ && typeof value?.description == 'string'
3471
+ && typeof value?.answer == 'string'
3472
+ && ['text', 'number', 'textarea'].includes(value?.inputType);
3327
3473
  };
3328
-
3329
- const CHANNEL_PUBLISH_SUBSCRIPTIONS = 'pub:subscriptions';
3330
- const CHANNEL_SUBSCRIBE_NOTIFICATIONS = 'sub:notifications';
3331
- const CHANNEL_SUBSCRIBE_CLIENT = (clientId) => `sub:client:${clientId}`;
3332
- const CHANNEL_PUBLISH_MESSAGES = 'pub:messages';
3333
- const CHANNEL_PRESENCE_CLIENT = 'pre:client';
3334
-
3335
- exports.ContestProblemBlockedByType = void 0;
3336
- (function (ContestProblemBlockedByType) {
3337
- ContestProblemBlockedByType["UNMET_PREREQUISITES"] = "UNMET_PREREQUISITES";
3338
- ContestProblemBlockedByType["MAX_ACCEPTED_SUBMISSIONS_ACHIEVED"] = "MAX_ACCEPTED_SUBMISSIONS_ACHIEVED";
3339
- ContestProblemBlockedByType["START_TIME_IN_THE_FUTURE"] = "START_TIME_IN_THE_FUTURE";
3340
- ContestProblemBlockedByType["END_TIME_IN_THE_PAST"] = "END_TIME_IN_THE_PAST";
3341
- })(exports.ContestProblemBlockedByType || (exports.ContestProblemBlockedByType = {}));
3342
-
3343
- exports.MemberType = void 0;
3344
- (function (MemberType) {
3345
- MemberType["USER"] = "USER";
3346
- MemberType["TEAM"] = "TEAM";
3347
- })(exports.MemberType || (exports.MemberType = {}));
3348
3474
 
3349
3475
  exports.ACCEPTED_PROGRAMMING_LANGUAGES = ACCEPTED_PROGRAMMING_LANGUAGES;
3350
3476
  exports.ASPECT_RATIO = ASPECT_RATIO;
3351
3477
  exports.AssignmentState = AssignmentState;
3352
3478
  exports.AssignmentType = AssignmentType;
3479
+ exports.CHANNEL_CLIENT_TRACK = CHANNEL_CLIENT_TRACK;
3480
+ exports.CHANNEL_CLIENT_TRACK_ALL = CHANNEL_CLIENT_TRACK_ALL;
3481
+ exports.CHANNEL_CONTEST = CHANNEL_CONTEST;
3353
3482
  exports.CHANNEL_PRESENCE_CLIENT = CHANNEL_PRESENCE_CLIENT;
3483
+ exports.CHANNEL_PROBLEM = CHANNEL_PROBLEM;
3484
+ exports.CHANNEL_PROBLEM_ALL = CHANNEL_PROBLEM_ALL;
3354
3485
  exports.CHANNEL_PUBLISH_MESSAGES = CHANNEL_PUBLISH_MESSAGES;
3355
3486
  exports.CHANNEL_PUBLISH_SUBSCRIPTIONS = CHANNEL_PUBLISH_SUBSCRIPTIONS;
3487
+ exports.CHANNEL_SESSION = CHANNEL_SESSION;
3488
+ exports.CHANNEL_SUBMISSION = CHANNEL_SUBMISSION;
3489
+ exports.CHANNEL_SUBMISSION_ALL = CHANNEL_SUBMISSION_ALL;
3356
3490
  exports.CHANNEL_SUBSCRIBE_CLIENT = CHANNEL_SUBSCRIBE_CLIENT;
3357
3491
  exports.CHANNEL_SUBSCRIBE_NOTIFICATIONS = CHANNEL_SUBSCRIBE_NOTIFICATIONS;
3492
+ exports.CHANNEL_USER = CHANNEL_USER;
3358
3493
  exports.CODE_LANGUAGE = CODE_LANGUAGE;
3359
3494
  exports.COMPANY_PLAN = COMPANY_PLAN;
3360
3495
  exports.CONTEST_ROLE = CONTEST_ROLE;
@@ -3459,8 +3594,11 @@ exports.contentsResponse = contentsResponse;
3459
3594
  exports.errorsResponse = errorsResponse;
3460
3595
  exports.getAssignmentCommentKey = getAssignmentCommentKey;
3461
3596
  exports.getAssignmentUserCommentKey = getAssignmentUserCommentKey;
3597
+ exports.getChannelOfWebSocketSubscribeEvent = getChannelOfWebSocketSubscribeEvent;
3462
3598
  exports.getClientId = getClientId;
3599
+ exports.getContestChannelParams = getContestChannelParams;
3463
3600
  exports.getContestCommentKey = getContestCommentKey;
3601
+ exports.getContestKeyOfWebSocketSubscribeEvent = getContestKeyOfWebSocketSubscribeEvent;
3464
3602
  exports.getDataLog = getDataLog;
3465
3603
  exports.getDataOfTestCase = getDataOfTestCase;
3466
3604
  exports.getDays = getDays;
@@ -3482,6 +3620,7 @@ exports.getTotalExercisesOfSummaryWorksheetsInPages = getTotalExercisesOfSummary
3482
3620
  exports.getUserKey = getUserKey;
3483
3621
  exports.getVerdictFromTestCase = getVerdictFromTestCase;
3484
3622
  exports.getWebSocketResponseEventKey = getWebSocketResponseEventKey;
3623
+ exports.getWebSocketResponseEventKeyOfResponse = getWebSocketResponseEventKeyOfResponse;
3485
3624
  exports.getWorksheetsInPages = getWorksheetsInPages;
3486
3625
  exports.getYears = getYears;
3487
3626
  exports.humanFileSize = humanFileSize;
@@ -3520,6 +3659,7 @@ exports.isSendDataWebSocketResponseEventDTO = isSendDataWebSocketResponseEventDT
3520
3659
  exports.isStringJson = isStringJson;
3521
3660
  exports.isSubmissionRunStatusMessageWebSocketResponseEventDTO = isSubmissionRunStatusMessageWebSocketResponseEventDTO;
3522
3661
  exports.isSubmissionsCrawlWebSocketResponseEventDTO = isSubmissionsCrawlWebSocketResponseEventDTO;
3662
+ exports.isSubscribeClientTrackDataWebSocketEventDTO = isSubscribeClientTrackDataWebSocketEventDTO;
3523
3663
  exports.isSubscribeClientTrackWebSocketEventDTO = isSubscribeClientTrackWebSocketEventDTO;
3524
3664
  exports.isSubscribeCodeRunStatusWebSocketEventDTO = isSubscribeCodeRunStatusWebSocketEventDTO;
3525
3665
  exports.isSubscribeContestChangesWebSocketEventDTO = isSubscribeContestChangesWebSocketEventDTO;
@@ -3529,6 +3669,7 @@ exports.isSubscribeSubmissionRunStatusWebSocketEventDTO = isSubscribeSubmissionR
3529
3669
  exports.isSubscribeSubmissionsCrawlWebSocketEventDTO = isSubscribeSubmissionsCrawlWebSocketEventDTO;
3530
3670
  exports.isSubscribeUserNotificationWebSocketEventDTO = isSubscribeUserNotificationWebSocketEventDTO;
3531
3671
  exports.isTeamMember = isTeamMember;
3672
+ exports.isUnsubscribeClientTrackDataWebSocketEventDTO = isUnsubscribeClientTrackDataWebSocketEventDTO;
3532
3673
  exports.isUnsubscribeClientTrackWebSocketEventDTO = isUnsubscribeClientTrackWebSocketEventDTO;
3533
3674
  exports.isUnsubscribeCodeRunStatusWebSocketEventDTO = isUnsubscribeCodeRunStatusWebSocketEventDTO;
3534
3675
  exports.isUnsubscribeContestChangesWebSocketEventDTO = isUnsubscribeContestChangesWebSocketEventDTO;
@@ -3542,6 +3683,7 @@ exports.isUserMessageWebSocketResponseEventDTO = isUserMessageWebSocketResponseE
3542
3683
  exports.isUserNotificationContestClarificationWebSocketResponseEventDTO = isUserNotificationContestClarificationWebSocketResponseEventDTO;
3543
3684
  exports.isUserNotificationSubmissionWebSocketResponseEventDTO = isUserNotificationSubmissionWebSocketResponseEventDTO;
3544
3685
  exports.isUserNotificationWebSocketResponseEventDTO = isUserNotificationWebSocketResponseEventDTO;
3686
+ exports.isWebSocketChannelsMessageDTO = isWebSocketChannelsMessageDTO;
3545
3687
  exports.isWebSocketResponseEventDTO = isWebSocketResponseEventDTO;
3546
3688
  exports.isWebsocketSubscription = isWebsocketSubscription;
3547
3689
  exports.isWorksheetAssignment = isWorksheetAssignment;