├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── eslint.config.js ├── jest.config.ts ├── media ├── banners │ ├── chrome-large-promo.png │ ├── chrome-large-promo.svg │ ├── chrome-marquee-promo.png │ ├── chrome-marquee-promo.svg │ ├── chrome-small-promo.png │ ├── chrome-small-promo.svg │ ├── github-social-preview.png │ └── github-social-preview.svg └── icons │ ├── icon-128.png │ ├── icon-16.png │ ├── icon-19.png │ ├── icon-20.png │ ├── icon-24.png │ ├── icon-32.png │ ├── icon-38.png │ ├── icon-48.png │ ├── icon-64.png │ └── icon-96.png ├── package.json ├── pnpm-lock.yaml ├── scripts ├── build │ ├── extension.ts │ ├── test.ts │ └── utils.ts ├── generate-banners.ts ├── start │ ├── chrome.ts │ ├── firefox.ts │ └── utils.ts └── utils.ts ├── src ├── background.ts ├── content.ts ├── hosts │ ├── CHelperHost.ts │ ├── CustomHost.ts │ ├── Host.ts │ └── hosts.ts ├── models │ ├── Batch.ts │ ├── Contest.ts │ ├── IOConfiguration.ts │ ├── LanguageConfiguration.ts │ ├── Sendable.ts │ ├── Task.ts │ ├── TaskBuilder.ts │ ├── Test.ts │ ├── TestType.ts │ └── messaging.ts ├── options.html ├── options.ts ├── parsers │ ├── ContestParser.ts │ ├── Parser.ts │ ├── SimpleContestParser.ts │ ├── contest │ │ ├── A2OnlineJudgeContestParser.ts │ │ ├── AtCoderContestParser.ts │ │ ├── BAPSOJContestParser.ts │ │ ├── BUCTOJContestParser.ts │ │ ├── BeecrowdContestParser.ts │ │ ├── COJContestParser.ts │ │ ├── CPythonUZContestParser.ts │ │ ├── CSESContestParser.ts │ │ ├── CSUACMOnlineJudgeContestParser.ts │ │ ├── CodeChefContestParser.ts │ │ ├── CodeMarshalContestParser.ts │ │ ├── CodeRunContestParser.ts │ │ ├── CodeforcesContestParser.ts │ │ ├── ContestHunterContestParser.ts │ │ ├── DMOJContestParser.ts │ │ ├── DOMjudgeContestParser.ts │ │ ├── ECNUOnlineJudgeContestParser.ts │ │ ├── EolympBasecampContestParser.ts │ │ ├── EolympNormalContestParser.ts │ │ ├── FZUOnlineJudgeContestParser.ts │ │ ├── HDOJContestParser.ts │ │ ├── HDOJNewContestParser.ts │ │ ├── HKOIOnlineJudgeContestParser.ts │ │ ├── HUSTOJSyzojContestParser.ts │ │ ├── HackerEarthContestParser.ts │ │ ├── HackerRankContestParser.ts │ │ ├── HihoCoderContestParser.ts │ │ ├── HydroContestParser.ts │ │ ├── KEPUZContestParser.ts │ │ ├── KattisContestParser.ts │ │ ├── KilonovaContestParser.ts │ │ ├── LanqiaoContestParser.ts │ │ ├── LibreOJContestParser.ts │ │ ├── LightOJContestParser.ts │ │ ├── LuoguContestParser.ts │ │ ├── MarisaOJContestParser.ts │ │ ├── NBUTOnlineJudgeContestParser.ts │ │ ├── NOJContestParser.ts │ │ ├── OpenJudgeContestParser.ts │ │ ├── PEGJudgeContestParser.ts │ │ ├── POJContestParser.ts │ │ ├── QDUOJContestParser.ts │ │ ├── RoboContestContestParser.ts │ │ ├── SeriousOJContestParser.ts │ │ ├── TLXContestParser.ts │ │ ├── TimusOnlineJudgeContestParser.ts │ │ ├── UOJContestParser.ts │ │ ├── UniversalCupContestParser.ts │ │ ├── VirtualJudgeContestParser.ts │ │ ├── YandexContestParser.ts │ │ ├── YukicoderContestParser.ts │ │ └── ZUFEOJContestParser.ts │ ├── parsers.ts │ └── problem │ │ ├── A2OnlineJudgeProblemParser.ts │ │ ├── ACMPProblemParser.ts │ │ ├── AcWingProblemParser.ts │ │ ├── AizuOnlineJudgeBetaProblemParser.ts │ │ ├── AizuOnlineJudgeProblemParser.ts │ │ ├── AlgoZenithNewProblemParser.ts │ │ ├── AlgoZenithOldProblemParser.ts │ │ ├── AlgotesterProblemParser.ts │ │ ├── AnarchyGolfProblemParser.ts │ │ ├── AtCoderProblemParser.ts │ │ ├── BAPSOJProblemParser.ts │ │ ├── BUCTOJProblemParser.ts │ │ ├── BaekjoonOnlineJudgeProblemParser.ts │ │ ├── BeecrowdProblemParser.ts │ │ ├── BloombergCodeConProblemParser.ts │ │ ├── COJProblemParser.ts │ │ ├── CPythonUZProblemParser.ts │ │ ├── CSAcademyProblemParser.ts │ │ ├── CSESProblemParser.ts │ │ ├── CSGOJProblemParser.ts │ │ ├── CSUACMOnlineJudgeProblemParser.ts │ │ ├── CodeChefNewProblemParser.ts │ │ ├── CodeChefOldProblemParser.ts │ │ ├── CodeDrillsProblemParser.ts │ │ ├── CodeMarshalProblemParser.ts │ │ ├── CodeRunProblemParser.ts │ │ ├── CodeUpProblemParser.ts │ │ ├── CodeforcesProblemParser.ts │ │ ├── ContestHunterProblemParser.ts │ │ ├── DMOJProblemParser.ts │ │ ├── DimikOJProblemParser.ts │ │ ├── ECNUOnlineJudgeProblemParser.ts │ │ ├── EolympBasecampProblemParser.ts │ │ ├── EolympNormalProblemParser.ts │ │ ├── FZUOnlineJudgeProblemParser.ts │ │ ├── GoogleCodingCompetitionsProblemParser.ts │ │ ├── HDOJNewProblemParser.ts │ │ ├── HDOJProblemParser.ts │ │ ├── HITOnlineJudgeProblemParser.ts │ │ ├── HKOIOnlineJudgeProblemParser.ts │ │ ├── HUSTOJSyzojProblemParser.ts │ │ ├── HackerEarthCodeArenaParser.ts │ │ ├── HackerEarthProblemParser.ts │ │ ├── HackerRankProblemParser.ts │ │ ├── HihoCoderProblemParser.ts │ │ ├── HrbustOnlineJudgeProblemParser.ts │ │ ├── HydroProblemParser.ts │ │ ├── ITCoderHUTECHProblemParser.ts │ │ ├── InfoArenaProblemParser.ts │ │ ├── JutgeProblemParser.ts │ │ ├── KEPUZProblemParser.ts │ │ ├── KattisProblemParser.ts │ │ ├── KilonovaProblemParser.ts │ │ ├── LSYOIProblemParser.ts │ │ ├── LanqiaoProblemParser.ts │ │ ├── LibraryCheckerOldProblemParser.ts │ │ ├── LibraryCheckerProblemParser.ts │ │ ├── LibreOJProblemParser.ts │ │ ├── LightOJProblemParser.ts │ │ ├── LuoguProblemParser.ts │ │ ├── MSKInformaticsProblemParser.ts │ │ ├── MarisaOJProblemParser.ts │ │ ├── MendoProblemParser.ts │ │ ├── MetaCodingCompetitionsProblemParser.ts │ │ ├── MrJudgeProblemParser.ts │ │ ├── NBUTOnlineJudgeProblemParser.ts │ │ ├── NOJProblemParser.ts │ │ ├── NepsAcademyProblemParser.ts │ │ ├── NewtonSchoolProblemParser.ts │ │ ├── NowCoderProblemParser.ts │ │ ├── OTOGProblemParser.ts │ │ ├── OmegaUpProblemParser.ts │ │ ├── OpenJudgeProblemParser.ts │ │ ├── PBInfoProblemParser.ts │ │ ├── PEGJudgeProblemParser.ts │ │ ├── POJProblemParser.ts │ │ ├── PTAProblemParser.ts │ │ ├── PandaOnlineJudgeProblemParser.ts │ │ ├── QBXTOJProblemParser.ts │ │ ├── QDUOJProblemParser.ts │ │ ├── QQWhaleProblemParser.ts │ │ ├── RoboContestProblemParser.ts │ │ ├── SDUTOnlineJudgeProblemParser.ts │ │ ├── SPOJProblemParser.ts │ │ ├── SSOIERProblemParser.ts │ │ ├── SeriousOJProblemParser.ts │ │ ├── SortMeProblemParser.ts │ │ ├── StarryCodingProblemParser.ts │ │ ├── TLXProblemParser.ts │ │ ├── TheJobOverflowProblemParser.ts │ │ ├── TimusOnlineJudgeProblemParser.ts │ │ ├── TophProblemParser.ts │ │ ├── UDebugProblemParser.ts │ │ ├── UOJProblemParser.ts │ │ ├── USACOProblemParser.ts │ │ ├── USACOTrainingProblemParser.ts │ │ ├── UVaOnlineJudgeProblemParser.ts │ │ ├── UniversalCupProblemParser.ts │ │ ├── VirtualJudgeProblemParser.ts │ │ ├── XCampProblemParser.ts │ │ ├── XXMProblemParser.ts │ │ ├── YandexProblemParser.ts │ │ ├── YukicoderProblemParser.ts │ │ ├── ZOJProblemParser.ts │ │ └── ZUFEOJProblemParser.ts ├── utils │ ├── browser.ts │ ├── config.ts │ ├── dom.ts │ ├── messaging.ts │ ├── noop.ts │ ├── pdf.ts │ ├── random.ts │ ├── request.ts │ └── zip.ts └── vendor │ └── match-pattern-to-reg-exp.ts ├── tests ├── before-functions.ts ├── build │ └── expose-parsers.ts ├── data │ ├── a2-online-judge │ │ └── problem │ │ │ └── normal.json │ ├── aizu-online-judge-beta │ │ └── problem │ │ │ ├── arena.json │ │ │ └── normal.json │ ├── aizu-online-judge │ │ └── problem │ │ │ ├── japanese.json │ │ │ └── normal.json │ ├── algotester │ │ └── problem │ │ │ └── normal.json │ ├── anarchy-golf │ │ └── problem │ │ │ └── normal.json │ ├── atcoder │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── interactive.json │ │ │ ├── normal.json │ │ │ └── normal_ja.json │ ├── baekjoon-online-judge │ │ └── problem │ │ │ ├── multiple-time-limits.json │ │ │ └── normal.json │ ├── buctoj │ │ └── problem │ │ │ └── normal.json │ ├── code-drills │ │ └── problem │ │ │ ├── contest-problem.json │ │ │ └── normal.json │ ├── codechef │ │ ├── contest │ │ │ ├── normal.json │ │ │ └── samples-in-api.json │ │ └── problem │ │ │ ├── new-copy-button.json │ │ │ ├── new-example-headers-as-normal-text.json │ │ │ ├── new-input-output-after-example-header.json │ │ │ ├── new-input-output-as-normal-text.json │ │ │ ├── new-input-output-in-different-pre.json │ │ │ ├── new-input-output-in-same-pre.json │ │ │ ├── new-tests-as-normal-text.json │ │ │ ├── old-copy-button.json │ │ │ ├── old-example-headers-as-normal-text.json │ │ │ ├── old-input-output-after-example-header.json │ │ │ ├── old-input-output-as-normal-text.json │ │ │ ├── old-input-output-in-different-pre.json │ │ │ ├── old-input-output-in-same-pre.json │ │ │ └── old-tests-as-normal-text.json │ ├── codeforces │ │ ├── contest │ │ │ ├── complete-problemset.json │ │ │ ├── normal.json │ │ │ └── statements-in-pdf.json │ │ └── problem │ │ │ ├── acm-sgu-ru-inside-table.json │ │ │ ├── acm-sgu-ru-not-inside-table.json │ │ │ ├── cursive-input-output.json │ │ │ ├── file-input-output.json │ │ │ ├── gym.json │ │ │ ├── highlighted-input-deep.json │ │ │ ├── highlighted-input.json │ │ │ ├── html-entities-1.json │ │ │ ├── html-entities-2.json │ │ │ ├── inside-group.json │ │ │ ├── interactive-russian.json │ │ │ ├── interactive.json │ │ │ ├── nbsp.json │ │ │ ├── normal.json │ │ │ └── russian-stdin-stdout.json │ ├── codemarshal │ │ └── problem │ │ │ └── normal.json │ ├── contest-hunter │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ └── normal.json │ ├── cpython-uz │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── contest.json │ │ │ ├── duel.json │ │ │ └── normal.json │ ├── cs-academy │ │ └── problem │ │ │ └── normal.json │ ├── cses │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── code_blocks_in_statement.json │ │ │ └── normal.json │ ├── dmoj │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── contest-with-p-number.json │ │ │ ├── contest-with-problem-number.json │ │ │ ├── contest-without-problem-number.json │ │ │ ├── normal.json │ │ │ └── output-for-sample-input.json │ ├── eolymp │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ └── normal.json │ ├── google-coding-competitions │ │ └── problem │ │ │ ├── codejam.json │ │ │ ├── kickstart-new.json │ │ │ ├── kickstart.json │ │ │ └── multiple-samples.json │ ├── hackerearth │ │ └── problem │ │ │ └── normal.json │ ├── hdoj │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── contest-problem.json │ │ │ └── normal.json │ ├── hrbust-online-judge │ │ └── problem │ │ │ ├── input-padding.json │ │ │ └── normal.json │ ├── hydro │ │ └── problem │ │ │ └── normal.json │ ├── infoarena │ │ └── problem │ │ │ ├── interactive-stdin-first.json │ │ │ ├── interactive-stdout-first.json │ │ │ ├── multiple-examples.json │ │ │ └── normal.json │ ├── jutge │ │ └── problem │ │ │ ├── interactive.json │ │ │ └── normal.json │ ├── kattis │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── interactive-1.json │ │ │ ├── interactive-2.json │ │ │ ├── lines-ending-with-spaces.json │ │ │ ├── no-output.json │ │ │ └── normal.json │ ├── kilonova │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── console.json │ │ │ ├── file.json │ │ │ └── multiple-examples.json │ ├── library-checker-old │ │ └── problem │ │ │ └── normal.json │ ├── library-checker │ │ └── problem │ │ │ └── normal.json │ ├── libreoj │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ └── normal.json │ ├── lightoj │ │ └── problem │ │ │ └── normal.json │ ├── meta-coding-competitions │ │ └── problem │ │ │ └── normal.json │ ├── mr-judge │ │ └── problem │ │ │ └── normal.json │ ├── neps-academy │ │ └── problem │ │ │ ├── lesson-br.json │ │ │ ├── lesson.json │ │ │ ├── normal-br.json │ │ │ └── normal.json │ ├── nerdarena │ │ └── problem │ │ │ ├── multiple-examples.json │ │ │ └── normal.json │ ├── noj │ │ └── problem │ │ │ ├── multiple-samples.json │ │ │ └── normal.json │ ├── omega-up │ │ └── problem │ │ │ └── normal.json │ ├── open-judge │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ └── normal.json │ ├── otog │ │ └── problem │ │ │ └── normal.json │ ├── pbinfo │ │ └── problem │ │ │ ├── console.json │ │ │ ├── file.json │ │ │ ├── multiple-examples.json │ │ │ ├── new-console.json │ │ │ ├── new-file.json │ │ │ └── new-multiple-examples.json │ ├── peg-judge │ │ └── problem │ │ │ └── normal.json │ ├── poj │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── normal.json │ │ │ └── with-source.json │ ├── robocontest │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── normal.json │ │ │ └── olympiad.json │ ├── sdut-online-judge │ │ └── problem │ │ │ └── normal.json │ ├── spoj │ │ └── problem │ │ │ ├── multiple-blocks.json │ │ │ ├── one-block-1.json │ │ │ ├── one-block-2.json │ │ │ ├── one-block-3.json │ │ │ ├── one-block-4.json │ │ │ └── two-blocks.json │ ├── ssoier │ │ └── problem │ │ │ ├── extended-problem-set.json │ │ │ └── normal.json │ ├── timus-online-judge │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── example-test-cases-one-column.json │ │ │ ├── normal.json │ │ │ └── russian.json │ ├── tlx │ │ └── problem │ │ │ ├── from_contest_en.json │ │ │ ├── from_contest_id.json │ │ │ ├── from_problemset_en.json │ │ │ └── from_problemset_id.json │ ├── toph │ │ └── problem │ │ │ ├── normal.json │ │ │ ├── samples-not-in-table.json │ │ │ └── time-limit-in-ms.json │ ├── udebug │ │ └── problem │ │ │ └── normal.json │ ├── uoj │ │ ├── contest │ │ │ ├── public-judge.json │ │ │ └── uoj.json │ │ └── problem │ │ │ ├── daimayuan-online-judge.json │ │ │ ├── public-judge.json │ │ │ └── uoj.json │ ├── usaco │ │ └── problem │ │ │ ├── interactive.json │ │ │ ├── multiple-sample-cases.json │ │ │ └── normal.json │ ├── virtual-judge │ │ ├── contest │ │ │ └── normal.json │ │ └── problem │ │ │ ├── 51nod.json │ │ │ ├── aizu.json │ │ │ ├── atcoder.json │ │ │ ├── codechef.json │ │ │ ├── codeforces-file-input-output.json │ │ │ ├── codeforces-gym-chinese.json │ │ │ ├── codeforces-gym.json │ │ │ ├── codeforces.json │ │ │ ├── csu.json │ │ │ ├── e-olymp.json │ │ │ ├── fzu.json │ │ │ ├── hdu.json │ │ │ ├── hiho-coder.json │ │ │ ├── hrbust.json │ │ │ ├── hysbz.json │ │ │ ├── kattis.json │ │ │ ├── light-oj.json │ │ │ ├── nbut.json │ │ │ ├── openj-bailian.json │ │ │ ├── openj-poj.json │ │ │ ├── poj.json │ │ │ ├── scu.json │ │ │ ├── sgu.json │ │ │ ├── spoj.json │ │ │ ├── topcoder.json │ │ │ ├── ural.json │ │ │ ├── uva-live.json │ │ │ ├── uva.json │ │ │ ├── zoj-3209.json │ │ │ └── zoj-3496.json │ ├── zoj │ │ └── problem │ │ │ └── normal.json │ └── zufeoj │ │ ├── contest │ │ └── normal.json │ │ └── problem │ │ └── normal.json └── parsers.spec.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.md] 10 | indent_size = 4 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v4 12 | 13 | - name: Set up PNPM 14 | uses: pnpm/action-setup@v4 15 | with: 16 | version: 10 17 | 18 | - name: Set up Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 22 22 | cache: pnpm 23 | 24 | - name: Install dependencies 25 | run: pnpm install --frozen-lockfile 26 | 27 | - name: Lint 28 | run: pnpm lint 29 | 30 | - name: Build 31 | run: pnpm build 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jasper van Merle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest/presets/default-esm', 3 | testEnvironment: 'node', 4 | collectCoverageFrom: ['src/**/*.ts'], 5 | testTimeout: 30000, 6 | maxConcurrency: 16, 7 | }; 8 | -------------------------------------------------------------------------------- /media/banners/chrome-large-promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/banners/chrome-large-promo.png -------------------------------------------------------------------------------- /media/banners/chrome-marquee-promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/banners/chrome-marquee-promo.png -------------------------------------------------------------------------------- /media/banners/chrome-small-promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/banners/chrome-small-promo.png -------------------------------------------------------------------------------- /media/banners/github-social-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/banners/github-social-preview.png -------------------------------------------------------------------------------- /media/icons/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-128.png -------------------------------------------------------------------------------- /media/icons/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-16.png -------------------------------------------------------------------------------- /media/icons/icon-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-19.png -------------------------------------------------------------------------------- /media/icons/icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-20.png -------------------------------------------------------------------------------- /media/icons/icon-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-24.png -------------------------------------------------------------------------------- /media/icons/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-32.png -------------------------------------------------------------------------------- /media/icons/icon-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-38.png -------------------------------------------------------------------------------- /media/icons/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-48.png -------------------------------------------------------------------------------- /media/icons/icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-64.png -------------------------------------------------------------------------------- /media/icons/icon-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmerle/competitive-companion/4225999c9d987186a072c8026c4ed6687cc5e3f5/media/icons/icon-96.png -------------------------------------------------------------------------------- /scripts/build/test.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'node:path'; 2 | import * as esbuild from 'esbuild'; 3 | import { projectRoot } from '../utils'; 4 | import { commonOptions, getBuildDirectory } from './utils'; 5 | 6 | await esbuild.build({ 7 | ...commonOptions, 8 | entryPoints: [path.resolve(projectRoot, 'tests/build/expose-parsers.ts')], 9 | outdir: await getBuildDirectory('test'), 10 | bundle: true, 11 | format: 'esm', 12 | }); 13 | -------------------------------------------------------------------------------- /scripts/start/chrome.ts: -------------------------------------------------------------------------------- 1 | import * as ChromeLauncher from 'chrome-launcher'; 2 | import { waitForBuild } from './utils'; 3 | 4 | await waitForBuild('chrome'); 5 | 6 | await ChromeLauncher.launch({ 7 | startingUrl: 'https://codeforces.com/problemset/problem/954/G', 8 | ignoreDefaultFlags: true, 9 | chromeFlags: ['--no-first-run', '--no-default-browser-check', '--start-maximized', '--load-extension=./build-chrome'], 10 | }); 11 | -------------------------------------------------------------------------------- /scripts/start/firefox.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'node:fs'; 2 | import * as path from 'node:path'; 3 | // @ts-expect-error There are no types for this import 4 | import * as webExt from 'web-ext'; 5 | import { projectRoot } from '../utils'; 6 | import { waitForBuild } from './utils'; 7 | 8 | await waitForBuild('firefox'); 9 | 10 | const extensionDir = path.join(projectRoot, 'build-firefox'); 11 | const tmpDir = path.join(projectRoot, 'firefox-tmp'); 12 | 13 | if (fs.existsSync(tmpDir)) { 14 | await fs.promises.rm(tmpDir, { recursive: true, force: true }); 15 | } 16 | 17 | await fs.promises.mkdir(tmpDir); 18 | process.env.TMPDIR = tmpDir; 19 | 20 | await webExt.cmd.run( 21 | { 22 | sourceDir: extensionDir, 23 | startUrl: 'https://codeforces.com/problemset/problem/954/G', 24 | pref: { 25 | 'devtools.browserconsole.filter.jswarn': 'false', 26 | 'devtools.webconsole.filter.warn': 'false', 27 | }, 28 | }, 29 | { 30 | shouldExitProgram: false, 31 | }, 32 | ); 33 | -------------------------------------------------------------------------------- /scripts/start/utils.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'node:fs'; 2 | import * as path from 'node:path'; 3 | import { projectRoot } from '../utils'; 4 | 5 | export async function waitForBuild(target: string): Promise { 6 | const backgroundFile = path.resolve(projectRoot, `build-${target}/js/background.js`); 7 | while (!fs.existsSync(backgroundFile)) { 8 | await new Promise(resolve => setTimeout(resolve, 250)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/utils.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'node:path'; 2 | import * as url from 'node:url'; 3 | 4 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 5 | 6 | export const projectRoot = path.dirname(__dirname); 7 | -------------------------------------------------------------------------------- /src/hosts/CHelperHost.ts: -------------------------------------------------------------------------------- 1 | import { Host } from './Host'; 2 | 3 | export class CHelperHost extends Host { 4 | public async send(data: string): Promise { 5 | await this.doSend('http://localhost:4243/', { 6 | body: `json\n${data}`, 7 | }); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/hosts/CustomHost.ts: -------------------------------------------------------------------------------- 1 | import { Host } from './Host'; 2 | 3 | export class CustomHost extends Host { 4 | public constructor(private port: number) { 5 | super(); 6 | } 7 | 8 | public async send(data: string): Promise { 9 | await this.doSend(`http://localhost:${this.port}/`, { 10 | body: data, 11 | headers: { 12 | 'Content-Type': 'application/json', 13 | }, 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/hosts/Host.ts: -------------------------------------------------------------------------------- 1 | import { config } from '../utils/config'; 2 | 3 | export abstract class Host { 4 | public abstract send(data: string): Promise; 5 | 6 | protected async doSend(url: string, options: RequestInit): Promise { 7 | const requestTimeout = await config.get('requestTimeout'); 8 | 9 | const abortController = new AbortController(); 10 | setTimeout(() => abortController.abort(), requestTimeout); 11 | 12 | try { 13 | await fetch(url, { 14 | method: 'POST', 15 | signal: abortController.signal, 16 | ...options, 17 | }); 18 | } catch (err) { 19 | // 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/hosts/hosts.ts: -------------------------------------------------------------------------------- 1 | import { config } from '../utils/config'; 2 | import { CHelperHost } from './CHelperHost'; 3 | import { CustomHost } from './CustomHost'; 4 | import { Host } from './Host'; 5 | 6 | const defaultHosts: Host[] = [new CHelperHost()]; 7 | const defaultPorts = [ 8 | 1327, // cpbooster 9 | 4244, // Hightail 10 | 6174, // Mind Sport 11 | 10042, // acmX 12 | 10043, // Caide and AI Virtual Assistant 13 | 10045, // CP Editor 14 | 27121, // Competitive Programming Helper 15 | ]; 16 | 17 | export async function getHosts(): Promise { 18 | const customPorts = await config.get('customPorts'); 19 | const uniquePorts = [...new Set(defaultPorts.concat(customPorts))]; 20 | return defaultHosts.concat(uniquePorts.map(port => new CustomHost(port))); 21 | } 22 | -------------------------------------------------------------------------------- /src/models/Batch.ts: -------------------------------------------------------------------------------- 1 | export interface Batch { 2 | id: string; 3 | size: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/models/Contest.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from './Sendable'; 2 | import { Task } from './Task'; 3 | 4 | export class Contest implements Sendable { 5 | public constructor(public tasks: Task[]) { 6 | for (const task of tasks) { 7 | task.batch.id = tasks[0].batch.id; 8 | task.batch.size = tasks.length; 9 | } 10 | } 11 | 12 | public async send(): Promise { 13 | for (const task of this.tasks) { 14 | await task.send(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/models/IOConfiguration.ts: -------------------------------------------------------------------------------- 1 | export interface InputConfiguration { 2 | type: 'stdin' | 'file' | 'regex'; 3 | fileName?: string; 4 | pattern?: string; 5 | } 6 | 7 | export interface OutputConfiguration { 8 | type: 'stdout' | 'file'; 9 | fileName?: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/models/LanguageConfiguration.ts: -------------------------------------------------------------------------------- 1 | export interface LanguageConfiguration { 2 | java: JavaConfiguration; 3 | } 4 | 5 | export interface JavaConfiguration { 6 | mainClass: string; 7 | taskClass: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/models/Sendable.ts: -------------------------------------------------------------------------------- 1 | export interface Sendable { 2 | send(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /src/models/Test.ts: -------------------------------------------------------------------------------- 1 | export class Test { 2 | public input: string; 3 | public output: string; 4 | 5 | public constructor(input: string, output: string, normalizeWhitespace: boolean) { 6 | this.input = this.correctData(input, normalizeWhitespace); 7 | this.output = this.correctData(output, normalizeWhitespace); 8 | } 9 | 10 | private correctData(data: string, normalizeWhitespace: boolean): string { 11 | data = data.replace('
', ''); 12 | 13 | if (normalizeWhitespace) { 14 | data = data 15 | .replace(/
/g, '\n') 16 | .replace(/ /g, '') 17 | .split('\n') 18 | .map(line => line.trimEnd()) 19 | .join('\n') 20 | .trimEnd(); 21 | } 22 | 23 | return data.endsWith('\n') || data.length === 0 ? data : data + '\n'; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/models/TestType.ts: -------------------------------------------------------------------------------- 1 | export enum TestType { 2 | Single = 'single', 3 | MultiNumber = 'multiNumber', 4 | } 5 | -------------------------------------------------------------------------------- /src/models/messaging.ts: -------------------------------------------------------------------------------- 1 | export interface Message { 2 | action: MessageAction; 3 | payload?: any; 4 | } 5 | 6 | export enum MessageAction { 7 | Parse, 8 | SendTask, 9 | SendTaskDone, 10 | SendTaskFailed, 11 | Fetch, 12 | FetchResult, 13 | FetchFailed, 14 | } 15 | -------------------------------------------------------------------------------- /src/parsers/SimpleContestParser.ts: -------------------------------------------------------------------------------- 1 | import { Task } from '../models/Task'; 2 | import { htmlToElement } from '../utils/dom'; 3 | import { request } from '../utils/request'; 4 | import { ContestParser } from './ContestParser'; 5 | import { Parser } from './Parser'; 6 | 7 | export abstract class SimpleContestParser extends ContestParser { 8 | protected abstract linkSelector: string; 9 | protected abstract problemParser: Parser; 10 | 11 | public canHandlePage(): boolean { 12 | return document.querySelector(this.linkSelector) !== null; 13 | } 14 | 15 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 16 | protected async getTasksToParse(html: string, url: string): Promise { 17 | const elem = htmlToElement(html); 18 | return [...elem.querySelectorAll(this.linkSelector)].map(el => (el as any).href); 19 | } 20 | 21 | protected async parseTask(url: string): Promise { 22 | const body = await request(url); 23 | const task = await this.problemParser.parse(url, body); 24 | return task as Task; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/parsers/contest/A2OnlineJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { A2OnlineJudgeProblemParser } from '../problem/A2OnlineJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class A2OnlineJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = 'table tbody tr td a[href^="p?ID="]'; 6 | protected problemParser = new A2OnlineJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://a2oj.com/ladder*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/AtCoderContestParser.ts: -------------------------------------------------------------------------------- 1 | import { AtCoderProblemParser } from '../problem/AtCoderProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class AtCoderContestParser extends SimpleContestParser { 5 | protected linkSelector = 'table tr td:first-child a'; 6 | protected problemParser = new AtCoderProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://atcoder.jp/contests/*/tasks']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/BAPSOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { BAPSOJProblemParser } from '../problem/BAPSOJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class BAPSOJContestParser extends SimpleContestParser { 5 | protected linkSelector = 'ul > a'; 6 | protected problemParser = new BAPSOJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://bapsoj.org/contests/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/BUCTOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { BUCTOJProblemParser } from '../problem/BUCTOJProblemParser'; 2 | import { HUSTOJSyzojContestParser } from './HUSTOJSyzojContestParser'; 3 | 4 | export class BUCTOJContestParser extends HUSTOJSyzojContestParser { 5 | protected problemParser = new BUCTOJProblemParser(); 6 | 7 | public getMatchPatterns(): string[] { 8 | return ['https://buctcoder.com/contest.php*']; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/parsers/contest/BeecrowdContestParser.ts: -------------------------------------------------------------------------------- 1 | import { BeecrowdProblemParser } from '../problem/BeecrowdProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class BeecrowdContestParser extends SimpleContestParser { 5 | protected linkSelector = '#table td.large > a'; 6 | protected problemParser = new BeecrowdProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://judge.beecrowd.com/*/challenges/contest/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/COJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { COJProblemParser } from '../problem/COJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class COJContestParser extends SimpleContestParser { 5 | protected linkSelector = '#problem td > a'; 6 | protected problemParser = new COJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://coj.uci.cu/contest/cproblems.xhtml*']; 10 | } 11 | 12 | public canHandlePage(): boolean { 13 | return true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/parsers/contest/CSESContestParser.ts: -------------------------------------------------------------------------------- 1 | import { CSESProblemParser } from '../problem/CSESProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class CSESContestParser extends SimpleContestParser { 5 | protected linkSelector = '.task-list.contest > .task > a'; 6 | protected problemParser = new CSESProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return [ 10 | 'https://cses.fi/*/list', 11 | 'https://cses.fi/*/list/', 12 | 'https://www.cses.fi/*/list', 13 | 'https://www.cses.fi/*/list/', 14 | ]; 15 | } 16 | 17 | public getExcludedMatchPatterns(): string[] { 18 | return [ 19 | 'https://cses.fi/problemset/list', 20 | 'https://cses.fi/problemset/list/', 21 | 'https://www.cses.fi/problemset/list', 22 | 'https://www.cses.fi/problemset/list/', 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/parsers/contest/CSUACMOnlineJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { CSUACMOnlineJudgeProblemParser } from '../problem/CSUACMOnlineJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class CSUACMOnlineJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = 'tbody > tr > td:nth-child(3) > a'; 6 | protected problemParser = new CSUACMOnlineJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['http://acm.csu.edu.cn/csuoj/contest/problemset*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/CodeMarshalContestParser.ts: -------------------------------------------------------------------------------- 1 | import { CodeMarshalProblemParser } from '../problem/CodeMarshalProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class CodeMarshalContestParser extends SimpleContestParser { 5 | protected linkSelector = '.panel-problems a.list-group-item'; 6 | protected problemParser = new CodeMarshalProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://algo.codemarshal.org/contests/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/CodeRunContestParser.ts: -------------------------------------------------------------------------------- 1 | import { CodeRunProblemParser } from '../problem/CodeRunProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class CodeRunContestParser extends SimpleContestParser { 5 | protected linkSelector = 'a[class^="CatalogSearchResultItem_problem-card__link"]'; 6 | protected problemParser = new CodeRunProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://coderun.yandex.ru/selections/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/ContestHunterContestParser.ts: -------------------------------------------------------------------------------- 1 | import { ContestHunterProblemParser } from '../problem/ContestHunterProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class ContestHunterContestParser extends SimpleContestParser { 5 | protected linkSelector = 6 | '.container > .row > .span12 > .table > tbody > tr:nth-child(2) > td:nth-child(2) > .table span[itemprop="name"] > a'; 7 | protected problemParser = new ContestHunterProblemParser(); 8 | 9 | public getMatchPatterns(): string[] { 10 | return ['http://noi-test.zzstep.com/contest/*']; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/parsers/contest/DMOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { DMOJProblemParser } from '../problem/DMOJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class DMOJContestParser extends SimpleContestParser { 5 | protected linkSelector = '.contest-problems tbody > tr > td:first-child > a'; 6 | protected problemParser = new DMOJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return Object.keys(DMOJProblemParser.DOMAINS).map(domain => `https://${domain}/contest/*`); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/ECNUOnlineJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { ECNUOnlineJudgeProblemParser } from '../problem/ECNUOnlineJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class ECNUOnlineJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = 'td.left.aligned > a:first-child'; 6 | protected problemParser = new ECNUOnlineJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://acm.ecnu.edu.cn/contest/*/']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/EolympNormalContestParser.ts: -------------------------------------------------------------------------------- 1 | import { EolympNormalProblemParser } from '../problem/EolympNormalProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class EolympNormalContestParser extends SimpleContestParser { 5 | protected linkSelector = '.eo-problem-row__name'; 6 | protected problemParser = new EolympNormalProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://www.eolymp.com/*/contests/*']; 10 | } 11 | 12 | public getRegularExpressions(): RegExp[] { 13 | return [/https:\/\/www[.]eolymp[.]com\/([a-z]+)\/contests\/(\d+)$/]; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/parsers/contest/FZUOnlineJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { FZUOnlineJudgeProblemParser } from '../problem/FZUOnlineJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class FZUOnlineJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = '.ct_list_content > table > tbody > tr > td:nth-child(3) > a'; 6 | protected problemParser = new FZUOnlineJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['http://acm.fzu.edu.cn/contest/list.php*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/HDOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { Task } from '../../models/Task'; 2 | import { HDOJProblemParser } from '../problem/HDOJProblemParser'; 3 | import { SimpleContestParser } from '../SimpleContestParser'; 4 | 5 | export class HDOJContestParser extends SimpleContestParser { 6 | protected linkSelector = 'tr.table_text a'; 7 | protected problemParser = new HDOJProblemParser(); 8 | 9 | public getMatchPatterns(): string[] { 10 | return ['https://acm.hdu.edu.cn/contests/contest_show.php*'].flatMap(p => [p, p.replace('https', 'http')]); 11 | } 12 | 13 | protected async parseTask(url: string): Promise { 14 | const task = await super.parseTask(url); 15 | 16 | // We need to wait between fetches to prevent getting rate limited 17 | await new Promise(resolve => { 18 | setTimeout(() => resolve(), 2000); 19 | }); 20 | 21 | return task; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/parsers/contest/HDOJNewContestParser.ts: -------------------------------------------------------------------------------- 1 | import { HDOJNewProblemParser } from '../problem/HDOJNewProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class HDOJNewContestParser extends SimpleContestParser { 5 | protected linkSelector = '.page-card-table > tbody > tr > td:nth-child(3) > a'; 6 | protected problemParser = new HDOJNewProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://acm.hdu.edu.cn/contest/problems\\?*'].flatMap(p => [p, p.replace('https', 'http')]); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/HKOIOnlineJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { HKOIOnlineJudgeProblemParser } from '../problem/HKOIOnlineJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class HKOIOnlineJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = 'table.table-hover tbody tr td:nth-child(2) a'; 6 | protected problemParser = new HKOIOnlineJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://judge.hkoi.org/contest/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/HUSTOJSyzojContestParser.ts: -------------------------------------------------------------------------------- 1 | import { SimpleContestParser } from '../SimpleContestParser'; 2 | 3 | export abstract class HUSTOJSyzojContestParser extends SimpleContestParser { 4 | protected linkSelector = 'table.ui.selectable > tbody > tr > td:nth-child(2) > a'; 5 | } 6 | -------------------------------------------------------------------------------- /src/parsers/contest/HackerEarthContestParser.ts: -------------------------------------------------------------------------------- 1 | import { HackerEarthProblemParser } from '../problem/HackerEarthProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class HackerEarthContestParser extends SimpleContestParser { 5 | protected linkSelector = '.problems-table .prob a, .problems-table a.track-problem-link'; 6 | protected problemParser = new HackerEarthProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://www.hackerearth.com/challenge/*/problems/']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/HihoCoderContestParser.ts: -------------------------------------------------------------------------------- 1 | import { HihoCoderProblemParser } from '../problem/HihoCoderProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class HihoCoderContestParser extends SimpleContestParser { 5 | protected linkSelector = '.contest-problems td.id > a'; 6 | protected problemParser = new HihoCoderProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://hihocoder.com/contest/*/problems']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/HydroContestParser.ts: -------------------------------------------------------------------------------- 1 | import { HydroProblemParser } from '../problem/HydroProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class HydroContestParser extends SimpleContestParser { 5 | protected linkSelector = '.col--problem.col--problem-name > a'; 6 | protected problemParser = new HydroProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return Object.keys(HydroProblemParser.DOMAINS).map(domain => `https://${domain}/contest/*`); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/KattisContestParser.ts: -------------------------------------------------------------------------------- 1 | import { KattisProblemParser } from '../problem/KattisProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class KattisContestParser extends SimpleContestParser { 5 | protected linkSelector = 'table.table2 > tbody > tr > td:first-of-type > a'; 6 | protected problemParser = new KattisProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://open.kattis.com/contests/*']; 10 | } 11 | 12 | public getRegularExpressions(): RegExp[] { 13 | return [/^https:\/\/.*[.]kattis[.]com\/contests\/([a-z0-9]+)(\/problems)?$/]; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/parsers/contest/KilonovaContestParser.ts: -------------------------------------------------------------------------------- 1 | import { KilonovaProblemParser } from '../problem/KilonovaProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class KilonovaContestParser extends SimpleContestParser { 5 | protected linkSelector = 'div.reset-list > ul > li > a[href^="/"]'; 6 | protected problemParser = new KilonovaProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://kilonova.ro/contests/*', 'https://kilonova.ro/problems/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/LibreOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { LibreOJProblemParser } from '../problem/LibreOJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class LibreOJContestParser extends SimpleContestParser { 5 | protected linkSelector = '.ui.selectable.celled.table > tbody > tr > td:nth-child(2) > a'; 6 | protected problemParser = new LibreOJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://libreoj.github.io/contest/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/LightOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { LightOJProblemParser } from '../problem/LightOJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class LightOJContestParser extends SimpleContestParser { 5 | protected linkSelector = '.card-body a.page-meta'; 6 | protected problemParser = new LightOJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://lightoj.com/contest/*/arena/']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/LuoguContestParser.ts: -------------------------------------------------------------------------------- 1 | import { LuoguProblemParser } from '../problem/LuoguProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class LuoguContestParser extends SimpleContestParser { 5 | protected linkSelector = 'div.title > a.title'; 6 | protected problemParser = new LuoguProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://www.luogu.com.cn/contest/*', 'https://www.luogu.com.cn/training/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/MarisaOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { MarisaOJProblemParser } from '../problem/MarisaOJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class MarisaOJContestParser extends SimpleContestParser { 5 | protected linkSelector = '.problem-table tbody > tr > td:nth-child(2) > a'; 6 | protected problemParser = new MarisaOJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://marisaoj.com/mashup/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/NBUTOnlineJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { NBUTOnlineJudgeProblemParser } from '../problem/NBUTOnlineJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class NBUTOnlineJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = '#problemlist td.br > a'; 6 | protected problemParser = new NBUTOnlineJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://ac.2333.moe/Contest/view/id/*.xhtml']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/NOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { Task } from '../../models/Task'; 2 | import { htmlToElement } from '../../utils/dom'; 3 | import { request } from '../../utils/request'; 4 | import { ContestParser } from '../ContestParser'; 5 | import { NOJProblemParser } from '../problem/NOJProblemParser'; 6 | 7 | export class NOJContestParser extends ContestParser { 8 | public getMatchPatterns(): string[] { 9 | return ['https://acm.njupt.edu.cn/contest/*/board/challenge']; 10 | } 11 | 12 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 13 | protected async getTasksToParse(html: string, url: string): Promise { 14 | const elem = htmlToElement(html); 15 | return [...elem.querySelectorAll('challenge-container > challenge-item')] 16 | .map(el => el.getAttribute('onclick')) 17 | .map(script => script.replace("location.href='", '').replace("'", '')) 18 | .map(partialUrl => `https://acm.njupt.edu.cn${partialUrl}`); 19 | } 20 | 21 | protected async parseTask(url: string): Promise { 22 | const body = await request(url); 23 | const parser = new NOJProblemParser(); 24 | const task = await parser.parse(url, body); 25 | return task as Task; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/parsers/contest/OpenJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { OpenJudgeProblemParser } from '../problem/OpenJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class OpenJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = '.contest-problem > table td.title > a'; 6 | protected problemParser = new OpenJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['http://*.openjudge.cn/*/']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/PEGJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { PEGJudgeProblemParser } from '../problem/PEGJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class PEGJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = '#content table tr > td:nth-child(2) a'; 6 | protected problemParser = new PEGJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://wcipeg.com/problems']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/POJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { POJProblemParser } from '../problem/POJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class POJContestParser extends SimpleContestParser { 5 | protected linkSelector = 'div[align=center] > table tr a'; 6 | protected problemParser = new POJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['http://poj.org/showcontest*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/RoboContestContestParser.ts: -------------------------------------------------------------------------------- 1 | import { RoboContestProblemParser } from '../problem/RoboContestProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class RoboContestContestParser extends SimpleContestParser { 5 | protected linkSelector = 'table th.text-center.align-middle[title] > a'; 6 | protected problemParser = new RoboContestProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://robocontest.uz/olympiads/*/results']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/SeriousOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { SeriousOJProblemParser } from '../problem/SeriousOJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class SeriousOJContestParser extends SimpleContestParser { 5 | protected linkSelector = '.col--problem.col--problem-name > a'; 6 | protected problemParser = new SeriousOJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://judge.eluminatis-of-lu.com/contest/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/TimusOnlineJudgeContestParser.ts: -------------------------------------------------------------------------------- 1 | import { TimusOnlineJudgeProblemParser } from '../problem/TimusOnlineJudgeProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class TimusOnlineJudgeContestParser extends SimpleContestParser { 5 | protected linkSelector = '.problemset td.name > a'; 6 | protected problemParser = new TimusOnlineJudgeProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['acm.timus.ru', 'timus.online', 'acm-judge.urfu.ru'].map(domain => `https://${domain}/problemset.aspx*`); 10 | } 11 | 12 | public getRegularExpressions(): RegExp[] { 13 | return [ 14 | /^https:\/\/acm[.]timus[.]ru\/problemset[.]aspx\?space=(\d+)(&locale=(en|ru))?$/, 15 | /^https:\/\/timus[.]online\/problemset[.]aspx\?space=(\d+)(&locale=(en|ru))?$/, 16 | ]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/parsers/contest/UOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { UOJProblemParser } from '../problem/UOJProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class UOJContestParser extends SimpleContestParser { 5 | protected linkSelector = '.top-buffer-md > .table-responsive > .table a'; 6 | protected problemParser = new UOJProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return Object.keys(UOJProblemParser.domains) 10 | .map(domain => `https://${domain}/contest/*`) 11 | .flatMap(p => [p, p.replace('https', 'http')]); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/parsers/contest/UniversalCupContestParser.ts: -------------------------------------------------------------------------------- 1 | import { UniversalCupProblemParser } from '../problem/UniversalCupProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class UniversalCupContestParser extends SimpleContestParser { 5 | protected linkSelector = '.table-text-center > tbody > tr > td > a'; 6 | protected problemParser = new UniversalCupProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://contest.ucup.ac/contest/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/YandexContestParser.ts: -------------------------------------------------------------------------------- 1 | import { YandexProblemParser } from '../problem/YandexProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class YandexContestParser extends SimpleContestParser { 5 | protected linkSelector = 'div.page__main > div.content > ul.tabs-menu_role_problems > li > a:nth-child(1)'; 6 | protected problemParser = new YandexProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | // Only available via the "Parse with" context menu as Yandex doesn't have a specific page that shows all problems 10 | return []; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/parsers/contest/YukicoderContestParser.ts: -------------------------------------------------------------------------------- 1 | import { YukicoderProblemParser } from '../problem/YukicoderProblemParser'; 2 | import { SimpleContestParser } from '../SimpleContestParser'; 3 | 4 | export class YukicoderContestParser extends SimpleContestParser { 5 | protected linkSelector = '#content > table > tbody > tr > td > a[href^="/problems/no"]'; 6 | protected problemParser = new YukicoderProblemParser(); 7 | 8 | public getMatchPatterns(): string[] { 9 | return ['https://yukicoder.me/contests/*']; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/parsers/contest/ZUFEOJContestParser.ts: -------------------------------------------------------------------------------- 1 | import { ZUFEOJProblemParser } from '../problem/ZUFEOJProblemParser'; 2 | import { HUSTOJSyzojContestParser } from './HUSTOJSyzojContestParser'; 3 | 4 | export class ZUFEOJContestParser extends HUSTOJSyzojContestParser { 5 | protected problemParser = new ZUFEOJProblemParser(); 6 | 7 | public getMatchPatterns(): string[] { 8 | return ['http://acm.ocrosoft.com/contest.php*']; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/parsers/problem/A2OnlineJudgeProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class A2OnlineJudgeProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://a2oj.com/p*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('A2 Online Judge').setUrl(url); 14 | 15 | const nameElem = elem.querySelector('#page > center > div'); 16 | task.setName(nameElem.childNodes[nameElem.childNodes.length - 1].textContent.trim()); 17 | 18 | const blocks = [...elem.querySelectorAll('#page > div')] 19 | .filter(elem => elem.textContent.includes('ample')) 20 | .map(elem => elem.nextElementSibling); 21 | 22 | for (let i = 0; i < blocks.length - 1; i += 2) { 23 | task.addTest(blocks[i].textContent, blocks[i + 1].textContent); 24 | } 25 | 26 | return task.build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/parsers/problem/AnarchyGolfProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class AnarchyGolfProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['http://golf.shinh.org/p.rb?*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('Anarchy Golf').setUrl(url); 14 | 15 | task.setName(elem.querySelector('h1').textContent); 16 | 17 | task.setTimeLimit(10000); 18 | task.setMemoryLimit(8192); 19 | 20 | const preBlocks = elem.querySelectorAll('pre'); 21 | for (let i = 0; i < preBlocks.length - 1; i += 2) { 22 | task.addTest(preBlocks[i].textContent, preBlocks[i + 1].textContent); 23 | } 24 | 25 | return task.build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/parsers/problem/BUCTOJProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { HUSTOJSyzojProblemParser } from './HUSTOJSyzojProblemParser'; 2 | 3 | export class BUCTOJProblemParser extends HUSTOJSyzojProblemParser { 4 | protected judge = 'BUCTOJ'; 5 | 6 | public getMatchPatterns(): string[] { 7 | return ['https://buctcoder.com/problem.php*']; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/parsers/problem/DimikOJProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class DimikOJProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://dimikoj.com/problems/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const doc = htmlToElement(html); 13 | const task = new TaskBuilder('Dimik OJ').setUrl(url); 14 | 15 | const headerText = doc.querySelector('.card-header').textContent; 16 | const problemTitle = headerText.slice(headerText.indexOf('—') + 1).trim(); 17 | task.setName(problemTitle); 18 | 19 | const submissionDiv = doc.querySelector('#submission'); 20 | const codeBlocks = [...submissionDiv.previousElementSibling.querySelectorAll('code')]; 21 | 22 | for (let i = 0; i < codeBlocks.length - 1; i += 2) { 23 | task.addTest(codeBlocks[i].textContent, codeBlocks[i + 1].textContent); 24 | } 25 | 26 | return task.build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/parsers/problem/HackerEarthCodeArenaParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { Task } from '../../models/Task'; 3 | import { Parser } from '../Parser'; 4 | import { HackerEarthProblemParser } from './HackerEarthProblemParser'; 5 | 6 | export class HackerEarthCodeArenaParser extends Parser { 7 | public problemParser: Parser = new HackerEarthProblemParser(); 8 | 9 | public getMatchPatterns(): string[] { 10 | return ['https://www.hackerearth.com/codearena/ring/*/*']; 11 | } 12 | 13 | public async parse(url: string, html: string): Promise { 14 | const task = (await this.problemParser.parse(url, html)) as Task; 15 | 16 | const id = /^https:\/\/www[.]hackerearth[.]com\/codearena\/ring\/(.*)\/(\?(.*))?$/.exec(url)[1]; 17 | task.name = `CodeArena ${id}`; 18 | task.group = 'HackerEarth - CodeArena'; 19 | 20 | return task; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/parsers/problem/LSYOIProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class LSYOIProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['http://lsyoi.top:88/problem.php?*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('LSYOI').setUrl(url); 14 | 15 | task.setName(elem.querySelector('.container > .panel').childNodes[1].childNodes[1].textContent.trim()); 16 | 17 | task.addTest(elem.querySelector('#sampleinput').textContent, document.querySelector('#sampleoutput').textContent); 18 | 19 | const timeLimitStr = elem.querySelectorAll('.green')[0].nextElementSibling.firstChild.textContent; 20 | task.setTimeLimit(parseFloat(timeLimitStr) * 1000); 21 | 22 | const memoryLimitStr = elem.querySelectorAll('.green')[1].nextSibling.textContent; 23 | task.setMemoryLimit(parseInt(/(\d+) MB/.exec(memoryLimitStr)[1], 10)); 24 | 25 | return task.build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/parsers/problem/LibraryCheckerOldProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class LibraryCheckerOldProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://old.yosupo.jp/problem/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('Library Checker').setUrl(url); 14 | 15 | task.setName(elem.querySelector('.uk-container > h1').textContent); 16 | 17 | task.setTimeLimit(5000); 18 | task.setMemoryLimit(1024); 19 | 20 | const preBlocks = [...elem.querySelectorAll('pre')].filter(block => block.querySelector('code') === null); 21 | for (let i = 0; i < preBlocks.length - 1; i += 2) { 22 | task.addTest(preBlocks[i].textContent, preBlocks[i + 1].textContent); 23 | } 24 | 25 | return task.build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/parsers/problem/MSKInformaticsProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class MSKInformaticsProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://informatics.msk.ru/mod/statements/view*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('MSK Informatics').setUrl(url); 14 | 15 | const title = elem.querySelector('.statements_toc_alpha strong'); 16 | const text = title.textContent; 17 | const regex = / ([A-Z])\. /; 18 | task.setName(regex.exec(text) ? regex.exec(text)[1] + '. ' + text.split('. ')[1] : text); 19 | 20 | elem.querySelectorAll('.sample-test').forEach(testElem => { 21 | const input = testElem.querySelector('.input > .content').textContent; 22 | const output = testElem.querySelector('.output > .content').textContent; 23 | 24 | task.addTest(input, output); 25 | }); 26 | 27 | return task.build(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/parsers/problem/PandaOnlineJudgeProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class PandaOnlineJudgeProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://pandaoj.com/problem/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('Panda Online Judge').setUrl(url); 14 | 15 | task.setName(elem.querySelector('.mat-card-title').textContent); 16 | 17 | const blocks = elem.querySelectorAll('pre.sample-box'); 18 | for (let i = 0; i < blocks.length - 1; i += 2) { 19 | task.addTest(blocks[i].textContent, blocks[i + 1].textContent); 20 | } 21 | 22 | const headers = elem.querySelectorAll('.mat-card-subtitle'); 23 | task.setTimeLimit(parseInt(/Time Limit: (\d+) ms/.exec(headers[0].textContent)[1], 10)); 24 | task.setMemoryLimit(parseInt(/Memory Limit: (\d+) MB/.exec(headers[1].textContent)[1], 10)); 25 | 26 | return task.build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/parsers/problem/QBXTOJProblemParser.ts: -------------------------------------------------------------------------------- 1 | import type { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class QBXTOJProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://noip.ac/rs/show_problem/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const doc = htmlToElement(html); 13 | const task = new TaskBuilder('QBXTOJ').setUrl(url); 14 | 15 | task.setName(doc.querySelector('h1.ui.header').textContent); 16 | 17 | const [, , timeMs, memMB] = [...doc.querySelector('table > tbody > tr').children].map( 18 | td => td.childNodes[0].textContent, 19 | ); 20 | 21 | task.setTimeLimit(parseFloat(timeMs.trim())); 22 | task.setMemoryLimit(parseInt(memMB.trim(), 10)); 23 | 24 | const codeBlocks = [...doc.querySelectorAll('.ui.segment > pre')]; 25 | 26 | for (let i = 0; i < codeBlocks.length - 1; i += 2) { 27 | task.addTest(codeBlocks[i].textContent, codeBlocks[i + 1].textContent); 28 | } 29 | 30 | return task.build(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/parsers/problem/SortMeProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class SortMeProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://sort-me.org/tasks/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('Sort Me').setUrl(url); 14 | 15 | task.setName(elem.querySelector('.task-content > h2').textContent); 16 | 17 | const categoryElem = elem.querySelector('.task-archive-dropdown.open > .task-archive-dropdown-title > p'); 18 | if (categoryElem !== null) { 19 | task.setCategory(categoryElem.textContent); 20 | } 21 | 22 | elem.querySelectorAll('.samples-item').forEach(itemElem => { 23 | const blocks = itemElem.querySelectorAll('pre'); 24 | task.addTest(blocks[0].textContent, blocks[1].textContent); 25 | }); 26 | 27 | return task.build(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/parsers/problem/TheJobOverflowProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class TheJobOverflowProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['http://thejoboverflow.com/problem/*', 'https://thejoboverflow.com/problem/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const doc = htmlToElement(html); 13 | const task = new TaskBuilder('TheJobOverflow').setUrl(url); 14 | 15 | const titleStr = doc.querySelector('#nav-problem h5').textContent; 16 | task.setName(titleStr.replace(/\s*:$/, '')); 17 | 18 | const inputs = [...doc.querySelectorAll('.sample-test > .input > .content')]; 19 | const outputs = [...doc.querySelectorAll('.sample-test > .output > .content')]; 20 | for (let i = 0; i < inputs.length && i < outputs.length; i++) { 21 | task.addTest(inputs[i].textContent, outputs[i].textContent); 22 | } 23 | 24 | return task.build(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/parsers/problem/XCampProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class XCampProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://contest.x-camp.org/contest/*/problem/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('X-Camp').setUrl(url); 14 | 15 | const nameElem = elem.querySelector('h4.contest-ant-typography'); 16 | task.setName(nameElem.textContent.replace(/\s\s+/g, ' ').trim()); 17 | 18 | const blocks = [...elem.querySelectorAll('.contest-ant-typography-copy')].map(elem => elem.parentElement); 19 | 20 | for (let i = 0; i < blocks.length - 1; i += 2) { 21 | task.addTest(blocks[i].textContent, blocks[i + 1].textContent); 22 | } 23 | 24 | return task.build(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/parsers/problem/YukicoderProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { Sendable } from '../../models/Sendable'; 2 | import { TaskBuilder } from '../../models/TaskBuilder'; 3 | import { htmlToElement } from '../../utils/dom'; 4 | import { Parser } from '../Parser'; 5 | 6 | export class YukicoderProblemParser extends Parser { 7 | public getMatchPatterns(): string[] { 8 | return ['https://yukicoder.me/problems/no/*']; 9 | } 10 | 11 | public async parse(url: string, html: string): Promise { 12 | const elem = htmlToElement(html); 13 | const task = new TaskBuilder('yukicoder').setUrl(url); 14 | 15 | const title = elem.querySelector('#content h3').textContent; 16 | task.setName(title.replace(/([^ ]) {2}([^ ])/g, '$1 $2')); 17 | 18 | const limitsStr = elem.querySelector('#content > div').textContent; 19 | task.setTimeLimit(parseFloat(/([0-9.]+)秒/.exec(limitsStr)[1]) * 1000); 20 | task.setMemoryLimit(parseInt(/(\d+) MB/.exec(limitsStr)[1], 10)); 21 | 22 | elem.querySelectorAll('#content .sample').forEach(sample => { 23 | const preBlocks = sample.querySelectorAll('pre'); 24 | task.addTest(preBlocks[0].textContent, preBlocks[1].textContent); 25 | }); 26 | 27 | return task.build(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/parsers/problem/ZUFEOJProblemParser.ts: -------------------------------------------------------------------------------- 1 | import { HUSTOJSyzojProblemParser } from './HUSTOJSyzojProblemParser'; 2 | 3 | export class ZUFEOJProblemParser extends HUSTOJSyzojProblemParser { 4 | protected judge = 'ZUFEOJ'; 5 | 6 | public getMatchPatterns(): string[] { 7 | return ['http://acm.ocrosoft.com/problem.php*']; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/browser.ts: -------------------------------------------------------------------------------- 1 | import type { Browser } from 'webextension-polyfill'; 2 | 3 | export const browser: Browser = 4 | typeof (globalThis as any | undefined).browser !== 'undefined' 5 | ? (globalThis as any).browser 6 | : (globalThis as any).chrome; 7 | -------------------------------------------------------------------------------- /src/utils/config.ts: -------------------------------------------------------------------------------- 1 | import { browser } from './browser'; 2 | 3 | interface ConfigItems { 4 | customPorts: number[]; 5 | customRules: [string, string][]; 6 | requestTimeout: number; 7 | debugMode: boolean; 8 | } 9 | 10 | class Config { 11 | private readonly defaults: Partial = { 12 | customPorts: [], 13 | customRules: [], 14 | requestTimeout: 500, 15 | debugMode: false, 16 | }; 17 | 18 | public async get(key: T): Promise { 19 | const data = await browser.storage.local.get(key); 20 | return (data[key] || this.defaults[key]) as ConfigItems[T]; 21 | } 22 | 23 | public set(key: T, value: ConfigItems[T]): Promise { 24 | return browser.storage.local.set({ [key]: value }); 25 | } 26 | } 27 | 28 | export const config = new Config(); 29 | -------------------------------------------------------------------------------- /src/utils/dom.ts: -------------------------------------------------------------------------------- 1 | import snarkdown from 'snarkdown'; 2 | 3 | export function htmlToElement(html: string): Element { 4 | return new DOMParser().parseFromString(html, 'text/html').documentElement; 5 | } 6 | 7 | export function markdownToHtml(markdown: string): string { 8 | return snarkdown(markdown); 9 | } 10 | 11 | export function decodeHtml(html: string): string { 12 | return html.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/messaging.ts: -------------------------------------------------------------------------------- 1 | import { MessageAction } from '../models/messaging'; 2 | import { browser } from './browser'; 3 | import { noop } from './noop'; 4 | 5 | export function sendToBackground(action: MessageAction, payload: any = {}): void { 6 | browser.runtime.sendMessage({ action, payload }).then(noop).catch(noop); 7 | } 8 | 9 | export function sendToContent(tabId: number, action: MessageAction, payload: any = {}): void { 10 | browser.tabs.sendMessage(tabId, { action, payload }).then(noop).catch(noop); 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/noop.ts: -------------------------------------------------------------------------------- 1 | export function noop(): void { 2 | // Do nothing 3 | } 4 | -------------------------------------------------------------------------------- /src/utils/random.ts: -------------------------------------------------------------------------------- 1 | export function uuidv4(): string { 2 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { 3 | const r = (Math.random() * 16) | 0, 4 | v = c == 'x' ? r : (r & 0x3) | 0x8; 5 | return v.toString(16); 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /tests/build/expose-parsers.ts: -------------------------------------------------------------------------------- 1 | // @ts-expect-error There are no types for this import 2 | import Nanobar from 'nanobar'; 3 | import { parsers } from '../../src/parsers/parsers'; 4 | 5 | for (const parser of parsers) { 6 | (window as any)[parser.constructor.name] = parser; 7 | } 8 | 9 | window.nanoBar = new Nanobar(); 10 | window.nanoBar.total = 0; 11 | window.nanoBar.advance = () => {}; 12 | -------------------------------------------------------------------------------- /tests/data/a2-online-judge/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://a2oj.com/p?ID=1", 3 | "parser": "A2OnlineJudgeProblemParser", 4 | "result": { 5 | "name": "1. Omar", 6 | "group": "A2 Online Judge", 7 | "url": "https://a2oj.com/p?ID=1", 8 | "interactive": false, 9 | "memoryLimit": 1024, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "5\n22 12\n23 12\n1 1\n2 3\n100 100\n", 14 | "output": "34\n35\n2\n5\n200\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "Omar" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/aizu-online-judge-beta/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://onlinejudge.u-aizu.ac.jp/challenges/sources/JOI/Prelim/0652", 3 | "parser": "AizuOnlineJudgeBetaProblemParser", 4 | "before": "beforeAizuOnlineJudgeBetaNormal", 5 | "result": { 6 | "name": "ソーシャルゲーム (Social Game)", 7 | "group": "Aizu Online Judge - JOI - Prelim", 8 | "url": "https://onlinejudge.u-aizu.ac.jp/challenges/sources/JOI/Prelim/0652", 9 | "interactive": false, 10 | "memoryLimit": 262, 11 | "timeLimit": 2000, 12 | "tests": [ 13 | { 14 | "input": "3 0 10\n", 15 | "output": "4\n" 16 | }, 17 | { 18 | "input": "1 2 10\n", 19 | "output": "8\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "SocialGame" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/aizu-online-judge/problem/japanese.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A&lang=ja", 3 | "parser": "AizuOnlineJudgeProblemParser", 4 | "before": "beforeAizuOnlineJudge", 5 | "result": { 6 | "name": "Projection", 7 | "group": "Aizu Online Judge - CGL - CGL_1_A", 8 | "url": "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A&lang=ja", 9 | "interactive": false, 10 | "memoryLimit": 131, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "0 0 3 4\n1\n2 5\n", 15 | "output": "3.1200000000 4.1600000000\n" 16 | }, 17 | { 18 | "input": "0 0 2 0\n3\n-1 1\n0 1\n1 1\n", 19 | "output": "-1.0000000000 0.0000000000\n0.0000000000 0.0000000000\n1.0000000000 0.0000000000\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "Projection" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/aizu-online-judge/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A&lang=en", 3 | "parser": "AizuOnlineJudgeProblemParser", 4 | "before": "beforeAizuOnlineJudge", 5 | "result": { 6 | "name": "Projection", 7 | "group": "Aizu Online Judge - CGL - CGL_1_A", 8 | "url": "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A&lang=en", 9 | "interactive": false, 10 | "memoryLimit": 131, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "0 0 2 0\n3\n-1 1\n0 1\n1 1\n", 15 | "output": "-1.0000000000 0.0000000000\n0.0000000000 0.0000000000\n1.0000000000 0.0000000000\n" 16 | }, 17 | { 18 | "input": "0 0 3 4\n1\n2 5\n", 19 | "output": "3.1200000000 4.1600000000\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "Projection" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/algotester/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://algotester.com/en/ArchiveProblem/DisplayWithFile/20024", 3 | "parser": "AlgotesterProblemParser", 4 | "result": { 5 | "name": "A plus B", 6 | "group": "Algotester", 7 | "url": "https://algotester.com/en/ArchiveProblem/DisplayWithFile/20024", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "4 7\n", 14 | "output": "11\n" 15 | }, 16 | { 17 | "input": "47 74\n", 18 | "output": "121\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "APlusB" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/atcoder/problem/interactive.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://atcoder.jp/contests/arc070/tasks/arc070_d", 3 | "parser": "AtCoderProblemParser", 4 | "result": { 5 | "name": "F - HonestOrUnkind", 6 | "group": "AtCoder - AtCoder Regular Contest 070", 7 | "url": "https://atcoder.jp/contests/arc070/tasks/arc070_d", 8 | "interactive": true, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [], 12 | "testType": "single", 13 | "input": { 14 | "type": "stdin" 15 | }, 16 | "output": { 17 | "type": "stdout" 18 | }, 19 | "languages": { 20 | "java": { 21 | "mainClass": "Main", 22 | "taskClass": "FHonestOrUnkind" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/data/atcoder/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://atcoder.jp/contests/abc096/tasks/abc096_a", 3 | "parser": "AtCoderProblemParser", 4 | "result": { 5 | "name": "A - Day of Takahashi", 6 | "group": "AtCoder - AtCoder Beginner Contest 096", 7 | "url": "https://atcoder.jp/contests/abc096/tasks/abc096_a", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "5 5\n", 14 | "output": "5\n" 15 | }, 16 | { 17 | "input": "2 1\n", 18 | "output": "1\n" 19 | }, 20 | { 21 | "input": "11 30\n", 22 | "output": "11\n" 23 | } 24 | ], 25 | "testType": "single", 26 | "input": { 27 | "type": "stdin" 28 | }, 29 | "output": { 30 | "type": "stdout" 31 | }, 32 | "languages": { 33 | "java": { 34 | "mainClass": "Main", 35 | "taskClass": "ADayOfTakahashi" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/data/atcoder/problem/normal_ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://atcoder.jp/contests/colopl2018-final/tasks/colopl2018_final_a", 3 | "parser": "AtCoderProblemParser", 4 | "result": { 5 | "name": "A - ファイティング・タカハシ", 6 | "group": "AtCoder - COLOCON -Colopl programming contest 2018- Final", 7 | "url": "https://atcoder.jp/contests/colopl2018-final/tasks/colopl2018_final_a", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "3\nABBAA\n", 14 | "output": "16\n" 15 | }, 16 | { 17 | "input": "4\nABBAAABBAA\n", 18 | "output": "46\n" 19 | }, 20 | { 21 | "input": "100\nAAABAAAABAAAAABBBBBBBBBAABBBBBBAAAAABBB\n", 22 | "output": "4900\n" 23 | } 24 | ], 25 | "testType": "single", 26 | "input": { 27 | "type": "stdin" 28 | }, 29 | "output": { 30 | "type": "stdout" 31 | }, 32 | "languages": { 33 | "java": { 34 | "mainClass": "Main", 35 | "taskClass": "A" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/data/baekjoon-online-judge/problem/multiple-time-limits.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.acmicpc.net/problem/23261", 3 | "parser": "BaekjoonOnlineJudgeProblemParser", 4 | "result": { 5 | "name": "Dogs and Cats", 6 | "group": "Baekjoon Online Judge", 7 | "url": "https://www.acmicpc.net/problem/23261", 8 | "interactive": false, 9 | "memoryLimit": 1024, 10 | "timeLimit": 40000, 11 | "tests": [ 12 | { 13 | "input": "3\n6 10 4 0\nCCDCDD\n4 1 2 0\nCCCC\n4 2 1 0\nDCCD\n", 14 | "output": "Case #1: YES\nCase #2: YES\nCase #3: NO\n" 15 | }, 16 | { 17 | "input": "2\n12 4 2 2\nCDCCCDCCDCDC\n8 2 1 3\nDCCCCCDC\n", 18 | "output": "Case #1: YES\nCase #2: NO\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "DogsAndCats" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/baekjoon-online-judge/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.acmicpc.net/problem/1008", 3 | "parser": "BaekjoonOnlineJudgeProblemParser", 4 | "result": { 5 | "name": "A/B", 6 | "group": "Baekjoon Online Judge", 7 | "url": "https://www.acmicpc.net/problem/1008", 8 | "interactive": false, 9 | "memoryLimit": 128, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "1 3\n", 14 | "output": "0.33333333333333333333333333333333\n" 15 | }, 16 | { 17 | "input": "4 5\n", 18 | "output": "0.8\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "AB" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/buctoj/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://buctcoder.com/problem.php?id=1150", 3 | "parser": "BUCTOJProblemParser", 4 | "result": { 5 | "name": "1150: LED Test", 6 | "group": "BUCTOJ", 7 | "url": "https://buctcoder.com/problem.php?id=1150", 8 | "interactive": false, 9 | "memoryLimit": 128, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "1\nYYYYNYY\n2\nNNNNNNN\nNNNNNNN\n2\nYYYYYYY\nYYYYYYY\n3\nYNYYYYY\nYNYYNYY\nNYYNNYY\n3\nYNYYYYN\nYNYYNYN\nNYYNNYN\n3\nYNYYYYN\nYNYYNYN\nNYYNYYN\n4\nYYYYYYY\nNYYNNNN\nNNYYYYN\nNNNYNNN\n3\nNNNNNNN\nYNNNNNN\nNNNNYNN\n0\n", 14 | "output": "MATCH\nMATCH\nMISMATCH\nMATCH\nMATCH\nMISMATCH\nMATCH\nMATCH\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "LEDTest" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/code-drills/problem/contest-problem.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codedrills.io/contests/amrita-icpc-practice-session-4/problems/maximum-prefix-mex-sum", 3 | "parser": "CodeDrillsProblemParser", 4 | "before": "beforeCodeDrills", 5 | "result": { 6 | "name": "Maximum Prefix Mex Sum", 7 | "group": "CodeDrills - Amrita ICPC Practice Session #4", 8 | "url": "https://codedrills.io/contests/amrita-icpc-practice-session-4/problems/maximum-prefix-mex-sum", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "2\n3\n1 2 1\n3\n1 0 1\n", 15 | "output": "6\n2\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "MaximumPrefixMexSum" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/code-drills/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codedrills.io/problems/beating-shell-sort", 3 | "parser": "CodeDrillsProblemParser", 4 | "before": "beforeCodeDrills", 5 | "result": { 6 | "name": "Beating Shell sort", 7 | "group": "CodeDrills", 8 | "url": "https://codedrills.io/problems/beating-shell-sort", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "2\n6 2\n", 15 | "output": "50000\n" 16 | }, 17 | { 18 | "input": "7\n701 301 132 57 23 10 4\n", 19 | "output": "69044\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "BeatingShellSort" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/new-copy-button.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems/BUS", 3 | "parser": "CodeChefNewProblemParser", 4 | "before": "beforeCodeChefNew", 5 | "result": { 6 | "name": "Bus full of passengers", 7 | "group": "CodeChef - START9", 8 | "url": "https://www.codechef.com/problems/BUS", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "2\n2 1 4\n+ 1\n+ 2\n- 1\n- 2\n3 2 6\n+ 2\n+ 1\n- 1\n+ 3\n- 3\n- 2\n", 15 | "output": "Inconsistent\nConsistent\n" 16 | }, 17 | { 18 | "input": "2\n100 10 5\n+ 1\n+ 2\n- 3\n+ 3\n- 2\n6 4 4\n+ 3\n+ 2\n+ 1\n+ 4\n", 19 | "output": "Inconsistent\nConsistent\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "BusFullOfPassengers" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/new-example-headers-as-normal-text.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems/FCTRL2", 3 | "parser": "CodeChefNewProblemParser", 4 | "before": "beforeCodeChefNew", 5 | "result": { 6 | "name": "Small factorials", 7 | "group": "CodeChef - Practice", 8 | "url": "https://www.codechef.com/problems/FCTRL2", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 235, 12 | "tests": [ 13 | { 14 | "input": "4\n1\n2\n5\n3\n", 15 | "output": "1\n2\n120\n6\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "SmallFactorials" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/new-input-output-after-example-header.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems/LAPIN", 3 | "parser": "CodeChefNewProblemParser", 4 | "before": "beforeCodeChefNew", 5 | "result": { 6 | "name": "Lapindromes", 7 | "group": "CodeChef - JUNE13", 8 | "url": "https://www.codechef.com/problems/LAPIN", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "6\ngaga\nabcde\nrotor\nxyzxy\nabbaab\nababc\n", 15 | "output": "YES\nNO\nYES\nYES\nNO\nNO\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "Lapindromes" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/new-input-output-as-normal-text.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems/TRISQ", 3 | "parser": "CodeChefNewProblemParser", 4 | "before": "beforeCodeChefNew", 5 | "result": { 6 | "name": "Fit Squares in Triangle", 7 | "group": "CodeChef - COOK55", 8 | "url": "https://www.codechef.com/problems/TRISQ", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "11\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n", 15 | "output": "0\n0\n0\n1\n1\n3\n3\n6\n6\n10\n10\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "FitSquaresInTriangle" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/new-input-output-in-different-pre.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/MAY18B/problems/RD19", 3 | "parser": "CodeChefNewProblemParser", 4 | "before": "beforeCodeChefNew", 5 | "result": { 6 | "name": "Minimum Deletions", 7 | "group": "CodeChef - MAY18B", 8 | "url": "https://www.codechef.com/MAY18B/problems/RD19", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "2\n2\n2 3\n2\n2 4\n", 15 | "output": "0\n-1\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "MinimumDeletions" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/new-input-output-in-same-pre.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/LTIME58A/problems/ZOZ", 3 | "parser": "CodeChefNewProblemParser", 4 | "before": "beforeCodeChefNew", 5 | "result": { 6 | "name": "Magic Elements", 7 | "group": "CodeChef - LTIME58A", 8 | "url": "https://www.codechef.com/LTIME58A/problems/ZOZ", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 500, 12 | "tests": [ 13 | { 14 | "input": "2\n4 4\n2 1 6 7\n4 2\n2 1 5 4\n", 15 | "output": "1\n0\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "MagicElements" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/new-tests-as-normal-text.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/KQ102018/problems/QM10B", 3 | "parser": "CodeChefNewProblemParser", 4 | "before": "beforeCodeChefNew", 5 | "result": { 6 | "name": "Total Graphs (keteki)", 7 | "group": "CodeChef - KQ102018", 8 | "url": "https://www.codechef.com/KQ102018/problems/QM10B", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [], 13 | "testType": "single", 14 | "input": { 15 | "type": "stdin" 16 | }, 17 | "output": { 18 | "type": "stdout" 19 | }, 20 | "languages": { 21 | "java": { 22 | "mainClass": "Main", 23 | "taskClass": "TotalGraphsKeteki" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/old-copy-button.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems-old/BUS", 3 | "parser": "CodeChefOldProblemParser", 4 | "before": "beforeCodeChefOld", 5 | "result": { 6 | "name": "Bus full of passengers", 7 | "group": "CodeChef - START9", 8 | "url": "https://www.codechef.com/problems-old/BUS", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "2\n2 1 4\n+ 1\n+ 2\n- 1\n- 2\n3 2 6\n+ 2\n+ 1\n- 1\n+ 3\n- 3\n- 2\n", 15 | "output": "Inconsistent\nConsistent\n" 16 | }, 17 | { 18 | "input": "2\n100 10 5\n+ 1\n+ 2\n- 3\n+ 3\n- 2\n6 4 4\n+ 3\n+ 2\n+ 1\n+ 4\n", 19 | "output": "Inconsistent\nConsistent\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "BusFullOfPassengers" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/old-example-headers-as-normal-text.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems-old/FCTRL2", 3 | "parser": "CodeChefOldProblemParser", 4 | "before": "beforeCodeChefOld", 5 | "result": { 6 | "name": "Small factorials", 7 | "group": "CodeChef - Practice", 8 | "url": "https://www.codechef.com/problems-old/FCTRL2", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 235, 12 | "tests": [ 13 | { 14 | "input": "4\n1\n2\n5\n3\n", 15 | "output": "1\n2\n120\n6\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "SmallFactorials" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/old-input-output-after-example-header.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems-old/LAPIN", 3 | "parser": "CodeChefOldProblemParser", 4 | "before": "beforeCodeChefOld", 5 | "result": { 6 | "name": "Lapindromes", 7 | "group": "CodeChef - JUNE13", 8 | "url": "https://www.codechef.com/problems-old/LAPIN", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "6\ngaga\nabcde\nrotor\nxyzxy\nabbaab\nababc\n", 15 | "output": "YES\nNO\nYES\nYES\nNO\nNO\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "Lapindromes" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/old-input-output-as-normal-text.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/problems-old/TRISQ", 3 | "parser": "CodeChefOldProblemParser", 4 | "before": "beforeCodeChefOld", 5 | "result": { 6 | "name": "Fit Squares in Triangle", 7 | "group": "CodeChef - COOK55", 8 | "url": "https://www.codechef.com/problems-old/TRISQ", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "11\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n", 15 | "output": "0\n0\n0\n1\n1\n3\n3\n6\n6\n10\n10\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "FitSquaresInTriangle" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/old-input-output-in-different-pre.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/MAY18B/problems-old/RD19", 3 | "parser": "CodeChefOldProblemParser", 4 | "before": "beforeCodeChefOld", 5 | "result": { 6 | "name": "Minimum Deletions", 7 | "group": "CodeChef - MAY18", 8 | "url": "https://www.codechef.com/MAY18B/problems-old/RD19", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "2\n2\n2 3\n2\n2 4\n", 15 | "output": "0\n-1\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "MinimumDeletions" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/old-input-output-in-same-pre.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/LTIME58A/problems-old/ZOZ", 3 | "parser": "CodeChefOldProblemParser", 4 | "before": "beforeCodeChefOld", 5 | "result": { 6 | "name": "Magic Elements", 7 | "group": "CodeChef - LTIME58", 8 | "url": "https://www.codechef.com/LTIME58A/problems-old/ZOZ", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 500, 12 | "tests": [ 13 | { 14 | "input": "2\n4 4\n2 1 6 7\n4 2\n2 1 5 4\n", 15 | "output": "1\n0\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "MagicElements" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codechef/problem/old-tests-as-normal-text.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.codechef.com/KQ102018/problems-old/QM10B", 3 | "parser": "CodeChefOldProblemParser", 4 | "before": "beforeCodeChefOld", 5 | "result": { 6 | "name": "Total Graphs (keteki)", 7 | "group": "CodeChef - KQ102018", 8 | "url": "https://www.codechef.com/KQ102018/problems-old/QM10B", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [], 13 | "testType": "single", 14 | "input": { 15 | "type": "stdin" 16 | }, 17 | "output": { 18 | "type": "stdout" 19 | }, 20 | "languages": { 21 | "java": { 22 | "mainClass": "Main", 23 | "taskClass": "TotalGraphsKeteki" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/acm-sgu-ru-inside-table.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemsets/acmsguru/problem/99999/123?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "123. The sum", 6 | "group": "Codeforces - acm.sgu.ru archive", 7 | "url": "https://codeforces.com/problemsets/acmsguru/problem/99999/123?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 4, 10 | "timeLimit": 250, 11 | "tests": [ 12 | { 13 | "input": "5\n", 14 | "output": "12\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "TheSum" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/acm-sgu-ru-not-inside-table.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemsets/acmsguru/problem/99999/553?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "553. Sultan's Pearls", 6 | "group": "Codeforces - acm.sgu.ru archive", 7 | "url": "https://codeforces.com/problemsets/acmsguru/problem/99999/553?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 262, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "5 2 1\n5 3\n4 2\n6 4\n3 2\n2 2\n", 14 | "output": "2 5\nTT\n" 15 | }, 16 | { 17 | "input": "20 7 2\n3 4\n8 4\n8 5\n6 14\n5 10\n3 18\n2 5\n2 4\n1 6\n3 11\n4 3\n3 5\n2 8\n4 6\n9 14\n7 2\n7 6\n6 4\n8 2\n10 5\n", 18 | "output": "11 60\nHTHTHTHHHHH\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "SultansPearls" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/cursive-input-output.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemset/problem/1220/C?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "C. Substring Game in the Lesson", 6 | "group": "Codeforces - Codeforces Round 586 (Div. 1 + Div. 2)", 7 | "url": "https://codeforces.com/problemset/problem/1220/C?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "abba\n", 14 | "output": "Mike\nAnn\nAnn\nMike\n" 15 | }, 16 | { 17 | "input": "cba\n", 18 | "output": "Mike\nMike\nMike\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "CSubstringGameInTheLesson" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/file-input-output.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemset/problem/234/A?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "A. Lefthanders and Righthanders", 6 | "group": "Codeforces - Codeforces Round 145 (Div. 2, ACM-ICPC Rules)", 7 | "url": "https://codeforces.com/problemset/problem/234/A?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "6\nLLRLLL\n", 14 | "output": "1 4\n2 5\n6 3\n" 15 | }, 16 | { 17 | "input": "4\nRRLL\n", 18 | "output": "3 1\n4 2\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "fileName": "input.txt", 24 | "type": "file" 25 | }, 26 | "output": { 27 | "fileName": "output.txt", 28 | "type": "file" 29 | }, 30 | "languages": { 31 | "java": { 32 | "mainClass": "Main", 33 | "taskClass": "ALefthandersAndRighthanders" 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/gym.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/gym/101991/problem/E?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "E. Exciting Menus", 6 | "group": "Codeforces - 2018 Arab Collegiate Programming Contest (ACPC 2018)", 7 | "url": "https://codeforces.com/gym/101991/problem/E?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 1024, 10 | "timeLimit": 4000, 11 | "tests": [ 12 | { 13 | "input": "2\n2\naabaa\naa\n0 0 0 0 100\n0 1\n4\nbbbaa\naa\naab\naax\n0 0 0 0 100\n0 0\n0 0 0\n0 0 0\n", 14 | "output": "500\n600\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "fileName": "exciting.in", 20 | "type": "file" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "EExcitingMenus" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/highlighted-input-deep.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/contest/1702/problem/C?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "C. Train and Queries", 6 | "group": "Codeforces - Codeforces Round 805 (Div. 3)", 7 | "url": "https://codeforces.com/contest/1702/problem/C?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 3000, 11 | "tests": [ 12 | { 13 | "input": "3\n6 3\n3 7 1 5 1 4\n3 5\n1 7\n3 10\n3 3\n1 2 1\n2 1\n1 2\n4 5\n7 5\n2 1 1 1 2 4 4\n1 3\n1 4\n2 1\n4 1\n1 2\n", 14 | "output": "YES\nNO\nNO\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nYES\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "CTrainAndQueries" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/highlighted-input.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemset/problem/1716/F?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "F. Bags with Balls", 6 | "group": "Codeforces - Educational Codeforces Round 133 (Rated for Div. 2)", 7 | "url": "https://codeforces.com/problemset/problem/1716/F?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 512, 10 | "timeLimit": 3000, 11 | "tests": [ 12 | { 13 | "input": "5\n2 3 8\n1 1 1\n1 5 10\n3 7 2000\n1337666 42424242 2000\n", 14 | "output": "1028\n1\n3\n729229716\n652219904\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "FBagsWithBalls" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/html-entities-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/contest/1131/problem/D?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "D. Gourmet choice", 6 | "group": "Codeforces - Codeforces Round 541 (Div. 2)", 7 | "url": "https://codeforces.com/contest/1131/problem/D?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "3 4\n>>>>\n>>>>\n>>>>\n", 14 | "output": "Yes\n2 2 2\n1 1 1 1\n" 15 | }, 16 | { 17 | "input": "3 3\n>>>\n<<<\n>>>\n", 18 | "output": "Yes\n3 1 3\n2 2 2\n" 19 | }, 20 | { 21 | "input": "3 2\n==\n=<\n==\n", 22 | "output": "No\n" 23 | } 24 | ], 25 | "testType": "single", 26 | "input": { 27 | "type": "stdin" 28 | }, 29 | "output": { 30 | "type": "stdout" 31 | }, 32 | "languages": { 33 | "java": { 34 | "mainClass": "Main", 35 | "taskClass": "DGourmetChoice" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/html-entities-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemset/problem/707/A?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "A. Brain's Photos", 6 | "group": "Codeforces - Codeforces Round 368 (Div. 2)", 7 | "url": "https://codeforces.com/problemset/problem/707/A?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "2 2\nC M\nY Y\n", 14 | "output": "#Color\n" 15 | }, 16 | { 17 | "input": "3 2\nW W\nW W\nB B\n", 18 | "output": "#Black&White\n" 19 | }, 20 | { 21 | "input": "1 1\nW\n", 22 | "output": "#Black&White\n" 23 | } 24 | ], 25 | "testType": "single", 26 | "input": { 27 | "type": "stdin" 28 | }, 29 | "output": { 30 | "type": "stdout" 31 | }, 32 | "languages": { 33 | "java": { 34 | "mainClass": "Main", 35 | "taskClass": "ABrainsPhotos" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/inside-group.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/group/MWSDmqGsZm/contest/219856/problem/A?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "A. Create A New String", 6 | "group": "Codeforces - Sheet #4 (Strings)", 7 | "url": "https://codeforces.com/group/MWSDmqGsZm/contest/219856/problem/A?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "LEVEL\nONE\n", 14 | "output": "5 3\nLEVEL ONE\n" 15 | }, 16 | { 17 | "input": "Programming\ncontest\n", 18 | "output": "11 7\nProgramming contest\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "ACreateANewString" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/interactive-russian.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/contest/810/problem/D?locale=ru", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "D. Очень приятно!", 6 | "group": "Codeforces - Codeforces Round 415 (Div. 2)", 7 | "url": "https://codeforces.com/contest/810/problem/D?locale=ru", 8 | "interactive": true, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "3 2\nNIE\nTAK\nNIE\nTAK\nTAK\nTAK\n", 14 | "output": "1 1 2\n1 2 1\n1 1 3\n1 3 1\n1 2 3\n1 3 2\n2 2 3\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "DOchenPriyatno" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/interactive.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/contest/810/problem/D?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "D. Glad to see you!", 6 | "group": "Codeforces - Codeforces Round 415 (Div. 2)", 7 | "url": "https://codeforces.com/contest/810/problem/D?locale=en", 8 | "interactive": true, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "3 2\nNIE\nTAK\nNIE\nTAK\nTAK\nTAK\n", 14 | "output": "1 1 2\n1 2 1\n1 1 3\n1 3 1\n1 2 3\n1 3 2\n2 2 3\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "DGladToSeeYou" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/nbsp.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/contest/767/problem/A?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "A. Snacktower", 6 | "group": "Codeforces - Codeforces Round 398 (Div. 2)", 7 | "url": "https://codeforces.com/contest/767/problem/A?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "3\n3 1 2\n", 14 | "output": "3\n\n2 1\n" 15 | }, 16 | { 17 | "input": "5\n4 5 1 2 3\n", 18 | "output": "\n5 4\n\n\n3 2 1\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "ASnacktower" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemset/problem/118/A?locale=en", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "A. String Task", 6 | "group": "Codeforces - Codeforces Beta Round 89 (Div. 2)", 7 | "url": "https://codeforces.com/problemset/problem/118/A?locale=en", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "tour\n", 14 | "output": ".t.r\n" 15 | }, 16 | { 17 | "input": "Codeforces\n", 18 | "output": ".c.d.f.r.c.s\n" 19 | }, 20 | { 21 | "input": "aBAcAba\n", 22 | "output": ".b.c.b\n" 23 | } 24 | ], 25 | "testType": "single", 26 | "input": { 27 | "type": "stdin" 28 | }, 29 | "output": { 30 | "type": "stdout" 31 | }, 32 | "languages": { 33 | "java": { 34 | "mainClass": "Main", 35 | "taskClass": "AStringTask" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/data/codeforces/problem/russian-stdin-stdout.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codeforces.com/problemset/problem/954/G?locale=ru", 3 | "parser": "CodeforcesProblemParser", 4 | "result": { 5 | "name": "G. Оборона крепости", 6 | "group": "Codeforces - Educational Codeforces Round 40 (рейтинговый для Див. 2)", 7 | "url": "https://codeforces.com/problemset/problem/954/G?locale=ru", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 1500, 11 | "tests": [ 12 | { 13 | "input": "5 0 6\n5 4 3 4 9\n", 14 | "output": "5\n" 15 | }, 16 | { 17 | "input": "4 2 0\n1 2 3 4\n", 18 | "output": "6\n" 19 | }, 20 | { 21 | "input": "5 1 1\n2 1 2 1 2\n", 22 | "output": "3\n" 23 | } 24 | ], 25 | "testType": "single", 26 | "input": { 27 | "type": "stdin" 28 | }, 29 | "output": { 30 | "type": "stdout" 31 | }, 32 | "languages": { 33 | "java": { 34 | "mainClass": "Main", 35 | "taskClass": "GOboronaKreposti" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/data/codemarshal/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://algo.codemarshal.org/problems/556a283cf661160300813812", 3 | "parser": "CodeMarshalProblemParser", 4 | "result": { 5 | "name": " CSE, DU তে স্বাগতম (Welcome to CSE, DU)", 6 | "group": "CodeMarshal", 7 | "url": "https://algo.codemarshal.org/problems/556a283cf661160300813812", 8 | "interactive": false, 9 | "memoryLimit": 1024, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "100 100 50\n20 10 3\n", 14 | "output": "150\n27\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "CSEDUWelcomeToCSEDU" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/contest-hunter/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "http://noi-test.zzstep.com/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0101%20a%5Eb", 3 | "parser": "ContestHunterProblemParser", 4 | "result": { 5 | "name": "0101 a^b", 6 | "group": "ContestHunter - 0x00「基本算法」例题", 7 | "url": "http://noi-test.zzstep.com/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0101%20a%5Eb", 8 | "interactive": false, 9 | "memoryLimit": 32, 10 | "timeLimit": 500, 11 | "tests": [ 12 | { 13 | "input": "2 3 9\n", 14 | "output": "8\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "Ab" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/cpython-uz/problem/contest.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://cpython.uz/competitions/contests/contest/297/problem/A", 3 | "parser": "CPythonUZProblemParser", 4 | "before": "beforeCPythonUZ", 5 | "result": { 6 | "name": "A. One Line | Divisible", 7 | "group": "CPython.uz - One Line #8 | Feat. Less Code", 8 | "url": "https://cpython.uz/competitions/contests/contest/297/problem/A", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 500, 12 | "tests": [ 13 | { 14 | "input": "4\n2\n", 15 | "output": "Yes\n" 16 | }, 17 | { 18 | "input": "2\n4\n", 19 | "output": "No\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "AOneLineDivisible" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/cpython-uz/problem/duel.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://cpython.uz/practice/duels/duel/12", 3 | "parser": "CPythonUZProblemParser", 4 | "before": "beforeCPythonUZ", 5 | "result": { 6 | "name": "A. Ifoda", 7 | "group": "CPython.uz", 8 | "url": "https://cpython.uz/practice/duels/duel/12", 9 | "interactive": false, 10 | "memoryLimit": 512, 11 | "timeLimit": 1000, 12 | "tests": [], 13 | "testType": "single", 14 | "input": { 15 | "type": "stdin" 16 | }, 17 | "output": { 18 | "type": "stdout" 19 | }, 20 | "languages": { 21 | "java": { 22 | "mainClass": "Main", 23 | "taskClass": "AIfoda" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/data/cpython-uz/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://cpython.uz/practice/problems/problem/1", 3 | "parser": "CPythonUZProblemParser", 4 | "before": "beforeCPythonUZ", 5 | "result": { 6 | "name": "The sum of two numbers", 7 | "group": "CPython.uz", 8 | "url": "https://cpython.uz/practice/problems/problem/1", 9 | "interactive": false, 10 | "memoryLimit": 250, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "2\n2\n", 15 | "output": "4\n" 16 | }, 17 | { 18 | "input": "5\n10\n", 19 | "output": "15\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "TheSumOfTwoNumbers" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/cs-academy/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://csacademy.com/contest/archive/task/addition/", 3 | "parser": "CSAcademyProblemParser", 4 | "before": "beforeCSAcademy", 5 | "result": { 6 | "name": "Addition", 7 | "group": "CS Academy", 8 | "url": "https://csacademy.com/contest/archive/task/addition/", 9 | "interactive": false, 10 | "memoryLimit": 128, 11 | "timeLimit": 500, 12 | "tests": [ 13 | { 14 | "input": "10 20\n", 15 | "output": "30\n" 16 | }, 17 | { 18 | "input": "333 876\n", 19 | "output": "1209\n" 20 | } 21 | ], 22 | "testType": "single", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Main", 32 | "taskClass": "Addition" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/cses/problem/code_blocks_in_statement.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://cses.fi/problemset/task/1729", 3 | "parser": "CSESProblemParser", 4 | "result": { 5 | "name": "Stick Game", 6 | "group": "CSES - CSES Problem Set", 7 | "url": "https://cses.fi/problemset/task/1729", 8 | "interactive": false, 9 | "memoryLimit": 512, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "10 3\n1 3 4\n", 14 | "output": "WLWWWWLWLW\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "StickGame" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/cses/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://cses.fi/problemset/task/1094", 3 | "parser": "CSESProblemParser", 4 | "result": { 5 | "name": "Increasing Array", 6 | "group": "CSES - CSES Problem Set", 7 | "url": "https://cses.fi/problemset/task/1094", 8 | "interactive": false, 9 | "memoryLimit": 512, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "5\n3 2 5 1 7\n", 14 | "output": "5\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "IncreasingArray" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/dmoj/problem/contest-with-p-number.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://dmoj.ca/problem/aac1p1", 3 | "parser": "DMOJProblemParser", 4 | "result": { 5 | "name": "P1 - Alpaca Shapes", 6 | "group": "DMOJ - An Animal Contest 1", 7 | "url": "https://dmoj.ca/problem/aac1p1", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "6 2\n", 14 | "output": "SQUARE\n" 15 | }, 16 | { 17 | "input": "12 124\n", 18 | "output": "CIRCLE\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "P1AlpacaShapes" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/dmoj/problem/contest-with-problem-number.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://dmoj.ca/problem/acc3p4", 3 | "parser": "DMOJProblemParser", 4 | "result": { 5 | "name": "Problem 4 - Range Updates and Range Queries", 6 | "group": "DMOJ - Another Contest 3", 7 | "url": "https://dmoj.ca/problem/acc3p4", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "3 4\n1 2 3 2\n2 1 1\n2 2 2\n2 3 3\n", 14 | "output": "0\n2\n4\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "Problem4RangeUpdatesAndRangeQueries" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/dmoj/problem/contest-without-problem-number.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://dmoj.ca/problem/canada21p1", 3 | "parser": "DMOJProblemParser", 4 | "result": { 5 | "name": "Bob and Canada", 6 | "group": "DMOJ - Canada Day Contest 2021", 7 | "url": "https://dmoj.ca/problem/canada21p1", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 3000, 11 | "tests": [ 12 | { 13 | "input": "8\n3\nRWR\n3\nWWW\n3\nWRR\n4\nRWRW\n6\nWWWRRR\n6\nWWRRWW\n10\nRRRRWWRWRR\n10\nWWRRWWWWRW\n", 14 | "output": "0\n2\n2\n1\n1\n3\n1\n3\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "BobAndCanada" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/dmoj/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://dmoj.ca/problem/aplusb", 3 | "parser": "DMOJProblemParser", 4 | "result": { 5 | "name": "A Plus B", 6 | "group": "DMOJ", 7 | "url": "https://dmoj.ca/problem/aplusb", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 5000, 11 | "tests": [ 12 | { 13 | "input": "2\n1 1\n-1 0\n", 14 | "output": "2\n-1\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "APlusB" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/dmoj/problem/output-for-sample-input.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://dmoj.ca/problem/ccc16s4", 3 | "parser": "DMOJProblemParser", 4 | "result": { 5 | "name": "S4 - Combining Riceballs", 6 | "group": "DMOJ - CCC '16", 7 | "url": "https://dmoj.ca/problem/ccc16s4", 8 | "interactive": false, 9 | "memoryLimit": 256, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "7\n47 12 12 3 9 9 3\n", 14 | "output": "48\n" 15 | }, 16 | { 17 | "input": "4\n1 2 3 1\n", 18 | "output": "3\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "S4CombiningRiceballs" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/eolymp/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.eolymp.com/en/problems/5", 3 | "parser": "EolympNormalProblemParser", 4 | "result": { 5 | "name": "Two factors", 6 | "group": "Eolymp", 7 | "url": "https://www.eolymp.com/en/problems/5", 8 | "interactive": false, 9 | "memoryLimit": 128, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "1\n", 14 | "output": "1\n" 15 | }, 16 | { 17 | "input": "2\n", 18 | "output": "4\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "TwoFactors" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/google-coding-competitions/problem/codejam.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codingcompetitions.withgoogle.com/codejam/round/0000000000007766/000000000004dbbd", 3 | "parser": "GoogleCodingCompetitionsProblemParser", 4 | "before": "beforeGoogleCodingCompetitions", 5 | "result": { 6 | "name": "Jurisdiction Restrictions", 7 | "group": "Google Coding Competitions - World Finals 2018 - Code Jam 2018", 8 | "url": "https://codingcompetitions.withgoogle.com/codejam/round/0000000000007766/000000000004dbbd", 9 | "interactive": false, 10 | "memoryLimit": 1024, 11 | "timeLimit": 30000, 12 | "tests": [ 13 | { 14 | "input": "2\n3 4 2\n1 1 1\n3 3 2\n5 5 2\n4 1 2\n3 2 2\n", 15 | "output": "Case #1: 4\nCase #2: 0\n" 16 | } 17 | ], 18 | "testType": "multiNumber", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Solution", 28 | "taskClass": "JurisdictionRestrictions" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/google-coding-competitions/problem/kickstart-new.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068cca3", 3 | "parser": "GoogleCodingCompetitionsProblemParser", 4 | "before": "beforeGoogleCodingCompetitions", 5 | "result": { 6 | "name": "K-Goodness String", 7 | "group": "Google Coding Competitions - Round A 2021 - Kick Start 2021", 8 | "url": "https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068cca3", 9 | "interactive": false, 10 | "memoryLimit": 1024, 11 | "timeLimit": 20000, 12 | "tests": [ 13 | { 14 | "input": "2\n5 1\nABCAA\n4 2\nABAA\n", 15 | "output": "Case #1: 0\nCase #2: 1\n" 16 | } 17 | ], 18 | "testType": "multiNumber", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Solution", 28 | "taskClass": "KGoodnessString" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/google-coding-competitions/problem/multiple-samples.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ffc7/00000000001d3f5b", 3 | "parser": "GoogleCodingCompetitionsProblemParser", 4 | "before": "beforeGoogleCodingCompetitions", 5 | "result": { 6 | "name": "Workout", 7 | "group": "Google Coding Competitions - Round A 2020 - Kick Start 2020", 8 | "url": "https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ffc7/00000000001d3f5b", 9 | "interactive": false, 10 | "memoryLimit": 1024, 11 | "timeLimit": 20000, 12 | "tests": [ 13 | { 14 | "input": "1\n3 1\n100 200 230\n", 15 | "output": "Case #1: 50\n" 16 | }, 17 | { 18 | "input": "3\n5 2\n10 13 15 16 17\n5 6\n9 10 20 26 30\n8 3\n1 2 3 4 5 6 7 10\n", 19 | "output": "Case #1: 2\nCase #2: 3\nCase #3: 1\n" 20 | } 21 | ], 22 | "testType": "multiNumber", 23 | "input": { 24 | "type": "stdin" 25 | }, 26 | "output": { 27 | "type": "stdout" 28 | }, 29 | "languages": { 30 | "java": { 31 | "mainClass": "Solution", 32 | "taskClass": "Workout" 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/data/hackerearth/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.hackerearth.com/practice/basic-programming/input-output/basics-of-input-output/practice-problems/algorithm/palindrome-check-2/", 3 | "parser": "HackerEarthProblemParser", 4 | "before": "beforeHackerEarth", 5 | "result": { 6 | "name": "Palindromic String", 7 | "group": "HackerEarth - Basic Programming - Input/Output - Basics of Input/Output", 8 | "url": "https://www.hackerearth.com/practice/basic-programming/input-output/basics-of-input-output/practice-problems/algorithm/palindrome-check-2/", 9 | "interactive": false, 10 | "memoryLimit": 256, 11 | "timeLimit": 1000, 12 | "tests": [ 13 | { 14 | "input": "aba\n", 15 | "output": "YES\n" 16 | } 17 | ], 18 | "testType": "single", 19 | "input": { 20 | "type": "stdin" 21 | }, 22 | "output": { 23 | "type": "stdout" 24 | }, 25 | "languages": { 26 | "java": { 27 | "mainClass": "Main", 28 | "taskClass": "PalindromicString" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/data/hdoj/problem/contest-problem.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=798", 3 | "parser": "HDOJProblemParser", 4 | "result": { 5 | "name": "Circular Coloring", 6 | "group": "HDOJ", 7 | "url": "https://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=798", 8 | "interactive": false, 9 | "memoryLimit": 132, 10 | "timeLimit": 6000, 11 | "tests": [ 12 | { 13 | "input": "1 2\n2 3\n5000 5000\n", 14 | "output": "6\n40\n975597525\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "CircularColoring" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/hdoj/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://acm.hdu.edu.cn/showproblem.php?pid=1000", 3 | "parser": "HDOJProblemParser", 4 | "result": { 5 | "name": "A + B Problem", 6 | "group": "HDOJ", 7 | "url": "https://acm.hdu.edu.cn/showproblem.php?pid=1000", 8 | "interactive": false, 9 | "memoryLimit": 65, 10 | "timeLimit": 2000, 11 | "tests": [ 12 | { 13 | "input": "1 1\n", 14 | "output": "2\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "ABProblem" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/hrbust-online-judge/problem/input-padding.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1000", 3 | "parser": "HrbustOnlineJudgeProblemParser", 4 | "result": { 5 | "name": "A + B Problem", 6 | "group": "Hrbust Online Judge", 7 | "url": "http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1000", 8 | "interactive": false, 9 | "memoryLimit": 65, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "1 2\n2 3\n", 14 | "output": "3\n5\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "ABProblem" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/hrbust-online-judge/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1054", 3 | "parser": "HrbustOnlineJudgeProblemParser", 4 | "result": { 5 | "name": "Brackets! Brackets!", 6 | "group": "Hrbust Online Judge", 7 | "url": "http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1054", 8 | "interactive": false, 9 | "memoryLimit": 65, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "2\n{{[[(())]]}}\n({[}])\n", 14 | "output": "Valid\nInvalid\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "BracketsBrackets" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/data/hydro/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://hydro.ac/p/H1000", 3 | "parser": "HydroProblemParser", 4 | "result": { 5 | "name": "#H1000. A + B Problem", 6 | "group": "Hydro", 7 | "url": "https://hydro.ac/p/H1000", 8 | "interactive": false, 9 | "memoryLimit": 1024, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "1 2\n", 14 | "output": "3\n" 15 | }, 16 | { 17 | "input": "3 4\n", 18 | "output": "7\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "H1000ABProblem" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/infoarena/problem/interactive-stdin-first.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.infoarena.ro/problema/cbinteractiv", 3 | "parser": "InfoArenaProblemParser", 4 | "result": { 5 | "name": "Cbinteractiv", 6 | "group": "InfoArena - ad-hoc", 7 | "url": "https://www.infoarena.ro/problema/cbinteractiv", 8 | "interactive": true, 9 | "memoryLimit": 128, 10 | "timeLimit": 200, 11 | "tests": [ 12 | { 13 | "input": "10\n1\n0\n", 14 | "output": "\n? 5\n? 4\n! 5\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "Cbinteractiv" 28 | } 29 | }, 30 | "batch": { 31 | "id": "3bb3bd4d-08c9-455b-b82b-43c6312db058", 32 | "size": 1 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/infoarena/problem/interactive-stdout-first.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.infoarena.ro/problema/interact", 3 | "parser": "InfoArenaProblemParser", 4 | "result": { 5 | "name": "Interact", 6 | "group": "InfoArena - FMI No Stress 8", 7 | "url": "https://www.infoarena.ro/problema/interact", 8 | "interactive": true, 9 | "memoryLimit": 256, 10 | "timeLimit": 500, 11 | "tests": [ 12 | { 13 | "input": "1\n0\n1\n1\n-1\n", 14 | "output": "? a\n? ba\n? ac\n? abc\n! abc\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "stdin" 20 | }, 21 | "output": { 22 | "type": "stdout" 23 | }, 24 | "languages": { 25 | "java": { 26 | "mainClass": "Main", 27 | "taskClass": "Interact" 28 | } 29 | }, 30 | "batch": { 31 | "id": "965f80d0-fdb6-45d2-9849-b976b6492ccc", 32 | "size": 1 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/infoarena/problem/multiple-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.infoarena.ro/problema/loto", 3 | "parser": "InfoArenaProblemParser", 4 | "result": { 5 | "name": "Loto", 6 | "group": "InfoArena - preONI 2004", 7 | "url": "https://www.infoarena.ro/problema/loto", 8 | "interactive": false, 9 | "memoryLimit": 64, 10 | "timeLimit": 90, 11 | "tests": [ 12 | { 13 | "input": "3 13\n1 2 3\n", 14 | "output": "1 1 2 3 3 3\n" 15 | }, 16 | { 17 | "input": "3 19\n1 2 3\n", 18 | "output": "-1\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "file", 24 | "fileName": "loto.in" 25 | }, 26 | "output": { 27 | "type": "file", 28 | "fileName": "loto.out" 29 | }, 30 | "languages": { 31 | "java": { 32 | "mainClass": "Main", 33 | "taskClass": "Loto" 34 | } 35 | }, 36 | "batch": { 37 | "id": "22892e9e-a5da-4cdd-8c84-198a57e9e9ee", 38 | "size": 1 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/data/infoarena/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://www.infoarena.ro/problema/biscuiti", 3 | "parser": "InfoArenaProblemParser", 4 | "result": { 5 | "name": "Biscuiti", 6 | "group": "InfoArena - info-arena 1.0", 7 | "url": "https://www.infoarena.ro/problema/biscuiti", 8 | "interactive": false, 9 | "memoryLimit": 64, 10 | "timeLimit": 175, 11 | "tests": [ 12 | { 13 | "input": "7\n9\n10\n6\n6\n4\n9\n8\n", 14 | "output": "36\n" 15 | } 16 | ], 17 | "testType": "single", 18 | "input": { 19 | "type": "file", 20 | "fileName": "biscuiti.in" 21 | }, 22 | "output": { 23 | "type": "file", 24 | "fileName": "biscuiti.out" 25 | }, 26 | "languages": { 27 | "java": { 28 | "mainClass": "Main", 29 | "taskClass": "Biscuiti" 30 | } 31 | }, 32 | "batch": { 33 | "id": "4d582d88-0997-4208-bdc8-64ea27493807", 34 | "size": 1 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/data/jutge/problem/interactive.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://jutge.org/problems/P75481_es", 3 | "parser": "JutgeProblemParser", 4 | "result": { 5 | "name": "Adivina un número (Interactivo)", 6 | "group": "Jutge", 7 | "url": "https://jutge.org/problems/P75481_es", 8 | "interactive": true, 9 | "memoryLimit": 1024, 10 | "timeLimit": 1000, 11 | "tests": [], 12 | "testType": "single", 13 | "input": { 14 | "type": "stdin" 15 | }, 16 | "output": { 17 | "type": "stdout" 18 | }, 19 | "languages": { 20 | "java": { 21 | "mainClass": "Main", 22 | "taskClass": "AdivinaUnNmeroInteractivo" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/data/jutge/problem/normal.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://jutge.org/problems/P14130_en", 3 | "parser": "JutgeProblemParser", 4 | "result": { 5 | "name": "Equal to the last one", 6 | "group": "Jutge", 7 | "url": "https://jutge.org/problems/P14130_en", 8 | "interactive": false, 9 | "memoryLimit": 1024, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "9\n1 7 3 2 4 7 5 8 7\n", 14 | "output": "2\n" 15 | }, 16 | { 17 | "input": "5\n-3 10 0 -2 7\n", 18 | "output": "0\n" 19 | } 20 | ], 21 | "testType": "single", 22 | "input": { 23 | "type": "stdin" 24 | }, 25 | "output": { 26 | "type": "stdout" 27 | }, 28 | "languages": { 29 | "java": { 30 | "mainClass": "Main", 31 | "taskClass": "EqualToTheLastOne" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/data/kattis/problem/interactive-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://open.kattis.com/problems/guess", 3 | "parser": "KattisProblemParser", 4 | "result": { 5 | "name": "Guess the Number", 6 | "group": "Kattis", 7 | "url": "https://open.kattis.com/problems/guess", 8 | "interactive": true, 9 | "memoryLimit": 1024, 10 | "timeLimit": 1000, 11 | "tests": [], 12 | "testType": "single", 13 | "input": { 14 | "type": "stdin" 15 | }, 16 | "output": { 17 | "type": "stdout" 18 | }, 19 | "languages": { 20 | "java": { 21 | "mainClass": "Main", 22 | "taskClass": "GuessTheNumber" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/data/kattis/problem/interactive-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://open.kattis.com/contests/nwerc2021open/problems/accessdenied", 3 | "parser": "KattisProblemParser", 4 | "result": { 5 | "name": "Problem A - Access Denied", 6 | "group": "Kattis - nwerc2021open", 7 | "url": "https://open.kattis.com/contests/nwerc2021open/problems/accessdenied", 8 | "interactive": true, 9 | "memoryLimit": 1024, 10 | "timeLimit": 2000, 11 | "tests": [], 12 | "testType": "single", 13 | "input": { 14 | "type": "stdin" 15 | }, 16 | "output": { 17 | "type": "stdout" 18 | }, 19 | "languages": { 20 | "java": { 21 | "mainClass": "Main", 22 | "taskClass": "ProblemAAccessDenied" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/data/kattis/problem/no-output.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://open.kattis.com/problems/backspace", 3 | "parser": "KattisProblemParser", 4 | "result": { 5 | "name": "Backspace", 6 | "group": "Kattis", 7 | "url": "https://open.kattis.com/problems/backspace", 8 | "interactive": false, 9 | "memoryLimit": 1024, 10 | "timeLimit": 1000, 11 | "tests": [ 12 | { 13 | "input": "a